Details
-
Bug
-
Status: Closed (View Workflow)
-
Major
-
Resolution: Fixed
-
10.6.3, 10.3.31, 10.2(EOL), 10.3(EOL), 10.4(EOL), 10.5, 10.6
-
None
-
debian, windows
Description
When a double encapsulated CTE query calls a function which reads a table which has been aliased in the CTE query, the optimizer cannot find the table anymore and ends with an error 1146 Table db.t1 doesn't exist.
Script to reproduce:
CREATE TABLE t1 (id INT(10) NOT NULL AUTO_INCREMENT PRIMARY KEY); |
/* Generate 10'000 entries */
|
INSERT INTO t1(id) SELECT @row := @row + 1 AS id FROM |
(SELECT 0 UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) t, |
(SELECT 0 UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) t2, |
(SELECT 0 UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) t3, |
(SELECT 0 UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) t4, |
(SELECT @row:=0) numbers; |
|
CREATE OR REPLACE FUNCTION check_my_id(in_id INT) RETURNS INTEGER |
READS SQL DATA
|
RETURN (SELECT id FROM t1 WHERE t1.id = in_id); |
|
|
WITH c1 AS (SELECT id FROM t1 a WHERE check_my_id(id) = id GROUP BY id), |
c2 AS (SELECT pt.id FROM c1 pt GROUP BY pt.id) |
SELECT id FROM c2 GROUP BY id |
UNION ALL |
SELECT id FROM c2; |
If the table alias (a) is removed in the CTE c1, the query works.
When I try on my real query (and not in the abbreviated example above), I sometimes get the error message and sometimes mysqld crashes with the error log attached.
Attachments
Issue Links
- relates to
-
MDEV-26025 Server crashes while executing query with CTE in PS/SP
-
- Closed
-
Yet if we try to execute the query
that uses the stored function
the above inconsistency brings us to an assertion failure.
Let's figure out how it happens.
So after parsing LEX::query_tables starts the chain of TABLE_LIST objects in the following order:
first the object for s1, then for t1(1), pt(1), s2, pt(2) and lastly the object for t1(2). Yet LEX::query_tables_last points to
TABLE_LIST::next_global in the object for pt(2) rather than for in the last of object of the chain. Bare in mind that at this moment all names to CTE (s1, pt(1), s2, pt(2) has been already resolved.
1. when executing open_tables()
1.1. for each elements from the chain LEX::query_tables open_and_process_table() is called
1.1.1. open_table() is called for t1(1)
1.1.2. open_table() is called for t1(2)
1.2 . open_and_process_routine() is called for each element from the list thd->lex->sroutines_list (with only one element)
1.2.1 open_table() is called for t1(SF) used in the stored function.
1..2.2. add_used_tables_to_table_list inserts the TABLE_LIST object for t1(SF) after the TABLE_LIST for pt(2) as the last element in the chain LEX::query_tables. The chain looks like this now s1, then for t1(1), pt(1), s2, pt(2), t1(SF).
2. lock_tables() is called for the chain s1, t1(1), pt(1), s2, pt(2), t1(SF). It locks TABLE_LIST::table for t1(1), but does not lock TABLE_LIST::table for t1(2) as the latter is out of the chain.
3. st_select_lex_unit::optimize() is called for the query. It sets TABLE_LIST::table->file->keyread for t1(1) and TABLE_LIST::table->file->keyread for t1(2) to 0 (the number of the index to be used when scanning the tables t1(1) and t1(2)).
4. st_select_lex_unit::exec() is called for the query. The execution comes to the evaluation of the condition f(id)=id.
4.1. open_table() is called for t1(SF) It sees that TABLE_LIST::table for t1(2) is not locked for usage and takes it to be used for t1(SF). When calling TABLE::init() it is noticed that TABLE_LIST::table->file->keyread for t1(2) is set to 0 while it should have been set to 64.