summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorOleksandr Byelkin <sanja@mariadb.com>2017-02-18 17:47:31 +0100
committerOleksandr Byelkin <sanja@mariadb.com>2017-10-13 19:32:38 +0200
commit235b68299bc112f9cb7be97af8d01bf904919a6b (patch)
treed108e57b12187165b353220c85e088c68df2b005 /sql
parent2bab29ebba7a641d43a98737fd1c160971357cd4 (diff)
downloadmariadb-git-235b68299bc112f9cb7be97af8d01bf904919a6b.tar.gz
MDEV-9619: Assertion `null_ref_table' failed in virtual table_map Item_direct_view_ref::used_tables() const on 2nd execution of PS
Refer left expression indirectly in case it changes from execution to execution.
Diffstat (limited to 'sql')
-rw-r--r--sql/item_row.cc30
-rw-r--r--sql/item_row.h1
-rw-r--r--sql/item_subselect.cc6
-rw-r--r--sql/opt_subselect.cc55
-rw-r--r--sql/sql_base.cc7
-rw-r--r--sql/sql_base.h5
-rw-r--r--sql/sql_do.cc2
-rw-r--r--sql/sql_insert.cc14
-rw-r--r--sql/sql_lex.h1
-rw-r--r--sql/sql_load.cc10
-rw-r--r--sql/sql_prepare.cc9
-rw-r--r--sql/sql_select.cc2
-rw-r--r--sql/sql_update.cc4
-rw-r--r--sql/table.h3
14 files changed, 116 insertions, 33 deletions
diff --git a/sql/item_row.cc b/sql/item_row.cc
index ee1d17213ee..9e81c053b69 100644
--- a/sql/item_row.cc
+++ b/sql/item_row.cc
@@ -44,7 +44,14 @@ Item_row::Item_row(List<Item> &arg):
//TODO: think placing 2-3 component items in item (as it done for function)
if ((arg_count= arg.elements))
+ {
items= (Item**) sql_alloc(sizeof(Item*)*arg_count);
+ if (!items)
+ {
+ arg_count= 0;
+ return;
+ }
+ }
else
items= 0;
List_iterator<Item> li(arg);
@@ -53,7 +60,28 @@ Item_row::Item_row(List<Item> &arg):
while ((item= li++))
{
items[i]= item;
- i++;
+ i++;
+ }
+}
+
+
+Item_row::Item_row(Item *item):
+ Item(),
+ used_tables_cache(0),
+ not_null_tables_cache(0),
+ arg_count(item->cols()),
+ const_item_cache(1),
+ with_null(0)
+{
+ items= (Item**) sql_alloc(sizeof(Item*) * arg_count);
+ if (!items)
+ {
+ arg_count= 0;
+ return;
+ }
+ for (uint i= 0; i < arg_count; i++)
+ {
+ items[i]= item->element_index(i);
}
}
diff --git a/sql/item_row.h b/sql/item_row.h
index aa56068f8ba..4d5c20711b5 100644
--- a/sql/item_row.h
+++ b/sql/item_row.h
@@ -35,6 +35,7 @@ public:
const_item_cache(item->const_item_cache),
with_null(0)
{}
+ Item_row(Item *item);
enum Type type() const { return ROW_ITEM; };
void illegal_method_call(const char *);
diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc
index ef90dd59be3..90f2bd5b9eb 100644
--- a/sql/item_subselect.cc
+++ b/sql/item_subselect.cc
@@ -1374,6 +1374,9 @@ Item_in_subselect::Item_in_subselect(Item * left_exp,
{
DBUG_ENTER("Item_in_subselect::Item_in_subselect");
left_expr_orig= left_expr= left_exp;
+ /* prepare to possible disassembling the item in convert_subq_to_sj() */
+ if (left_exp->type() == Item::ROW_ITEM)
+ left_expr_orig= new Item_row(left_exp);
func= &eq_creator;
init(select_lex, new select_exists_subselect(this));
max_columns= UINT_MAX;
@@ -1398,6 +1401,9 @@ Item_allany_subselect::Item_allany_subselect(Item * left_exp,
{
DBUG_ENTER("Item_allany_subselect::Item_allany_subselect");
left_expr_orig= left_expr= left_exp;
+ /* prepare to possible disassembling the item in convert_subq_to_sj() */
+ if (left_exp->type() == Item::ROW_ITEM)
+ left_expr_orig= new Item_row(left_exp);
func= func_creator(all_arg);
init(select_lex, new select_exists_subselect(this));
max_columns= 1;
diff --git a/sql/opt_subselect.cc b/sql/opt_subselect.cc
index af1abb2001e..69a5367cdf1 100644
--- a/sql/opt_subselect.cc
+++ b/sql/opt_subselect.cc
@@ -1609,6 +1609,7 @@ static bool convert_subq_to_sj(JOIN *parent_join, Item_in_subselect *subq_pred)
sj-nest.
*/
st_select_lex *subq_lex= subq_pred->unit->first_select();
+ DBUG_ASSERT(subq_lex->next_select() == NULL);
nested_join->join_list.empty();
List_iterator_fast<TABLE_LIST> li(subq_lex->top_join_list);
TABLE_LIST *tl;
@@ -1706,7 +1707,8 @@ static bool convert_subq_to_sj(JOIN *parent_join, Item_in_subselect *subq_pred)
if (subq_pred->left_expr->cols() == 1)
{
- nested_join->sj_outer_expr_list.push_back(subq_pred->left_expr);
+ /* add left = select_list_element */
+ nested_join->sj_outer_expr_list.push_back(&subq_pred->left_expr);
/*
Create Item_func_eq. Note that
1. this is done on the statement, not execution, arena
@@ -1718,24 +1720,61 @@ static bool convert_subq_to_sj(JOIN *parent_join, Item_in_subselect *subq_pred)
*/
Item_func_eq *item_eq=
new Item_func_eq(subq_pred->left_expr_orig, subq_lex->ref_pointer_array[0]);
+ if (!item_eq)
+ DBUG_RETURN(TRUE);
if (subq_pred->left_expr_orig != subq_pred->left_expr)
thd->change_item_tree(item_eq->arguments(), subq_pred->left_expr);
item_eq->in_equality_no= 0;
sj_nest->sj_on_expr= and_items(sj_nest->sj_on_expr, item_eq);
}
- else
+ else if (subq_pred->left_expr->type() == Item::ROW_ITEM)
{
+ /*
+ disassemple left expression and add
+ left1 = select_list_element1 and left2 = select_list_element2 ...
+ */
for (uint i= 0; i < subq_pred->left_expr->cols(); i++)
{
nested_join->sj_outer_expr_list.push_back(subq_pred->left_expr->
- element_index(i));
- Item_func_eq *item_eq=
- new Item_func_eq(subq_pred->left_expr->element_index(i),
+ addr(i));
+ Item_func_eq *item_eq=
+ new Item_func_eq(subq_pred->left_expr_orig->element_index(i),
subq_lex->ref_pointer_array[i]);
+ if (!item_eq)
+ DBUG_RETURN(TRUE);
+ DBUG_ASSERT(subq_pred->left_expr->element_index(i)->fixed);
+ if (subq_pred->left_expr_orig->element_index(i) !=
+ subq_pred->left_expr->element_index(i))
+ thd->change_item_tree(item_eq->arguments(),
+ subq_pred->left_expr->element_index(i));
item_eq->in_equality_no= i;
sj_nest->sj_on_expr= and_items(sj_nest->sj_on_expr, item_eq);
}
}
+ else
+ {
+ /*
+ add row operation
+ left = (select_list_element1, select_list_element2, ...)
+ */
+ Item_row *row= new Item_row(subq_lex->pre_fix);
+ /* fix fields on subquery was call so they should be the same */
+ DBUG_ASSERT(subq_pred->left_expr->cols() == row->cols());
+ if (!row)
+ DBUG_RETURN(TRUE);
+ nested_join->sj_outer_expr_list.push_back(&subq_pred->left_expr);
+ Item_func_eq *item_eq=
+ new Item_func_eq(subq_pred->left_expr_orig, row);
+ if (!item_eq)
+ DBUG_RETURN(TRUE);
+ for (uint i= 0; i < row->cols(); i++)
+ {
+ if (row->element_index(i) != subq_lex->ref_pointer_array[i])
+ thd->change_item_tree(row->addr(i), subq_lex->ref_pointer_array[i]);
+ }
+ item_eq->in_equality_no= 0;
+ sj_nest->sj_on_expr= and_items(sj_nest->sj_on_expr, item_eq);
+ }
/*
Fix the created equality and AND
@@ -3285,8 +3324,8 @@ void restore_prev_sj_state(const table_map remaining_tables,
ulonglong get_bound_sj_equalities(TABLE_LIST *sj_nest,
table_map remaining_tables)
{
- List_iterator<Item> li(sj_nest->nested_join->sj_outer_expr_list);
- Item *item;
+ List_iterator<Item_ptr> li(sj_nest->nested_join->sj_outer_expr_list);
+ Item **item;
uint i= 0;
ulonglong res= 0;
while ((item= li++))
@@ -3297,7 +3336,7 @@ ulonglong get_bound_sj_equalities(TABLE_LIST *sj_nest,
class and see if there is an element that is bound?
(this is an optional feature)
*/
- if (!(item->used_tables() & remaining_tables))
+ if (!(item[0]->used_tables() & remaining_tables))
{
res |= 1ULL << i;
}
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index 7f84f35c825..c06c4fcff29 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -8128,13 +8128,15 @@ int setup_wild(THD *thd, TABLE_LIST *tables, List<Item> &fields,
bool setup_fields(THD *thd, Item **ref_pointer_array,
List<Item> &fields, enum_mark_columns mark_used_columns,
- List<Item> *sum_func_list, bool allow_sum_func)
+ List<Item> *sum_func_list, List<Item> *pre_fix,
+ bool allow_sum_func)
{
reg2 Item *item;
enum_mark_columns save_mark_used_columns= thd->mark_used_columns;
nesting_map save_allow_sum_func= thd->lex->allow_sum_func;
List_iterator<Item> it(fields);
bool save_is_item_list_lookup;
+ bool make_pre_fix= (pre_fix && (pre_fix->elements == 0));
DBUG_ENTER("setup_fields");
DBUG_PRINT("enter", ("ref_pointer_array: %p", ref_pointer_array));
@@ -8181,6 +8183,9 @@ bool setup_fields(THD *thd, Item **ref_pointer_array,
thd->lex->current_select->cur_pos_in_select_list= 0;
while ((item= it++))
{
+ if (make_pre_fix)
+ pre_fix->push_back(item, thd->stmt_arena->mem_root);
+
if ((!item->fixed && item->fix_fields(thd, it.ref())) ||
(item= *(it.ref()))->check_cols(1))
{
diff --git a/sql/sql_base.h b/sql/sql_base.h
index d49554d5473..0cde933afb8 100644
--- a/sql/sql_base.h
+++ b/sql/sql_base.h
@@ -216,7 +216,8 @@ int setup_wild(THD *thd, TABLE_LIST *tables, List<Item> &fields,
List<Item> *sum_func_list, uint wild_num);
bool setup_fields(THD *thd, Item** ref_pointer_array,
List<Item> &item, enum_mark_columns mark_used_columns,
- List<Item> *sum_func_list, bool allow_sum_func);
+ List<Item> *sum_func_list, List<Item> *pre_fix,
+ bool allow_sum_func);
void unfix_fields(List<Item> &items);
bool fill_record(THD *thd, Field **field, List<Item> &values,
bool ignore_errors, bool use_value);
@@ -407,7 +408,7 @@ inline bool setup_fields_with_no_wrap(THD *thd, Item **ref_pointer_array,
bool res;
thd->lex->select_lex.no_wrap_view_item= TRUE;
res= setup_fields(thd, ref_pointer_array, item, mark_used_columns,
- sum_func_list, allow_sum_func);
+ sum_func_list, NULL, allow_sum_func);
thd->lex->select_lex.no_wrap_view_item= FALSE;
return res;
}
diff --git a/sql/sql_do.cc b/sql/sql_do.cc
index 4ba887b5ab2..46bdb421b3a 100644
--- a/sql/sql_do.cc
+++ b/sql/sql_do.cc
@@ -28,7 +28,7 @@ bool mysql_do(THD *thd, List<Item> &values)
List_iterator<Item> li(values);
Item *value;
DBUG_ENTER("mysql_do");
- if (setup_fields(thd, 0, values, MARK_COLUMNS_NONE, 0, 0))
+ if (setup_fields(thd, 0, values, MARK_COLUMNS_NONE, 0, NULL, 0))
DBUG_RETURN(TRUE);
while ((value = li++))
value->val_int();
diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc
index 70a12faafb5..267a9a6f94e 100644
--- a/sql/sql_insert.cc
+++ b/sql/sql_insert.cc
@@ -262,7 +262,7 @@ static int check_insert_fields(THD *thd, TABLE_LIST *table_list,
if (table_list->is_view())
unfix_fields(fields);
- res= setup_fields(thd, 0, fields, MARK_COLUMNS_WRITE, 0, 0);
+ res= setup_fields(thd, 0, fields, MARK_COLUMNS_WRITE, 0, NULL, 0);
/* Restore the current context. */
ctx_state.restore_state(context, table_list);
@@ -373,7 +373,7 @@ static int check_update_fields(THD *thd, TABLE_LIST *insert_table_list,
}
/* Check the fields we are going to modify */
- if (setup_fields(thd, 0, update_fields, MARK_COLUMNS_WRITE, 0, 0))
+ if (setup_fields(thd, 0, update_fields, MARK_COLUMNS_WRITE, 0, NULL, 0))
return -1;
if (insert_table_list->is_view() &&
@@ -810,7 +810,7 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
my_error(ER_WRONG_VALUE_COUNT_ON_ROW, MYF(0), counter);
goto abort;
}
- if (setup_fields(thd, 0, *values, MARK_COLUMNS_READ, 0, 0))
+ if (setup_fields(thd, 0, *values, MARK_COLUMNS_READ, 0, NULL, 0))
goto abort;
}
its.rewind ();
@@ -1452,7 +1452,7 @@ bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list,
table_list->next_local= 0;
context->resolve_in_table_list_only(table_list);
- res= (setup_fields(thd, 0, *values, MARK_COLUMNS_READ, 0, 0) ||
+ res= (setup_fields(thd, 0, *values, MARK_COLUMNS_READ, 0, NULL, 0) ||
check_insert_fields(thd, context->table_list, fields, *values,
!insert_into_view, 0, &map));
@@ -1468,7 +1468,7 @@ bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list,
}
if (!res)
- res= setup_fields(thd, 0, update_values, MARK_COLUMNS_READ, 0, 0);
+ res= setup_fields(thd, 0, update_values, MARK_COLUMNS_READ, 0, NULL, 0);
if (!res && duplic == DUP_UPDATE)
{
@@ -3369,7 +3369,7 @@ select_insert::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
*/
lex->current_select= &lex->select_lex;
- res= (setup_fields(thd, 0, values, MARK_COLUMNS_READ, 0, 0) ||
+ res= (setup_fields(thd, 0, values, MARK_COLUMNS_READ, 0, NULL, 0) ||
check_insert_fields(thd, table_list, *fields, values,
!insert_into_view, 1, &map));
@@ -3425,7 +3425,7 @@ select_insert::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
ctx_state.get_first_name_resolution_table();
res= res || setup_fields(thd, 0, *info.update_values,
- MARK_COLUMNS_READ, 0, 0);
+ MARK_COLUMNS_READ, 0, NULL, 0);
if (!res)
{
/*
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index d283085886e..3dcf8769c14 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -758,6 +758,7 @@ public:
Group_list_ptrs *group_list_ptrs;
List<Item> item_list; /* list of fields & expressions */
+ List<Item> pre_fix; /* above list before fix_fields */
List<String> interval_list;
bool is_item_list_lookup;
/*
diff --git a/sql/sql_load.cc b/sql/sql_load.cc
index 23865ab8983..5029efa7d68 100644
--- a/sql/sql_load.cc
+++ b/sql/sql_load.cc
@@ -293,15 +293,15 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
Let us also prepare SET clause, altough it is probably empty
in this case.
*/
- if (setup_fields(thd, 0, set_fields, MARK_COLUMNS_WRITE, 0, 0) ||
- setup_fields(thd, 0, set_values, MARK_COLUMNS_READ, 0, 0))
+ if (setup_fields(thd, 0, set_fields, MARK_COLUMNS_WRITE, 0, NULL, 0) ||
+ setup_fields(thd, 0, set_values, MARK_COLUMNS_READ, 0, NULL, 0))
DBUG_RETURN(TRUE);
}
else
{ // Part field list
/* TODO: use this conds for 'WITH CHECK OPTIONS' */
- if (setup_fields(thd, 0, fields_vars, MARK_COLUMNS_WRITE, 0, 0) ||
- setup_fields(thd, 0, set_fields, MARK_COLUMNS_WRITE, 0, 0) ||
+ if (setup_fields(thd, 0, fields_vars, MARK_COLUMNS_WRITE, 0, NULL, 0) ||
+ setup_fields(thd, 0, set_fields, MARK_COLUMNS_WRITE, 0, NULL, 0) ||
check_that_all_fields_are_given_values(thd, table, table_list))
DBUG_RETURN(TRUE);
/*
@@ -320,7 +320,7 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
}
}
/* Fix the expressions in SET clause */
- if (setup_fields(thd, 0, set_values, MARK_COLUMNS_READ, 0, 0))
+ if (setup_fields(thd, 0, set_values, MARK_COLUMNS_READ, 0, NULL, 0))
DBUG_RETURN(TRUE);
}
diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc
index 094677e150d..851e4f7b8ab 100644
--- a/sql/sql_prepare.cc
+++ b/sql/sql_prepare.cc
@@ -1307,7 +1307,7 @@ static bool mysql_test_insert(Prepared_statement *stmt,
my_error(ER_WRONG_VALUE_COUNT_ON_ROW, MYF(0), counter);
goto error;
}
- if (setup_fields(thd, 0, *values, MARK_COLUMNS_NONE, 0, 0))
+ if (setup_fields(thd, 0, *values, MARK_COLUMNS_NONE, 0, NULL, 0))
goto error;
}
}
@@ -1397,7 +1397,7 @@ static int mysql_test_update(Prepared_statement *stmt,
table_list->register_want_access(want_privilege);
#endif
thd->lex->select_lex.no_wrap_view_item= TRUE;
- res= setup_fields(thd, 0, select->item_list, MARK_COLUMNS_READ, 0, 0);
+ res= setup_fields(thd, 0, select->item_list, MARK_COLUMNS_READ, 0, NULL, 0);
thd->lex->select_lex.no_wrap_view_item= FALSE;
if (res)
goto error;
@@ -1408,7 +1408,8 @@ static int mysql_test_update(Prepared_statement *stmt,
(SELECT_ACL & ~table_list->table->grant.privilege);
table_list->register_want_access(SELECT_ACL);
#endif
- if (setup_fields(thd, 0, stmt->lex->value_list, MARK_COLUMNS_NONE, 0, 0) ||
+ if (setup_fields(thd, 0, stmt->lex->value_list, MARK_COLUMNS_NONE, 0, NULL,
+ 0) ||
check_unique_table(thd, table_list))
goto error;
/* TODO: here we should send types of placeholders to the client. */
@@ -1575,7 +1576,7 @@ static bool mysql_test_do_fields(Prepared_statement *stmt,
if (open_normal_and_derived_tables(thd, tables, MYSQL_OPEN_FORCE_SHARED_MDL,
DT_PREPARE | DT_CREATE))
DBUG_RETURN(TRUE);
- DBUG_RETURN(setup_fields(thd, 0, *values, MARK_COLUMNS_NONE, 0, 0));
+ DBUG_RETURN(setup_fields(thd, 0, *values, MARK_COLUMNS_NONE, 0, NULL, 0));
}
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 6e67bb11015..c7f547edbc0 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -724,7 +724,7 @@ JOIN::prepare(Item ***rref_pointer_array,
wild_num)) ||
select_lex->setup_ref_array(thd, real_og_num) ||
setup_fields(thd, (*rref_pointer_array), fields_list, MARK_COLUMNS_READ,
- &all_fields, 1) ||
+ &all_fields, &select_lex->pre_fix, 1) ||
setup_without_group(thd, (*rref_pointer_array), tables_list,
select_lex->leaf_tables, fields_list,
all_fields, &conds, order, group_list,
diff --git a/sql/sql_update.cc b/sql/sql_update.cc
index 060952a589d..ede38468513 100644
--- a/sql/sql_update.cc
+++ b/sql/sql_update.cc
@@ -361,7 +361,7 @@ int mysql_update(THD *thd,
table_list->grant.want_privilege= table->grant.want_privilege=
(SELECT_ACL & ~table->grant.privilege);
#endif
- if (setup_fields(thd, 0, values, MARK_COLUMNS_READ, 0, 0))
+ if (setup_fields(thd, 0, values, MARK_COLUMNS_READ, 0, NULL, 0))
{
free_underlaid_joins(thd, select_lex);
DBUG_RETURN(1); /* purecov: inspected */
@@ -1521,7 +1521,7 @@ int multi_update::prepare(List<Item> &not_used_values,
reference tables
*/
- int error= setup_fields(thd, 0, *values, MARK_COLUMNS_READ, 0, 0);
+ int error= setup_fields(thd, 0, *values, MARK_COLUMNS_READ, 0, NULL, 0);
ti.rewind();
while ((table_ref= ti++))
diff --git a/sql/table.h b/sql/table.h
index dde01a85d77..c981243f28c 100644
--- a/sql/table.h
+++ b/sql/table.h
@@ -33,6 +33,7 @@
/* Structs that defines the TABLE */
class Item; /* Needed by ORDER */
+typedef Item (*Item_ptr);
class Item_subselect;
class Item_field;
class GRANT_TABLE;
@@ -2348,7 +2349,7 @@ typedef struct st_nested_join
table_map sj_depends_on;
/* Outer non-trivially correlated tables */
table_map sj_corr_tables;
- List<Item> sj_outer_expr_list;
+ List<Item_ptr> sj_outer_expr_list;
/**
True if this join nest node is completely covered by the query execution
plan. This means two things.