mirror of
https://github.com/MariaDB/server.git
synced 2025-07-29 05:21:33 +03:00
Merge branch '10.5' into 10.6
This commit is contained in:
@ -57,6 +57,7 @@
|
||||
*/
|
||||
|
||||
#include "mariadb.h" /* NO_EMBEDDED_ACCESS_CHECKS */
|
||||
#include "sql_list.h"
|
||||
#include "sql_priv.h"
|
||||
#include "sql_insert.h"
|
||||
#include "sql_update.h" // compare_record
|
||||
@ -716,6 +717,8 @@ bool mysql_insert(THD *thd, TABLE_LIST *table_list,
|
||||
Name_resolution_context_state ctx_state;
|
||||
SELECT_LEX *returning= thd->lex->has_returning() ? thd->lex->returning() : 0;
|
||||
unsigned char *readbuff= NULL;
|
||||
List<List_item> insert_values_cache;
|
||||
bool cache_insert_values= FALSE;
|
||||
|
||||
#ifndef EMBEDDED_LIBRARY
|
||||
char *query= thd->query();
|
||||
@ -773,7 +776,7 @@ bool mysql_insert(THD *thd, TABLE_LIST *table_list,
|
||||
|
||||
if ((res= mysql_prepare_insert(thd, table_list, fields, values,
|
||||
update_fields, update_values, duplic,
|
||||
&unused_conds, FALSE)))
|
||||
&unused_conds, FALSE, &cache_insert_values)))
|
||||
{
|
||||
retval= thd->is_error();
|
||||
if (res < 0)
|
||||
@ -1007,8 +1010,41 @@ bool mysql_insert(THD *thd, TABLE_LIST *table_list,
|
||||
if (returning)
|
||||
fix_rownum_pointers(thd, thd->lex->returning(), &info.accepted_rows);
|
||||
|
||||
if (cache_insert_values)
|
||||
{
|
||||
insert_values_cache.empty();
|
||||
while ((values= its++))
|
||||
{
|
||||
List<Item> *caches= new (thd->mem_root) List_item;
|
||||
List_iterator_fast<Item> iv(*values);
|
||||
Item *item;
|
||||
if (caches == 0)
|
||||
{
|
||||
error= 1;
|
||||
goto values_loop_end;
|
||||
}
|
||||
caches->empty();
|
||||
while((item= iv++))
|
||||
{
|
||||
Item_cache *cache= item->get_cache(thd);
|
||||
if (!cache)
|
||||
{
|
||||
error= 1;
|
||||
goto values_loop_end;
|
||||
}
|
||||
cache->setup(thd, item);
|
||||
caches->push_back(cache);
|
||||
}
|
||||
insert_values_cache.push_back(caches);
|
||||
}
|
||||
its.rewind();
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
List_iterator_fast<List_item> itc(insert_values_cache);
|
||||
List_iterator_fast<List_item> *itr;
|
||||
|
||||
DBUG_PRINT("info", ("iteration %llu", iteration));
|
||||
if (iteration && bulk_parameters_set(thd))
|
||||
{
|
||||
@ -1016,7 +1052,24 @@ bool mysql_insert(THD *thd, TABLE_LIST *table_list,
|
||||
goto values_loop_end;
|
||||
}
|
||||
|
||||
while ((values= its++))
|
||||
if (cache_insert_values)
|
||||
{
|
||||
List_item *caches;
|
||||
while ((caches= itc++))
|
||||
{
|
||||
List_iterator_fast<Item> ic(*caches);
|
||||
Item_cache *cache;
|
||||
while((cache= (Item_cache*) ic++))
|
||||
{
|
||||
cache->cache_value();
|
||||
}
|
||||
}
|
||||
itc.rewind();
|
||||
itr= &itc;
|
||||
}
|
||||
else
|
||||
itr= &its;
|
||||
while ((values= (*itr)++))
|
||||
{
|
||||
if (fields.elements || !value_count)
|
||||
{
|
||||
@ -1120,7 +1173,7 @@ bool mysql_insert(THD *thd, TABLE_LIST *table_list,
|
||||
info.accepted_rows++;
|
||||
thd->get_stmt_da()->inc_current_row_for_warning();
|
||||
}
|
||||
its.rewind();
|
||||
itr->rewind();
|
||||
iteration++;
|
||||
} while (bulk_parameters_iterations(thd));
|
||||
|
||||
@ -1609,6 +1662,7 @@ static void prepare_for_positional_update(TABLE *table, TABLE_LIST *tables)
|
||||
table_list Global/local table list
|
||||
where Where clause (for insert ... select)
|
||||
select_insert TRUE if INSERT ... SELECT statement
|
||||
cache_insert_values insert's VALUES(...) has to be pre-computed
|
||||
|
||||
TODO (in far future)
|
||||
In cases of:
|
||||
@ -1630,7 +1684,7 @@ int mysql_prepare_insert(THD *thd, TABLE_LIST *table_list,
|
||||
List<Item> &fields, List_item *values,
|
||||
List<Item> &update_fields, List<Item> &update_values,
|
||||
enum_duplicates duplic, COND **where,
|
||||
bool select_insert)
|
||||
bool select_insert, bool * const cache_insert_values)
|
||||
{
|
||||
SELECT_LEX *select_lex= thd->lex->first_select_lex();
|
||||
Name_resolution_context *context= &select_lex->context;
|
||||
@ -1718,6 +1772,15 @@ int mysql_prepare_insert(THD *thd, TABLE_LIST *table_list,
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
|
||||
/*
|
||||
Check if we read from the same table we're inserting into.
|
||||
Queries like INSERT INTO t1 VALUES ((SELECT ... FROM t1...)) have
|
||||
to pre-compute the VALUES part.
|
||||
Reading from the same table in the RETURNING clause is not allowed.
|
||||
|
||||
INSERT...SELECT detects this case in select_insert::prepare and also
|
||||
uses buffering to handle it correcly.
|
||||
*/
|
||||
if (!select_insert)
|
||||
{
|
||||
Item *fake_conds= 0;
|
||||
@ -1725,10 +1788,30 @@ int mysql_prepare_insert(THD *thd, TABLE_LIST *table_list,
|
||||
if ((duplicate= unique_table(thd, table_list, table_list->next_global,
|
||||
CHECK_DUP_ALLOW_DIFFERENT_ALIAS)))
|
||||
{
|
||||
update_non_unique_table_error(table_list, "INSERT", duplicate);
|
||||
DBUG_RETURN(1);
|
||||
/*
|
||||
This is INSERT INTO ... VALUES (...) and it must pre-compute the
|
||||
values to be inserted.
|
||||
*/
|
||||
(*cache_insert_values)= true;
|
||||
}
|
||||
else
|
||||
(*cache_insert_values)= false;
|
||||
|
||||
select_lex->fix_prepare_information(thd, &fake_conds, &fake_conds);
|
||||
|
||||
if ((*cache_insert_values) && thd->lex->has_returning())
|
||||
{
|
||||
// Check if the table we're inserting into is also in RETURNING clause
|
||||
TABLE_LIST *dup=
|
||||
unique_table_in_insert_returning_subselect(thd, table_list,
|
||||
thd->lex->returning());
|
||||
if (dup)
|
||||
{
|
||||
if (dup != ERROR_TABLE)
|
||||
update_non_unique_table_error(table_list, "INSERT", duplicate);
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
Only call prepare_for_posistion() if we are not performing a DELAYED
|
||||
@ -3864,6 +3947,7 @@ int mysql_insert_select_prepare(THD *thd, select_result *sel_res)
|
||||
int res;
|
||||
LEX *lex= thd->lex;
|
||||
SELECT_LEX *select_lex= lex->first_select_lex();
|
||||
bool cache_insert_values= false;
|
||||
DBUG_ENTER("mysql_insert_select_prepare");
|
||||
|
||||
/*
|
||||
@ -3874,7 +3958,7 @@ int mysql_insert_select_prepare(THD *thd, select_result *sel_res)
|
||||
if ((res= mysql_prepare_insert(thd, lex->query_tables, lex->field_list, 0,
|
||||
lex->update_list, lex->value_list,
|
||||
lex->duplicates,
|
||||
&select_lex->where, TRUE)))
|
||||
&select_lex->where, TRUE, &cache_insert_values)))
|
||||
DBUG_RETURN(res);
|
||||
|
||||
/*
|
||||
|
Reference in New Issue
Block a user