Bug #112439 Incorrect results when using VALUES statement as derived query
Submitted: 22 Sep 2023 23:33 Modified: 25 Sep 2023 7:48
Reporter: Manuel Ung Email Updates:
Status: Duplicate Impact on me:
None 
Category:MySQL Server: Optimizer Severity:S2 (Serious)
Version:8.1, 8.0.34 OS:Any
Assigned to: CPU Architecture:Any

[22 Sep 2023 23:33] Manuel Ung
Description:
MySQL returns incorrect results when using VALUES statement as a dependent subquery. This is because any conditions pushed to the subquery as part of query transformation is being ignored.

The issue is that JOIN::create_root_access_path_for_join is not generating any FilterIterator operators based any WHERE conditions, if query_block->is_table_value_constructor is true. HAVING/LIMIT clause is handled by JOIN::attach_access_paths_for_having_and_limit, but WHERE conditions are not handled.

An easy way to figure out which query patterns hit this issue is to add this assert and run through the test suite to see which queries are being executed incorrectly.

diff --git a/sql/sql_executor.cc b/sql/sql_executor.cc
index 2497b38b834..7a2df43213d 100644
--- a/sql/sql_executor.cc
+++ b/sql/sql_executor.cc
@@ -2884,6 +2884,7 @@ AccessPath *JOIN::create_root_access_path_for_join() {
   // OK, so we're good. Go through the tables and make the join access paths.
   AccessPath *path = nullptr;
   if (query_block->is_table_value_constructor) {
+    assert(!query_block->where_cond());
     best_rowcount = query_block->row_value_list->size();
     path = NewTableValueConstructorAccessPath(thd);
     path->num_output_rows = query_block->row_value_list->size();

How to repeat:
mysql> create table t (i int primary key);
Query OK, 0 rows affected (0.04 sec)

mysql> insert into t values (1), (2), (3);
Query OK, 3 rows affected (0.02 sec)
Records: 3  Duplicates: 0  Warnings: 0

mysql> select * from t where i in (VALUES ROW(1), ROW(2));
+---+
| i |
+---+
| 1 |
| 2 |
| 3 |
+---+
3 rows in set (0.00 sec)

mysql> select * from t where i in (SELECT 1 UNION SELECT 2);
+---+
| i |
+---+
| 1 |
| 2 |
+---+
2 rows in set (0.00 sec)

Suggested fix:
JOIN::create_root_access_path_for_join should check for where conditions on query_block and create filter operators.

In my specific example, we should just do semijoin transformation here which avoids this issue, but that's a separate feature request...
[25 Sep 2023 6:58] MySQL Verification Team
Hello Manuel,

Thank you for the report and detailed analysis.

regards,
Umesh
[25 Sep 2023 7:47] Knut Anders Hatlen
Posted by developer:
 
This bug has been fixed in mysql-trunk as part of Bug#30775369/Bug#98268 (wrong result with "IN" comparator and a TABLE VALUE CONSTRUCTOR). The fix will most likely be included in MySQL 8.3.0. Closing as duplicate.