#首先看一下這個(gè)sp涉及的instr。
MySQL> show procedure code p1;
+-----+---------------------------------------+
| Pos | Instruction |
+-----+---------------------------------------+
| 0 | stmt "update t1 set b='aa' where a=1" |
+-----+---------------------------------------+
1 row in set (0.01 sec)
可以看到這個(gè)sp只涉及了sp_instr_stmt::execute的運(yùn)行,因此跟蹤一下代碼找到sp_lex_instr::validate_lex_and_execute_core,可以發(fā)現(xiàn)這個(gè)函數(shù)里面有一個(gè)無限while循環(huán),如果發(fā)現(xiàn)is_invalid()的話就重新執(zhí)行parse動(dòng)作,如果!is_invalid()就直接執(zhí)行exec_core,這個(gè)跟上面的運(yùn)行步驟就對(duì)的上了。但是表結(jié)構(gòu)變更后在哪里被判定為rc=true的呢,那就從reset_lex_and_exec_core這個(gè)函數(shù)繼續(xù)跟蹤下去。
bool sp_lex_instr::validate_lex_and_execute_core(THD *thd, uint *nextp,
bool open_tables) {
while (true) {
if (is_invalid() || (m_lex->has_udf() && !m_first_execution)) {
LEX *lex = parse_expr(thd, thd->sp_runtime_ctx->sp);
}
bool rc = reset_lex_and_exec_core(thd, nextp, open_tables);
if (!rc) return false;
thd->clear_error();
invalidate();
}
}
#跟蹤代碼發(fā)現(xiàn)有一個(gè)check_and_update_table_version函數(shù)是用來check表版本是否一致的
#打印堆??匆幌麓a調(diào)用過程:
Thread 51 "mysqld" hit Breakpoint 6, check_and_update_table_version (thd=0x7fff70001060, tables=0x7fff702c4e20,
table_share=0x7fff70297640) at /mysql/sql/sql_base.cc:3722
3722 if (!tables->is_table_ref_id_equal(table_share)) {
(gdb) bt
#0 check_and_update_table_version (thd=0x7fff70001060, tables=0x7fff702c4e20, table_share=0x7fff70297640)
at /mysql/sql/sql_base.cc:3722
#1 0x0000000003340f71 in open_and_process_table (thd=0x7fff70001060, lex=0x7fff702c2650, tables=0x7fff702c4e20,
counter=0x7fff702c26a8, prelocking_strategy=0x7fffec2e7478, has_prelocking_list=false, ot_ctx=0x7fffec2e7368)
at /MySQL/sql/sql_base.cc:5223
#2 0x000000000333f788 in open_tables (thd=0x7fff70001060, start=0x7fffec2e7488, counter=0x7fff702c26a8, flags=0,
prelocking_strategy=0x7fffec2e7478) at /mysql/sql/sql_base.cc:5968
#3 0x0000000003343c96 in open_tables_for_query (thd=0x7fff70001060, tables=0x7fff702c4e20, flags=0)
at /MySQL/sql/sql_base.cc:6958
#4 0x0000000003514334 in Sql_cmd_dml::execute (this=0x7fff702c6138, thd=0x7fff70001060)
at /MySQL/sql/sql_select.cc:543
#5 0x0000000003475097 in mysql_execute_command (thd=0x7fff70001060, first_level=false)
at /MySQL/sql/sql_parse.cc:3832
#6 0x00000000033075c6 in sp_instr_stmt::exec_core (this=0x7fff70249a80, thd=0x7fff70001060, nextp=0x7fffec2eac38)
at /MySQL/sql/sp_instr.cc:1008
#7 0x00000000033052ed in sp_lex_instr::reset_lex_and_exec_core (this=0x7fff70249a80, thd=0x7fff70001060,
nextp=0x7fffec2eac38, open_tables=false) at /mysql/sql/sp_instr.cc:457
#8 0x00000000033060a4 in sp_lex_instr::validate_lex_and_execute_core (this=0x7fff70249a80, thd=0x7fff70001060,
nextp=0x7fffec2eac38, open_tables=false) at /mysql/sql/sp_instr.cc:741
#9 0x0000000003306748 in sp_instr_stmt::execute (this=0x7fff70249a80, thd=0x7fff70001060, nextp=0x7fffec2eac38)
at /MySQL/sql/sp_instr.cc:925
#10 0x00000000032f4d74 in sp_head::execute (this=0x7fff7018e7a0, thd=0x7fff70001060, merge_da_on_success=true)
at /MySQL/sql/sp_head.cc:2272
#11 0x00000000032f80e1 in sp_head::execute_procedure (this=0x7fff7018e7a0, thd=0x7fff70001060, args=0x0)
at /MySQL/sql/sp_head.cc:2977
#可以發(fā)現(xiàn)open_tables函數(shù)調(diào)用了這個(gè)函數(shù),這個(gè)函數(shù)調(diào)用了ask_to_reprepare,
#在sp運(yùn)行中這個(gè)ask_to_reprepare返回的是true。因此這里就解開了之前的問題,
#為何表版本更新了會(huì)return true然后重新進(jìn)行parse操作。
static bool check_and_update_table_version(THD *thd, TABLE_LIST *tables,
TABLE_SHARE *table_share) {
if (!tables->is_table_ref_id_equal(table_share)) {
/*
Version of the table share is different from the
previous execution of the prepared statement, and it is
unacceptable for this SQLCOM.
*/
if (ask_to_reprepare(thd)) return true;
/* Always maintain the latest version and type */
tables->set_table_ref_id(table_share);
}
return false;
}