mirror of
https://github.com/MariaDB/server.git
synced 2025-01-16 12:02:42 +01:00
Bug#25122: Views based on a self-joined table aren't insertable.
When INSERT is done over a view the table being inserted into is checked to be unique among all views tables. But if the view contains self-joined table an error will be thrown even if all tables are used under different aliases. The unique_table() function now also checks tables' aliases when needed. sql/mysql_priv.h: Bug#25122: Views based on a self-joined table aren't insertable. Updated prototype of the unique_table() function. sql/sql_base.cc: Bug#25122: Views based on a self-joined table aren't insertable. Now the unique_table() function checks tables' aliases when needed. sql/sql_delete.cc: Bug#25122: Views based on a self-joined table aren't insertable. Updated calls to the unique_table() function. sql/sql_insert.cc: Bug#25122: Views based on a self-joined table aren't insertable. Updated calls to the unique_table() function. sql/sql_load.cc: Bug#25122: Views based on a self-joined table aren't insertable. Updated calls to the unique_table() function. sql/sql_parse.cc: Bug#25122: Views based on a self-joined table aren't insertable. Updated calls to the unique_table() function. sql/sql_update.cc: Bug#25122: Views based on a self-joined table aren't insertable. Updated calls to the unique_table() function.
This commit is contained in:
parent
6d537f01fd
commit
1437a9c532
7 changed files with 19 additions and 13 deletions
|
@ -1064,7 +1064,8 @@ TABLE_LIST *find_table_in_list(TABLE_LIST *table,
|
|||
st_table_list *TABLE_LIST::*link,
|
||||
const char *db_name,
|
||||
const char *table_name);
|
||||
TABLE_LIST *unique_table(THD *thd, TABLE_LIST *table, TABLE_LIST *table_list);
|
||||
TABLE_LIST *unique_table(THD *thd, TABLE_LIST *table, TABLE_LIST *table_list,
|
||||
bool check_alias);
|
||||
TABLE **find_temporary_table(THD *thd, const char *db, const char *table_name);
|
||||
bool close_temporary_table(THD *thd, const char *db, const char *table_name);
|
||||
void close_temporary(TABLE *table, bool delete_table);
|
||||
|
|
|
@ -796,6 +796,7 @@ TABLE_LIST *find_table_in_list(TABLE_LIST *table,
|
|||
thd thread handle
|
||||
table table which should be checked
|
||||
table_list list of tables
|
||||
check_alias whether to check tables' aliases
|
||||
|
||||
NOTE: to exclude derived tables from check we use following mechanism:
|
||||
a) during derived table processing set THD::derived_tables_processing
|
||||
|
@ -823,10 +824,11 @@ TABLE_LIST *find_table_in_list(TABLE_LIST *table,
|
|||
0 if table is unique
|
||||
*/
|
||||
|
||||
TABLE_LIST* unique_table(THD *thd, TABLE_LIST *table, TABLE_LIST *table_list)
|
||||
TABLE_LIST* unique_table(THD *thd, TABLE_LIST *table, TABLE_LIST *table_list,
|
||||
bool check_alias)
|
||||
{
|
||||
TABLE_LIST *res;
|
||||
const char *d_name, *t_name;
|
||||
const char *d_name, *t_name, *t_alias;
|
||||
DBUG_ENTER("unique_table");
|
||||
DBUG_PRINT("enter", ("table alias: %s", table->alias));
|
||||
|
||||
|
@ -854,6 +856,7 @@ TABLE_LIST* unique_table(THD *thd, TABLE_LIST *table, TABLE_LIST *table_list)
|
|||
}
|
||||
d_name= table->db;
|
||||
t_name= table->table_name;
|
||||
t_alias= table->alias;
|
||||
|
||||
DBUG_PRINT("info", ("real table: %s.%s", d_name, t_name));
|
||||
for (;;)
|
||||
|
@ -861,6 +864,8 @@ TABLE_LIST* unique_table(THD *thd, TABLE_LIST *table, TABLE_LIST *table_list)
|
|||
if (((! (res= find_table_in_global_list(table_list, d_name, t_name))) &&
|
||||
(! (res= mysql_lock_have_duplicate(thd, table, table_list)))) ||
|
||||
((!res->table || res->table != table->table) &&
|
||||
(!check_alias || !(lower_case_table_names ?
|
||||
strcasecmp(t_alias, res->alias) : strcmp(t_alias, res->alias))) &&
|
||||
res->select_lex && !res->select_lex->exclude_from_table_unique_test &&
|
||||
!res->prelocking_placeholder))
|
||||
break;
|
||||
|
|
|
@ -370,7 +370,7 @@ bool mysql_prepare_delete(THD *thd, TABLE_LIST *table_list, Item **conds)
|
|||
}
|
||||
{
|
||||
TABLE_LIST *duplicate;
|
||||
if ((duplicate= unique_table(thd, table_list, table_list->next_global)))
|
||||
if ((duplicate= unique_table(thd, table_list, table_list->next_global, 0)))
|
||||
{
|
||||
update_non_unique_table_error(table_list, "DELETE", duplicate);
|
||||
DBUG_RETURN(TRUE);
|
||||
|
@ -462,7 +462,7 @@ bool mysql_multi_delete_prepare(THD *thd)
|
|||
{
|
||||
TABLE_LIST *duplicate;
|
||||
if ((duplicate= unique_table(thd, target_tbl->correspondent_table,
|
||||
lex->query_tables)))
|
||||
lex->query_tables, 0)))
|
||||
{
|
||||
update_non_unique_table_error(target_tbl->correspondent_table,
|
||||
"DELETE", duplicate);
|
||||
|
|
|
@ -1044,7 +1044,7 @@ bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list,
|
|||
{
|
||||
Item *fake_conds= 0;
|
||||
TABLE_LIST *duplicate;
|
||||
if ((duplicate= unique_table(thd, table_list, table_list->next_global)))
|
||||
if ((duplicate= unique_table(thd, table_list, table_list->next_global, 1)))
|
||||
{
|
||||
update_non_unique_table_error(table_list, "INSERT", duplicate);
|
||||
DBUG_RETURN(TRUE);
|
||||
|
@ -2424,7 +2424,7 @@ select_insert::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
|
|||
query
|
||||
*/
|
||||
if (!(lex->current_select->options & OPTION_BUFFER_RESULT) &&
|
||||
unique_table(thd, table_list, table_list->next_global))
|
||||
unique_table(thd, table_list, table_list->next_global, 0))
|
||||
{
|
||||
/* Using same table for INSERT and SELECT */
|
||||
lex->current_select->options|= OPTION_BUFFER_RESULT;
|
||||
|
|
|
@ -175,7 +175,7 @@ bool mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
|
|||
table is marked to be 'used for insert' in which case we should never
|
||||
mark this table as as 'const table' (ie, one that has only one row).
|
||||
*/
|
||||
if (unique_table(thd, table_list, table_list->next_global))
|
||||
if (unique_table(thd, table_list, table_list->next_global, 0))
|
||||
{
|
||||
my_error(ER_UPDATE_TABLE_USED, MYF(0), table_list->table_name);
|
||||
DBUG_RETURN(TRUE);
|
||||
|
|
|
@ -2993,7 +2993,7 @@ mysql_execute_command(THD *thd)
|
|||
if (!(create_info.options & HA_LEX_CREATE_TMP_TABLE))
|
||||
{
|
||||
TABLE_LIST *duplicate;
|
||||
if ((duplicate= unique_table(thd, create_table, select_tables)))
|
||||
if ((duplicate= unique_table(thd, create_table, select_tables, 0)))
|
||||
{
|
||||
update_non_unique_table_error(create_table, "CREATE", duplicate);
|
||||
res= 1;
|
||||
|
@ -3009,7 +3009,7 @@ mysql_execute_command(THD *thd)
|
|||
tab= tab->next_local)
|
||||
{
|
||||
TABLE_LIST *duplicate;
|
||||
if ((duplicate= unique_table(thd, tab, select_tables)))
|
||||
if ((duplicate= unique_table(thd, tab, select_tables, 0)))
|
||||
{
|
||||
update_non_unique_table_error(tab, "CREATE", duplicate);
|
||||
res= 1;
|
||||
|
|
|
@ -636,7 +636,7 @@ bool mysql_prepare_update(THD *thd, TABLE_LIST *table_list,
|
|||
/* Check that we are not using table that we are updating in a sub select */
|
||||
{
|
||||
TABLE_LIST *duplicate;
|
||||
if ((duplicate= unique_table(thd, table_list, table_list->next_global)))
|
||||
if ((duplicate= unique_table(thd, table_list, table_list->next_global, 0)))
|
||||
{
|
||||
update_non_unique_table_error(table_list, "UPDATE", duplicate);
|
||||
my_error(ER_UPDATE_TABLE_USED, MYF(0), table_list->table_name);
|
||||
|
@ -863,7 +863,7 @@ reopen_tables:
|
|||
tl->lock_type != TL_READ_NO_INSERT)
|
||||
{
|
||||
TABLE_LIST *duplicate;
|
||||
if ((duplicate= unique_table(thd, tl, table_list)))
|
||||
if ((duplicate= unique_table(thd, tl, table_list, 0)))
|
||||
{
|
||||
update_non_unique_table_error(table_list, "UPDATE", duplicate);
|
||||
DBUG_RETURN(TRUE);
|
||||
|
@ -1082,7 +1082,7 @@ static bool safe_update_on_fly(THD *thd, JOIN_TAB *join_tab,
|
|||
List<Item> *fields)
|
||||
{
|
||||
TABLE *table= join_tab->table;
|
||||
if (unique_table(thd, table_ref, all_tables))
|
||||
if (unique_table(thd, table_ref, all_tables, 0))
|
||||
return 0;
|
||||
switch (join_tab->type) {
|
||||
case JT_SYSTEM:
|
||||
|
|
Loading…
Reference in a new issue