1 # name : show_temp.patch
2 # introduced : 11 or before
3 # maintainer : Yasufumi
6 # Any small change to this file in the main branch
7 # should be done or reviewed by the maintainer!
14 + SCH_GLOBAL_TEMPORARY_TABLES,
19 SCH_TABLE_CONSTRAINTS,
22 + SCH_TEMPORARY_TABLES,
29 {"show_storage_engines", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_STORAGE_ENGINES]), SHOW_LONG_STATUS},
30 {"show_table_status", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_TABLE_STATUS]), SHOW_LONG_STATUS},
31 {"show_tables", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_TABLES]), SHOW_LONG_STATUS},
32 + {"show_temporary_tables",(char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_TEMPORARY_TABLES]), SHOW_LONG_STATUS},
33 {"show_triggers", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_TRIGGERS]), SHOW_LONG_STATUS},
34 {"show_variables", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_VARIABLES]), SHOW_LONG_STATUS},
35 {"show_warnings", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_WARNS]), SHOW_LONG_STATUS},
37 PSI_mutex_key key_LOCK_des_key_file;
38 #endif /* HAVE_OPENSSL */
40 +PSI_mutex_key key_LOCK_temporary_tables;
41 PSI_mutex_key key_BINLOG_LOCK_index, key_BINLOG_LOCK_prep_xids,
42 key_delayed_insert_mutex, key_hash_filo_lock, key_LOCK_active_mi,
43 key_LOCK_connection_count, key_LOCK_crypt, key_LOCK_delayed_create,
45 { &key_LOCK_system_variables_hash, "LOCK_system_variables_hash", PSI_FLAG_GLOBAL},
46 { &key_LOCK_table_share, "LOCK_table_share", PSI_FLAG_GLOBAL},
47 { &key_LOCK_thd_data, "THD::LOCK_thd_data", 0},
48 + { &key_LOCK_temporary_tables, "THD::LOCK_temporary_tables", 0},
49 { &key_LOCK_user_conn, "LOCK_user_conn", PSI_FLAG_GLOBAL},
50 { &key_LOCK_uuid_generator, "LOCK_uuid_generator", PSI_FLAG_GLOBAL},
51 { &key_LOG_LOCK_log, "LOG::LOCK_log", 0},
55 When a command is added here, be sure it's also added in mysqld.cc
56 in "struct show_var_st status_vars[]= {" ...
58 + SQLCOM_SHOW_TEMPORARY_TABLES,
59 /* This should be the last !!! */
62 --- a/sql/sql_parse.cc
63 +++ b/sql/sql_parse.cc
65 sql_command_flags[SQLCOM_SHOW_TABLES]= (CF_STATUS_COMMAND |
66 CF_SHOW_TABLE_COMMAND |
67 CF_REEXECUTION_FRAGILE);
68 + sql_command_flags[SQLCOM_SHOW_TEMPORARY_TABLES]= (CF_STATUS_COMMAND |
69 + CF_SHOW_TABLE_COMMAND |
70 + CF_REEXECUTION_FRAGILE);
71 sql_command_flags[SQLCOM_SHOW_TABLE_STATUS]= (CF_STATUS_COMMAND |
72 CF_SHOW_TABLE_COMMAND |
73 CF_REEXECUTION_FRAGILE);
78 + case SCH_TEMPORARY_TABLES:
79 + case SCH_GLOBAL_TEMPORARY_TABLES:
85 case SQLCOM_SHOW_DATABASES:
86 case SQLCOM_SHOW_TABLES:
87 + case SQLCOM_SHOW_TEMPORARY_TABLES:
88 case SQLCOM_SHOW_TRIGGERS:
89 case SQLCOM_SHOW_TABLE_STATUS:
90 case SQLCOM_SHOW_OPEN_TABLES:
95 + case SCH_TEMPORARY_TABLES:
96 + case SCH_GLOBAL_TEMPORARY_TABLES:
100 --- a/sql/sql_show.cc
101 +++ b/sql/sql_show.cc
102 @@ -2692,6 +2692,7 @@
104 case SQLCOM_SHOW_TABLES:
105 case SQLCOM_SHOW_TABLE_STATUS:
106 + case SQLCOM_SHOW_TEMPORARY_TABLES:
107 case SQLCOM_SHOW_TRIGGERS:
108 case SQLCOM_SHOW_EVENTS:
109 thd->make_lex_string(&lookup_field_values->db_value,
110 @@ -3283,6 +3284,231 @@
111 return (uint) OPEN_FULL_TABLE;
115 + @brief Change I_S table item list for SHOW [GLOBAL] TEMPORARY TABLES [FROM/IN db]
117 + @param[in] thd thread handler
118 + @param[in] schema_table I_S table
120 + @return Operation status
124 +int make_temporary_tables_old_format(THD *thd, ST_SCHEMA_TABLE *schema_table)
127 + String buffer(tmp,sizeof(tmp), thd->charset());
128 + LEX *lex= thd->lex;
129 + Name_resolution_context *context= &lex->select_lex.context;
131 + if (thd->lex->option_type == OPT_GLOBAL) {
132 + ST_FIELD_INFO *field_info= &schema_table->fields_info[0];
133 + Item_field *field= new Item_field(context, NullS, NullS, field_info->field_name);
134 + if (add_item_to_list(thd, field))
136 + field->set_name(field_info->old_name, strlen(field_info->old_name), system_charset_info);
139 + ST_FIELD_INFO *field_info= &schema_table->fields_info[2];
141 + buffer.append(field_info->old_name);
142 + buffer.append(lex->select_lex.db);
144 + if (lex->wild && lex->wild->ptr())
146 + buffer.append(STRING_WITH_LEN(" ("));
147 + buffer.append(lex->wild->ptr());
148 + buffer.append(')');
151 + Item_field *field= new Item_field(context, NullS, NullS, field_info->field_name);
152 + if (add_item_to_list(thd, field))
155 + field->set_name(buffer.ptr(), buffer.length(), system_charset_info);
160 + @brief Fill records for temporary tables by reading info from table object
162 + @param[in] thd thread handler
163 + @param[in] table I_S table
164 + @param[in] tmp_table temporary table
165 + @param[in] db database name
167 + @return Operation status
172 +static int store_temporary_table_record(THD *thd, TABLE *table, TABLE *tmp_table, const char *db, bool table_name_only)
174 + CHARSET_INFO *cs= system_charset_info;
175 + DBUG_ENTER("store_temporary_table_record");
177 + if (db && my_strcasecmp(cs, db, tmp_table->s->db.str))
180 + restore_record(table, s->default_values);
183 + table->field[0]->store((longlong) thd->thread_id, TRUE);
186 + table->field[1]->store(tmp_table->s->db.str, tmp_table->s->db.length, cs);
189 + table->field[2]->store(tmp_table->s->table_name.str, tmp_table->s->table_name.length, cs);
191 + if (table_name_only)
192 + DBUG_RETURN(schema_table_store_record(thd, table));
195 + handler *handle= tmp_table->file;
196 + char *engineType = (char *)(handle ? handle->table_type() : "UNKNOWN");
197 + table->field[3]->store(engineType, strlen(engineType), cs);
200 + if (tmp_table->s->path.str) {
201 + char *p=strstr(tmp_table->s->path.str, "#sql");
202 + int len=tmp_table->s->path.length-(p-tmp_table->s->path.str);
203 + table->field[4]->store(p, min(FN_REFLEN, len), cs);
207 + handler *file= tmp_table->file;
214 + TODO: InnoDB stat(file) checks file on short names within data dictionary
215 + rather than using full path, because of that, temp files created in
216 + TMPDIR will not have access/create time as it will not find the file
218 + The fix is to patch InnoDB to use full path
220 + file->info(HA_STATUS_VARIABLE | HA_STATUS_TIME | HA_STATUS_NO_LOCK);
222 + table->field[5]->store((longlong) file->stats.records, TRUE);
223 + table->field[5]->set_notnull();
225 + table->field[6]->store((longlong) file->stats.mean_rec_length, TRUE);
226 + table->field[7]->store((longlong) file->stats.data_file_length, TRUE);
227 + table->field[8]->store((longlong) file->stats.index_file_length, TRUE);
228 + if (file->stats.create_time)
230 + thd->variables.time_zone->gmt_sec_to_TIME(&time,
231 + (my_time_t) file->stats.create_time);
232 + table->field[9]->store_time(&time, MYSQL_TIMESTAMP_DATETIME);
233 + table->field[9]->set_notnull();
235 + if (file->stats.update_time)
237 + thd->variables.time_zone->gmt_sec_to_TIME(&time,
238 + (my_time_t) file->stats.update_time);
239 + table->field[10]->store_time(&time, MYSQL_TIMESTAMP_DATETIME);
240 + table->field[10]->set_notnull();
244 + DBUG_RETURN(schema_table_store_record(thd, table));
248 + @brief Fill I_S tables with global temporary tables
250 + @param[in] thd thread handler
251 + @param[in] tables I_S table
252 + @param[in] cond 'WHERE' condition
254 + @return Operation status
259 +static int fill_global_temporary_tables(THD *thd, TABLE_LIST *tables, COND *cond)
261 + DBUG_ENTER("fill_global_temporary_tables");
263 + mysql_mutex_lock(&LOCK_thread_count);
265 + bool table_names_only= (thd->lex->sql_command == SQLCOM_SHOW_TEMPORARY_TABLES) ? 1 : 0;
266 + I_List_iterator<THD> it(threads);
270 +#ifndef NO_EMBEDDED_ACCESS_CHECKS
271 + Security_context *sctx= thd->security_ctx;
275 + while ((thd_item=it++)) {
276 + mysql_mutex_lock(&thd_item->LOCK_temporary_tables);
277 + for (tmp=thd_item->temporary_tables; tmp; tmp=tmp->next) {
279 +#ifndef NO_EMBEDDED_ACCESS_CHECKS
280 + if (test_all_bits(sctx->master_access, DB_ACLS))
283 + db_access= (acl_get(sctx->host, sctx->ip, sctx->priv_user, tmp->s->db.str, 0) | sctx->master_access);
285 + if (!(db_access & DB_ACLS) && check_grant_db(thd,tmp->s->db.str)) {
286 + //no access for temp tables within this db for user
291 + THD *t= tmp->in_use;
294 + if (store_temporary_table_record(thd_item, tables->table, tmp, thd->lex->select_lex.db, table_names_only)) {
296 + mysql_mutex_unlock(&thd_item->LOCK_temporary_tables);
297 + mysql_mutex_unlock(&LOCK_thread_count);
303 + mysql_mutex_unlock(&thd_item->LOCK_temporary_tables);
306 + mysql_mutex_unlock(&LOCK_thread_count);
311 + @brief Fill I_S tables with session temporary tables
313 + @param[in] thd thread handler
314 + @param[in] tables I_S table
315 + @param[in] cond 'WHERE' condition
317 + @return Operation status
322 +int fill_temporary_tables(THD *thd, TABLE_LIST *tables, COND *cond)
324 + DBUG_ENTER("fill_temporary_tables");
326 + if (thd->lex->option_type == OPT_GLOBAL)
327 + DBUG_RETURN(fill_global_temporary_tables(thd, tables, cond));
329 + bool table_names_only= (thd->lex->sql_command == SQLCOM_SHOW_TEMPORARY_TABLES) ? 1 : 0;
332 + for (tmp=thd->temporary_tables; tmp; tmp=tmp->next) {
333 + if (store_temporary_table_record(thd, tables->table, tmp, thd->lex->select_lex.db, table_names_only)) {
341 Try acquire high priority share metadata lock on a table (with
342 @@ -7046,6 +7272,25 @@
343 {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
346 +ST_FIELD_INFO temporary_table_fields_info[]=
348 + {"SESSION_ID", 4, MYSQL_TYPE_LONGLONG, 0, 0, "Session", SKIP_OPEN_TABLE},
349 + {"TABLE_SCHEMA", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, "Db", SKIP_OPEN_TABLE},
350 + {"TABLE_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, "Temp_tables_in_", SKIP_OPEN_TABLE},
351 + {"ENGINE", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, "Engine", OPEN_FRM_ONLY},
352 + {"NAME", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, "Name", SKIP_OPEN_TABLE},
353 + {"TABLE_ROWS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
354 + MY_I_S_UNSIGNED, "Rows", OPEN_FULL_TABLE},
355 + {"AVG_ROW_LENGTH", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
356 + MY_I_S_UNSIGNED, "Avg Row", OPEN_FULL_TABLE},
357 + {"DATA_LENGTH", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
358 + MY_I_S_UNSIGNED, "Data Length", OPEN_FULL_TABLE},
359 + {"INDEX_LENGTH", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
360 + MY_I_S_UNSIGNED, "Index Size", OPEN_FULL_TABLE},
361 + {"CREATE_TIME", 0, MYSQL_TYPE_DATETIME, 0, 1, "Create Time", OPEN_FULL_TABLE},
362 + {"UPDATE_TIME", 0, MYSQL_TYPE_DATETIME, 0, 1, "Update Time", OPEN_FULL_TABLE},
363 + {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
366 ST_FIELD_INFO columns_fields_info[]=
368 @@ -7660,6 +7905,9 @@
369 hton_fill_schema_table, 0, 0, -1, -1, 0, 0},
370 {"GLOBAL_STATUS", variables_fields_info, create_schema_table,
371 fill_status, make_old_format, 0, 0, -1, 0, 0},
372 + {"GLOBAL_TEMPORARY_TABLES", temporary_table_fields_info, create_schema_table,
373 + fill_global_temporary_tables, make_temporary_tables_old_format, 0, 2, 3, 0,
374 + OPEN_TABLE_ONLY|OPTIMIZE_I_S_TABLE},
375 {"GLOBAL_VARIABLES", variables_fields_info, create_schema_table,
376 fill_variables, make_old_format, 0, 0, -1, 0, 0},
377 {"KEY_COLUMN_USAGE", key_column_usage_fields_info, create_schema_table,
378 @@ -7709,6 +7957,9 @@
379 get_all_tables, make_table_names_old_format, 0, 1, 2, 1, 0},
380 {"TABLE_PRIVILEGES", table_privileges_fields_info, create_schema_table,
381 fill_schema_table_privileges, 0, 0, -1, -1, 0, 0},
382 + {"TEMPORARY_TABLES", temporary_table_fields_info, create_schema_table,
383 + fill_temporary_tables, make_temporary_tables_old_format, 0, 2, 3, 0,
384 + OPEN_TABLE_ONLY|OPTIMIZE_I_S_TABLE},
385 {"TRIGGERS", triggers_fields_info, create_schema_table,
386 get_all_tables, make_old_format, get_schema_triggers_record, 5, 6, 0,
387 OPEN_TRIGGER_ONLY|OPTIMIZE_I_S_TABLE},
388 --- a/sql/sql_yacc.yy
389 +++ b/sql/sql_yacc.yy
390 @@ -10898,6 +10898,15 @@
391 if (prepare_schema_table(YYTHD, lex, 0, SCH_TABLE_NAMES))
394 + | opt_var_type TEMPORARY TABLES opt_db
397 + lex->sql_command= SQLCOM_SHOW_TEMPORARY_TABLES;
398 + lex->option_type= $1;
399 + lex->select_lex.db= $4;
400 + if (prepare_schema_table(YYTHD, lex, 0, SCH_TEMPORARY_TABLES))
403 | opt_full TRIGGERS_SYM opt_db wild_and_where
409 extern PSI_mutex_key key_LOCK_des_key_file;
412 +extern PSI_mutex_key key_LOCK_temporary_tables;
413 extern PSI_mutex_key key_BINLOG_LOCK_index, key_BINLOG_LOCK_prep_xids,
414 key_delayed_insert_mutex, key_hash_filo_lock, key_LOCK_active_mi,
415 key_LOCK_connection_count, key_LOCK_crypt, key_LOCK_delayed_create,
416 --- a/sql/sql_base.cc
417 +++ b/sql/sql_base.cc
418 @@ -1651,12 +1651,16 @@
419 if (!mysql_bin_log.is_open())
423 + mysql_mutex_lock(&thd->LOCK_temporary_tables);
424 for (table= thd->temporary_tables; table; table= tmp_next)
426 tmp_next= table->next;
427 close_temporary(table, 1, 1);
429 thd->temporary_tables= 0;
430 + mysql_mutex_unlock(&thd->LOCK_temporary_tables);
435 @@ -1669,6 +1673,8 @@
437 memcpy(buf, stub, stub_len);
439 + mysql_mutex_lock(&thd->LOCK_temporary_tables);
442 Insertion sort of temp tables by pseudo_thread_id to build ordered list
443 of sublists of equal pseudo_thread_id
444 @@ -1790,6 +1796,8 @@
445 thd->variables.option_bits&= ~OPTION_QUOTE_SHOW_CREATE; /* restore option */
446 thd->temporary_tables=0;
448 + mysql_mutex_unlock(&thd->LOCK_temporary_tables);
453 @@ -2167,6 +2175,8 @@
454 table->s->db.str, table->s->table_name.str,
455 (long) table, table->alias));
457 + mysql_mutex_lock(&thd->LOCK_temporary_tables);
461 table->prev->next= table->next;
462 @@ -2193,6 +2203,9 @@
463 slave_open_temp_tables--;
465 close_temporary(table, free_share, delete_table);
467 + mysql_mutex_unlock(&thd->LOCK_temporary_tables);
472 @@ -5932,6 +5945,7 @@
473 if (add_to_temporary_tables_list)
475 /* growing temp list at the head */
476 + mysql_mutex_lock(&thd->LOCK_temporary_tables);
477 tmp_table->next= thd->temporary_tables;
479 tmp_table->next->prev= tmp_table;
480 @@ -5939,6 +5953,7 @@
481 thd->temporary_tables->prev= 0;
482 if (thd->slave_thread)
483 slave_open_temp_tables++;
484 + mysql_mutex_unlock(&thd->LOCK_temporary_tables);
486 tmp_table->pos_in_table_list= 0;
487 DBUG_PRINT("tmptable", ("opened table: '%s'.'%s' 0x%lx", tmp_table->s->db.str,
488 --- a/sql/sql_class.cc
489 +++ b/sql/sql_class.cc
493 mysql_mutex_init(key_LOCK_thd_data, &LOCK_thd_data, MY_MUTEX_INIT_FAST);
494 + mysql_mutex_init(key_LOCK_temporary_tables, &LOCK_temporary_tables,
495 + MY_MUTEX_INIT_FAST);
497 /* Variables with default values */
499 @@ -1348,6 +1350,7 @@
501 free_root(&transaction.mem_root,MYF(0));
502 mysql_mutex_destroy(&LOCK_thd_data);
503 + mysql_mutex_destroy(&LOCK_temporary_tables);
505 dbug_sentry= THD_SENTRY_GONE;
507 --- a/sql/sql_class.h
508 +++ b/sql/sql_class.h
509 @@ -1002,6 +1002,11 @@
510 XXX Why are internal temporary tables added to this list?
512 TABLE *temporary_tables;
514 + Protects temporary_tables.
516 + mysql_mutex_t LOCK_temporary_tables;
518 TABLE *derived_tables;
520 During a MySQL session, one can lock tables in two modes: automatic
522 +++ b/mysql-test/r/percona_show_temp_tables.result
524 +drop table if exists t1,t2,t3;
525 +drop database if exists showtemp;
526 +create database if not exists showtemp;
528 +create temporary table t1(id int);
529 +create temporary table t2(id int);
530 +create temporary table showtemp.t3(id int);
531 +insert into t1 values(10),(20),(30),(40);
532 +insert into showtemp.t3 values(999);
533 +show temporary tables;
537 +show temporary tables from test;
541 +show temporary tables in showtemp;
542 +Temp_tables_in_showtemp
544 +select table_schema, table_name, engine, table_rows from Information_schema.temporary_tables;
545 +table_schema table_name engine table_rows
546 +showtemp t3 MyISAM 1
549 +select table_schema, table_name, engine, table_rows from Information_schema.global_temporary_tables;
550 +table_schema table_name engine table_rows
551 +showtemp t3 MyISAM 1
554 +select table_schema, table_name, engine, table_rows from Information_schema.global_temporary_tables where table_schema='showtemp';
555 +table_schema table_name engine table_rows
556 +showtemp t3 MyISAM 1
557 +select table_schema, table_name, engine, table_rows from Information_schema.global_temporary_tables where table_schema='temp';
558 +table_schema table_name engine table_rows
559 +drop table if exists showtemp.t2;
560 +create temporary table t1(id int);
561 +create temporary table showtemp.t2(id int);
562 +show temporary tables;
565 +select table_schema, table_name, engine, table_rows from Information_schema.global_temporary_tables;
566 +table_schema table_name engine table_rows
567 +showtemp t2 MyISAM 0
569 +showtemp t3 MyISAM 1
572 +drop table showtemp.t2;
574 +select table_schema, table_name, engine, table_rows from Information_schema.global_temporary_tables;
575 +table_schema table_name engine table_rows
576 +showtemp t3 MyISAM 1
580 +drop table showtemp.t3;
581 +drop database showtemp;
583 +++ b/mysql-test/t/percona_show_temp_tables.test
585 +# Uses GRANT commands that usually disabled in embedded server
586 +-- source include/not_embedded.inc
588 +# Save the initial number of concurrent sessions
589 +--source include/count_sessions.inc
592 +# Test of SHOW [GLOBAL] TEMPORARY TABLES [FROM/IN] DB and
593 +# Information_schema.temporary_tables and global_temporary_tables
596 +connect(stcon1,localhost,root,,test);
597 +connect(stcon2,localhost,root,,test);
602 +drop table if exists t1,t2,t3;
603 +drop database if exists showtemp;
604 +create database if not exists showtemp;
608 +create temporary table t1(id int);
609 +create temporary table t2(id int);
610 +create temporary table showtemp.t3(id int);
611 +insert into t1 values(10),(20),(30),(40);
612 +insert into showtemp.t3 values(999);
614 +show temporary tables;
615 +# "Session" is not same value always. mysql-test cannot test it always.
616 +#show global temporary tables;
617 +show temporary tables from test;
618 +show temporary tables in showtemp;
619 +select table_schema, table_name, engine, table_rows from Information_schema.temporary_tables;
620 +select table_schema, table_name, engine, table_rows from Information_schema.global_temporary_tables;
621 +select table_schema, table_name, engine, table_rows from Information_schema.global_temporary_tables where table_schema='showtemp';
622 +select table_schema, table_name, engine, table_rows from Information_schema.global_temporary_tables where table_schema='temp';
627 +drop table if exists showtemp.t2;
629 +create temporary table t1(id int);
630 +create temporary table showtemp.t2(id int);
631 +show temporary tables;
632 +select table_schema, table_name, engine, table_rows from Information_schema.global_temporary_tables;
633 +drop table showtemp.t2;
639 +select table_schema, table_name, engine, table_rows from Information_schema.global_temporary_tables;
642 +drop table showtemp.t3;
643 +drop database showtemp;
648 +# Wait till all disconnects are completed
649 +--source include/wait_until_count_sessions.inc