SHOW系コマンドとinformation_schemaデータベースの関係
MySQLではver5.0からinformation_schema対応が行われています。information_schemaですが、これはANSI標準SQL2003かなにかで定義されている機能のひとつで、RDBMSからテーブル等に関するメタ情報を取得したいときに使えるRDBMS間共通のインタフェースとして用意されています(あってるよね?)。
ver5.0以前は
MySQLではver4.1まではそういったメタ情報はSHOW系コマンドによってアクセス手段が提供されていました。
SHOW TABLES; SHOW DATABSES; SHOW INDEXES FROM...; ...
ver5.0からは
MySQL 5.0からは従来のSHOW系コマンドに加え、information_schemaデータベースからSELECTで情報を取得できるようになっています。
information_schemaにはこんなテーブルがあります。これはUnix/Linuxでいうところの/procファイルシステムのアイデアに近い、いわゆる仮想テーブルです。実体があるわけではないです。
[information_schema] > show tables; +---------------------------------------+ | Tables_in_information_schema | +---------------------------------------+ | CHARACTER_SETS | | COLLATIONS | | COLLATION_CHARACTER_SET_APPLICABILITY | | COLUMNS | | COLUMN_PRIVILEGES | | KEY_COLUMN_USAGE | | PROFILING | | ROUTINES | | SCHEMATA | | SCHEMA_PRIVILEGES | | STATISTICS | | TABLES | | TABLE_CONSTRAINTS | | TABLE_PRIVILEGES | | TRIGGERS | | USER_PRIVILEGES | | VIEWS | +---------------------------------------+ 17 rows in set (0.00 sec)
前置きは終わり
で、このエントリはこんなこと↑↑を書いておくために作成したわけじゃありません。show系コマンドとinformation_schema系テーブルの関連についてメモっておくために書いているのです。
MySQL 5.0と4.1の大きな実装上の違いのひとつですが、このshow系コマンドはver4.1まではメタ情報を返す実装が施されていたのが、ver5.0からのshow系コマンドは内部でinformation_schemaテーブルに対してSELECT文を発行する実装になっているのです。
SHOW TABLE STATUSを処理するパーサ(sql/sql_yacc.yy)のソースコード
| TABLE_SYM STATUS_SYM opt_db wild_and_where { LEX *lex= Lex; lex->sql_command= SQLCOM_SELECT; lex->orig_sql_command= SQLCOM_SHOW_TABLE_STATUS; lex->select_lex.db= $3; if (prepare_schema_table(YYTHD, lex, 0, SCH_TABLES)) MYSQL_YYABORT; }
オリジナルのSQLコマンドは"SQLCOM_SHOW_TABLE_STATUS"なんですが、この後の処理は"SQLCOM_SELECT"として扱うようにしています。この時、SELECT対象のテーブルを用意する必要がありますので、prepare_schema_table関数に"SCH_TABLES"を渡しているわけです。
ここでこの先を読み解くヒントとなるのがこの"SCH_TABLES"だったりするわけですが。。。
enum enum_schema_tables
sql/table.hに以下の定義があります。
enum enum_schema_tables { SCH_CHARSETS= 0, SCH_COLLATIONS, SCH_COLLATION_CHARACTER_SET_APPLICABILITY, SCH_COLUMNS, SCH_COLUMN_PRIVILEGES, SCH_KEY_COLUMN_USAGE, SCH_OPEN_TABLES, SCH_PROFILING, SCH_PROCEDURES, SCH_SCHEMATA, SCH_SCHEMA_PRIVILEGES, SCH_STATISTICS, SCH_STATUS, SCH_TABLES, SCH_TABLE_CONSTRAINTS, SCH_TABLE_NAMES, SCH_TABLE_PRIVILEGES, SCH_TRIGGERS, SCH_USER_PRIVILEGES, SCH_VARIABLES, SCH_VIEWS };
information_schemaデータベースで"SHOW TABLES"を実施した結果と似たようなテーブル名が散見されますね。
ところが、このEnumに存在するテーブルのうち、いくつかのテーブルがinformation_schema上では見えません。
SHOW OPEN TABLESはhiddenなinformation_schemaテーブルにアクセスして情報を返す
先ほどのEnumを使用してアクセスされる配列があります。それがST_SCHEMA_TABLE型の配列、schema_tablesです。sql/sql_show.ccにあります。
ST_SCHEMA_TABLE schema_tables[]= { {"CHARACTER_SETS", charsets_fields_info, create_schema_table, fill_schema_charsets, make_character_sets_old_format, 0, -1, -1, 0}, {"COLLATIONS", collation_fields_info, create_schema_table, fill_schema_collation, make_old_format, 0, -1, -1, 0}, {"COLLATION_CHARACTER_SET_APPLICABILITY", coll_charset_app_fields_info, create_schema_table, fill_schema_coll_charset_app, 0, 0, -1, -1, 0}, {"COLUMNS", columns_fields_info, create_schema_table, get_all_tables, make_columns_old_format, get_schema_column_record, 1, 2, 0}, {"COLUMN_PRIVILEGES", column_privileges_fields_info, create_schema_table, fill_schema_column_privileges, 0, 0, -1, -1, 0}, {"KEY_COLUMN_USAGE", key_column_usage_fields_info, create_schema_table, get_all_tables, 0, get_schema_key_column_usage_record, 4, 5, 0}, {"OPEN_TABLES", open_tables_fields_info, create_schema_table, fill_open_tables, make_old_format, 0, -1, -1, 1}, {"PROFILING", query_profile_statistics_info, create_schema_table, fill_query_profile_statistics_info, NULL, NULL, -1, -1, false}, {"ROUTINES", proc_fields_info, create_schema_table, fill_schema_proc, make_proc_old_format, 0, -1, -1, 0}, {"SCHEMATA", schema_fields_info, create_schema_table, fill_schema_shemata, make_schemata_old_format, 0, 1, -1, 0}, {"SCHEMA_PRIVILEGES", schema_privileges_fields_info, create_schema_table, fill_schema_schema_privileges, 0, 0, -1, -1, 0}, {"STATISTICS", stat_fields_info, create_schema_table, get_all_tables, make_old_format, get_schema_stat_record, 1, 2, 0}, {"STATUS", variables_fields_info, create_schema_table, fill_status, make_old_format, 0, -1, -1, 1}, {"TABLES", tables_fields_info, create_schema_table, get_all_tables, make_old_format, get_schema_tables_record, 1, 2, 0}, {"TABLE_CONSTRAINTS", table_constraints_fields_info, create_schema_table, get_all_tables, 0, get_schema_constraints_record, 3, 4, 0}, {"TABLE_NAMES", table_names_fields_info, create_schema_table, get_all_tables, make_table_names_old_format, 0, 1, 2, 1}, {"TABLE_PRIVILEGES", table_privileges_fields_info, create_schema_table, fill_schema_table_privileges, 0, 0, -1, -1, 0}, {"TRIGGERS", triggers_fields_info, create_schema_table, get_all_tables, make_old_format, get_schema_triggers_record, 5, 6, 0}, {"USER_PRIVILEGES", user_privileges_fields_info, create_schema_table, fill_schema_user_privileges, 0, 0, -1, -1, 0}, {"VARIABLES", variables_fields_info, create_schema_table, fill_variables, make_old_format, 0, -1, -1, 1}, {"VIEWS", view_fields_info, create_schema_table, get_all_tables, 0, get_schema_views_record, 1, 2, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0} };
ここで、1つ前のエントリで触れていた"SHOW OPEN TABLES"について見てみましょう。schema_tablesの中に"OPEN TABLES"というinformation_schemaテーブルが定義されていますが、"SHOW TABLES"で得られたinformation_schemaのテーブル名一覧には名前がありませんでした。
もしかしたら隠しテーブルなのかもしれない、ということでST_SCHEMA_TABLE構造体の定義を見てみます。sql/table.hです。
typedef struct st_schema_table { const char* table_name; ST_FIELD_INFO *fields_info; /* Create information_schema table */ TABLE *(*create_table) (THD *thd, struct st_table_list *table_list); /* Fill table with data */ int (*fill_table) (THD *thd, struct st_table_list *tables, COND *cond); /* Handle fileds for old SHOW */ int (*old_format) (THD *thd, struct st_schema_table *schema_table); int (*process_table) (THD *thd, struct st_table_list *tables, TABLE *table, bool res, const char *base_name, const char *file_name); int idx_field1, idx_field2; bool hidden; } ST_SCHEMA_TABLE;
予想通り、hiddenというメンバがありますね。schema_tablesの"OPEN TABLE"の代入値を見てみると、、、最後の値が1になっていますね。
というわけで、SHOW OPEN TABLESコマンドが内部的にアクセスするinformation_schemaのテーブルは隠しテーブルだということが分かりました。