テーブル取得・解放まとめ

ここ1週間くらいうにゅうにゅ悩んでいたのですが、やっとこリソース解放洩れが無いような形でのコードの書き方がわかったのでまとめておきます。

以下のdbに操作対象のデータベース名、wildにテーブル名を指定するためのパターン(LIKE演算子で指定した内容)が入っているものとします。

char *db;
char *wild;

まず最初に以下のようにテーブル名の探索を行います。

  List<char> files;
  char path[FN_LEN];
  (void) sprintf(path, "%s/%s", mysql_data_home, db);
  (void) unpack_dirname(path, path);
  if (find_files(thd, &files, db, path, wild, 0))
    DBUG_RETURN(-1);

ここでキーとなるのはfind_files関数です。データベースディレクトリへのpathを上記のように作成した後、find_files関数にdbとwildを投げると、Listに該当するテーブル名を格納してくれます。

mysql_data_homeはデータディレクトリへの絶対パスを保持しているグローバル変数、FN_LENは256です。

次に、いま取得したList型のfilesからIteratorを作成し、while文とかでループ処理に持っていきます。

  char *file_name;
  List_iterator_fast<char> it(files);
  while (file_name = it++)
  {
    TABLE_LIST table_list;
    bzero((char*) &table_list, sizeof(table_list));
    table_list.db = db;
    table_list.table_name = file_name;
    table_list.alias = file_name;
    TABLE *table = open_ltable(thd, &table_list, TL_READ);

    /* 
       ここにtableに対してやりたい処理を書く
    */
     
    close_thread_tables(thd, 0);
  }

open_ltableやopen_tableなどの関数には引数にTABLE_LISTという構造体があり、これを簡単手軽に作ってくれる・探し出してきてくれるようなユーティリティ関数を最初は探していたのですが、結局これというのはありませんでした。その代わりに、TABLE_LISTを自分で初期化して作るという方法が可能です。

open_ltable関数は、open_table関数をラップしている関数で、第3引数で指定されたフラグを元に、ロックの制御を行います。数日前のおいらはopen_ltableを使わずに直接open_tableを使ってあれこれやろうとして苦戦していたわけなのですが、このへんはopen_ltableに任せてしまった方がとりあえずは楽ということが分かりました。

やりたい処理が終わったら、close_thread_tables関数でリソースを解放します。これをやらないと、他のSQLコマンドの処理に問題を起こします。

テーブルのopen、それとcloseに関してはいくつかの関数がそれぞれあって、どれをどう使えば良いのかが最初はまったく分からなかったのですが、試行錯誤 + MySQL 4.0系などの古いソースの読み漁りで上記パターンに到達しました。

MySQL 5系だとSHOW系コマンドはinformation_schemaへのSELECT実行へと内部的にマッピングされるため、参考になるようなソースはあまり見付からなかったのですが、4系とかだとSHOWコマンドが自力でテーブル名の探索を初めとしていろいろ処理しているので、非常に参考になりました。