Native関数呼び出しの仕組み
JOIN::exec()からuとsで追いかけてたら訳分からなくなったので、とりあえずlpad関数にbを仕込んで実行し、btしてみますた。
#0 Item_func_lpad::func_name (this=0x8add0e0) at item_strfunc.h:532 #1 0x0812fb2b in Item_func::agg_arg_charsets (this=0x8add0e0, c=@0x8add118, items=0x45b51e50, nitems=2, flags=3) at item_func.h:183 #2 0x0814808c in Item_func_lpad::fix_length_and_dec (this=0x8add0e0) at item_strfunc.cc:2228 #3 0x0812381f in Item_func::fix_fields (this=0x8add0e0, thd=0x8abdc50, ref=0x8add1bc) at item_func.cc:189 #4 0x081cf7c4 in setup_fields (thd=0x8abdc50, ref_pointer_array=0x8ade020, fields=@0x8abdf44, set_query_id=true, sum_func_list=0x8addf6c, allow_sum_func=true) at sql_base.cc:4337 #5 0x081d7f2d in JOIN::prepare (this=0x8add250, rref_pointer_array=0x8abdfe0, tables_init=0x0, wild_num=0, conds_init=0x0, og_num=0, order_init=0x0, group_init=0x0, having_init=0x0, proc_param_init=0x0, select_lex_arg=0x8abdebc, unit_arg=0x8abdc9c) at sql_select.cc:339 #6 0x081dc0b0 in mysql_select (thd=0x8abdc50, rref_pointer_array=0x8abdfe0, tables=0x0, wild_num=0, fields=@0x8abdf44, conds=0x0, og_num=0, order=0x0, group=0x0, having=0x0, proc_param=0x0, select_options=2156153344, result=0x8add240, unit=0x8abdc9c, select_lex=0x8abdebc) at sql_select.cc:1879 ...
func_nameとval_str関数。
#0 Item_func_lpad::val_str (this=0x8add0e0, str=0x45b51c90) at item_strfunc.cc:2256 #1 0x0810d72b in Item::send (this=0x8add0e0, protocol=0x8abe6d8, buffer=0x45b51c90) at item.cc:4432 #2 0x0817d174 in select_send::send_data (this=0x8add240, items=@0x8abdf44) at sql_class.cc:939 #3 0x081da918 in JOIN::exec (this=0x8add250) at sql_select.cc:1264 #4 0x081dc155 in mysql_select (thd=0x8abdc50, rref_pointer_array=0x8abdfe0, tables=0x0, wild_num=0, fields=@0x8abdf44, conds=0x0, og_num=0, order=0x0, group=0x0, having=0x0, proc_param=0x0, select_options=2156153344, result=0x8add240, unit=0x8abdc9c, select_lex=0x8abdebc) at sql_select.cc:1901 ...
例えば、、、以下のSQL文を実行する際、"lpad"を呼び出すという情報はどこでどのように格納されているのか、を知りたい。
SELECT lpad("hoge", 10, "@");
select_lexをいろいろ漁っているんだがー、どれだー?(^^;
JOIN::prepareから見ていくと、どうも既にselect_lexに突っ込まれているItemオブジェクトを使って処理しているようだ。となると誰かが既にlpadを特定してItemオブジェクトをnewしたということに。となるとこれはたぶんparserであろう。えーparser読むの嫌いw
なんとなく眺めていたらよさげな関数を発見! create_func_XXXというのがあるらしい。create_func_lpadとか。
Item *create_func_lpad(Item* a, Item *b, Item *c) { return new Item_func_lpad(a,b,c); }
btはこんな感じ。
#0 create_func_lpad (a=0x8adcf68, b=0x8adcff0, c=0x8add070) at item_create.cc:240 #1 0x081b6c99 in MYSQLparse (yythd=0x8abdc50) at sql_yacc.yy:4373 #2 0x081a9d6c in mysql_parse (thd=0x8abdc50, inBuf=0x8adcf10 "select lpad(\"aaa\", 5,\"@\" )", length=26) at sql_parse.cc:5660 #3 0x081a00a6 in dispatch_command (command=COM_QUERY, thd=0x8abdc50, packet=0x8ad4ee1 "select lpad(\"aaa\", 5,\"@\" )", packet_length=27) at sql_parse.cc:1736 #4 0x0819f8f0 in do_command (thd=0x8abdc50) at sql_parse.cc:1522 #5 0x0819ed25 in handle_one_connection (arg=0x8abdc50) at sql_parse.cc:1165 #6 0x4002ab63 in start_thread () from /lib/tls/libpthread.so.0 #7 0x4023418a in clone () from /lib/tls/libc.so.6
さらにlex.hからは貴重な情報が!
static SYMBOL sql_functions[] = { { "ABS", F_SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_abs)}, { "ACOS", F_SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_acos)}, { "ADDDATE", SYM(ADDDATE_SYM)}, ... { "LPAD", F_SYM(FUNC_ARG3),0,CREATE_FUNC(create_func_lpad)}, ... }
SYMBOL構造体は以下。
typedef struct st_symbol { const char *name; uint tok; uint length; void *create_func; struct st_sym_group *group; } SYMBOL;
CREATE_FUNCマクロは展開すると関数ポインタ+st_sym_group構造体へのポインタとなる。
#define CREATE_FUNC(A) (void *)(SYM_OR_NULL(A)), &sym_group_common
パーサがItemオブジェクトをnewする。sql_yacc.ccのMYSQLparse関数。
case 800: #line 4373 "sql_yacc.yy" { if (!(yyvsp[-2].symbol).symbol->create_func) { my_error(ER_FEATURE_DISABLED, MYF(0), (yyvsp[-2].symbol).symbol->group->name, (yyvsp[-2].symbol).symbol->group->needed_define); YYABORT; } (yyval.item)= ((Item*(*)(void))((yyvsp[-2].symbol).symbol->create_func))(); } break;
newされたItemオブジェクトがmysql_select以下で使用され、呼び出される。