一、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-hk/n/361268.html
微信掃一掃
支付寶掃一掃