Bug #110045 Negative numbers on digests

Submitted: 13 Feb 2023 11:07 Modified: 15 Jan 20:37
Reporter: Yakir Gibraltar (OCA) Email Updates:
Status: Closed Impact on me:
None 
Category:MySQL Server: Performance Schema Severity:S3 (Non-critical)
Version:8.0.32 OS:Linux
Assigned to: Marc ALFF CPU Architecture:x86
Tags: digest, digests, performance_schema

[13 Feb 2023 11:07] Yakir Gibraltar
Description:
Hi, 
Negative numbers on digests in "where" not parsed out properly .
For example query:
"SELECT -1 WHERE 1 = -1" 
Generating:
"SELECT ? WHERE ? = - ?"
Instead:
"SELECT ? WHERE ? = ?"

Thank you. 

How to repeat:
db13:test> SELECT statement_digest_text("SELECT -1 WHERE 1 = 1");
+------------------------------------------------+
| statement_digest_text("SELECT -1 WHERE 1 = 1") |
+------------------------------------------------+
| SELECT ? WHERE ? = ?                           |
+------------------------------------------------+
1 row in set (0.00 sec)

db13:test> SELECT statement_digest_text("SELECT -1 WHERE 1 = -1");
+-------------------------------------------------+
| statement_digest_text("SELECT -1 WHERE 1 = -1") |
+-------------------------------------------------+
| SELECT ? WHERE ? = - ?                          |
+-------------------------------------------------+
1 row in set (0.00 sec)

Suggested fix:
SELECT statement_digest_text("SELECT -1 WHERE 1 = -1");
Should return : 
SELECT ? WHERE ? = ?
[13 Feb 2023 11:33] MySQL Verification Team
Hello Yakir,

Thank you for the report.

regards,
Umesh
[6 Nov 2025 13:38] Yakir Gibraltar
Patch for gen_lex_token.cc and tests to fix this bug

(*) I confirm the code being submitted is offered under the terms of the OCA, and that I am authorized to contribute it.

Contribution: bug110045_complete.patch (application/octet-stream, text), 8.38 KiB.

[6 Nov 2025 14:42] Yakir Gibraltar
I've created a patch that fixes the digest normalization issue for unary operators (+ and -) after comparison operators and CASE keywords.

Current MySQL Behavior (Broken):

mysql>   SELECT
    ->     STATEMENT_DIGEST_TEXT('SELECT * FROM t WHERE a = 1') AS digest_positive,
    ->     STATEMENT_DIGEST_TEXT('SELECT * FROM t WHERE a = -1') AS digest_negative,
    ->     STATEMENT_DIGEST_TEXT('SELECT * FROM t WHERE a = 1') =
    ->     STATEMENT_DIGEST_TEXT('SELECT * FROM t WHERE a = -1') AS are_equal;
+---------------------------------+-----------------------------------+-----------+
| digest_positive                 | digest_negative                   | are_equal |
+---------------------------------+-----------------------------------+-----------+
| SELECT * FROM `t` WHERE `a` = ? | SELECT * FROM `t` WHERE `a` = - ? |         0 |
+---------------------------------+-----------------------------------+-----------+
1 row in set (0.00 sec)

mysql>   SELECT
    ->     STATEMENT_DIGEST_TEXT('SELECT CASE WHEN a > 0 THEN 1 END FROM t') AS digest_positive,
    ->     STATEMENT_DIGEST_TEXT('SELECT CASE WHEN a > 0 THEN -1 END FROM t') AS digest_negative,
    ->     STATEMENT_DIGEST_TEXT('SELECT CASE WHEN a > 0 THEN 1 END FROM t') =
    ->     STATEMENT_DIGEST_TEXT('SELECT CASE WHEN a > 0 THEN -1 END FROM t') AS are_equal;
+----------------------------------------------+------------------------------------------------+-----------+
| digest_positive                              | digest_negative                                | are_equal |
+----------------------------------------------+------------------------------------------------+-----------+
| SELECT CASE WHEN `a` > ? THEN ? END FROM `t` | SELECT CASE WHEN `a` > ? THEN - ? END FROM `t` |         0 |
+----------------------------------------------+------------------------------------------------+-----------+
1 row in set (0.01 sec)

mysql>   SELECT
    ->     STATEMENT_DIGEST_TEXT('SELECT CASE WHEN a > 0 THEN 1 ELSE 2 END FROM t') AS digest_positive,
    ->     STATEMENT_DIGEST_TEXT('SELECT CASE WHEN a > 0 THEN -1 ELSE -2 END FROM t') AS digest_negative,
    ->     STATEMENT_DIGEST_TEXT('SELECT CASE WHEN a > 0 THEN 1 ELSE 2 END FROM t') =
    ->     STATEMENT_DIGEST_TEXT('SELECT CASE WHEN a > 0 THEN -1 ELSE -2 END FROM t') AS are_equal;
+-----------------------------------------------------+---------------------------------------------------------+-----------+
| digest_positive                                     | digest_negative                                         | are_equal |
+-----------------------------------------------------+---------------------------------------------------------+-----------+
| SELECT CASE WHEN `a` > ? THEN ? ELSE ? END FROM `t` | SELECT CASE WHEN `a` > ? THEN - ? ELSE - ? END FROM `t` |         0 |
+-----------------------------------------------------+---------------------------------------------------------+-----------+
1 row in set (0.00 sec)

Fixed Version:

mysql>   SELECT
    ->     STATEMENT_DIGEST_TEXT('SELECT * FROM t WHERE a = 1') AS digest_positive,
    ->     STATEMENT_DIGEST_TEXT('SELECT * FROM t WHERE a = -1') AS digest_negative,
    ->     STATEMENT_DIGEST_TEXT('SELECT * FROM t WHERE a = 1') =
    ->     STATEMENT_DIGEST_TEXT('SELECT * FROM t WHERE a = -1') AS are_equal;
+---------------------------------+---------------------------------+-----------+
| digest_positive                 | digest_negative                 | are_equal |
+---------------------------------+---------------------------------+-----------+
| SELECT * FROM `t` WHERE `a` = ? | SELECT * FROM `t` WHERE `a` = ? |         1 |
+---------------------------------+---------------------------------+-----------+
1 row in set (0.00 sec)

mysql>   SELECT
    ->     STATEMENT_DIGEST_TEXT('SELECT CASE WHEN a > 0 THEN 1 END FROM t') AS digest_positive,
    ->     STATEMENT_DIGEST_TEXT('SELECT CASE WHEN a > 0 THEN -1 END FROM t') AS digest_negative,
    ->     STATEMENT_DIGEST_TEXT('SELECT CASE WHEN a > 0 THEN 1 END FROM t') =
    ->     STATEMENT_DIGEST_TEXT('SELECT CASE WHEN a > 0 THEN -1 END FROM t') AS are_equal;
+----------------------------------------------+----------------------------------------------+-----------+
| digest_positive                              | digest_negative                              | are_equal |
+----------------------------------------------+----------------------------------------------+-----------+
| SELECT CASE WHEN `a` > ? THEN ? END FROM `t` | SELECT CASE WHEN `a` > ? THEN ? END FROM `t` |         1 |
+----------------------------------------------+----------------------------------------------+-----------+
1 row in set (0.00 sec)

mysql>   SELECT
    ->     STATEMENT_DIGEST_TEXT('SELECT CASE WHEN a > 0 THEN 1 ELSE 2 END FROM t') AS digest_positive,
    ->     STATEMENT_DIGEST_TEXT('SELECT CASE WHEN a > 0 THEN -1 ELSE -2 END FROM t') AS digest_negative,
    ->     STATEMENT_DIGEST_TEXT('SELECT CASE WHEN a > 0 THEN 1 ELSE 2 END FROM t') =
    ->     STATEMENT_DIGEST_TEXT('SELECT CASE WHEN a > 0 THEN -1 ELSE -2 END FROM t') AS are_equal;
+-----------------------------------------------------+-----------------------------------------------------+-----------+
| digest_positive                                     | digest_negative                                     | are_equal |
+-----------------------------------------------------+-----------------------------------------------------+-----------+
| SELECT CASE WHEN `a` > ? THEN ? ELSE ? END FROM `t` | SELECT CASE WHEN `a` > ? THEN ? ELSE ? END FROM `t` |         1 |
+-----------------------------------------------------+-----------------------------------------------------+-----------+
1 row in set (0.00 sec)

Note:
This bug was originally reported for WHERE clauses. During testing, I found the same issue with CASE statements, so the patch fixes both.

Solution:
The patch marks comparison operators (=, <=>, !=, <>, <, >, <=, >=) and CASE keywords (THEN, ELSE) as start_expr tokens in sql/gen_lex_token.cc. This ensures unary +/- are properly normalized.

Files Modified:
- sql/gen_lex_token.cc
- mysql-test/suite/perfschema/t/unary_digest.test
- mysql-test/suite/perfschema/r/unary_digest.result

Patch applies cleanly to MySQL 8.0, 8.4, and trunk. All tests pass.
Patch file attached.

Thank you,
 Yakir Gibraltar
[26 Nov 2025 11:17] Aaditya Dubey
Hi Team,

I’ve reviewed and tested the PR, and can confirm that it is a valid issue and the PR correctly addresses it. Please review the PR from your side as well and include the fix in an upcoming MySQL release, if possible.
[28 Nov 2025 16:41] Marc ALFF
Thanks for the contribution.
[15 Jan 20:37] Edward Gilmore
Posted by developer:
 
Added the following note to the MySQL Server 9.6.0 release notes:
		
Negative numbers on digests in WHERE were not parsed properly.

Portions of this website are copyright © 2001, 2002 The PHP Group

Page generated in 0.043 sec. using MySQL 8.4.7-u6-cloud

Timestamp references displayed by the system are UTC.
Content reproduced on this site is the property of the respective copyright holders.
It is not reviewed in advance by Oracle and does not necessarily represent the opinion of Oracle or any other party.