From c04a320c31dbc2cd7a349065c9a1c1f0ea989e57 Mon Sep 17 00:00:00 2001 From: Rashid Mahmood Date: Wed, 3 Jun 2026 07:12:52 +0400 Subject: [PATCH] fix(optimizer): handle multi-arg XOR in normalize predicate lengths _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 #7698 CLAUDE --- sqlglot/optimizer/normalize.py | 2 +- tests/test_optimizer.py | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/sqlglot/optimizer/normalize.py b/sqlglot/optimizer/normalize.py index 98f297d1a1..8a81d345e7 100644 --- a/sqlglot/optimizer/normalize.py +++ b/sqlglot/optimizer/normalize.py @@ -143,7 +143,7 @@ def _predicate_lengths( return depth += 1 - left, right = expression.args.values() + left, right = expression.left, expression.right if isinstance(expression, exp.And if dnf else exp.Or): for a in _predicate_lengths(left, dnf, max_, depth): diff --git a/tests/test_optimizer.py b/tests/test_optimizer.py index 0dd9ab5831..ba4e96f8d9 100644 --- a/tests/test_optimizer.py +++ b/tests/test_optimizer.py @@ -341,6 +341,14 @@ def test_normalize(self): "x AND (y OR z)", ) + # A multi-argument XOR is a Connector with more than two operands, which + # previously crashed predicate-length estimation with + # "ValueError: too many values to unpack". See #7698. + self.assertEqual( + normalization_distance(parse_one("(a AND b) OR XOR(c, d, e)", dialect="mysql")), + 4, + ) + self.check_file("normalize", normalize, schema=self.schema) @patch("sqlglot.generator.logger")