LEX *lex = thd->lex;
switch (lex->sql_command) {
case SQLCOM_CREATE_DB: mysql_create_db();
case SQLCOM_CREATE_TABLE: mysql_create_table();
case SQLCOM_INSERT: mysql_insert();
case SQLCOM_SELECT: execute_sqlcom_select();
}
mysql_create_db(THD *thd, char *dbname, create_info, silent)
lock_schema_name(thd, dbname);
path = build_table_filename(path, path_length, dbname, tablename="", table_extension="", flags = 0);
// mysql_data_dir/db/
my_mkdir(path, 0777, ...);
// mysql_data_dir/db/db.opt
write_db_opt(thd, path, create_info);
mysql_file_create(path);
mysql_file_write("default-character-set=xxx\ndefault-collation=xxx\n");
if (!silent) {
my_ok();
}
mysql_create_table(THD *thd, TABLE_LIST *create_table, create_info, alter_info)
/* 搞不清楚.frm文件的格式,编译一个debug版本的mysql nemiver一下.
mkdir -p mysql-debug/data
cd mysql-5.5.53
mkdir bld
cd bld
cmake ..
cmake-gui
修改install path, data path, with_debug, generate
make
make install
cd mysql-debug
./scripts/mysql_install_db --defaults-file=debug.cnf
cat debug.cnf
[client]
port = 3307
socket = /tmp/mysqld-debug.sock
[mysqld_safe]
socket = /tmp/mysqld-debug.sock
[mysqld]
user = heguangyu5
pid-file = /tmp/mysqld-debug.pid
socket = /tmp/mysqld-debug.sock
port = 3307
basedir = /home/heguangyu5/tmp/mysql-debug
datadir = /home/heguangyu5/tmp/mysql-debug/data
./bin/mysqld_safe --defaults-file=debug.cnf
./bin/mysqladmin --defaults-file=debug.cnf -uroot password '123456'
mysql -h127.0.0.1 -uroot -p123456 -P 3307
./bin/mysqladmin -h127.0.0.1 -uroot -p123456 -P 3307 shutdown
nemiver ./bin/mysqld \
--defaults-file=debug.cnf \
--plugin-dir=/home/heguangyu5/tmp/mysql-debug/lib/plugin \
--log-error=/home/heguangyu5/tmp/mysql-debug/data/localhost.err
File -> Open Source File -> sql/sql_table.cc
*/
open_and_lock_tables(); // 在lxr里找不到open_and_lock_tables(..., prelocking_strategy)
// 这个函数定义在sql/sql_base.cc#5562
// open_tables(..., prelocking_strategy)定义在sql/sql_base.cc#4837
// 这个地方没有点其它的背景说明是搞不明白了.
mysql_create_table_no_lock(thd, create_table->db, create_table->table_name, ...);
check_engine(); // 检查下对应的engine是否启用,以及创建表的名称和数据库的名称是否已占用.
// 比如mysql.user表就不能创建
set_table_default_charset();
// 调用engine的create()方法,create()方法返回一个handler,调用handler->init()方法
handler *file = get_new_handler(handlerton* create_info->db_type);
mysql_prepare_create_table();
ha_table_exists_in_engine(thd, db, table_name);
rea_create_table(); // create frm file
mysql_create_frm();
file->ha_create_handler_files();
file->ha_create();
// storage是怎么加载运行的?
main()
init_server_components()
plugin_init()
// for each mysql_mandatory_plugins(builtin plugins)
// 执行cmake后在sql/sql_builtin.cc里可以找到myisam,csv
register_builtin() // static HASH plugin_hash[MYSQL_MAX_PLUGIN_TYPE_NUM];
plugin_initialize(); // only for MyISAM, CSV
// MyISAM: ha_initialize_handerton()
myisam_init(hton);
// for each plugin_array // 上边只init了MyISAM和CSV,其它builtin plugin在这里init
plugin_initialize();
plugin->init();
// 看看MyISAM是怎么实现create()方法和handler的ha_create_handler_files,ha_create的
myisam_hton->create = myisam_create_handler(); => new ha_myisam();
ha_myisam->init(); => cached_table_flags = HA_NULL_IN_KEY | HA_CAN_FULLTEXT | ...
ha_myisam->ha_create_handler_files(); // return FALSE
ha_myisam->ha_create(); => ha_myisam::create() => mi_create() 创建 .MYI .MYD 文件
mysql_insert()
open_and_lock_tables();
mysql_prepare_insert();
write_record();
talbe->file->ha_write_row(); => ha_myisam::write_row(); => mi_write();
execute_sqlcom_select()
open_and_lock_tables();
handle_select();
if (union) {
mysql_union();
} else {
mysql_select();
}
// mysql_union() 最终也是执行mysql_select()
mysql_select()
if (select_lex->join != 0) {
// union
join = select_lex->join;
} else {
join = new JOIN();
}
join->optimize();
make_join_readinfo()
for (i = join->const_tables; i < join->tables; i++) {
JOIN_TAB *tab = join->join_tab + i;
tab.next_select = sub_select();
pick_table_access_method(tab);
JT_CONST: read_first_record = join_read_const;
read_record = join_no_more_records;
JT_EQ_REF: read_first_record = join_read_key;
read_record = join_no_more_records;
JT_REF: read_first_record = join_read_always_key;
read_record = join_read_next_same;
// ...
}
join->join_tab[join->tables-1].next_select = 0;
join->exec();
do_select(curr_join, curr_fields_list, NULL, procedure);
join->join_tab[join->table-1].next_select = end_send;
join_tab = join->join_tab + join->const_tables;
if (join->tables === join->const_tables) {
// tables和const_tables什么区别?
// 如果表里只有一条记录或者是通过主键或uniq key做的select,这些table称为const table
if (!conds || conds->val_int()) {
// 如果有其它where条件, conds->val_int() 返回1表示match,返回0表示not match
end_send();
}
} else {
sub_select();
(*join_tab->read_first_record)(join_tab);
evaluate_join_record(join, join_tab, error);
// 如果还有其它join,继续sub_select()
rc = (*join_tab->next_select)(join, join_tab+1, 0); => sub_select();
// 否则,返回 OK 或 NO_MORE_ROWS
while (rc == NESTED_LOOP_OK) {
read_record();
rc = evaluate_join_record();
}
/*
sub_select()
read_first_record()
evaluate_join_record()
sub_select()
read_first_record()
evaluate_join_record()
end_send()
while (OK) {
read_record() => join_no_more_records(); => -1 // EQ_REF
evaluate_join_record() => NO_MORE_ROWS
}
return OK;
return OK;
while (OK) {
read_record() => rr_sequential()
evaluate_join_record()
sub_select()
read_first_record()
evaluate_join_record()
}
*/
}