Skip to content

Commit e048289

Browse files
committed
MDEV-27937 Assertion failure when executing prepared statement with ? in IN list
This bug affected queries with IN predicates that contain parameter markers in the value list. Such queries are executed via prepared statements. The problem appeared only if the number of elements in the value list was greater than the set value of the system variable in_predicate_conversion_threshold. The patch unconditionally prohibits conversion of an IN predicate to the equivalent IN predicand if the value list of the IN predicate contains parameters markers. Approved by Oleksandr Byelkin <sanja@mariadb.com>
1 parent 549a71e commit e048289

File tree

5 files changed

+83
-6
lines changed

5 files changed

+83
-6
lines changed

mysql-test/main/opt_tvc.result

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -732,3 +732,30 @@ a b
732732
4 4
733733
drop table t1;
734734
SET @@in_predicate_conversion_threshold= default;
735+
#
736+
# MDEV-27937: Prepared statement with ? in the list if IN predicate
737+
#
738+
set in_predicate_conversion_threshold=2;
739+
create table t1 (id int, a int, b int);
740+
insert into t1 values (1,3,30), (2,7,70), (3,1,10);
741+
prepare stmt from "
742+
select * from t1 where a in (7, ?, 5, 1);
743+
";
744+
execute stmt using 3;
745+
id a b
746+
1 3 30
747+
2 7 70
748+
3 1 10
749+
deallocate prepare stmt;
750+
prepare stmt from "
751+
select * from t1 where (a,b) in ((7,70), (3,?), (5,50), (1,10));
752+
";
753+
execute stmt using 30;
754+
id a b
755+
1 3 30
756+
2 7 70
757+
3 1 10
758+
deallocate prepare stmt;
759+
drop table t1;
760+
set in_predicate_conversion_threshold=default;
761+
# End of 10.3 tests

mysql-test/main/opt_tvc.test

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -428,3 +428,29 @@ eval $query;
428428
drop table t1;
429429
SET @@in_predicate_conversion_threshold= default;
430430

431+
--echo #
432+
--echo # MDEV-27937: Prepared statement with ? in the list if IN predicate
433+
--echo #
434+
435+
set in_predicate_conversion_threshold=2;
436+
437+
create table t1 (id int, a int, b int);
438+
insert into t1 values (1,3,30), (2,7,70), (3,1,10);
439+
440+
prepare stmt from "
441+
select * from t1 where a in (7, ?, 5, 1);
442+
";
443+
execute stmt using 3;
444+
deallocate prepare stmt;
445+
446+
prepare stmt from "
447+
select * from t1 where (a,b) in ((7,70), (3,?), (5,50), (1,10));
448+
";
449+
execute stmt using 30;
450+
deallocate prepare stmt;
451+
452+
drop table t1;
453+
454+
set in_predicate_conversion_threshold=default;
455+
456+
--echo # End of 10.3 tests

sql/item_cmpfunc.cc

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4472,10 +4472,11 @@ void Item_func_in::mark_as_condition_AND_part(TABLE_LIST *embedding)
44724472
Query_arena *arena, backup;
44734473
arena= thd->activate_stmt_arena_if_needed(&backup);
44744474

4475-
if (to_be_transformed_into_in_subq(thd))
4475+
if (!transform_into_subq_checked)
44764476
{
4477-
transform_into_subq= true;
4478-
thd->lex->current_select->in_funcs.push_back(this, thd->mem_root);
4477+
if ((transform_into_subq= to_be_transformed_into_in_subq(thd)))
4478+
thd->lex->current_select->in_funcs.push_back(this, thd->mem_root);
4479+
transform_into_subq_checked= true;
44794480
}
44804481

44814482
if (arena)

sql/item_cmpfunc.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2299,6 +2299,7 @@ class Item_func_in :public Item_func_opt_neg,
22992299
SEL_TREE *get_func_mm_tree(RANGE_OPT_PARAM *param,
23002300
Field *field, Item *value);
23012301
bool transform_into_subq;
2302+
bool transform_into_subq_checked;
23022303
public:
23032304
/// An array of values, created when the bisection lookup method is used
23042305
in_vector *array;
@@ -2321,6 +2322,7 @@ class Item_func_in :public Item_func_opt_neg,
23212322
Item_func_opt_neg(thd, list),
23222323
Predicant_to_list_comparator(thd, arg_count - 1),
23232324
transform_into_subq(false),
2325+
transform_into_subq_checked(false),
23242326
array(0), have_null(0),
23252327
arg_types_compatible(FALSE), emb_on_expr_nest(0)
23262328
{ }

sql/sql_tvc.cc

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -900,8 +900,6 @@ Item *Item_func_in::in_predicate_to_in_subs_transformer(THD *thd,
900900
if (!transform_into_subq)
901901
return this;
902902

903-
transform_into_subq= false;
904-
905903
List<List_item> values;
906904

907905
LEX *lex= thd->lex;
@@ -1058,15 +1056,38 @@ uint32 Item_func_in::max_length_of_left_expr()
10581056

10591057
bool Item_func_in::to_be_transformed_into_in_subq(THD *thd)
10601058
{
1059+
bool is_row_list= args[1]->type() == Item::ROW_ITEM;
10611060
uint values_count= arg_count-1;
10621061

1063-
if (args[1]->type() == Item::ROW_ITEM)
1062+
if (is_row_list)
10641063
values_count*= ((Item_row *)(args[1]))->cols();
10651064

10661065
if (thd->variables.in_subquery_conversion_threshold == 0 ||
10671066
thd->variables.in_subquery_conversion_threshold > values_count)
10681067
return false;
10691068

1069+
if (!(thd->lex->context_analysis_only & CONTEXT_ANALYSIS_ONLY_PREPARE))
1070+
return true;
1071+
1072+
/* Occurence of '?' in IN list is checked only for PREPARE <stmt> commands */
1073+
for (uint i=1; i < arg_count; i++)
1074+
{
1075+
if (!is_row_list)
1076+
{
1077+
if (args[i]->type() == Item::PARAM_ITEM)
1078+
return false;
1079+
}
1080+
else
1081+
{
1082+
Item_row *row_list= (Item_row *)(args[i]);
1083+
for (uint j=0; j < row_list->cols(); j++)
1084+
{
1085+
if (row_list->element_index(j)->type() == Item::PARAM_ITEM)
1086+
return false;
1087+
}
1088+
}
1089+
}
1090+
10701091
return true;
10711092
}
10721093

0 commit comments

Comments
 (0)