mirror of
https://github.com/MariaDB/server.git
synced 2025-07-10 04:22:00 +03:00
merge
This commit is contained in:
@ -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;
|
||||
}
|
||||
|
||||
@ -135,7 +177,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
|
||||
@ -202,17 +244,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;
|
||||
}
|
||||
|
||||
@ -220,6 +259,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++))
|
||||
@ -463,7 +505,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();
|
||||
thd->abort_on_warning= 0;
|
||||
DBUG_RETURN(0);
|
||||
|
||||
@ -473,7 +515,7 @@ abort:
|
||||
end_delayed_insert(thd);
|
||||
#endif
|
||||
free_underlaid_joins(thd, &thd->lex->select_lex);
|
||||
table->insert_values=0;
|
||||
table_list->clear_insert_values();
|
||||
thd->abort_on_warning= 0;
|
||||
DBUG_RETURN(-1);
|
||||
}
|
||||
@ -504,8 +546,9 @@ static bool check_view_insertability(TABLE_LIST *view, ulong query_id)
|
||||
{
|
||||
uint num= view->view->select_lex.item_list.elements;
|
||||
TABLE *table= view->table;
|
||||
Item **trans_start= view->field_translation, **trans_end=trans_start+num;
|
||||
Item **trans;
|
||||
Field_translator *trans_start= view->field_translation,
|
||||
*trans_end= trans_start + num;
|
||||
Field_translator *trans;
|
||||
Field **field_ptr= table->field;
|
||||
ulong other_query_id= query_id - 1;
|
||||
DBUG_ENTER("check_key_in_view");
|
||||
@ -518,7 +561,7 @@ static bool check_view_insertability(TABLE_LIST *view, ulong query_id)
|
||||
{
|
||||
Item_field *field;
|
||||
/* simple SELECT list entry (field without expression) */
|
||||
if (!(field= (*trans)->filed_for_view_update()))
|
||||
if (!(field= trans->item->filed_for_view_update()))
|
||||
DBUG_RETURN(TRUE);
|
||||
if (field->field->unireg_check == Field::NEXT_NUMBER)
|
||||
view->contain_auto_increment= 1;
|
||||
@ -530,7 +573,7 @@ static bool check_view_insertability(TABLE_LIST *view, ulong query_id)
|
||||
for (trans= trans_start; trans != trans_end; trans++)
|
||||
{
|
||||
/* Thanks to test above, we know that all columns are of type Item_field */
|
||||
Item_field *field= (Item_field *)(*trans);
|
||||
Item_field *field= (Item_field *)trans->item;
|
||||
if (field->field->query_id == query_id)
|
||||
DBUG_RETURN(TRUE);
|
||||
field->field->query_id= query_id;
|
||||
@ -549,7 +592,7 @@ static bool check_view_insertability(TABLE_LIST *view, ulong query_id)
|
||||
{
|
||||
if (trans == trans_end)
|
||||
DBUG_RETURN(TRUE); // Field was not part of view
|
||||
if (((Item_field *)(*trans))->field == *field_ptr)
|
||||
if (((Item_field *)trans->item)->field == *field_ptr)
|
||||
break; // ok
|
||||
}
|
||||
}
|
||||
@ -569,33 +612,35 @@ 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);
|
||||
DBUG_ENTER("mysql_prepare_insert_check_table");
|
||||
|
||||
if (setup_tables(thd, table_list, where))
|
||||
DBUG_RETURN(1);
|
||||
if (setup_tables(thd, table_list, where, &thd->lex->select_lex.leaf_tables,
|
||||
0))
|
||||
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);
|
||||
}
|
||||
|
||||
@ -624,8 +669,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) ||
|
||||
@ -1649,22 +1695,48 @@ 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");
|
||||
/*
|
||||
SELECT_LEX do not belong to INSERT statement, so we can't add WHERE
|
||||
clasue if table is VIEW
|
||||
*/
|
||||
lex->query_tables->no_where_clause= 1;
|
||||
if (mysql_prepare_insert_check_table(thd, lex->query_tables,
|
||||
lex->field_list,
|
||||
&lex->select_lex.where))
|
||||
DBUG_RETURN(-1);
|
||||
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;
|
||||
/* 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);
|
||||
}
|
||||
|
||||
@ -1693,6 +1765,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;
|
||||
|
Reference in New Issue
Block a user