MySQL协议分析
1 交互過(guò)程
MySQL客戶(hù)端與服務(wù)器的交互主要分為兩個(gè)階段:握手認(rèn)證階段和命令執(zhí)行階段。
1.1 握手認(rèn)證階段
握手認(rèn)證階段為客戶(hù)端與服務(wù)器建立連接后進(jìn)行,交互過(guò)程如下:
- 服務(wù)器 -> 客戶(hù)端:握手初始化消息
- 客戶(hù)端 -> 服務(wù)器:登陸認(rèn)證消息
- 服務(wù)器 -> 客戶(hù)端:認(rèn)證結(jié)果消息
1.2 命令執(zhí)行階段
客戶(hù)端認(rèn)證成功后,會(huì)進(jìn)入命令執(zhí)行階段,交互過(guò)程如下:
- 客戶(hù)端 -> 服務(wù)器:執(zhí)行命令消息
- 服務(wù)器 -> 客戶(hù)端:命令執(zhí)行結(jié)果
MySQL客戶(hù)端與服務(wù)器的完整交互過(guò)程如下:
2 基本類(lèi)型
2.1 整型值
MySQL報(bào)文中整型值分別有1、2、3、4、8字節(jié)長(zhǎng)度,使用小字節(jié)序傳輸。
2.2 字符串(以NULL結(jié)尾)(Null-Terminated String)
字符串長(zhǎng)度不固定,當(dāng)遇到'NULL'(0x00)字符時(shí)結(jié)束。
2.3 二進(jìn)制數(shù)據(jù)(長(zhǎng)度編碼)(Length Coded Binary)
數(shù)據(jù)長(zhǎng)度不固定,長(zhǎng)度值由數(shù)據(jù)前的1-9個(gè)字節(jié)決定,其中長(zhǎng)度值所占的字節(jié)數(shù)不定,字節(jié)數(shù)由第1個(gè)字節(jié)決定,如下表:
| 0-250 | 0 | 第一個(gè)字節(jié)值即為數(shù)據(jù)的真實(shí)長(zhǎng)度 |
| 251 | 0 | 空數(shù)據(jù),數(shù)據(jù)的真實(shí)長(zhǎng)度為零 |
| 252 | 2 | 后續(xù)額外2個(gè)字節(jié)標(biāo)識(shí)了數(shù)據(jù)的真實(shí)長(zhǎng)度 |
| 253 | 3 | 后續(xù)額外3個(gè)字節(jié)標(biāo)識(shí)了數(shù)據(jù)的真實(shí)長(zhǎng)度 |
| 254 | 8 | 后續(xù)額外8個(gè)字節(jié)標(biāo)識(shí)了數(shù)據(jù)的真實(shí)長(zhǎng)度 |
2.4 字符串(長(zhǎng)度編碼)(Length Coded String)
字符串長(zhǎng)度不固定,無(wú)'NULL'(0x00)結(jié)束符,編碼方式與上面的 Length Coded Binary 相同。
3 報(bào)文結(jié)構(gòu)
報(bào)文分為消息頭和消息體兩部分,其中消息頭占用固定的4個(gè)字節(jié),消息體長(zhǎng)度由消息頭中的長(zhǎng)度字段決定,報(bào)文結(jié)構(gòu)如下:
3.1 消息頭
3.1.1 報(bào)文長(zhǎng)度
用于標(biāo)記當(dāng)前請(qǐng)求消息的實(shí)際數(shù)據(jù)長(zhǎng)度值,以字節(jié)為單位,占用3個(gè)字節(jié),最大值為 0xFFFFFF,即接近 16 MB 大小(比16MB少1個(gè)字節(jié))。
3.1.2 序號(hào)
在一次完整的請(qǐng)求/響應(yīng)交互過(guò)程中,用于保證消息順序的正確,每次客戶(hù)端發(fā)起請(qǐng)求時(shí),序號(hào)值都會(huì)從0開(kāi)始計(jì)算。
3.2 消息體
消息體用于存放請(qǐng)求的內(nèi)容及響應(yīng)的數(shù)據(jù),長(zhǎng)度由消息頭中的長(zhǎng)度值決定。
4 報(bào)文類(lèi)型
4.1 登陸認(rèn)證交互報(bào)文
4.1.1 握手初始化報(bào)文(服務(wù)器 -> 客戶(hù)端)
服務(wù)協(xié)議版本號(hào):該值由 PROTOCOL_VERSION 宏定義決定(參考MySQL源代碼/include/mysql_version.h頭文件定義)
服務(wù)版本信息:該值為字符串,由 MYSQL_SERVER_VERSION 宏定義決定(參考MySQL源代碼/include/mysql_version.h頭文件定義)
服務(wù)器線(xiàn)程ID:服務(wù)器為當(dāng)前連接所創(chuàng)建的線(xiàn)程ID。
挑戰(zhàn)隨機(jī)數(shù):MySQL數(shù)據(jù)庫(kù)用戶(hù)認(rèn)證采用的是挑戰(zhàn)/應(yīng)答的方式,服務(wù)器生成該挑戰(zhàn)數(shù)并發(fā)送給客戶(hù)端,由客戶(hù)端進(jìn)行處理并返回相應(yīng)結(jié)果,然后服務(wù)器檢查是否與預(yù)期的結(jié)果相同,從而完成用戶(hù)認(rèn)證的過(guò)程。
服務(wù)器權(quán)能標(biāo)志:用于與客戶(hù)端協(xié)商通訊方式,各標(biāo)志位含義如下(參考MySQL源代碼/include/mysql_com.h中的宏定義):
| CLIENT_LONG_PASSWORD | 0x0001 | new more secure passwords |
| CLIENT_FOUND_ROWS | 0x0002 | Found instead of affected rows |
| CLIENT_LONG_FLAG | 0x0004 | Get all column flags |
| CLIENT_CONNECT_WITH_DB | 0x0008 | One can specify db on connect |
| CLIENT_NO_SCHEMA | 0x0010 | Do not allow database.table.column |
| CLIENT_COMPRESS | 0x0020 | Can use compression protocol |
| CLIENT_ODBC | 0x0040 | Odbc client |
| CLIENT_LOCAL_FILES | 0x0080 | Can use LOAD DATA LOCAL |
| CLIENT_IGNORE_SPACE | 0x0100 | Ignore spaces before '(' |
| CLIENT_PROTOCOL_41 | 0x0200 | New 4.1 protocol |
| CLIENT_INTERACTIVE | 0x0400 | This is an interactive client |
| CLIENT_SSL | 0x0800 | Switch to SSL after handshake |
| CLIENT_IGNORE_SIGPIPE | 0x1000 | IGNORE sigpipes |
| CLIENT_TRANSACTIONS | 0x2000 | Client knows about transactions |
| CLIENT_RESERVED | 0x4000 | Old flag for 4.1 protocol |
| CLIENT_SECURE_CONNECTION | 0x8000 | New 4.1 authentication |
| CLIENT_MULTI_STATEMENTS | 0x0001 0000 | Enable/disable multi-stmt support |
| CLIENT_MULTI_RESULTS | 0x0002 0000 | Enable/disable multi-results |
字符編碼:標(biāo)識(shí)服務(wù)器所使用的字符集。
服務(wù)器狀態(tài):狀態(tài)值定義如下(參考MySQL源代碼/include/mysql_com.h中的宏定義):
| SERVER_STATUS_IN_TRANS | 0x0001 |
| SERVER_STATUS_AUTOCOMMIT | 0x0002 |
| SERVER_STATUS_CURSOR_EXISTS | 0x0040 |
| SERVER_STATUS_LAST_ROW_SENT | 0x0080 |
| SERVER_STATUS_DB_DROPPED | 0x0100 |
| SERVER_STATUS_NO_BACKSLASH_ESCAPES | 0x0200 |
| SERVER_STATUS_METADATA_CHANGED | 0x0400 |
4.1.2 登陸認(rèn)證報(bào)文(客戶(hù)端 -> 服務(wù)器)
MySQL 4.0 及之前的版本
MySQL 4.1 及之后的版本
客戶(hù)端權(quán)能標(biāo)志:用于與客戶(hù)端協(xié)商通訊方式,標(biāo)志位含義與握手初始化報(bào)文中的相同。客戶(hù)端收到服務(wù)器發(fā)來(lái)的初始化報(bào)文后,會(huì)對(duì)服務(wù)器發(fā)送的權(quán)能標(biāo)志進(jìn)行修改,保留自身所支持的功能,然后將權(quán)能標(biāo)返回給服務(wù)器,從而保證服務(wù)器與客戶(hù)端通訊的兼容性。
最大消息長(zhǎng)度:客戶(hù)端發(fā)送請(qǐng)求報(bào)文時(shí)所支持的最大消息長(zhǎng)度值。
字符編碼:標(biāo)識(shí)通訊過(guò)程中使用的字符編碼,與服務(wù)器在認(rèn)證初始化報(bào)文中發(fā)送的相同。
用戶(hù)名:客戶(hù)端登陸用戶(hù)的用戶(hù)名稱(chēng)。
挑戰(zhàn)認(rèn)證數(shù)據(jù):客戶(hù)端用戶(hù)密碼使用服務(wù)器發(fā)送的挑戰(zhàn)隨機(jī)數(shù)進(jìn)行加密后,生成挑戰(zhàn)認(rèn)證數(shù)據(jù),然后返回給服務(wù)器,用于對(duì)用戶(hù)身份的認(rèn)證。
數(shù)據(jù)庫(kù)名稱(chēng):當(dāng)客戶(hù)端的權(quán)能標(biāo)志位 CLIENT_CONNECT_WITH_DB 被置位時(shí),該字段必須出現(xiàn)。
4.2 客戶(hù)端命令請(qǐng)求報(bào)文(客戶(hù)端 -> 服務(wù)器)
命令:用于標(biāo)識(shí)當(dāng)前請(qǐng)求消息的類(lèi)型,例如切換數(shù)據(jù)庫(kù)(0x02)、查詢(xún)命令(0x03)等。命令值的取值范圍及說(shuō)明如下表(參考MySQL源代碼/include/mysql_com.h頭文件中的定義):
| 0x00 | COM_SLEEP | (內(nèi)部線(xiàn)程狀態(tài)) | (無(wú)) |
| 0x01 | COM_QUIT | 關(guān)閉連接 | mysql_close |
| 0x02 | COM_INIT_DB | 切換數(shù)據(jù)庫(kù) | mysql_select_db |
| 0x03 | COM_QUERY | SQL查詢(xún)請(qǐng)求 | mysql_real_query |
| 0x04 | COM_FIELD_LIST | 獲取數(shù)據(jù)表字段信息 | mysql_list_fields |
| 0x05 | COM_CREATE_DB | 創(chuàng)建數(shù)據(jù)庫(kù) | mysql_create_db |
| 0x06 | COM_DROP_DB | 刪除數(shù)據(jù)庫(kù) | mysql_drop_db |
| 0x07 | COM_REFRESH | 清除緩存 | mysql_refresh |
| 0x08 | COM_SHUTDOWN | 停止服務(wù)器 | mysql_shutdown |
| 0x09 | COM_STATISTICS | 獲取服務(wù)器統(tǒng)計(jì)信息 | mysql_stat |
| 0x0A | COM_PROCESS_INFO | 獲取當(dāng)前連接的列表 | mysql_list_processes |
| 0x0B | COM_CONNECT | (內(nèi)部線(xiàn)程狀態(tài)) | (無(wú)) |
| 0x0C | COM_PROCESS_KILL | 中斷某個(gè)連接 | mysql_kill |
| 0x0D | COM_DEBUG | 保存服務(wù)器調(diào)試信息 | mysql_dump_debug_info |
| 0x0E | COM_PING | 測(cè)試連通性 | mysql_ping |
| 0x0F | COM_TIME | (內(nèi)部線(xiàn)程狀態(tài)) | (無(wú)) |
| 0x10 | COM_DELAYED_INSERT | (內(nèi)部線(xiàn)程狀態(tài)) | (無(wú)) |
| 0x11 | COM_CHANGE_USER | 重新登陸(不斷連接) | mysql_change_user |
| 0x12 | COM_BINLOG_DUMP | 獲取二進(jìn)制日志信息 | (無(wú)) |
| 0x13 | COM_TABLE_DUMP | 獲取數(shù)據(jù)表結(jié)構(gòu)信息 | (無(wú)) |
| 0x14 | COM_CONNECT_OUT | (內(nèi)部線(xiàn)程狀態(tài)) | (無(wú)) |
| 0x15 | COM_REGISTER_SLAVE | 從服務(wù)器向主服務(wù)器進(jìn)行注冊(cè) | (無(wú)) |
| 0x16 | COM_STMT_PREPARE | 預(yù)處理SQL語(yǔ)句 | mysql_stmt_prepare |
| 0x17 | COM_STMT_EXECUTE | 執(zhí)行預(yù)處理語(yǔ)句 | mysql_stmt_execute |
| 0x18 | COM_STMT_SEND_LONG_DATA | 發(fā)送BLOB類(lèi)型的數(shù)據(jù) | mysql_stmt_send_long_data |
| 0x19 | COM_STMT_CLOSE | 銷(xiāo)毀預(yù)處理語(yǔ)句 | mysql_stmt_close |
| 0x1A | COM_STMT_RESET | 清除預(yù)處理語(yǔ)句參數(shù)緩存 | mysql_stmt_reset |
| 0x1B | COM_SET_OPTION | 設(shè)置語(yǔ)句選項(xiàng) | mysql_set_server_option |
| 0x1C | COM_STMT_FETCH | 獲取預(yù)處理語(yǔ)句的執(zhí)行結(jié)果 | mysql_stmt_fetch |
參數(shù):內(nèi)容是用戶(hù)在MySQL客戶(hù)端輸入的命令(不包括每行命令結(jié)尾的";"分號(hào))。另外這個(gè)字段的字符串不是以NULL字符結(jié)尾,而是通過(guò)消息頭中的長(zhǎng)度值計(jì)算而來(lái)。
例如:當(dāng)我們?cè)贛ySQL客戶(hù)端中執(zhí)行use hutaow;命令時(shí)(切換到hutaow數(shù)據(jù)庫(kù)),發(fā)送的請(qǐng)求報(bào)文數(shù)據(jù)會(huì)是下面的樣子:
0x02 0x68 0x75 0x74 0x61 0x6f 0x77其中,0x02為請(qǐng)求類(lèi)型值COM_INIT_DB,后面的0x68 0x75 0x74 0x61 0x6f 0x77為ASCII字符hutaow。
4.2.1 COM_QUIT 消息報(bào)文
功能:關(guān)閉當(dāng)前連接(客戶(hù)端退出),無(wú)參數(shù)。
4.2.2 COM_INIT_DB 消息報(bào)文
功能:切換數(shù)據(jù)庫(kù),對(duì)應(yīng)的SQL語(yǔ)句為USE <database>。
| n | 數(shù)據(jù)庫(kù)名稱(chēng)(字符串到達(dá)消息尾部時(shí)結(jié)束,無(wú)結(jié)束符) |
4.2.3 COM_QUERY 消息報(bào)文
功能:最常見(jiàn)的請(qǐng)求消息類(lèi)型,當(dāng)用戶(hù)執(zhí)行SQL語(yǔ)句時(shí)發(fā)送該消息。
| n | SQL語(yǔ)句(字符串到達(dá)消息尾部時(shí)結(jié)束,無(wú)結(jié)束符) |
4.2.4 COM_FIELD_LIST 消息報(bào)文
功能:查詢(xún)某表的字段(列)信息,等同于SQL語(yǔ)句SHOW [FULL] FIELDS FROM ...。
| n | 表格名稱(chēng)(Null-Terminated String) |
| n | 字段(列)名稱(chēng)或通配符(可選) |
4.2.5 COM_CREATE_DB 消息報(bào)文
功能:創(chuàng)建數(shù)據(jù)庫(kù),該消息已過(guò)時(shí),而被SQL語(yǔ)句CREATE DATABASE代替。
| n | 數(shù)據(jù)庫(kù)名稱(chēng)(字符串到達(dá)消息尾部時(shí)結(jié)束,無(wú)結(jié)束符) |
4.2.6 COM_DROP_DB 消息報(bào)文
功能:刪除數(shù)據(jù)庫(kù),該消息已過(guò)時(shí),而被SQL語(yǔ)句DROP DATABASE代替。
| n | 數(shù)據(jù)庫(kù)名稱(chēng)(字符串到達(dá)消息尾部時(shí)結(jié)束,無(wú)結(jié)束符) |
4.2.7 COM_REFRESH 消息報(bào)文
功能:清除緩存,等同于SQL語(yǔ)句FLUSH,或是執(zhí)行mysqladmin flush-foo命令時(shí)發(fā)送該消息。
| 1 | 清除緩存選項(xiàng)(位圖方式存儲(chǔ),各標(biāo)志位含義如下) |
| ? | 0x01: REFRESH_GRANT |
| ? | 0x02: REFRESH_LOG |
| ? | 0x04: REFRESH_TABLES |
| ? | 0x08: REFRESH_HOSTS |
| ? | 0x10: REFRESH_STATUS |
| ? | 0x20: REFRESH_THREADS |
| ? | 0x40: REFRESH_SLAVE |
| ? | 0x80: REFRESH_MASTER |
4.2.8 COM_SHUTDOWN 消息報(bào)文
功能:停止MySQL服務(wù)。執(zhí)行mysqladmin shutdown命令時(shí)發(fā)送該消息。
| 1 | 停止服務(wù)選項(xiàng) |
| ? | 0x00: SHUTDOWN_DEFAULT |
| ? | 0x01: SHUTDOWN_WAIT_CONNECTIONS |
| ? | 0x02: SHUTDOWN_WAIT_TRANSACTIONS |
| ? | 0x08: SHUTDOWN_WAIT_UPDATES |
| ? | 0x10: SHUTDOWN_WAIT_ALL_BUFFERS |
| ? | 0x11: SHUTDOWN_WAIT_CRITICAL_BUFFERS |
| ? | 0xFE: KILL_QUERY |
| ? | 0xFF: KILL_CONNECTION |
4.2.9 COM_STATISTICS 消息報(bào)文
功能:查看MySQL服務(wù)的統(tǒng)計(jì)信息(例如運(yùn)行時(shí)間、每秒查詢(xún)次數(shù)等)。執(zhí)行mysqladmin status命令時(shí)發(fā)送該消息,無(wú)參數(shù)。
4.2.10 COM_PROCESS_INFO 消息報(bào)文
功能:獲取當(dāng)前活動(dòng)的線(xiàn)程(連接)列表。等同于SQL語(yǔ)句SHOW PROCESSLIST,或是執(zhí)行mysqladmin processlist命令時(shí)發(fā)送該消息,無(wú)參數(shù)。
4.2.11 COM_PROCESS_KILL 消息報(bào)文
功能:要求服務(wù)器中斷某個(gè)連接。等同于SQL語(yǔ)句KILL <id>。
| 4 | 連接ID號(hào)(小字節(jié)序) |
4.2.12 COM_DEBUG 消息報(bào)文
功能:要求服務(wù)器將調(diào)試信息保存下來(lái),保存的信息多少依賴(lài)于編譯選項(xiàng)設(shè)置(debug=no|yes|full)。執(zhí)行mysqladmin debug命令時(shí)發(fā)送該消息,無(wú)參數(shù)。
4.2.13 COM_PING 消息報(bào)文
功能:該消息用來(lái)測(cè)試連通性,同時(shí)會(huì)將服務(wù)器的無(wú)效連接(超時(shí))計(jì)數(shù)器清零。執(zhí)行mysqladmin ping命令時(shí)發(fā)送該消息,無(wú)參數(shù)。
4.2.14 COM_CHANGE_USER 消息報(bào)文
功能:在不斷連接的情況下重新登陸,該操作會(huì)銷(xiāo)毀MySQL服務(wù)器端的會(huì)話(huà)上下文(包括臨時(shí)表、會(huì)話(huà)變量等)。有些連接池用這種方法實(shí)現(xiàn)清除會(huì)話(huà)上下文。
| n | 用戶(hù)名(字符串以NULL結(jié)尾) |
| n | 密碼(挑戰(zhàn)數(shù)) |
| ? | MySQL 3.23 版本:Null-Terminated String(長(zhǎng)度9字節(jié)) |
| ? | MySQL 4.1 版本:Length Coded String(長(zhǎng)度1+21字節(jié)) |
| n | 數(shù)據(jù)庫(kù)名稱(chēng)(Null-Terminated String) |
| 2 | 字符編碼 |
4.2.15 COM_BINLOG_DUMP 消息報(bào)文
功能:該消息是備份連接時(shí)由從服務(wù)器向主服務(wù)器發(fā)送的最后一個(gè)請(qǐng)求,主服務(wù)器收到后,會(huì)響應(yīng)一系列的報(bào)文,每個(gè)報(bào)文都包含一個(gè)二進(jìn)制日志事件。如果主服務(wù)器出現(xiàn)故障時(shí),會(huì)發(fā)送一個(gè)EOF報(bào)文。
| 4 | 二進(jìn)制日志數(shù)據(jù)的起始位置(小字節(jié)序) |
| 4 | 二進(jìn)制日志數(shù)據(jù)標(biāo)志位(目前未使用,永遠(yuǎn)為0x00) |
| 4 | 從服務(wù)器的服務(wù)器ID值(小字節(jié)序) |
| n | 二進(jìn)制日志的文件名稱(chēng)(可選,默認(rèn)值為主服務(wù)器上第一個(gè)有效的文件名) |
4.2.16 COM_TABLE_DUMP 消息報(bào)文
功能:將數(shù)據(jù)表從主服務(wù)器復(fù)制到從服務(wù)器中,執(zhí)行SQL語(yǔ)句LOAD TABLE ... FROM MASTER時(shí)發(fā)送該消息。目前該消息已過(guò)時(shí),不再使用。
| n | 數(shù)據(jù)庫(kù)名稱(chēng)(Length Coded String) |
| n | 數(shù)據(jù)表名稱(chēng)(Length Coded String) |
4.2.17 COM_REGISTER_SLAVE 消息報(bào)文
功能:在從服務(wù)器report_host變量設(shè)置的情況下,當(dāng)備份連接時(shí)向主服務(wù)器發(fā)送的注冊(cè)消息。
| 4 | 從服務(wù)器ID值(小字節(jié)序) |
| n | 主服務(wù)器IP地址(Length Coded String) |
| n | 主服務(wù)器用戶(hù)名(Length Coded String) |
| n | 主服務(wù)器密碼(Length Coded String) |
| 2 | 主服務(wù)器端口號(hào) |
| 4 | 安全備份級(jí)別(由MySQL服務(wù)器rpl_recovery_rank變量設(shè)置,暫時(shí)未使用) |
| 4 | 主服務(wù)器ID值(值恒為0x00) |
4.2.18 COM_PREPARE 消息報(bào)文
功能:預(yù)處理SQL語(yǔ)句,使用帶有"?"占位符的SQL語(yǔ)句時(shí)發(fā)送該消息。
| n | 帶有"?"占位符的SQL語(yǔ)句(字符串到達(dá)消息尾部時(shí)結(jié)束,無(wú)結(jié)束符) |
4.2.19 COM_EXECUTE 消息報(bào)文
功能:執(zhí)行預(yù)處理語(yǔ)句。
| 4 | 預(yù)處理語(yǔ)句的ID值 |
| 1 | 標(biāo)志位 |
| ? | 0x00: CURSOR_TYPE_NO_CURSOR |
| ? | 0x01: CURSOR_TYPE_READ_ONLY |
| ? | 0x02: CURSOR_TYPE_FOR_UPDATE |
| ? | 0x04: CURSOR_TYPE_SCROLLABLE |
| 4 | 保留(值恒為0x01) |
| 如果參數(shù)數(shù)量大于0 | ? |
| n | 空位圖(Null-Bitmap,長(zhǎng)度 = (參數(shù)數(shù)量 + 7) / 8 字節(jié)) |
| 1 | 參數(shù)分隔標(biāo)志 |
| 如果參數(shù)分隔標(biāo)志值為1 | ? |
| n | 每個(gè)參數(shù)的類(lèi)型值(長(zhǎng)度 = 參數(shù)數(shù)量 * 2 字節(jié)) |
| n | 每個(gè)參數(shù)的值 |
4.2.20 COM_LONG_DATA 消息報(bào)文
該消息報(bào)文有兩種形式,一種用于發(fā)送二進(jìn)制數(shù)據(jù),另一種用于發(fā)送文本數(shù)據(jù)。
功能:用于發(fā)送二進(jìn)制(BLOB)類(lèi)型的數(shù)據(jù)(調(diào)用mysql_stmt_send_long_data函數(shù))。
| 4 | 預(yù)處理語(yǔ)句的ID值(小字節(jié)序) |
| 2 | 參數(shù)序號(hào)(小字節(jié)序) |
| n | 數(shù)據(jù)負(fù)載(數(shù)據(jù)到達(dá)消息尾部時(shí)結(jié)束,無(wú)結(jié)束符) |
功能:用于發(fā)送超長(zhǎng)字符串類(lèi)型的數(shù)據(jù)(調(diào)用mysql_send_long_data函數(shù))
| 4 | 預(yù)處理語(yǔ)句的ID值(小字節(jié)序) |
| 2 | 參數(shù)序號(hào)(小字節(jié)序) |
| 2 | 數(shù)據(jù)類(lèi)型(未使用) |
| n | 數(shù)據(jù)負(fù)載(數(shù)據(jù)到達(dá)消息尾部時(shí)結(jié)束,無(wú)結(jié)束符) |
4.2.21 COM_CLOSE_STMT 消息報(bào)文
功能:銷(xiāo)毀預(yù)處理語(yǔ)句。
| 4 | 預(yù)處理語(yǔ)句的ID值(小字節(jié)序) |
4.2.22 COM_RESET_STMT 消息報(bào)文
功能:將預(yù)處理語(yǔ)句的參數(shù)緩存清空。多數(shù)情況和COM_LONG_DATA一起使用。
| 4 | 預(yù)處理語(yǔ)句的ID值(小字節(jié)序) |
4.2.23 COM_SET_OPTION 消息報(bào)文
功能:設(shè)置語(yǔ)句選項(xiàng),選項(xiàng)值為/include/mysql_com.h頭文件中定義的enum_mysql_set_option枚舉類(lèi)型:
- MYSQL_OPTION_MULTI_STATEMENTS_ON
- MYSQL_OPTION_MULTI_STATEMENTS_OFF
| 2 | 選項(xiàng)值(小字節(jié)序) |
4.2.24 COM_FETCH_STMT 消息報(bào)文
功能:獲取預(yù)處理語(yǔ)句的執(zhí)行結(jié)果(一次可以獲取多行數(shù)據(jù))。
| 4 | 預(yù)處理語(yǔ)句的ID值(小字節(jié)序) |
| 4 | 數(shù)據(jù)的行數(shù)(小字節(jié)序) |
4.3 服務(wù)器響應(yīng)報(bào)文(服務(wù)器 -> 客戶(hù)端)
當(dāng)客戶(hù)端發(fā)起認(rèn)證請(qǐng)求或命令請(qǐng)求后,服務(wù)器會(huì)返回相應(yīng)的執(zhí)行結(jié)果給客戶(hù)端。客戶(hù)端在收到響應(yīng)報(bào)文后,需要首先檢查第1個(gè)字節(jié)的值,來(lái)區(qū)分響應(yīng)報(bào)文的類(lèi)型。
| OK 響應(yīng)報(bào)文 | 0x00 |
| Error 響應(yīng)報(bào)文 | 0xFF |
| Result Set 報(bào)文 | 0x01 - 0xFA |
| Field 報(bào)文 | 0x01 - 0xFA |
| Row Data 報(bào)文 | 0x01 - 0xFA |
| EOF 報(bào)文 | 0xFE |
注:響應(yīng)報(bào)文的第1個(gè)字節(jié)在不同類(lèi)型中含義不同,比如在OK報(bào)文中,該字節(jié)并沒(méi)有實(shí)際意義,值恒為0x00;而在Result Set報(bào)文中,該字節(jié)又是長(zhǎng)度編碼的二進(jìn)制數(shù)據(jù)結(jié)構(gòu)(Length Coded Binary)中的第1字節(jié)。
4.3.1 OK 響應(yīng)報(bào)文
客戶(hù)端的命令執(zhí)行正確時(shí),服務(wù)器會(huì)返回OK響應(yīng)報(bào)文。
MySQL 4.0 及之前的版本
| 1 | OK報(bào)文,值恒為0x00 |
| 1-9 | 受影響行數(shù)(Length Coded Binary) |
| 1-9 | 索引ID值(Length Coded Binary) |
| 2 | 服務(wù)器狀態(tài) |
| n | 服務(wù)器消息(字符串到達(dá)消息尾部時(shí)結(jié)束,無(wú)結(jié)束符) |
MySQL 4.1 及之后的版本
| 1 | OK報(bào)文,值恒為0x00 |
| 1-9 | 受影響行數(shù)(Length Coded Binary) |
| 1-9 | 索引ID值(Length Coded Binary) |
| 2 | 服務(wù)器狀態(tài) |
| 2 | 告警計(jì)數(shù) |
| n | 服務(wù)器消息(字符串到達(dá)消息尾部時(shí)結(jié)束,無(wú)結(jié)束符,可選) |
受影響行數(shù):當(dāng)執(zhí)行INSERT/UPDATE/DELETE語(yǔ)句時(shí)所影響的數(shù)據(jù)行數(shù)。
索引ID值:該值為AUTO_INCREMENT索引字段生成,如果沒(méi)有索引字段,則為0x00。注意:當(dāng)INSERT插入語(yǔ)句為多行數(shù)據(jù)時(shí),該索引ID值為第一個(gè)插入的數(shù)據(jù)行索引值,而非最后一個(gè)。
服務(wù)器狀態(tài):客戶(hù)端可以通過(guò)該值檢查命令是否在事務(wù)處理中。
告警計(jì)數(shù):告警發(fā)生的次數(shù)。
服務(wù)器消息:服務(wù)器返回給客戶(hù)端的消息,一般為簡(jiǎn)單的描述性字符串,可選字段。
4.3.2 Error 響應(yīng)報(bào)文
MySQL 4.0 及之前的版本
| 1 | Error報(bào)文,值恒為0xFF |
| 2 | 錯(cuò)誤編號(hào)(小字節(jié)序) |
| n | 服務(wù)器消息 |
MySQL 4.1 及之后的版本
| 1 | Error報(bào)文,值恒為0xFF |
| 2 | 錯(cuò)誤編號(hào)(小字節(jié)序) |
| 1 | 服務(wù)器狀態(tài)標(biāo)志,恒為'#'字符 |
| 5 | 服務(wù)器狀態(tài)(5個(gè)字符) |
| n | 服務(wù)器消息 |
錯(cuò)誤編號(hào):錯(cuò)誤編號(hào)值定義在源代碼/include/mysqld_error.h頭文件中。
服務(wù)器狀態(tài):服務(wù)器將錯(cuò)誤編號(hào)通過(guò)mysql_errno_to_sqlstate函數(shù)轉(zhuǎn)換為狀態(tài)值,狀態(tài)值由5字節(jié)的ASCII字符組成,定義在源代碼/include/sql_state.h頭文件中。
服務(wù)器消息:錯(cuò)誤消息字符串到達(dá)消息尾時(shí)結(jié)束,長(zhǎng)度可以由消息頭中的長(zhǎng)度值計(jì)算得出。消息長(zhǎng)度為0-512字節(jié)。
4.3.3 Result Set 消息
當(dāng)客戶(hù)端發(fā)送查詢(xún)請(qǐng)求后,在沒(méi)有錯(cuò)誤的情況下,服務(wù)器會(huì)返回結(jié)果集(Result Set)給客戶(hù)端。
Result Set 消息分為五部分,結(jié)構(gòu)如下:
| [Result Set Header] | 列數(shù)量 |
| [Field] | 列信息(多個(gè)) |
| [EOF] | 列結(jié)束 |
| [Row Data] | 行數(shù)據(jù)(多個(gè)) |
| [EOF] | 數(shù)據(jù)結(jié)束 |
4.3.4 Result Set Header 結(jié)構(gòu)
| 1-9 | Field結(jié)構(gòu)計(jì)數(shù)(Length Coded Binary) |
| 1-9 | 額外信息(Length Coded Binary) |
Field結(jié)構(gòu)計(jì)數(shù):用于標(biāo)識(shí)Field結(jié)構(gòu)的數(shù)量,取值范圍0x00-0xFA。
額外信息:可選字段,一般情況下不應(yīng)該出現(xiàn)。只有像SHOW COLUMNS這種語(yǔ)句的執(zhí)行結(jié)果才會(huì)用到額外信息(標(biāo)識(shí)表格的列數(shù)量)。
4.3.5 Field 結(jié)構(gòu)
Field為數(shù)據(jù)表的列信息,在Result Set中,Field會(huì)連續(xù)出現(xiàn)多次,次數(shù)由Result Set Header結(jié)構(gòu)中的IField結(jié)構(gòu)計(jì)數(shù)值決定。
MySQL 4.0 及之前的版本
| n | 數(shù)據(jù)表名稱(chēng)(Length Coded String) |
| n | 列(字段)名稱(chēng)(Length Coded String) |
| 4 | 列(字段)長(zhǎng)度(Length Coded String) |
| 2 | 列(字段)類(lèi)型(Length Coded String) |
| 2 | 列(字段)標(biāo)志(Length Coded String) |
| 1 | 整型值精度 |
| n | 默認(rèn)值(Length Coded String) |
MySQL 4.1 及之后的版本
| n | 目錄名稱(chēng)(Length Coded String) |
| n | 數(shù)據(jù)庫(kù)名稱(chēng)(Length Coded String) |
| n | 數(shù)據(jù)表名稱(chēng)(Length Coded String) |
| n | 數(shù)據(jù)表原始名稱(chēng)(Length Coded String) |
| n | 列(字段)名稱(chēng)(Length Coded String) |
| 4 | 列(字段)原始名稱(chēng)(Length Coded String) |
| 1 | 填充值 |
| 2 | 字符編碼 |
| 4 | 列(字段)長(zhǎng)度 |
| 1 | 列(字段)類(lèi)型 |
| 2 | 列(字段)標(biāo)志 |
| 1 | 整型值精度 |
| 2 | 填充值(0x00) |
| n | 默認(rèn)值(Length Coded String) |
目錄名稱(chēng):在4.1及之后的版本中,該字段值為"def"。
數(shù)據(jù)庫(kù)名稱(chēng):數(shù)據(jù)庫(kù)名稱(chēng)標(biāo)識(shí)。
數(shù)據(jù)表名稱(chēng):數(shù)據(jù)表的別名(AS之后的名稱(chēng))。
數(shù)據(jù)表原始名稱(chēng):數(shù)據(jù)表的原始名稱(chēng)(AS之前的名稱(chēng))。
列(字段)名稱(chēng):列(字段)的別名(AS之后的名稱(chēng))。
列(字段)原始名稱(chēng):列(字段)的原始名稱(chēng)(AS之前的名稱(chēng))。
字符編碼:列(字段)的字符編碼值。
列(字段)長(zhǎng)度:列(字段)的長(zhǎng)度值,真實(shí)長(zhǎng)度可能小于該值,例如VARCHAR(2)類(lèi)型的字段實(shí)際只能存儲(chǔ)1個(gè)字符。
列(字段)類(lèi)型:列(字段)的類(lèi)型值,取值范圍如下(參考源代碼/include/mysql_com.h頭文件中的enum_field_type枚舉類(lèi)型定義):
| 0x00 | FIELD_TYPE_DECIMAL |
| 0x01 | FIELD_TYPE_TINY |
| 0x02 | FIELD_TYPE_SHORT |
| 0x03 | FIELD_TYPE_LONG |
| 0x04 | FIELD_TYPE_FLOAT |
| 0x05 | FIELD_TYPE_DOUBLE |
| 0x06 | FIELD_TYPE_NULL |
| 0x07 | FIELD_TYPE_TIMESTAMP |
| 0x08 | FIELD_TYPE_LONGLONG |
| 0x09 | FIELD_TYPE_INT24 |
| 0x0A | FIELD_TYPE_DATE |
| 0x0B | FIELD_TYPE_TIME |
| 0x0C | FIELD_TYPE_DATETIME |
| 0x0D | FIELD_TYPE_YEAR |
| 0x0E | FIELD_TYPE_NEWDATE |
| 0x0F | FIELD_TYPE_VARCHAR (new in MySQL 5.0) |
| 0x10 | FIELD_TYPE_BIT (new in MySQL 5.0) |
| 0xF6 | FIELD_TYPE_NEWDECIMAL (new in MYSQL 5.0) |
| 0xF7 | FIELD_TYPE_ENUM |
| 0xF8 | FIELD_TYPE_SET |
| 0xF9 | FIELD_TYPE_TINY_BLOB |
| 0xFA | FIELD_TYPE_MEDIUM_BLOB |
| 0xFB | FIELD_TYPE_LONG_BLOB |
| 0xFC | FIELD_TYPE_BLOB |
| 0xFD | FIELD_TYPE_VAR_STRING |
| 0xFE | FIELD_TYPE_STRING |
| 0xFF | FIELD_TYPE_GEOMETRY |
列(字段)標(biāo)志:各標(biāo)志位定義如下(參考源代碼/include/mysql_com.h頭文件中的宏定義):
| 0x0001 | NOT_NULL_FLAG |
| 0x0002 | PRI_KEY_FLAG |
| 0x0004 | UNIQUE_KEY_FLAG |
| 0x0008 | MULTIPLE_KEY_FLAG |
| 0x0010 | BLOB_FLAG |
| 0x0020 | UNSIGNED_FLAG |
| 0x0040 | ZEROFILL_FLAG |
| 0x0080 | BINARY_FLAG |
| 0x0100 | ENUM_FLAG |
| 0x0200 | AUTO_INCREMENT_FLAG |
| 0x0400 | TIMESTAMP_FLAG |
| 0x0800 | SET_FLAG |
數(shù)值精度:該字段對(duì)DECIMAL和NUMERIC類(lèi)型的數(shù)值字段有效,用于標(biāo)識(shí)數(shù)值的精度(小數(shù)點(diǎn)位置)。
默認(rèn)值:該字段用在數(shù)據(jù)表定義中,普通的查詢(xún)結(jié)果中不會(huì)出現(xiàn)。
附:Field結(jié)構(gòu)的相關(guān)處理函數(shù):
- 客戶(hù)端:/client/client.c源文件中的unpack_fields函數(shù)
- 服務(wù)器:/sql/sql_base.cc源文件中的send_fields函數(shù)
4.3.6 EOF 結(jié)構(gòu)
EOF結(jié)構(gòu)用于標(biāo)識(shí)Field和Row Data的結(jié)束,在預(yù)處理語(yǔ)句中,EOF也被用來(lái)標(biāo)識(shí)參數(shù)的結(jié)束。
MySQL 4.0 及之前的版本
| 1 | EOF值(0xFE) |
MySQL 4.1 及之后的版本
| 1 | EOF值(0xFE) |
| 2 | 告警計(jì)數(shù) |
| 2 | 狀態(tài)標(biāo)志位 |
告警計(jì)數(shù):服務(wù)器告警數(shù)量,在所有數(shù)據(jù)都發(fā)送給客戶(hù)端后該值才有效。
狀態(tài)標(biāo)志位:包含類(lèi)似SERVER_MORE_RESULTS_EXISTS這樣的標(biāo)志位。
注:由于EOF值與其它Result Set結(jié)構(gòu)共用1字節(jié),所以在收到報(bào)文后需要對(duì)EOF包的真實(shí)性進(jìn)行校驗(yàn),校驗(yàn)條件為:
- 第1字節(jié)值為0xFE
- 包長(zhǎng)度小于9字節(jié)
附:EOF結(jié)構(gòu)的相關(guān)處理函數(shù):
- 服務(wù)器:protocol.cc源文件中的send_eof函數(shù)
4.3.7 Row Data 結(jié)構(gòu)
在Result Set消息中,會(huì)包含多個(gè)Row Data結(jié)構(gòu),每個(gè)Row Data結(jié)構(gòu)又包含多個(gè)字段值,這些字段值組成一行數(shù)據(jù)。
| n | 字段值(Length Coded String) |
| ... | (一行數(shù)據(jù)中包含多個(gè)字段值) |
字段值:行數(shù)據(jù)中的字段值,字符串形式。
附:Row Data結(jié)構(gòu)的相關(guān)處理函數(shù):
- 客戶(hù)端:/client/client.c源文件中的read_rows函數(shù)
4.3.8 Row Data 結(jié)構(gòu)(二進(jìn)制數(shù)據(jù))
該結(jié)構(gòu)用于傳輸二進(jìn)制的字段值,既可以是服務(wù)器返回的結(jié)果,也可以是由客戶(hù)端發(fā)送的(當(dāng)執(zhí)行預(yù)處理語(yǔ)句時(shí),客戶(hù)端使用Result Set消息來(lái)發(fā)送參數(shù)及數(shù)據(jù))。
| 1 | 結(jié)構(gòu)頭(0x00) |
| (列數(shù)量 + 7 + 2) / 8 | 空位圖 |
| n | 字段值 |
| ... | (一行數(shù)據(jù)中包含多個(gè)字段值) |
空位圖:前2個(gè)比特位被保留,值分別為0和1,以保證不會(huì)和OK、Error包的首字節(jié)沖突。在MySQL 5.0及之后的版本中,這2個(gè)比特位的值都為0。
字段值:行數(shù)據(jù)中的字段值,二進(jìn)制形式。
4.3.9 PREPARE_OK 響應(yīng)報(bào)文(Prepared Statement)
用于響應(yīng)客戶(hù)端發(fā)起的預(yù)處理語(yǔ)句報(bào)文,組成結(jié)構(gòu)如下:
| [PREPARE_OK] | PREPARE_OK結(jié)構(gòu) |
| 如果參數(shù)數(shù)量大于0 | ? |
| [Field] | 與Result Set消息結(jié)構(gòu)相同 |
| [EOF] | ? |
| 如果列數(shù)大于0 | ? |
| [Field] | 與Result Set消息結(jié)構(gòu)相同 |
| [EOF] | ? |
其中 PREPARD_OK 的結(jié)構(gòu)如下:
| 1 | OK報(bào)文,值為0x00 |
| 4 | 預(yù)處理語(yǔ)句ID值 |
| 2 | 列數(shù)量 |
| 2 | 參數(shù)數(shù)量 |
| 1 | 填充值(0x00) |
| 2 | 告警計(jì)數(shù) |
4.3.10 Parameter 響應(yīng)報(bào)文(Prepared Statement)
預(yù)處理語(yǔ)句的值與參數(shù)正確對(duì)應(yīng)后,服務(wù)器會(huì)返回 Parameter 報(bào)文。
| 2 | 類(lèi)型 |
| 2 | 標(biāo)志 |
| 1 | 數(shù)值精度 |
| 4 | 字段長(zhǎng)度 |
類(lèi)型:與 Field 結(jié)構(gòu)中的字段類(lèi)型相同。
標(biāo)志:與 Field 結(jié)構(gòu)中的字段標(biāo)志相同。
數(shù)值精度:與 Field 結(jié)構(gòu)中的數(shù)值精度相同。
字段長(zhǎng)度:與 Field 結(jié)構(gòu)中的字段長(zhǎng)度相同。
5 參考資料
《MySQL Internals Manual:?MySQL Client/Server Protocol》
總結(jié)
- 上一篇: presto编译
- 下一篇: Spark SQL CLI 运行