[MDEV-22779] Crash: Prepared Statement with a '?' parameter inside a re-used CTE Created: 2020-06-02 Updated: 2021-04-19 Resolved: 2020-06-14 |
|
| Status: | Closed |
| Project: | MariaDB Server |
| Component/s: | Optimizer - CTE |
| Affects Version/s: | 10.3.21 |
| Fix Version/s: | 10.2.33, 10.3.24, 10.4.14, 10.5.5 |
| Type: | Bug | Priority: | Major |
| Reporter: | Sergei Petrunia | Assignee: | Sergei Petrunia |
| Resolution: | Fixed | Votes: | 0 |
| Labels: | None | ||
| Environment: |
AWS Linux |
||
| Description |
|
I don't have a testcase, I only have a customer's core file. As far as I was able to investigate, the following has happened: 1. There is a big query with nested SELECTs and non-recursive CTEs. Some CTEs are used multiple times. 2. The query is submitted to server as a Prepared Statement. The prepared statement has many '?' parameters. 3. [At least] one of the parameters is inside in a CTE that's reused and it used like so:
We crash in optimize_keyuse(), when we are trying to process a KEYUSE element created from the above equality. We crash somewhere here:
The cause is that the keyuse has:
With PARAM_TABLE_BIT, the "if (n_tables == 1)" branch is taken, and we get a tablenr value, but join->table[tablenr] is not pointing to a valid TABLE object hence we get a poorly-reproducible crash. We should not get {{ keyuse->used_tables = PARAM_TABLE_BIT}}. We do, because
(which also shouldn't be happening). There is Prepared_statement::param_array which is an array of "primary" parameter instances, and
However, I can find $keyuse->val in
That is, it is a "secondary" Item_param object that was created for a CTE. Further, I observe that
|
| Comments |
| Comment by Sergei Petrunia [ 2020-06-02 ] | ||||||||||||||||||||||||||||||||||||||
|
Documentation about Execute in the protocol: https://mariadb.com/kb/en/com_stmt_execute/ According to Diego,
| ||||||||||||||||||||||||||||||||||||||
| Comment by Sergei Petrunia [ 2020-06-03 ] | ||||||||||||||||||||||||||||||||||||||
|
Decoding the Client's packet
0xfd=253=MYSQL_TYPE_VAR_STRING (see Noe that send_type=1... This goes against the "exotic client didn't send the | ||||||||||||||||||||||||||||||||||||||
| Comment by Sergei Petrunia [ 2020-06-13 ] | ||||||||||||||||||||||||||||||||||||||
|
No, one doesn't need an "exotic" client after all. I was mistaken. | ||||||||||||||||||||||||||||||||||||||
| Comment by Sergei Petrunia [ 2020-06-13 ] | ||||||||||||||||||||||||||||||||||||||
|
The steps to reproduce are: Apply this patch:
Then, start the server with slow-query-log enabled. Then, prepare the dataset:
Then, prepare and execute this Prepared Statement. It must be done through client-server binary protocol.
Here is a program that does that using Connector/C: https://gist.github.com/spetrunia/a3b98df451f8a8e42df51319181a259a This will cause the assert to fire on the server:
| ||||||||||||||||||||||||||||||||||||||
| Comment by Sergei Petrunia [ 2020-06-13 ] | ||||||||||||||||||||||||||||||||||||||
|
There is a call to Item_param::sync_clones made in EXECUTE:
But this one "distributes" the the no-value state:
| ||||||||||||||||||||||||||||||||||||||
| Comment by Sergei Petrunia [ 2020-06-13 ] | ||||||||||||||||||||||||||||||||||||||
|
Then, Prepared_statement::set_parameters calls set_params insert_params_with_log doesn't have the
call while insert_params() and other such functions do | ||||||||||||||||||||||||||||||||||||||
| Comment by Sergei Petrunia [ 2020-06-13 ] | ||||||||||||||||||||||||||||||||||||||
|
bb-10.2-mdev22779 | ||||||||||||||||||||||||||||||||||||||
| Comment by Sergei Petrunia [ 2020-07-02 ] | ||||||||||||||||||||||||||||||||||||||
A correction: the fix is in the source for these MariaDB versions: 10.5.5, 10.2.33, 10.3.24, 10.4.14 (none of them is released yet at the moment). |