Update from MySQL 8.4 to MySQL 9.7#1344
Conversation
|
Great start! For test case 2, do you think we could still report it and then disable its generation until the bug is resolved, despite being deprecated? It is a bug after all. If you prefer not to, that's also fine. For test case 3, I guess you could go ahead and report it? For test case 4, disabling indices altogether would significantly restrict the search space as you pointed out. Perhaps, could we instead insert only integer values or so for now? |
52f6b1c to
d96b4f9
Compare
There was a problem hiding this comment.
I guess this was accidentally checked in?
There was a problem hiding this comment.
Yes, I can remove the edits to this file
|
Hi Manuel, I have pushed updates to this branch and updated the PR description. This PR is now ready for full review and merging once any remaining issues have been addressed. I have organised it as multiple commits which can be squashed as desired. Regarding your comments:
|
| sb.append(MySQLVisitor.asString(gen.generateConstant())); | ||
| MySQLExpression constExpr; | ||
| // loop to regenerate until expression is valid (for bug workarounds) | ||
| while (true) { |
There was a problem hiding this comment.
as a kind of sanity check, could we add a loop counter and add a named constant as a threshold? like this, in case we change the code later on and, due to a bug, we have an infinite loop, we can detect that case by throwing an assertion error if the threshold is exceeded.
There was a problem hiding this comment.
I have now implemented this
| sb.append(" UNSIGNED"); | ||
| } | ||
| if (!globalState.usesPQS() && Randomly.getBoolean()) { | ||
| if (Randomly.getBoolean() && !globalState.getDbmsSpecificOptions().getTestOracleFactory().stream().anyMatch(o -> o == MySQLOracleFactory.TLP_WHERE || o == MySQLOracleFactory.PQS || o == MySQLOracleFactory.DQP)) { |
There was a problem hiding this comment.
I guess here, the bug ID is missing?
There was a problem hiding this comment.
This is in response to test case 2, which is expected MySQL behaviour. The listed oracles would flag that expected behaviour as a bug, but it is not actually a bug. So, I have provided this workaround without assigning any bug ID to it. Does that sound suitable?
|
It seems that the general tests are failing due to a formatting error. You can run |
…ng generation (which may implicitly cast to undesirable integer/double)
…L in MySQL despite the behaviour being expected
d96b4f9 to
5004bc5
Compare
|
I rebased to remove the initial edits to .settings/org.eclipse.jdt.core.prefs, did a new commit to add the loop counter, and reformatted to pass the general tests |
|
I will investigate why the MySQL CI is failing |
…MIT and known SELECT/DML error discrepancies Appends rowId as an ORDER BY tiebreaker to eliminate non-determinism when user columns contain duplicate values (e.g. NULLs) under LIMIT. Introduces isKnownSelectDMLDiscrepancy to suppress false positives from error codes that MySQL legitimately raises in UPDATE/DELETE but not SELECT (or vice versa) due to differing execution paths: WHERE-clause type coercion (1292, 1366), functional index maintenance (1030, 3751), and range optimizer memory limits (3170).
903adcc to
f952b25
Compare
|
After my latest commit, the MySQL CI is now passing. Summary of the failing test cases identified and fixed: Test case 7Reduced input (indicative): CREATE TABLE t0(c0 DECIMAL ZEROFILL UNIQUE);
INSERT INTO t0(c0) VALUES(NULL), (NULL), (1284856216), ...;
SELECT rowId FROM t0 WHERE <cond> ORDER BY t0.c0 LIMIT 7;
UPDATE t0 SET updated=1 WHERE <cond> ORDER BY t0.c0 LIMIT 7;
DELETE FROM t0 WHERE <cond> ORDER BY t0.c0 LIMIT 7;Error:
Conclusion: This is not a DBMS bug. When Test case 8Reduced input (indicative): CREATE TABLE t0(c0 DECIMAL);
INSERT INTO t0(c0) VALUES(...);
SELECT rowId FROM t0 WHERE (t0.c0) NOT IN ("yS", NULL, ...);
UPDATE t0 SET updated=1 WHERE (t0.c0) NOT IN ("yS", NULL, ...);
DELETE FROM t0 WHERE (t0.c0) NOT IN ("yS", NULL, ...);Related errors:
Conclusion: This is not a DBMS bug. MySQL evaluates type-incompatible literals in WHERE clauses (e.g. string The initial fix of adding 1292 and 1366 to Test case 9Reduced input (indicative): CREATE TABLE t0(c0 INT, c1 DECIMAL UNSIGNED ZEROFILL);
CREATE INDEX i2 ON t0(LEAST(t0.c1, ...), (... XOR ...));
INSERT INTO t0 VALUES(...);
SELECT rowId FROM t0 WHERE <cond>;
UPDATE t0 SET updated=1 WHERE <cond>;
DELETE FROM t0 WHERE <cond>;Error:
Conclusion: This is not a DBMS bug. The table has a functional index whose expression uses Test case 10Reduced input (indicative): CREATE TABLE t0(c0 MEDIUMTEXT);
CREATE INDEX i72 ON t0(c0(4));
INSERT INTO t0(c0) VALUES(...);
SELECT rowId FROM t0 WHERE t0.c0;
UPDATE t0 SET updated=1 WHERE t0.c0;
DELETE FROM t0 WHERE t0.c0;Error:
Conclusion: This is not a DBMS bug. MySQL's range optimiser has a configurable memory budget ( |
| */ | ||
| private static boolean isKnownSelectDMLDiscrepancy(SQLQueryError error) { | ||
| switch (error.getCode()) { | ||
| case 1030: |
There was a problem hiding this comment.
As a nitpick, I think this would be more readable and easier to maintain by making these values part of an enum, so you can attach the individual comments above to each enum value.
|
Thanks a lot! Could you please take a look at the small nitpick? After that, we can merge the PR. |
…nerator MySQL rejects CREATE INDEX with a prefix key part (e.g. c0(3)) on a column that participates in PARTITION BY KEY(). MySQLIndexGenerator generated these without checking partition membership and did not include this error in ExpectedErrors, causing checkException to escalate it to a fatal AssertionError. Adds the error substring to the expected errors list.
ccc08cb to
9efa585
Compare
|
I have made the improvement in MySQLDQEOracle by refactoring into an enum. Also discovered an unrelated issue with MySQLIndexGenerator which was rare enough to have not surfaced until now, and fixed that (detailed below). CI is passing again (apart from the tests for some other DBMSs, which were already failing before this PR). Test case 11Reduced input (indicative): CREATE TABLE t0(c0 VARCHAR(500)) ENGINE = InnoDB PARTITION BY KEY (c0);
CREATE INDEX i1 USING BTREE ON t0(c0(3)) VISIBLE;Error:
Conclusion: This is not a DBMS bug. MySQL does not permit prefix key parts (e.g. |
Summary
This PR updates the supported MySQL version from 8.4 to 9.7.0, and the associated JDBC driver from mysql-connector-java 8.0.30 to mysql-connector-j 9.7.0.
Below is an overview of the newly encountered errors and their fixes.
Test case 1
Reduced input:
Error:
Incorrect FLOAT value: '' for column 'c1' at row 1Conclusion:
This is not a DBMS bug; rather, it is due to invalid insertion by SQLancer. A solution would be to modify the SQLancer generation phase to avoid placing strings in FLOAT fields. However (in keeping with SQLancer’s approach for similar cases), the implemented solution is to add the error as an ExpectedError to MySQLErrors.
Likewise for
Incorrect DOUBLE value.Test case 2
Reduced input:
Error:
TLPWhereOracle:
The content of the result sets mismatch!Conclusion:
It appears that the
ZEROFILLproperty is lost when doing a union of multiple tables, causing the first query to be zero-filled and not the second.However, this is expected behaviour as per MySQL documentation, which states, “The ZEROFILL attribute is ignored for columns involved in expressions or UNION queries.” (https://dev.mysql.com/doc/refman/9.7/en/numeric-type-attributes.html). Therefore, this is not a DBMS bug.
The implemented solution is to prevent use of the ZEROFILL attribute when testing with oracles for which inconsistent ZEROFILL may lead to flagging of errors (PQS, TLP, and DQP).
Note, the
ZEROFILLattribute in MySQL is deprecated for numeric data types, so may be removed in a future version (https://dev.mysql.com/doc/refman/9.7/en/numeric-type-syntax.html). However, while it remains available, it will continue to be implemented in SQLancer.Test case 3 (bug120710)
Reduced input (exhibit A):
Error:
TLPWhereOracle:
The size of the result sets mismatch!The bug appears when inserting a number that rounds to 0 followed by a NULL value (or the other way round) into a
DECIMAL-type column. The identified bug-inducing test cases all involve theIFNULLfunction.This bug is not present in MySQL 8.4.
Conclusion:
This is a DBMS bug. It has been simplified and reported to the developers (https://bugs.mysql.com/bug.php?id=120710).
Until the bug is fixed, the workaround implemented in SQLancer is to avoid the insertion of numbers that round to 0 into
DECIMAL-type columns in MySQL.Test case 4 (bug120711)
Reduced input:
Error:
TLPWhereOracle:
The size of the result sets mismatch!The bug appears when creating an index on a column, then inserting a value in the range$[0.5,1.5)$ (i.e., which rounds to 1). The bug also appears the other way round (i.e., when first inserting and then creating an index). The identified bug-inducing test cases all involve the
IFNULLfunction.The bug is present for any of the integer data types (
INTEGER,INT,SMALLINT,TINYINT,MEDIUMINT,BIGINT).The bug is also present in MySQL 8.4.
Conclusion:
This is a DBMS bug. It has been simplified and reported to the developers (https://bugs.mysql.com/bug.php?id=120711).
Until the bug is fixed, the workaround implemented in SQLancer is to avoid the insertion of values which round to 1 into integer-type columns. This approach restricts the search space less than preventing index creation.
Test case 5
Error:
All runs using CERTOracle throw
SQLException: Column Index out of range, 10 > 1.Conclusion:
This is not a DBMS bug; rather, it is due to an assumption of SQLancer no longer being valid. As of MySQL 9.5.0, the default explain format changed from
TRADITIONALtoTREE(https://dev.mysql.com/doc/relnotes/mysql/9.7/en/news-9-5-0.html). This breaks the parser of CERTOracle’s EXPLAIN queries.The implemented solution is to modify
MySQLExpressionGenerator's implementation of thegenerateExplainQuerymethod to specifyFORMAT=TRADITIONALin the generated statement.Test case 6 (bug120712)
Input:
Error:
CERTOracle:
Inconsistent result for query. The more restrictive query (query 2) is estimated to have a higher row count than the more relaxed query (query 1).The bug occurs when an index is created between two NULL inserts. The issue is not specific to INT columns (it is still present when the column is changed to FLOAT).
Conclusion:
This is a DBMS bug. It has been simplified and reported to the developers (https://bugs.mysql.com/bug.php?id=120712).
This must be worked around in SQLancer until the bug is fixed. We would ideally either prevent creating indices on columns which already have a NULL value, or prevent inserting a NULL value into columns which already have an index.
However, both of these options would involve a large refactor. Implementing the former would require tracking whether each column has had a NULL inserted or not; the latter would require tracking whether each column is currently an index or not. Alternatively, one could query for nulls each time a CREATE INDEX statement may be generated, or read schema information each time a NULL may be generated (respectively). However, this would be too computationally expensive.
The simpler options are to either prevent index creation entirely or prevent NULL inserts entirely. Unfortunately, either of these would restrict a lot of the search space (as many bugs are discovered through inserting NULLs or creating indices). As this bug is related specifically to the CERT oracle and the EXPLAIN statement, index creation is particularly relevant, as it is more closely tied to the optimiser’s row estimation logic. Therefore, it was chosen to prevent NULL inserts. The workaround is only implemented when the CERT oracle is used (therefore, the search space remains relaxed for other oracles).
However, preventing NULL inserts poses difficulties when using C-Reduce to reduce other bug-inducing CERT test cases. C-Reduce may, for example, reduce
INSERT INTO t0 VALUES(123);toINSERT INTO t0 VALUES();, which is effectively inserting a NULL value. Therefore, though the bug is avoided by SQLancer, it may be encountered during C-Reduce’s reduction of a different bug, causing the process to become side-tracked from the actual bug of interest. Those using C-Reduce should bear this in mind when attempting to reduce MySQL bugs flagged by the CERT oracle.