一、MySQL源碼結構
MySQL源碼結構十分清晰,主要分為server、client、embedded、libmysql、mysys、regex、sql、vio、zlib幾個模塊。
其中,server是MySQL server的主體代碼;client是MySQL的命令行客戶端代碼;embedded是嵌入式庫代碼;libmysql是MySQL C函數庫代碼;mysys是MySQL底層系統函數庫代碼;regex是正則表達式支持代碼;sql是SQL語句解析器代碼;vio是MySQL I/O模塊代碼;zlib是數據壓縮庫代碼。
除了以上主要模塊外,MySQL源碼中還涉及到一些額外的庫,如iconv、openssl、pcre等。
MySQL源碼結構清晰,功能分明,模塊耦合度低,可以很方便地進行針對性的調試和擴展。
二、MySQL Server源碼分析
1. 數據結構
MySQL Server中的數據結構十分複雜,需要深入了解MySQL的內部機制才能理解其設計。
其中,MySQL通過表定義、表數據、索引文件三部分組成了數據存儲層。表定義使用數據字典維護,包含表結構、列定義、約束條件等信息;表數據分為數據行和NULL值標示符兩部分,數據行按照列欄位順序存儲,而NULL值標示符則由點陣圖維護;索引文件則由哈希表、B+tree等數據結構維護。
/* 欄位的描述結構體 */ struct st_field_info { uint name_length; char *name; char *table_name; uint table_length; char *database_name; uint db_length; char *org_name; uint org_name_length; char *def; uint def_length; ulonglong length; uint flags; uint decimals; uint charsetnr; enum_field_types type; // 列類型 }; /* 指向存儲引擎的handler結構體 */ struct st_handler { int (*write_row)(THD *thd, uchar **row); int (*update_row)(THD *thd, uchar *old_row, uchar **new_row); int (*delete_row)(THD *thd, uchar *row); }; /* 表定義結構體 */ struct TABLE { TABLE_SHARE *s; // 表結構共享體 dynamic_array *field; // 資料庫表中的每一列 HA_CREATE_INFO *file; // 創建並處理存儲文件的信息 create_field **create_field; File file_sort; // 用於排序的文件 key_map *key_map; TABLE_LIST *reginfo; MY_BITMAP null_bytes; // NULL值標示符點陣圖 uint field_count; uint db_type; DYNAMIC_ARRAY checksums; ulonglong options; key_map *key_info; uint max_rows, min_rows; mark_table_pos *pos; handler *file_handle; // 存儲引擎handler st_table_share *table_share; MY_BITMAP bit_fields; // 位欄位標誌點陣圖 char *db, *alias, *table_name, *real_name; // 真實表名 char *update_low_priority; char *select_lex_start; Bool ex_update, no_replicate; ulonglong stats_auto_recalc; };
2. SQL解析過程
MySQL的SQL解析器是MySQL Server的核心部分之一,其主要功能是將SQL語句解析為內部數據結構,並根據數據結構執行相應的操作。
SQL解析的過程主要包括以下幾個步驟。
- 語法解析:將SQL語句解析為語法樹。
- 語義解析:在語法樹上添加語義信息,如查詢子句所使用的表、列等。
- 查詢重寫:對SQL語句進行優化、變形,生成可執行的查詢計劃。
- 執行查詢計劃:基於查詢計劃執行SQL語句,獲取查詢結果。
/* SQL解析器主處理函數 */ int mysql_execute_command(THD *thd) { switch (thd->lex->sql_command) { case SQLCOM_SELECT: // SELECT語句處理 case SQLCOM_DELETE: // DELETE語句處理 case SQLCOM_UPDATE: // UPDATE語句處理 case SQLCOM_INSERT: // INSERT語句處理 if (table->file->ha_misc_flags & HA_CAN_INSERT_DELAYED && thd->is_delayed_insert()) { if (table->file->state == handler::STATE_CLOSED) { if (open_delayed_table(thd)) // 檢查是否已打開延遲插入表 goto end; } if (!ha_write_row(table->file, buffer)) { // 寫入行 if (ha_write_error(table->file)) // 寫入行出錯 mysql_print_error(thd, MYF(0), ER_CHECKREAD); } } else if (require_prelocking || thd->options & OPTION_FOUND_ROWS) { error = execute_prepared_stmt(thd); // 執行準備語句 } else { error = execute_ha_data(node, buffer); // 執行SQL語句 if (error == HA_ERR_WRONG_COMMAND) { if (is_select(thd, *thd->query_string, thd->lex->current_pos)) { // 如果非法SQL是SELECT語句則將max_error_count減1 thd->variables.max_error_count-= error_count_adjustment; error_count_adjustment= 0; } goto err; } } break; ...... }
3. 存儲引擎介面
MySQL的存儲引擎介面是MySQL Server與存儲引擎之間的橋樑,用於處理MySQL Server與具體存儲引擎的交互操作。
MySQL通過handler結構體對存儲引擎進行封裝,存儲引擎需要實現該結構體中的操作函數。
/* MYSQL存儲引擎handler結構體 */ struct handler { const char *name; // 引擎名字 ulonglong flags; // 引擎標誌位 handler *next,*prev; // 指向下一個、上一個handler uint (*create)(THD *thd); // 創建表 int (*write_row)(THD *thd, uchar **row); // 插入一行 bool (*update_row)(THD *thd, uchar *old_row, uchar **new_row); // 更新一行 void (*delete_row)(THD *thd, uchar *row); // 刪除一行 int (*index_first)(uchar *buf); // 哈希表索引,通過key找到第一行 int (*index_last)(uchar *buf); // 哈希表索引,通過key找到最後一行 int (*index_next)(uchar *buf); // 哈希表索引,通過key找到下一行 int (*index_prev)(uchar *buf); // 哈希表索引,通過key找到上一行 int (*index_read_map)(uchar *buf, key_map *keyinfo, uchar *param); // 哈希表索引 THR_LOCK_DATA **mdl_request(uint no_of_tables, TABLE **tables, enum thr_lock_type lock_type); // 獲得MDL鎖 };
三、MySQL Client源碼分析
1. SQL語句執行過程
MySQL Client的主要功能是與MySQL Server進行通信,並根據用戶輸入的SQL語句生成相應的協議命令並發送給MySQL Server。
SQL語句執行過程主要包括以下幾個步驟。
- 設置連接參數:包括資料庫名稱、伺服器地址、用戶名、密碼等。
- 連接MySQL Server,並進行認證。
- 構造SQL語句並發送給MySQL Server。
- 接收MySQL Server返回的結果,並進行結果處理。
- 關閉連接。
2. C API介面
MySQL Client的C API介面提供了豐富的操作MySQL的函數,具有高度的靈活性和可擴展性。
以下代碼展示如何使用C API連接MySQL Server,並執行一條簡單的SELECT語句。
#include int main() { MYSQL mysql; MYSQL_RES *res; MYSQL_ROW row; int error = -1; /* 初始化mysql結構體 */ mysql_init(&mysql); /* 連接MySQL Server */ if (!mysql_real_connect(&mysql, "localhost", "root", NULL, "test", 0, NULL, 0)) { printf("Failed to connect to MySQL Server: %s\n", mysql_error(&mysql)); goto end; } /* 執行SELECT語句 */ if (mysql_real_query(&mysql, "SELECT * FROM db", strlen("SELECT * FROM db")) != 0) { printf("Failed to execute SQL: %s\n", mysql_error(&mysql)); goto end; } /* 獲取查詢結果 */ res = mysql_store_result(&mysql); while ((row = mysql_fetch_row(res))) { printf("%s, %s, %s\n", row[0], row[1], row[2]); } error = 0; end: /* 關閉連接並釋放資源 */ mysql_free_result(res); mysql_close(&mysql); return error; }
四、MySQL存儲引擎開發
1. 存儲引擎框架
MySQL存儲引擎開發需要進行基於handler結構體的封裝,以便能夠與MySQL Server進行交互。
以下代碼展示了如何實現一個最基本的存儲引擎,並在MySQL Server中進行使用。
/* MyISAM存儲引擎類 */#include
#include
#include
#includestatic struct st_handler myisam_handler = {
"myisam", // 引擎名字
HA_BINLOG_STMT_CAPABLE // 引擎標誌位
| HA_CAN_RECREATE // 引擎標誌位
| HA_SUPPORT_CLUST_INDEX // 引擎標誌位
| HA_FILE_BASED, // 引擎標誌位
NULL, NULL, NULL, NULL, NULL, // 幾個操作函數都置為NULL,無需重載
NULL, NULL, NULL, NULL, NULL
};class MyISAM: public handler
{
public:
MyISAM(handlerton *hton, TABLE_SHARE *table_arg);
protected:
virtual ~MyISAM();
public:
virtual uint index_flags(uint inx, uint part, bool all_parts);
virtual const char **bas_ext();
virtual int rnd_init(bool scan);
virtual int rnd_next(uchar *buf);
virtual int rnd_pos(uchar *buf, uchar *pos);
virtual void position(const uchar *record);
virtual int info(uint);
virtual void print_error(int);
private:
MI_INFO m_info;
char m_path[FN_REFLEN];
DBUG_ENTER("MyISAM::MyISAM");
memset(&m_info, 0, sizeof(m_info));
memcpy(&m_handler, &myisam_handler, sizeof(handler));
if (table_arg == NULL) {
DBUG_VOID_RETURN;
}
fopen_system tmp_file(table_arg->db_type == DB_TYPE_COMMENT ? NULL:
table_arg->path.str);
char buff[FN_REFLEN + FN_EX_REFLEN + 2];
DBUG_PRINT("info", ("path=%s, share.rol_type() = %d",
table_arg->path.str, table_arg->file_type == MYSQL_OPEN_FRM));
make_frm_name(buff, table_arg->path.str, table_arg->alias);
DBUG_PRINT("info", ("frm_name=%s", buff));
if (mi_open((char*) table_arg->alias, &m_info原創文章,作者:VZWTL,如若轉載,請註明出處:https://www.506064.com/zh-tw/n/361268.html