1
0
mirror of https://github.com/MariaDB/server.git synced 2025-07-30 16:24:05 +03:00

MDEV-11129 CREATE OR REPLACE TABLE t1 AS SELECT spfunc() crashes if spfunc() references t1

Fixed by extending unique_table() with a flag to not allow usage of
the replaced table.

I also cleaned up find_dup_table() to not use goto next.
I also added more comments to the code in find_dup_table()
This commit is contained in:
Monty
2018-05-16 21:51:46 +03:00
parent d703e09cd6
commit ef295c31e3
7 changed files with 82 additions and 22 deletions

View File

@ -1278,7 +1278,8 @@ TABLE_LIST *find_table_in_list(TABLE_LIST *table,
@param thd thread handle
@param table table which should be checked
@param table_list list of tables
@param check_alias whether to check tables' aliases
@param check_flag whether to check tables' aliases
Currently this is only used by INSERT
NOTE: to exclude derived tables from check we use following mechanism:
a) during derived table processing set THD::derived_tables_processing
@ -1307,9 +1308,9 @@ TABLE_LIST *find_table_in_list(TABLE_LIST *table,
static
TABLE_LIST* find_dup_table(THD *thd, TABLE_LIST *table, TABLE_LIST *table_list,
bool check_alias)
uint check_flag)
{
TABLE_LIST *res;
TABLE_LIST *res= 0;
const char *d_name, *t_name, *t_alias;
DBUG_ENTER("find_dup_table");
DBUG_PRINT("enter", ("table alias: %s", table->alias));
@ -1345,17 +1346,15 @@ TABLE_LIST* find_dup_table(THD *thd, TABLE_LIST *table, TABLE_LIST *table_list,
retry:
DBUG_PRINT("info", ("real table: %s.%s", d_name, t_name));
for (TABLE_LIST *tl= table_list;;)
for (TABLE_LIST *tl= table_list; tl ; tl= tl->next_global, res= 0)
{
if (tl &&
tl->select_lex && tl->select_lex->master_unit() &&
if (tl->select_lex && tl->select_lex->master_unit() &&
tl->select_lex->master_unit()->executed)
{
/*
There is no sense to check tables of already executed parts
of the query
*/
tl= tl->next_global;
continue;
}
/*
@ -1364,21 +1363,29 @@ retry:
*/
if (! (res= find_table_in_global_list(tl, d_name, t_name)))
break;
tl= res; // We can continue search after this table
/* Skip if same underlying table. */
if (res->table && (res->table == table->table))
goto next;
continue;
if (check_flag & CHECK_DUP_FOR_CREATE)
DBUG_RETURN(res);
/* Skip if table alias does not match. */
if (check_alias)
if (check_flag & CHECK_DUP_FOR_CREATE)
{
if (my_strcasecmp(table_alias_charset, t_alias, res->alias))
goto next;
continue;
}
/*
Skip if marked to be excluded (could be a derived table) or if
entry is a prelocking placeholder.
If table is not excluded (could be a derived table) and table is not
a prelocking placeholder then we found either a duplicate entry
or a table that is part of a derived table (handled below).
Examples are:
INSERT INTO t1 SELECT * FROM t1;
INSERT INTO t1 SELECT * FROM view_containing_t1;
*/
if (res->select_lex &&
!res->select_lex->exclude_from_table_unique_test &&
@ -1390,14 +1397,17 @@ retry:
processed in derived table or top select of multi-update/multi-delete
(exclude_from_table_unique_test) or prelocking placeholder.
*/
next:
tl= res->next_global;
DBUG_PRINT("info",
("found same copy of table or table which we should skip"));
}
if (res && res->belong_to_derived)
{
/* Try to fix */
/*
We come here for queries of type:
INSERT INTO t1 (SELECT tmp.a FROM (select * FROM t1) as tmp);
Try to fix by materializing the derived table
*/
TABLE_LIST *derived= res->belong_to_derived;
if (derived->is_merged_derived())
{
@ -1429,7 +1439,7 @@ next:
TABLE_LIST*
unique_table(THD *thd, TABLE_LIST *table, TABLE_LIST *table_list,
bool check_alias)
uint check_flag)
{
TABLE_LIST *dup;
@ -1443,12 +1453,12 @@ unique_table(THD *thd, TABLE_LIST *table, TABLE_LIST *table_list,
for (child= table->next_global; child && child->parent_l == table;
child= child->next_global)
{
if ((dup= find_dup_table(thd, child, child->next_global, check_alias)))
if ((dup= find_dup_table(thd, child, child->next_global, check_flag)))
break;
}
}
else
dup= find_dup_table(thd, table, table_list, check_alias);
dup= find_dup_table(thd, table, table_list, check_flag);
return dup;
}
/*