Skip to content

Commit ec745f7

Browse files
committed
Bug#20454533: Assertion failed: sargables == 0 || *keyfields ...
The fix for "regression from bug#19789450" had a problem for some non-SELECT statements: These statements call st_select_lex::prepare() after preparing some items specific to the UPDATE/DELETE operation, so the prepare() call is clearing cond_count set for such references. When a derived table is involved in the UPDATE, conditions counted in the derived table are propagated to the outer query block. This happens before cond_count is cleared in ::prepare(). The fix is to move the resetting of cond_count, etc from ::prepare() to reinit_stmt_before_use(). Thus, the fields are reset by the st_select_lex constructor for the first ::prepare(), for the subsequent ::prepare()s, they are reset by reinit_stmt_before_use()
1 parent 5968a23 commit ec745f7

File tree

4 files changed

+47
-5
lines changed

4 files changed

+47
-5
lines changed

mysql-test/r/update.result

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -625,3 +625,20 @@ id select_type table partitions type possible_keys key key_len ref rows filtered
625625
UPDATE t2, v1 AS t SET t2.b = t.a+5 ;
626626
DROP VIEW v1;
627627
DROP TABLE t1, t2;
628+
# Bug#20454533: Assertion failed: sargables == 0 || *keyfields ...
629+
CREATE TABLE t1(
630+
a int,
631+
c int,
632+
e int,
633+
f int,
634+
g blob,
635+
h int,
636+
i int,
637+
j blob,
638+
unique key (g(221),c),
639+
unique key (c,a,j(148)),
640+
key (i)
641+
) engine=innodb;
642+
UPDATE (SELECT 1 AS a FROM t1 NATURAL JOIN t1 AS t2) AS x, t1
643+
SET t1.e= x.a;
644+
DROP TABLE t1;

mysql-test/t/update.test

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -574,3 +574,23 @@ eval $query;
574574
DROP VIEW v1;
575575
DROP TABLE t1, t2;
576576

577+
--echo # Bug#20454533: Assertion failed: sargables == 0 || *keyfields ...
578+
579+
CREATE TABLE t1(
580+
a int,
581+
c int,
582+
e int,
583+
f int,
584+
g blob,
585+
h int,
586+
i int,
587+
j blob,
588+
unique key (g(221),c),
589+
unique key (c,a,j(148)),
590+
key (i)
591+
) engine=innodb;
592+
593+
UPDATE (SELECT 1 AS a FROM t1 NATURAL JOIN t1 AS t2) AS x, t1
594+
SET t1.e= x.a;
595+
596+
DROP TABLE t1;

sql/sql_prepare.cc

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2353,6 +2353,16 @@ void reinit_stmt_before_use(THD *thd, LEX *lex)
23532353
/* see unique_table() */
23542354
sl->exclude_from_table_unique_test= FALSE;
23552355

2356+
/*
2357+
These must be reset before every new preparation.
2358+
@note done here and not in st_select_lex::prepare() since for
2359+
multi-table UPDATE and DELETE, derived tables are merged into
2360+
the outer query block before ::prepare() is called.
2361+
*/
2362+
sl->cond_count= 0;
2363+
sl->between_count= 0;
2364+
sl->max_equal_elems= 0;
2365+
23562366
if (sl->where_cond())
23572367
{
23582368
DBUG_ASSERT(sl->where_cond()->real_item()); // no dangling 'ref'

sql/sql_resolver.cc

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -113,11 +113,6 @@ bool SELECT_LEX::prepare(THD *thd)
113113
Opt_trace_object trace_prepare(trace, "join_preparation");
114114
trace_prepare.add_select_number(select_number);
115115
Opt_trace_array trace_steps(trace, "steps");
116-
117-
// These must be reset before every condition preparation
118-
cond_count= 0;
119-
between_count= 0;
120-
max_equal_elems= 0;
121116

122117
// Initially, "all_fields" is the select list
123118
all_fields= fields_list;

0 commit comments

Comments
 (0)