mirror of
https://github.com/MariaDB/server.git
synced 2025-07-30 16:24:05 +03:00
MDEV-406: ANALYZE $stmt: get ANALYZE work for subqueries
- "ANALYZE $stmt" should discard select's output, but it should still evaluate the output columns (otherwise, subqueries in select list are not executed) - SHOW EXPLAIN's code practice of calling JOIN::save_explain_data() after JOIN::exec() is disastrous for ANALYZE, because it resets all counters after the first execution. It is stopped = "Late" test_if_skip_sort_order() calls explicitly update their part of the query plan. = Also, I had to rewrite I_S optimization to actually have optimization and execution stages.
This commit is contained in:
198
sql/sql_show.cc
198
sql/sql_show.cc
@ -121,12 +121,6 @@ append_algorithm(TABLE_LIST *table, String *buff);
|
||||
|
||||
static COND * make_cond_for_info_schema(COND *cond, TABLE_LIST *table);
|
||||
|
||||
typedef struct st_lookup_field_values
|
||||
{
|
||||
LEX_STRING db_value, table_value;
|
||||
bool wild_db_value, wild_table_value;
|
||||
} LOOKUP_FIELD_VALUES;
|
||||
|
||||
bool get_lookup_field_values(THD *, COND *, TABLE_LIST *, LOOKUP_FIELD_VALUES *);
|
||||
|
||||
/***************************************************************************
|
||||
@ -4628,6 +4622,10 @@ public:
|
||||
from frm files and storage engine are filled by the function
|
||||
get_all_tables().
|
||||
|
||||
@note This function assumes optimize_for_get_all_tables() has been
|
||||
run for the table and produced a "read plan" in
|
||||
tables->is_table_read_plan.
|
||||
|
||||
@param[in] thd thread handler
|
||||
@param[in] tables I_S table
|
||||
@param[in] cond 'WHERE' condition
|
||||
@ -4644,16 +4642,16 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
|
||||
TABLE_LIST table_acl_check;
|
||||
SELECT_LEX *lsel= tables->schema_select_lex;
|
||||
ST_SCHEMA_TABLE *schema_table= tables->schema_table;
|
||||
LOOKUP_FIELD_VALUES lookup_field_vals;
|
||||
IS_table_read_plan *plan= tables->is_table_read_plan;
|
||||
enum enum_schema_tables schema_table_idx;
|
||||
Dynamic_array<LEX_STRING*> db_names;
|
||||
COND *partial_cond= 0;
|
||||
Item *partial_cond= plan->partial_cond;
|
||||
int error= 1;
|
||||
Open_tables_backup open_tables_state_backup;
|
||||
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
||||
Security_context *sctx= thd->security_ctx;
|
||||
#endif
|
||||
uint table_open_method;
|
||||
uint table_open_method= tables->table_open_method;
|
||||
bool can_deadlock;
|
||||
DBUG_ENTER("get_all_tables");
|
||||
|
||||
@ -4677,9 +4675,6 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
|
||||
thd->reset_n_backup_open_tables_state(&open_tables_state_backup);
|
||||
|
||||
schema_table_idx= get_schema_table_idx(schema_table);
|
||||
tables->table_open_method= table_open_method=
|
||||
get_table_open_method(tables, schema_table, schema_table_idx);
|
||||
DBUG_PRINT("open_method", ("%d", tables->table_open_method));
|
||||
/*
|
||||
this branch processes SHOW FIELDS, SHOW INDEXES commands.
|
||||
see sql_parse.cc, prepare_schema_table() function where
|
||||
@ -4703,44 +4698,12 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (get_lookup_field_values(thd, cond, tables, &lookup_field_vals))
|
||||
if (plan->no_rows)
|
||||
{
|
||||
error= 0;
|
||||
goto err;
|
||||
}
|
||||
|
||||
DBUG_PRINT("info",("db_name='%s', table_name='%s'",
|
||||
lookup_field_vals.db_value.str,
|
||||
lookup_field_vals.table_value.str));
|
||||
|
||||
if (!lookup_field_vals.wild_db_value && !lookup_field_vals.wild_table_value)
|
||||
{
|
||||
/*
|
||||
if lookup value is empty string then
|
||||
it's impossible table name or db name
|
||||
*/
|
||||
if ((lookup_field_vals.db_value.str &&
|
||||
!lookup_field_vals.db_value.str[0]) ||
|
||||
(lookup_field_vals.table_value.str &&
|
||||
!lookup_field_vals.table_value.str[0]))
|
||||
{
|
||||
error= 0;
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
if (lookup_field_vals.db_value.length &&
|
||||
!lookup_field_vals.wild_db_value)
|
||||
tables->has_db_lookup_value= TRUE;
|
||||
if (lookup_field_vals.table_value.length &&
|
||||
!lookup_field_vals.wild_table_value)
|
||||
tables->has_table_lookup_value= TRUE;
|
||||
|
||||
if (tables->has_db_lookup_value && tables->has_table_lookup_value)
|
||||
partial_cond= 0;
|
||||
else
|
||||
partial_cond= make_cond_for_info_schema(cond, tables);
|
||||
|
||||
if (lex->describe)
|
||||
{
|
||||
/* EXPLAIN SELECT */
|
||||
@ -4750,7 +4713,7 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
|
||||
|
||||
bzero((char*) &table_acl_check, sizeof(table_acl_check));
|
||||
|
||||
if (make_db_list(thd, &db_names, &lookup_field_vals))
|
||||
if (make_db_list(thd, &db_names, &plan->lookup_field_vals))
|
||||
goto err;
|
||||
for (size_t i=0; i < db_names.elements(); i++)
|
||||
{
|
||||
@ -4765,7 +4728,7 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
|
||||
{
|
||||
Dynamic_array<LEX_STRING*> table_names;
|
||||
int res= make_table_name_list(thd, &table_names, lex,
|
||||
&lookup_field_vals, db_name);
|
||||
&plan->lookup_field_vals, db_name);
|
||||
if (res == 2) /* Not fatal error, continue */
|
||||
continue;
|
||||
if (res)
|
||||
@ -4802,8 +4765,8 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
|
||||
already created by make_table_name_list() function).
|
||||
*/
|
||||
if (!table_open_method && schema_table_idx == SCH_TABLES &&
|
||||
(!lookup_field_vals.table_value.length ||
|
||||
lookup_field_vals.wild_table_value))
|
||||
(!plan->lookup_field_vals.table_value.length ||
|
||||
plan->lookup_field_vals.wild_table_value))
|
||||
{
|
||||
table->field[0]->store(STRING_WITH_LEN("def"), system_charset_info);
|
||||
if (schema_table_store_record(thd, table))
|
||||
@ -7979,6 +7942,137 @@ int make_schema_select(THD *thd, SELECT_LEX *sel,
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Optimize reading from an I_S table.
|
||||
|
||||
@detail
|
||||
This function prepares a plan for populating an I_S table with
|
||||
get_all_tables().
|
||||
|
||||
The plan is in IS_table_read_plan structure, it is saved in
|
||||
tables->is_table_read_plan.
|
||||
|
||||
@return
|
||||
false - Ok
|
||||
true - Out Of Memory
|
||||
|
||||
*/
|
||||
|
||||
static bool optimize_for_get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
|
||||
{
|
||||
SELECT_LEX *lsel= tables->schema_select_lex;
|
||||
ST_SCHEMA_TABLE *schema_table= tables->schema_table;
|
||||
enum enum_schema_tables schema_table_idx;
|
||||
IS_table_read_plan *plan;
|
||||
DBUG_ENTER("get_all_tables");
|
||||
|
||||
if (!(plan= new IS_table_read_plan()))
|
||||
DBUG_RETURN(1);
|
||||
|
||||
tables->is_table_read_plan= plan;
|
||||
|
||||
schema_table_idx= get_schema_table_idx(schema_table);
|
||||
tables->table_open_method= get_table_open_method(tables, schema_table,
|
||||
schema_table_idx);
|
||||
DBUG_PRINT("open_method", ("%d", tables->table_open_method));
|
||||
|
||||
/*
|
||||
this branch processes SHOW FIELDS, SHOW INDEXES commands.
|
||||
see sql_parse.cc, prepare_schema_table() function where
|
||||
this values are initialized
|
||||
*/
|
||||
if (lsel && lsel->table_list.first)
|
||||
{
|
||||
/* These do not need to have a query plan */
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (get_lookup_field_values(thd, cond, tables, &plan->lookup_field_vals))
|
||||
{
|
||||
plan->no_rows= true;
|
||||
goto end;
|
||||
}
|
||||
|
||||
DBUG_PRINT("info",("db_name='%s', table_name='%s'",
|
||||
plan->lookup_field_vals.db_value.str,
|
||||
plan->lookup_field_vals.table_value.str));
|
||||
|
||||
if (!plan->lookup_field_vals.wild_db_value &&
|
||||
!plan->lookup_field_vals.wild_table_value)
|
||||
{
|
||||
/*
|
||||
if lookup value is empty string then
|
||||
it's impossible table name or db name
|
||||
*/
|
||||
if ((plan->lookup_field_vals.db_value.str &&
|
||||
!plan->lookup_field_vals.db_value.str[0]) ||
|
||||
(plan->lookup_field_vals.table_value.str &&
|
||||
!plan->lookup_field_vals.table_value.str[0]))
|
||||
{
|
||||
plan->no_rows= true;
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
||||
if (plan->has_db_lookup_value() && plan->has_table_lookup_value())
|
||||
plan->partial_cond= 0;
|
||||
else
|
||||
plan->partial_cond= make_cond_for_info_schema(cond, tables);
|
||||
|
||||
end:
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
This is the optimizer part of get_schema_tables_result().
|
||||
*/
|
||||
|
||||
bool optimize_schema_tables_reads(JOIN *join)
|
||||
{
|
||||
THD *thd= join->thd;
|
||||
bool result= 0;
|
||||
DBUG_ENTER("optimize_schema_tables_reads");
|
||||
|
||||
for (JOIN_TAB *tab= first_linear_tab(join, WITH_CONST_TABLES);
|
||||
tab;
|
||||
tab= next_linear_tab(join, tab, WITH_BUSH_ROOTS))
|
||||
{
|
||||
if (!tab->table || !tab->table->pos_in_table_list)
|
||||
continue;
|
||||
|
||||
TABLE_LIST *table_list= tab->table->pos_in_table_list;
|
||||
if (table_list->schema_table && thd->fill_information_schema_tables())
|
||||
{
|
||||
/* A value of 0 indicates a dummy implementation */
|
||||
if (table_list->schema_table->fill_table == 0)
|
||||
continue;
|
||||
|
||||
/* skip I_S optimizations specific to get_all_tables */
|
||||
if (table_list->schema_table->fill_table != get_all_tables)
|
||||
continue;
|
||||
|
||||
Item *cond= tab->select_cond;
|
||||
if (tab->cache_select && tab->cache_select->cond)
|
||||
{
|
||||
/*
|
||||
If join buffering is used, we should use the condition that is
|
||||
attached to the join cache. Cache condition has a part of WHERE that
|
||||
can be checked when we're populating this table.
|
||||
join_tab->select_cond is of no interest, because it only has
|
||||
conditions that depend on both this table and previous tables in the
|
||||
join order.
|
||||
*/
|
||||
cond= tab->cache_select->cond;
|
||||
}
|
||||
|
||||
optimize_for_get_all_tables(thd, table_list, cond);
|
||||
}
|
||||
}
|
||||
DBUG_RETURN(result);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Fill temporary schema tables before SELECT
|
||||
|
||||
@ -7987,6 +8081,10 @@ int make_schema_select(THD *thd, SELECT_LEX *sel,
|
||||
join join which use schema tables
|
||||
executed_place place where I_S table processed
|
||||
|
||||
SEE ALSO
|
||||
The optimization part is done by get_schema_tables_result(). This function
|
||||
is run on query execution.
|
||||
|
||||
RETURN
|
||||
FALSE success
|
||||
TRUE error
|
||||
@ -8007,7 +8105,7 @@ bool get_schema_tables_result(JOIN *join,
|
||||
|
||||
for (JOIN_TAB *tab= first_linear_tab(join, WITH_CONST_TABLES);
|
||||
tab;
|
||||
tab= next_linear_tab(join, tab, WITHOUT_BUSH_ROOTS))
|
||||
tab= next_linear_tab(join, tab, WITH_BUSH_ROOTS))
|
||||
{
|
||||
if (!tab->table || !tab->table->pos_in_table_list)
|
||||
break;
|
||||
|
Reference in New Issue
Block a user