说明:
以下所有说明都以 MySQL 5.7.25 源码为例 ,存储引擎为InnoDB。
mysql客户端登录之后,需要使用use database_name
选取表空间并切换到具体的表空间下进行操作,否则会报错:
使用前未使用use database_name
mysql>show tables;
ERROR 1046 (3D000): No database selected
选取并切换:
mysql>use test;
mysql>show tables;
+-----------------+
| Tables_in_test |
+-----------------+
| t1 |
| t2 |
+-----------------+
2 rows in set (0.00 sec)
在mysql客户端上执行use database_name
,其实背后是一套组合的操作命令,大概的主要操作流程为;
SELECT DATABASE()
获取当前的database
的名称;use database_name
中的name
和current_db_name
是否一致;show databases
查询所有的databases
并且校验选择use database_name
中对应的database
;show tables
打开所有的tables
;mysql_client
com_use(String *buffer MY_ATTRIBUTE((unused)), char *line)
get_current_db();
>get_current_db
if !mysql_query(&mysql, "SELECT DATABASE()") && res=mysql_use_result(&mysql)
MYSQL_ROW = mysql_fetch_row(res)
if row && row[0]
current_db = my_strdup(PSI_NOT_INSTRUMENTED, row[0], MYF(MY_WME))
mysql_free_result(res)
fi
fi
<get_current_db
if !current_db || cmp_database(charset_info, current_db, tmp) //current_db="innodb", tmp="ywx"
fi
if select_db; THEN//select_db = 2
if mysql_select_db(&mysql, tmp)
fi
my_free(current_db)
current_db = my_strdup(PSI_NOT_INSTRUMENTED, tmp, MYF(MY_WME)
fi
if (select_db > 1)
build_completion_hash(opt_rehash, 1)
>build_completion_hash
if (mysql_query(&mysql,"show databases") == 0)// "show databasess"
fi
if (mysql_query(&mysql,"show tables")==0)//"show tables"
if !(tables = mysql_store_result(&mysql))
else
while table_row=mysql_fetch_row(tables)
do
done
fi
fi
<build_completion_hash
fi
服务端对应客户端不同阶段的请求处理为:
SELECT DATABASE()
请求;SELECT DATABASE()
走的是SELECT
流程,DATABASE()
作为一个function
的形式进行处理,其yacc
语法规则为:function_call_conflict:
ASCII_SYM '(' expr ')'
{
$$= NEW_PTN Item_func_ascii(@$, $3);
}
...
| DATABASE '(' ')'
{
$$= NEW_PTN Item_func_database(@$);
}
show databases
请求, yacc
语法规则为:show:
SHOW
{
LEX *lex=Lex;
new (&lex->create_info) HA_CREATE_INFO;
}
show_param
;
show_param:
DATABASES opt_wild_or_where
{
LEX *lex= Lex;
lex->sql_command= SQLCOM_SHOW_DATABASES;
if (prepare_schema_table(YYTHD, lex, 0, SCH_SCHEMATA))
MYSQL_YYABORT;
}
show tables
,yacc
语法规则为:show:
SHOW
{
LEX *lex=Lex;
new (&lex->create_info) HA_CREATE_INFO;
}
show_param
;
show_param:
| opt_full TABLES opt_db opt_wild_or_where
{
LEX *lex= Lex;
lex->sql_command= SQLCOM_SHOW_TABLES;
lex->select_lex->db= $3;
if (prepare_schema_table(YYTHD, lex, 0, SCH_TABLE_NAMES))
MYSQL_YYABORT;
}
mysql_execute_command
switch lex->sql_command:
case SQLCOM_SHOW_DATABASES:
case SQLCOM_SHOW_TABLES:
case SQLCOM_SELECT:
res= execute_sqlcom_select(thd, all_tables)
>execute_sqlcom_select
if !open_tables_for_query(thd, all_tables, 0); THEN
if lex->is_explain(); THEN
Query_result *const result= new Query_result_send
res= handle_query(thd, lex, result, 0, 0)
else
res= handle_query(thd, lex, result, 0, 0)
fi
fi
<execute_sqlcom_select
handle_query
const bool single_query= unit->is_simple()
//phase 1: prepare
if single_query; THEN
unit->set_limit(unit->global_parameters())
select->context.resolve_in_select_list= true
select->set_query_result(result)
select->make_active_options(added_options, removed_options)
select->fields_list= select->item_list
if select->prepare(thd); THEN
fi
unit->set_prepared()
ELSE
if unit->prepare(thd, result, SELECT_NO_UNLOCK | added_options, removed_options); THEN
fi
fi
if lock_tables(thd, lex->query_tables, lex->table_count, 0); THEN
fi
//register query result in cache
query_cache.store_query(thd, lex->query_tables)
//phase 2: optimize
if single_query; THEN
if select->optimize(thd); THEN
fi
unit->set_optimized()
ELSE
if select->optimize(thd); THEN
fi
fi
//phase 3: execute
if lex->is_explain(); THEN
if explain_query(thd, unit); THEN
fi
ELSE
if single_query; THEN
select->join->exec()
unit->set_executed()
if thd->is_error() ; THEN
goto err;
else
if (unit->execute(thd)); THEN
goto err;
fi
res= unit->cleanup(false)