Skip to content

fix(optimizer): handle multi-arg XOR in normalize predicate lengths [CLAUDE]#7699

Closed
code-with-rashid wants to merge 1 commit into
tobymao:mainfrom
code-with-rashid:fix-normalize-multi-arg-xor
Closed

fix(optimizer): handle multi-arg XOR in normalize predicate lengths [CLAUDE]#7699
code-with-rashid wants to merge 1 commit into
tobymao:mainfrom
code-with-rashid:fix-normalize-multi-arg-xor

Conversation

@code-with-rashid

Copy link
Copy Markdown

Problem

normalize crashes with ValueError: too many values to unpack (expected 2) on boolean expressions containing a function-form XOR(...):

import sqlglot
from sqlglot.optimizer.normalize import normalize

e = sqlglot.parse_one("SELECT * FROM t WHERE (a AND b) OR XOR(c, d, e)", dialect="mysql")
normalize(e)
# ValueError: too many values to unpack (expected 2)
#   sqlglot/optimizer/normalize.py, in _predicate_lengths: left, right = expression.args.values()

Closes #7698.

Cause

_predicate_lengths() did left, right = expression.args.values(), assuming every exp.Connector has exactly two operands (this, expression). That holds for And/Or and binary a XOR b, but Xor is also a Func, so the function form XOR(a, b, c) parses to a Connector whose args also include expressions (and round_input) — more than two values — and the unpack fails.

Fix

Use the canonical Connector.left / Connector.right accessors instead of unpacking the raw args dict. Behavior is unchanged for all two-operand connectors; multi-arg Xor no longer crashes.

Tests

Added a regression assertion to test_normalize exercising normalization_distance on (a AND b) OR XOR(c, d, e). python -m unittest tests.test_optimizer passes (79 tests); ruff and mypy are clean.


Disclosure: prepared with the assistance of an AI agent (model: Claude), per the repository's contributor policy.

_predicate_lengths unpacked `expression.args.values()`, assuming every
Connector has exactly two operands. A function-form XOR(a, b, c) is a
Connector with more than two args, so normalize crashed with
"ValueError: too many values to unpack (expected 2)". Use the canonical
Connector.left/right accessors instead.

Closes tobymao#7698

CLAUDE

depth += 1
left, right = expression.args.values()
left, right = expression.left, expression.right

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are we only getting left and right, given the presence of the other XOR operands? Isn't this effectively discarding the rest of them?

Also, I don't think MySQL supports XOR(c, d, e):

Server version: 9.6.0 Homebrew
mysql> select xor(1, 2, 3);
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'xor(1, 2, 3)' at line 1

@georgesittas

Copy link
Copy Markdown
Collaborator

I think this PR is just treating a symptom. I'll give this a whirl, I think assigning left, right is correct, but there's another refactor that I'd like to try.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ValueError in normalize optimizer: "too many values to unpack (expected 2)"

2 participants