[MDEV-23886] Reusing CTE inside a function fails with table doesn't exist Created: 2020-10-04 Updated: 2021-10-14 Resolved: 2021-06-08 |
|
| Status: | Closed |
| Project: | MariaDB Server |
| Component/s: | Optimizer - CTE |
| Affects Version/s: | 10.5.5, 10.2, 10.3, 10.4, 10.5 |
| Fix Version/s: | 10.6.2, 10.2.39, 10.3.30, 10.4.20, 10.5.11 |
| Type: | Bug | Priority: | Critical |
| Reporter: | Szatox | Assignee: | Igor Babaev |
| Resolution: | Fixed | Votes: | 1 |
| Labels: | None | ||
| Issue Links: |
|
||||||||||||||||||||||||||||||||
| Description |
|
When I try to use a single CTE multiple times inside a stored function, the function fails with
Returns -> ERROR 1146 (42S02): Table 'test.testtab' doesn't exist Running the same query without wrapping it in a function works fine:
Returns -> 18 The same error occurs when:
|
| Comments |
| Comment by Alice Sherepa [ 2020-10-05 ] | |||||||||||
|
Thanks a lot! Reproducible on 10.2-10.5:
| |||||||||||
| Comment by Igor Babaev [ 2020-10-08 ] | |||||||||||
|
This bug practically prevents using queries with more than one reference to the same CTE in stored procedures / stored functions. That's why I marked it as 'Critical'. | |||||||||||
| Comment by Alice Sherepa [ 2021-04-20 ] | |||||||||||
|
one more test case (
| |||||||||||
| Comment by Igor Babaev [ 2021-05-06 ] | |||||||||||
|
In the current code binding of a table reference to the specification of the corresponding CTE happens in open_and_process_table(). If the table reference is not the first in the query the specification is cloned in the same way as it is cloned for any view reference. This works fine for standalone queries, but does not work for stored procedures / functions for the following reason. | |||||||||||
| Comment by Igor Babaev [ 2021-05-10 ] | |||||||||||
|
Let's see how exactly we come to a bogus error message for a call of the function:
The function contains 4 table references with aliases t1, s,t, dt.
is processed for the first time the function open_and_process_routine() is called that in its turn calls sp_cache_routine() starting parsing of the body of the function f1. The only query of the body is parsed and the chain of 4 TABLE_LIST objects for table references t1,s,t,dt is attached to the query. At the very end of the parsing process for the query the function sp_head::merge_table_list looks through this chain and puts some basic info about the references to t1,s,t into a hash table. When parsing of f1 is finished the control returns to open_and_process_routine() and the function DML_prelocking_strategy::handle_routine is called. The latter invokes the function sp_head::add_used_tables_to_table_list() that looks through the hash table mentioned above and using the info from the elements in table construct a chain of TABLE_LIST objects for t,s,t1 These objects are qualified as placeholders and contain only basic info for locking t,s,t1. Then pre-locking for t,s,t1 is performed. The process tries to open t and fails. Also it fails with opening s. Finally it succeeds with opening t1. Then the control comes to the lock_tables(). The function forms an array of pointers to the TABLE structures for t,s,t1. Only the pointer to t1 is not NULL. After this the function mysql_lock_tables() is called. Now we come to the point where the only query of f1 is processed. The function open_tables() is called for the list of TABLE_LIST objects created for t1,s,t,dt that was attached to the query at the parsing stage. For each TABLE_LIST object the function open_and_process_table() is called. When it's called the TABLE_LIST object created for t the function finds out that t refers to cte1 and it's the second reference to cte1. The parser is called the specification of cte1 that inserts afrer TABLE_LIST object for t a new TABLE_LIST object for the second instance of t1. After this open_and_process_table() is called for this instance. The function sees that the instance has not been locked and an error message is reported. | |||||||||||
| Comment by Oleksandr Byelkin [ 2021-05-21 ] | |||||||||||
|
OK to push | |||||||||||
| Comment by Marko Mäkelä [ 2021-05-24 ] | |||||||||||
|
igor and sanja, this was apparently pushed to 10.2. I failed to find a 10.3 or 10.4 version of this. On merge to 10.3 I had to resolve numerous conflicts, but the tests passed for me. On an attempted merge to 10.4, I was less lucky, and 3 tests fail. Please fix. | |||||||||||
| Comment by Marko Mäkelä [ 2021-05-25 ] | |||||||||||
|
This was pushed separately to 10.4. It looks like some adjustment for 10.5 is needed too. | |||||||||||
| Comment by Marko Mäkelä [ 2021-05-26 ] | |||||||||||
|
This was pushed separately to 10.5 and finally merged to 10.6.
| |||||||||||
| Comment by Igor Babaev [ 2021-06-08 ] | |||||||||||
|
A fix for this bug was pushed into 10.2. Then an adjusted fix was pushed into 10.4. Another variant was pushed into 10.5. |