Skip to content

Let postfix IS tests chain onto predicate results - #2840

Merged
manticore-projects merged 1 commit into
JSQLParser:masterfrom
princejain756:postfix-is-chain
Oct 21, 2026
Merged

manticore-projects merged 1 commit into
JSQLParser:masterfrom
princejain756:postfix-is-chain

Conversation

@princejain756

Copy link
Copy Markdown
Contributor

Summary

A boolean test applied to a comparison or another predicate is a parse error: a > 0 IS TRUE, a IN (1, 2) IS FALSE and a IS NULL IS NOT TRUE all fail at the IS, while the same tests on a bare column or a parenthesized comparison parse (#2759).

SQL:2016 6.39 defines <boolean test> ::= <boolean primary> [ IS [NOT] <truth value> ], so the test applies to any boolean primary. PostgreSQL, MySQL and SQLite all accept these forms.

The condition suffix dispatch fired once: a > 0 consumed the > comparison and the trailing IS TRUE had nowhere to go. Postfix IS predicates (IS [NOT] NULL / TRUE / FALSE / UNKNOWN / JSON) now chain onto the result of any earlier suffix in a loop.

Two traps the loop has to avoid, both covered by a semantic guard (isPostfixIsTestAhead) rather than first tokens:

  • IS DISTINCT FROM is also IS-led but takes a right-hand operand; the guard only enters on TRUE/FALSE/UNKNOWN/NULL/JSON, so a IS DISTINCT FROM b still resolves through the existing first-suffix dispatch.
  • NOT NULL as a column constraint after a DEFAULT expression (CREATE TABLE t (a INT DEFAULT 1 > 0 NOT NULL, ...)) is in IsNullExpression's first set; the guard rejects it before the loop commits, so that path is unchanged.

Test plan

  • SELECT * FROM t WHERE a > 0 IS TRUE parses and round-trips
  • SELECT * FROM t WHERE a IN (1, 2) IS FALSE parses and round-trips
  • SELECT * FROM t WHERE a IS NULL IS NOT TRUE chains both tests
  • SELECT * FROM t WHERE a IS TRUE IS FALSE chains a test onto a test
  • CREATE TABLE t (a INT DEFAULT 1 > 0 NOT NULL, b INT) keeps NOT NULL as a column constraint (existing ColumnDefaultExpressionTest)
  • Full suite: 10,737 tests, 0 failures

A boolean test applied to a comparison or another predicate was a
parse error: a > 0 IS TRUE, a IN (1, 2) IS FALSE, a IS NULL IS NOT
TRUE all failed at the IS, though SQL:2016 6.39 applies IS [NOT]
{TRUE|FALSE|UNKNOWN} to any boolean primary and PostgreSQL, MySQL
and SQLite accept the forms.

After the first condition suffix, postfix IS predicates (IS [NOT]
NULL / TRUE / FALSE / UNKNOWN / JSON) now chain onto the result. A
semantic guard keeps the loop from claiming IS DISTINCT FROM and
from consuming a column's NOT NULL constraint after a DEFAULT
expression.

Fixes JSQLParser#2759
@manticore-projects

Copy link
Copy Markdown
Contributor

SQL:2016 6.39 defines ::= [ IS [NOT] ], so the test applies to any boolean primary. PostgreSQL, MySQL and SQLite all accept these forms.

That's a strong argument, even I can't ignore.
Thank your for providing this PR, I will merge when tests will have passed.

| LOOKAHEAD(3) result=IsDistinctExpression(left)
| result=SimilarToExpression(left)
)
// SQL:2016 6.39: a boolean test applies to any boolean primary,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Kudos, clean documentation! I like this.

@manticore-projects
manticore-projects merged commit f5f3699 into JSQLParser:master Oct 21, 2026
10 checks passed
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.

2 participants