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以下で使用され、呼び出される。