Title: [BUG] EXCEPT ALL/DISTINCT and MINUS ALL/DISTINCT modifiers lost during parse-toString round-trip · Issue #2419 · JSQLParser/JSqlParser · GitHub
Open Graph Title: [BUG] EXCEPT ALL/DISTINCT and MINUS ALL/DISTINCT modifiers lost during parse-toString round-trip · Issue #2419 · JSQLParser/JSqlParser
X Title: [BUG] EXCEPT ALL/DISTINCT and MINUS ALL/DISTINCT modifiers lost during parse-toString round-trip · Issue #2419 · JSQLParser/JSqlParser
Description: Description EXCEPT ALL, EXCEPT DISTINCT, MINUS ALL, and MINUS DISTINCT modifiers are silently dropped during parsing. The parser accepts the modifier syntax but does not pass the captured modifier string to the ExceptOp and MinusOp const...
Open Graph Description: Description EXCEPT ALL, EXCEPT DISTINCT, MINUS ALL, and MINUS DISTINCT modifiers are silently dropped during parsing. The parser accepts the modifier syntax but does not pass the captured modifier ...
X Description: Description EXCEPT ALL, EXCEPT DISTINCT, MINUS ALL, and MINUS DISTINCT modifiers are silently dropped during parsing. The parser accepts the modifier syntax but does not pass the captured modifier ...
Opengraph URL: https://github.com/JSQLParser/JSqlParser/issues/2419
X: @github
Domain: github.com
{"@context":"https://schema.org","@type":"DiscussionForumPosting","headline":"[BUG] EXCEPT ALL/DISTINCT and MINUS ALL/DISTINCT modifiers lost during parse-toString round-trip","articleBody":"### Description\n\n`EXCEPT ALL`, `EXCEPT DISTINCT`, `MINUS ALL`, and `MINUS DISTINCT` modifiers are silently dropped during parsing. The parser accepts the modifier syntax but does not pass the captured modifier string to the `ExceptOp` and `MinusOp` constructors.\n\n### Reproducer\n\n```java\nString sql = \"SELECT a FROM t1 EXCEPT ALL SELECT a FROM t2\";\nStatement stmt = CCJSqlParserUtil.parse(sql);\nSystem.out.println(stmt.toString());\n// Expected: SELECT a FROM t1 EXCEPT ALL SELECT a FROM t2\n// Actual: SELECT a FROM t1 EXCEPT SELECT a FROM t2\n```\n\nThe same issue affects `MINUS ALL`:\n```java\nString sql = \"SELECT a FROM t1 MINUS ALL SELECT a FROM t2\";\nStatement stmt = CCJSqlParserUtil.parse(sql);\nSystem.out.println(stmt.toString());\n// Expected: SELECT a FROM t1 MINUS ALL SELECT a FROM t2\n// Actual: SELECT a FROM t1 MINUS SELECT a FROM t2\n```\n\n### Root Cause\n\nIn `JSqlParserCC.jjt`, the `SetOperationList` rule captures the modifier via `modifier=SetOperationModifier()` but constructs `MinusOp` and `ExceptOp` with their no-arg constructors (which default to empty string), discarding the modifier:\n\n```\n\u003cK_MINUS\u003e [ modifier=SetOperationModifier() ] { MinusOp minus = new MinusOp(); ... }\n\u003cK_EXCEPT\u003e [ modifier=SetOperationModifier() ] { ExceptOp except = new ExceptOp(); ... }\n```\n\nCompare with `UnionOp` and `IntersectOp` which correctly pass the modifier:\n```\n\u003cK_UNION\u003e [ modifier=SetOperationModifier() ] { UnionOp union = new UnionOp(modifier); ... }\n\u003cK_INTERSECT\u003e [ modifier=SetOperationModifier() ] { IntersectOp intersect = new IntersectOp(modifier); ... }\n```\n\nAdditionally, the `modifier` variable was not reset between iterations of the set-operation loop, causing modifiers to leak from one operator to the next (e.g., `UNION ALL ... EXCEPT` would incorrectly make the EXCEPT inherit `ALL`).\n\n### Impact\n\n- **Semantic correctness**: `EXCEPT ALL` preserves duplicates while `EXCEPT` removes them. Silently dropping the `ALL` modifier changes query semantics.\n- **Round-trip fidelity**: `parse(sql).toString()` does not reproduce the original SQL.\n\n### Affected versions\n\nCurrent `master` (regression introduced in commit `5fe938bc` which refactored `SetOperationModifier` handling for the `CORRESPONDING` feature).\n\n### Fix\n\n1. Pass `modifier` to `MinusOp` and `ExceptOp` constructors\n2. Reset `modifier = null` at the start of each set-operation loop iteration\n\nA PR with the fix and regression tests will follow.","author":{"url":"https://github.com/queelius","@type":"Person","name":"queelius"},"datePublished":"2026-03-25T10:46:56.000Z","interactionStatistic":{"@type":"InteractionCounter","interactionType":"https://schema.org/CommentAction","userInteractionCount":0},"url":"https://github.com/2419/JSqlParser/issues/2419"}
| route-pattern | /_view_fragments/issues/show/:user_id/:repository/:id/issue_layout(.:format) |
| route-controller | voltron_issues_fragments |
| route-action | issue_layout |
| fetch-nonce | v2:8de52610-5aa2-bffb-685b-6d3b2cba976d |
| current-catalog-service-hash | 81bb79d38c15960b92d99bca9288a9108c7a47b18f2423d0f6438c5b7bcd2114 |
| request-id | 91AC:144FE2:141C5D8:1CDDC01:6A634B38 |
| html-safe-nonce | 525c43b760fa51aff4a61426c69c69bc8d969bee9c3956dfdefcd0d13811f005 |
| visitor-payload | eyJyZWZlcnJlciI6IiIsInJlcXVlc3RfaWQiOiI5MUFDOjE0NEZFMjoxNDFDNUQ4OjFDRERDMDE6NkE2MzRCMzgiLCJ2aXNpdG9yX2lkIjoiMTg1MTY3NzczMzAwNzA4NDM0NCIsInJlZ2lvbl9lZGdlIjoiaWFkIiwicmVnaW9uX3JlbmRlciI6ImlhZCJ9 |
| visitor-hmac | 3934b60ad0dcc39c243e6ac8e588b99acfb2472cbeb90881a178c3b29c6d023b |
| hovercard-subject-tag | issue:4134411160 |
| github-keyboard-shortcuts | repository,issues,copilot |
| google-site-verification | Apib7-x98H0j5cPqHWwSMm6dNU4GmODRoqxLiDzdx9I |
| octolytics-url | https://collector.github.com/github/collect |
| analytics-location | / |
| fb:app_id | 1401488693436528 |
| apple-itunes-app | app-id=1477376905, app-argument=https://github.com/_view_fragments/issues/show/JSQLParser/JSqlParser/2419/issue_layout |
| twitter:image | https://opengraph.githubassets.com/893d94d653732adc642a11de68a51091578705489c95dd482bdb6d7479fcee94/JSQLParser/JSqlParser/issues/2419 |
| twitter:card | summary_large_image |
| og:image | https://opengraph.githubassets.com/893d94d653732adc642a11de68a51091578705489c95dd482bdb6d7479fcee94/JSQLParser/JSqlParser/issues/2419 |
| og:image:alt | Description EXCEPT ALL, EXCEPT DISTINCT, MINUS ALL, and MINUS DISTINCT modifiers are silently dropped during parsing. The parser accepts the modifier syntax but does not pass the captured modifier ... |
| og:image:width | 1200 |
| og:image:height | 600 |
| og:site_name | GitHub |
| og:type | object |
| og:author:username | queelius |
| hostname | github.com |
| expected-hostname | github.com |
| None | 59e55daad7174ca59d63c6974d58276ccb5477442e550bebb3c035e1bef11c94 |
| turbo-cache-control | no-preview |
| go-import | github.com/JSQLParser/JSqlParser git https://github.com/JSQLParser/JSqlParser.git |
| octolytics-dimension-user_id | 4643847 |
| octolytics-dimension-user_login | JSQLParser |
| octolytics-dimension-repository_id | 1944709 |
| octolytics-dimension-repository_nwo | JSQLParser/JSqlParser |
| octolytics-dimension-repository_public | true |
| octolytics-dimension-repository_is_fork | false |
| octolytics-dimension-repository_network_root_id | 1944709 |
| octolytics-dimension-repository_network_root_nwo | JSQLParser/JSqlParser |
| turbo-body-classes | logged-out env-production page-responsive |
| disable-turbo | false |
| browser-stats-url | https://api.github.com/_private/browser/stats |
| browser-errors-url | https://api.github.com/_private/browser/errors |
| release | 990295d92a4cc7b63fbbd83a046217cd7d77d49c |
| ui-target | full |
| theme-color | #1e2327 |
| color-scheme | light dark |
Links:
Viewport: width=device-width