the crash can also be reproduced with any of the following UPDATE statements.
UPDATE
(SELECT (5, (WITH cte AS (SELECT 1) SELECT a FROM t1))) dt
JOIN t1 t
ON t.a=dt.a
SET t.a = 1;
UPDATE
(SELECT a FROM t1
WHERE (5, (WITH cte AS (SELECT 1) SELECT a FROM t1 WHERE a > 4)) <= (5,a)) dt
JOIN t1 t
ON t.a=dt.a
SET t.a = 1;
The first statement is expected to return the error message:
ERROR 1241 (21000): Operand should contain 1 column(s)
The second statement is expected to update the record of t1 where a=7:
MariaDB [test]> SELECT * FROM t1;
+------+
| a |
+------+
| 3 |
| 1 |
| 1 |
+------+
Igor Babaev (Inactive)
added a comment - - edited Given the table t1 built with the commands
CREATE TABLE t1 (a int ) ENGINE=MYISAM;
INSERT INTO t1 VALUES (3), (7), (1);
the crash can also be reproduced with any of the following UPDATE statements.
UPDATE
( SELECT (5, ( WITH cte AS ( SELECT 1) SELECT a FROM t1))) dt
JOIN t1 t
ON t.a=dt.a
SET t.a = 1;
UPDATE
( SELECT a FROM t1
WHERE (5, ( WITH cte AS ( SELECT 1) SELECT a FROM t1 WHERE a > 4)) <= (5,a)) dt
JOIN t1 t
ON t.a=dt.a
SET t.a = 1;
The first statement is expected to return the error message:
ERROR 1241 (21000): Operand should contain 1 column(s)
The second statement is expected to update the record of t1 where a=7:
MariaDB [test]> SELECT * FROM t1;
+------+
| a |
+------+
| 3 |
| 1 |
| 1 |
+------+
As we can see the code of the function With_element::prepare_unreferenced() before the patch did not properly restored the value of thd->lex->context_analysis_only. As a result it became 0 after the call of this function. This function is called when JOIN::prepare() is called for the subquery
(WITH cte AS (SELECT 1) SELECT a FROM t1 WHERE a > 4)
This happens when Item_row::fix_fields() calls fix_fields() for its second argument.
Note that after the call of With_element::prepare_unreferenced() remains 0. As a result the subquery is considered as a constant and Item_row::fix_fields() tries to execute it calling the virtual function is_null() for it.
It causes an assertion failure because the call of Item_row::fix_fields() happens during the invocation of Multiupdate_prelocking_strategy::handle_end() that calls mysql_derived_prepare for the derived table dt when proper locks for used tables has not been acquired yet.
With this patch the value of thd->lex->context_analysis_only is restored to CONTEXT_ANALYSIS_ONLY_DERIVED
that is set in the function mysql_multi_update_prepare().
Igor Babaev (Inactive)
added a comment - The following patch fixes the problem.
diff --git a/sql/sql_cte.cc b/sql/sql_cte.cc
index 2e67259..9c8e3c0 100644
--- a/sql/sql_cte.cc
+++ b/sql/sql_cte.cc
@@ -1241,14 +1241,14 @@ bool With_element::prepare_unreferenced(THD *thd)
sl= sl->next_select())
sl->context.outer_context= 0;
+ uint8 save_context_analysys_only= thd->lex->context_analysis_only;
thd->lex->context_analysis_only|= CONTEXT_ANALYSIS_ONLY_DERIVED;
if (!spec->prepared &&
(spec->prepare(spec->derived, 0, 0) ||
rename_columns_of_derived_unit(thd, spec) ||
check_duplicate_names(thd, first_sl->item_list, 1)))
rc= true;
-
- thd->lex->context_analysis_only&= ~CONTEXT_ANALYSIS_ONLY_DERIVED;
+ thd->lex->context_analysis_only= save_context_analysys_only;
return rc;
}
As we can see the code of the function With_element::prepare_unreferenced() before the patch did not properly restored the value of thd->lex->context_analysis_only. As a result it became 0 after the call of this function. This function is called when JOIN::prepare() is called for the subquery
(WITH cte AS (SELECT 1) SELECT a FROM t1 WHERE a > 4)
This happens when Item_row::fix_fields() calls fix_fields() for its second argument.
Note that after the call of With_element::prepare_unreferenced() remains 0. As a result the subquery is considered as a constant and Item_row::fix_fields() tries to execute it calling the virtual function is_null() for it.
It causes an assertion failure because the call of Item_row::fix_fields() happens during the invocation of Multiupdate_prelocking_strategy::handle_end() that calls mysql_derived_prepare for the derived table dt when proper locks for used tables has not been acquired yet.
With this patch the value of thd->lex->context_analysis_only is restored to CONTEXT_ANALYSIS_ONLY_DERIVED
that is set in the function mysql_multi_update_prepare().
Given the table t1 built with the commands
the crash can also be reproduced with any of the following UPDATE statements.
The first statement is expected to return the error message:
ERROR 1241 (21000): Operand should contain 1 column(s)
The second statement is expected to update the record of t1 where a=7:
MariaDB [test]> SELECT * FROM t1;
+------+
| a |
+------+
| 3 |
| 1 |
| 1 |
+------+