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

support of join view updateability (WL#1809)

This commit is contained in:
bell@sanja.is.com.ua
2004-09-15 23:42:56 +03:00
parent f797298fc5
commit 67fcac7a87
38 changed files with 717 additions and 102 deletions

View File

@ -21,6 +21,7 @@
#include "sql_acl.h"
#include "sp_head.h"
#include "sql_trigger.h"
#include "sql_select.h"
static int check_null_fields(THD *thd,TABLE *entry);
#ifndef EMBEDDED_LIBRARY
@ -31,6 +32,7 @@ static void end_delayed_insert(THD *thd);
extern "C" pthread_handler_decl(handle_delayed_insert,arg);
static void unlink_blobs(register TABLE *table);
#endif
static bool check_view_insertability(TABLE_LIST *view, ulong query_id);
/* Define to force use of my_malloc() if the allocated memory block is big */
@ -54,8 +56,22 @@ check_insert_fields(THD *thd, TABLE_LIST *table_list, List<Item> &fields,
{
TABLE *table= table_list->table;
if (!table_list->updatable)
{
my_error(ER_NON_UPDATABLE_TABLE, MYF(0), table_list->alias, "INSERT");
return -1;
}
if (fields.elements == 0 && values.elements != 0)
{
if (!table)
{
DBUG_ASSERT(table_list->view &&
table_list->ancestor && table_list->ancestor->next_local);
my_error(ER_VIEW_NO_INSERT_FIELD_LIST, MYF(0),
table_list->view_db.str, table_list->view_name.str);
return -1;
}
if (values.elements != table->fields)
{
my_printf_error(ER_WRONG_VALUE_COUNT_ON_ROW,
@ -97,6 +113,23 @@ check_insert_fields(THD *thd, TABLE_LIST *table_list, List<Item> &fields,
thd->lex->select_lex.no_wrap_view_item= 0;
if (res)
return -1;
if (table == 0)
{
/* it is join view => we need to find table for update */
List_iterator_fast<Item> it(fields);
Item *item;
TABLE_LIST *tbl= 0;
table_map map= 0;
while (item= it++)
map|= item->used_tables();
if (table_list->check_single_table(&tbl, map) || tbl == 0)
{
my_error(ER_VIEW_MULTIUPDATE, MYF(0),
table_list->view_db.str, table_list->view_name.str);
return -1;
}
table_list->table= table= tbl->table;
}
if (check_unique && thd->dupp_field)
{
@ -111,6 +144,15 @@ check_insert_fields(THD *thd, TABLE_LIST *table_list, List<Item> &fields,
#ifndef NO_EMBEDDED_ACCESS_CHECKS
table->grant.want_privilege=(SELECT_ACL & ~table->grant.privilege);
#endif
if (check_key_in_view(thd, table_list) ||
(table_list->view &&
check_view_insertability(table_list, thd->query_id)))
{
my_error(ER_NON_UPDATABLE_TABLE, MYF(0), table_list->alias, "INSERT");
return -1;
}
return 0;
}
@ -134,7 +176,7 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list,
ulong counter = 1;
ulonglong id;
COPY_INFO info;
TABLE *table;
TABLE *table= 0;
List_iterator_fast<List_item> its(values_list);
List_item *values;
#ifndef EMBEDDED_LIBRARY
@ -201,17 +243,14 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list,
if (res || thd->is_fatal_error)
DBUG_RETURN(-1);
table= table_list->table;
thd->proc_info="init";
thd->used_tables=0;
values= its++;
if (duplic == DUP_UPDATE && !table->insert_values)
if (duplic == DUP_UPDATE)
{
/* it should be allocated before Item::fix_fields() */
table->insert_values=
(byte *)alloc_root(&thd->mem_root, table->rec_buff_length);
if (!table->insert_values)
if (table_list->set_insert_values(&thd->mem_root))
goto abort;
}
@ -219,6 +258,9 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list,
update_fields, update_values, duplic))
goto abort;
/* mysql_prepare_insert set table_list->table if it was not set */
table= table_list->table;
// is table which we are changing used somewhere in other parts of query
value_count= values->elements;
while ((values= its++))
@ -437,7 +479,7 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list,
::send_ok(thd, (ulong) thd->row_count_func, id, buff);
}
free_underlaid_joins(thd, &thd->lex->select_lex);
table->insert_values=0;
table_list->clear_insert_values();
DBUG_RETURN(0);
abort:
@ -446,7 +488,7 @@ abort:
end_delayed_insert(thd);
#endif
free_underlaid_joins(thd, &thd->lex->select_lex);
table->insert_values=0;
table_list->clear_insert_values();
DBUG_RETURN(-1);
}
@ -542,11 +584,12 @@ static bool check_view_insertability(TABLE_LIST *view, ulong query_id)
where Pointer to where clause
RETURN
0 ok
1 ERROR
0 ok
1 ERROR and message sent to client
-1 ERROR but message is not sent to client
*/
static bool mysql_prepare_insert_check_table(THD *thd, TABLE_LIST *table_list,
static int mysql_prepare_insert_check_table(THD *thd, TABLE_LIST *table_list,
List<Item> &fields, COND **where)
{
bool insert_into_view= (table_list->view != 0);
@ -554,22 +597,22 @@ static bool mysql_prepare_insert_check_table(THD *thd, TABLE_LIST *table_list,
if (setup_tables(thd, table_list, where, &thd->lex->select_lex.leaf_tables,
0))
DBUG_RETURN(1);
DBUG_RETURN(thd->net.report_error ? -1 : 1);
if (insert_into_view && !fields.elements)
{
thd->lex->empty_field_list_on_rset= 1;
insert_view_fields(&fields, table_list);
if (!table_list->table)
{
DBUG_ASSERT(table_list->view &&
table_list->ancestor && table_list->ancestor->next_local);
my_error(ER_VIEW_NO_INSERT_FIELD_LIST, MYF(0),
table_list->view_db.str, table_list->view_name.str);
DBUG_RETURN(-1);
}
DBUG_RETURN(insert_view_fields(&fields, table_list));
}
if (!table_list->updatable ||
check_key_in_view(thd, table_list) ||
(insert_into_view &&
check_view_insertability(table_list, thd->query_id)))
{
my_error(ER_NON_UPDATABLE_TABLE, MYF(0), table_list->alias, "INSERT");
DBUG_RETURN(1);
}
DBUG_RETURN(0);
}
@ -598,8 +641,9 @@ int mysql_prepare_insert(THD *thd, TABLE_LIST *table_list, TABLE *table,
int res;
DBUG_ENTER("mysql_prepare_insert");
if (mysql_prepare_insert_check_table(thd, table_list, fields, &unused_conds))
DBUG_RETURN(-1);
if ((res= mysql_prepare_insert_check_table(thd, table_list,
fields, &unused_conds)))
DBUG_RETURN(res);
if (check_insert_fields(thd, table_list, fields, *values, 1,
!insert_into_view) ||
@ -1607,21 +1651,43 @@ bool delayed_insert::handle_inserts(void)
RETURN
0 OK
-1 Error
1 Error sent to client
-1 Error is not sent to client
*/
int mysql_insert_select_prepare(THD *thd)
{
LEX *lex= thd->lex;
TABLE_LIST* first_select_table=
(TABLE_LIST*)lex->select_lex.table_list.first;
TABLE_LIST* first_select_leaf_table;
int res;
DBUG_ENTER("mysql_insert_select_prepare");
if (mysql_prepare_insert_check_table(thd, lex->query_tables,
lex->field_list,
&lex->select_lex.where))
DBUG_RETURN(-1);
/* exclude first table from leaf tables list, because it belong to INSERT */
if ((res= mysql_prepare_insert_check_table(thd, lex->query_tables,
lex->field_list,
&lex->select_lex.where)))
DBUG_RETURN(res);
/*
setup was done in mysql_insert_select_prepare, but we have to mark
first local table
*/
if (first_select_table)
first_select_table->setup_is_done= 1;
/*
exclude first table from leaf tables list, because it belong to
INSERT
*/
DBUG_ASSERT(lex->select_lex.leaf_tables);
lex->leaf_tables_insert= lex->select_lex.leaf_tables;
lex->select_lex.leaf_tables= lex->select_lex.leaf_tables->next_leaf;
/* skip all leaf tables belonged to view where we are insert */
for (first_select_leaf_table= lex->select_lex.leaf_tables->next_leaf;
first_select_leaf_table &&
first_select_leaf_table->belong_to_view &&
first_select_leaf_table->belong_to_view ==
lex->leaf_tables_insert->belong_to_view;
first_select_leaf_table= first_select_leaf_table->next_leaf)
{}
lex->select_lex.leaf_tables= first_select_leaf_table;
DBUG_RETURN(0);
}
@ -1635,6 +1701,23 @@ select_insert::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
if (check_insert_fields(thd, table_list, *fields, values, 1,
!insert_into_view))
DBUG_RETURN(1);
/*
if it is INSERT into join view then check_insert_fields already found
real table for insert
*/
table= table_list->table;
/*
Is table which we are changing used somewhere in other parts of
query
*/
if (!(thd->lex->current_select->options & OPTION_BUFFER_RESULT) &&
unique_table(table_list, table_list->next_independent()))
{
/* Using same table for INSERT and SELECT */
thd->lex->current_select->options|= OPTION_BUFFER_RESULT;
thd->lex->current_select->join->select_options|= OPTION_BUFFER_RESULT;
}
restore_record(table,default_values); // Get empty record
table->next_number_field=table->found_next_number_field;