Today, while helping someone find some of the code that implements SHOW VARIABLES I was reminded at how insanely complex it all got with the information_schema implementation and the changes to the SHOW commands that came with it. Specifically, I was trying to find exactly how the SHOW VARIABLES output gets populated — what the source data is.
By way of example, I present the code to implement it in 5.1.51 (the new way), and in 4.1.21 (the old way). I, at least, have a much easier time sorting out the old way. They both start with the same basic entry point, in the parser, in show: within sql/sql_yacc.yy.
SHOW VARIABLES in MySQL 5.1.51
sql/sql_yacc.yy
The show token just does some initialization.
10062 show: 10063 SHOW 10064 { 10065 LEX *lex=Lex; 10066 lex->wild=0; 10067 lex->lock_option= TL_READ; 10068 mysql_init_select(lex); 10069 lex->current_select->parsing_place= SELECT_LIST; 10070 bzero((char*) &lex->create_info,sizeof(lex->create_info)); 10071 } 10072 show_param 10073 {} 10074 ;
The command-specific work is done in show_param, but prepare_schema_table just sets up essentially a temporary table.
10076 show_param: ... 10273 | opt_var_type VARIABLES wild_and_where 10274 { 10275 LEX *lex= Lex; 10276 lex->sql_command= SQLCOM_SHOW_VARIABLES; 10277 lex->option_type= $1; 10278 if (prepare_schema_table(YYTHD, lex, 0, SCH_VARIABLES)) 10279 MYSQL_YYABORT; 10280 }
sql/sql_parse.cc
Another hoop…
1754 int prepare_schema_table(THD *thd, LEX *lex, Table_ident *table_ident, 1755 enum enum_schema_tables schema_table_idx) 1756 { ... 1849 if (make_schema_select(thd, select_lex, schema_table_idx)) 1850 { 1851 DBUG_RETURN(1); 1852 }
sql/sql_show.cc
Through a few hoops, and sel->add_table_to_list(…) adds the new temporary table to the select list.
6076 int make_schema_select(THD *thd, SELECT_LEX *sel, 6077 enum enum_schema_tables schema_table_idx) 6078 { 6079 ST_SCHEMA_TABLE *schema_table= get_schema_table(schema_table_idx); 6080 LEX_STRING db, table; 6081 DBUG_ENTER("make_schema_select"); 6082 DBUG_PRINT("enter", ("mysql_schema_select: %s", schema_table->table_name)); ... 6087 thd->make_lex_string(&db, INFORMATION_SCHEMA_NAME.str, 6088 INFORMATION_SCHEMA_NAME.length, 0); 6089 thd->make_lex_string(&table, schema_table->table_name, 6090 strlen(schema_table->table_name), 0); 6091 if (schema_table->old_format(thd, schema_table) || 6092 !sel->add_table_to_list(thd, new Table_ident(thd, db, table, 0), 6093 0, 0, TL_READ)) 6094 { 6095 DBUG_RETURN(1); 6096 } 6097 DBUG_RETURN(0); 6098 }
At this point an internal query has basically been built to do:
SELECT * FROM INFORMATION_SCHEMA.VARIABLES
So now that table needs to be populated, but you’ll need to happen to just know where to look to find the rest of the code…
sql/sql_show.cc
The schema_tables array lists all of the information_schema tables and how they are each populated.
6805 ST_SCHEMA_TABLE schema_tables[]= 6806 { ... 6879 {"VARIABLES", variables_fields_info, create_schema_table, fill_variables, 6880 make_old_format, 0, 0, -1, 1, 0}, ... 6884 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0} 6885 };
The schema_tables array says fill_variables can take care of it…
5441 int fill_variables(THD *thd, TABLE_LIST *tables, COND *cond) 5442 { ... 5458 res= show_status_array(thd, wild, enumerate_sys_vars(thd, sorted_vars), 5459 option_type, NULL, "", tables->table, upper_case_names, cond); ... 5461 DBUG_RETURN(res); 5462 }
And then show_status_array just knows how to return a SHOW_VAR *, the real work happens in enumerate_sys_vars.
sql/set_var.cc
And finally the SHOW_VAR *result can be populated from the in-memory structures, in this case the system_variable_hash.
3346 SHOW_VAR* enumerate_sys_vars(THD *thd, bool sorted) 3347 { 3348 int count= system_variable_hash.records, i; 3349 int size= sizeof(SHOW_VAR) * (count + 1); 3350 SHOW_VAR *result= (SHOW_VAR*) thd->alloc(size); 3351 3352 if (result) 3353 { 3354 SHOW_VAR *show= result; 3355 3356 for (i= 0; i < count; i++) 3357 { 3358 sys_var *var= (sys_var*) hash_element(&system_variable_hash, i); 3359 show->name= var->name; 3360 show->value= (char*) var; 3361 show->type= SHOW_SYS; 3362 show++; 3363 } 3364 3365 /* sort into order */ 3366 if (sorted) 3367 my_qsort(result, count, sizeof(SHOW_VAR), 3368 (qsort_cmp) show_cmp); 3369 3370 /* make last element empty */ 3371 bzero(show, sizeof(SHOW_VAR)); 3372 } 3373 return result; 3374 }
SHOW VARIABLES in MySQL 4.1.24
sql/sql_yacc.yy
The same basic entry point.
4422 show: SHOW 4423 { 4424 LEX *lex=Lex; 4425 lex->wild=0; 4426 bzero((char*) &lex->create_info,sizeof(lex->create_info)); 4427 } 4428 show_param 4429 {} 4430 ;
The SQLCOM_SHOW_VARIABLES is saved for later use, denoting what kind of SHOW this query is.
4432 show_param: ... 4531 | opt_var_type VARIABLES wild 4532 { 4533 THD *thd= YYTHD; 4534 thd->lex->sql_command= SQLCOM_SHOW_VARIABLES; 4535 thd->lex->option_type= (enum_var_type) $1; 4536 }
sql/sql_parse.cc
In mysql_execute_command a mega switch statement decides what function will handle this query.
1992 void 1993 mysql_execute_command(THD *thd) 1994 { ... 3260 case SQLCOM_SHOW_VARIABLES: 3261 res= mysqld_show(thd, (lex->wild ? lex->wild->ptr() : NullS), 3262 init_vars, lex->option_type, 3263 &LOCK_global_system_variables); 3264 break;
sql/sql_show.cc
And the magic happens here, in a single function.
1815 int mysqld_show(THD *thd, const char *wild, show_var_st *variables, 1816 enum enum_var_type value_type, 1817 pthread_mutex_t *mutex) 1818 { 1819 char buff[1024]; 1820 List<item> field_list; 1821 Protocol *protocol= thd->protocol; 1822 LEX_STRING null_lex_str; 1823 DBUG_ENTER("mysqld_show"); 1824 1825 field_list.push_back(new Item_empty_string("Variable_name",30)); 1826 field_list.push_back(new Item_empty_string("Value",256)); 1827 if (protocol->send_fields(&field_list,1)) 1828 DBUG_RETURN(1); 1829 null_lex_str.str= 0; 1830 null_lex_str.length= 0; 1831 1832 pthread_mutex_lock(mutex); 1833 for (; variables->name; variables++) 1834 { ... 2128 } 2129 pthread_mutex_unlock(mutex); 2130 send_eof(thd); 2131 DBUG_RETURN(0); 2132 2133 err: 2134 pthread_mutex_unlock(mutex); 2135 DBUG_RETURN(1); 2136 }
Much simpler, in my opinion.