diff options
author | unknown <bell@sanja.is.com.ua> | 2004-09-15 23:42:56 +0300 |
---|---|---|
committer | unknown <bell@sanja.is.com.ua> | 2004-09-15 23:42:56 +0300 |
commit | 9aa459f0df7e000224e4ac54c5009eac42ef365a (patch) | |
tree | 3ce3368d9a9eb09ff501cbcf82391101c7e06b40 /sql/sql_insert.cc | |
parent | 55a8c28c27778d018a145ce25e61bdcda7a764a5 (diff) | |
download | mariadb-git-9aa459f0df7e000224e4ac54c5009eac42ef365a.tar.gz |
support of join view updateability (WL#1809)
include/mysqld_error.h:
new error mesaages
mysql-test/r/view.result:
tests of updatint/inserting join views
mysql-test/t/view.test:
tests of updatint/inserting join views
sql/mysql_priv.h:
support of "usual UPDATE" -> "multi UPDATE" conversion
sql/share/czech/errmsg.txt:
new error mesaages
sql/share/danish/errmsg.txt:
new error mesaages
sql/share/dutch/errmsg.txt:
new error mesaages
sql/share/english/errmsg.txt:
new error mesaages
sql/share/estonian/errmsg.txt:
new error mesaages
sql/share/french/errmsg.txt:
new error mesaages
sql/share/german/errmsg.txt:
new error mesaages
sql/share/greek/errmsg.txt:
new error mesaages
sql/share/hungarian/errmsg.txt:
new error mesaages
sql/share/italian/errmsg.txt:
new error mesaages
sql/share/japanese/errmsg.txt:
new error mesaages
sql/share/korean/errmsg.txt:
new error mesaages
sql/share/norwegian-ny/errmsg.txt:
new error mesaages
sql/share/norwegian/errmsg.txt:
new error mesaages
sql/share/polish/errmsg.txt:
new error mesaages
sql/share/portuguese/errmsg.txt:
new error mesaages
sql/share/romanian/errmsg.txt:
new error mesaages
sql/share/russian/errmsg.txt:
new error mesaages
sql/share/serbian/errmsg.txt:
new error mesaages
sql/share/slovak/errmsg.txt:
new error mesaages
sql/share/spanish/errmsg.txt:
new error mesaages
sql/share/swedish/errmsg.txt:
new error mesaages
sql/share/ukrainian/errmsg.txt:
new error mesaages
sql/sql_base.cc:
test to avoid join virew to be catched here
sql/sql_class.h:
support of join views add to update
sql/sql_delete.cc:
support of join views add to delete(error issue)
sql/sql_insert.cc:
support of join views add to insert
(order of some check changed, to allow find table which will be inserted in, when we will know which fields will be inserted)
mechanism of calling setup_tables() only once fixed for INSERT SELECT
sql/sql_parse.cc:
support of "usual UPDATE" -> "multi UPDATE" conversion
mysql_insert_select_prepare now called in same environment for usual queries and PS preparing
support of join views add to delete (error issue)
sql/sql_prepare.cc:
support of "usual UPDATE" -> "multi UPDATE" conversion
support of join views add to delete (error issue)
sql/sql_update.cc:
support of join views add to update
sql/sql_view.cc:
join views made updatable
sql/sql_view.h:
insert_view_fields now can check some errors
sql/table.cc:
methods to support recursive walk by tables tree
sql/table.h:
methods to support recursive walk by tables tree
Diffstat (limited to 'sql/sql_insert.cc')
-rw-r--r-- | sql/sql_insert.cc | 143 |
1 files changed, 113 insertions, 30 deletions
diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 03028a13d19..9690b9289ba 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -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; |