Commit 3f73b8a
sql: parenthesize the IS DISTINCT FROM right-hand side by its left edge
`Parser::parse_is` parses the right-hand side of `IS DISTINCT FROM` with
`parse_subexpr(<IS precedence>)`, so a RHS whose left spine binds at or
below `IS` (`OR`/`AND`/another `IS`) re-associates out of the `IS` on
reparse: `a IS DISTINCT FROM b OR c` parses as `(a IS DISTINCT FROM b) OR c`.
The printer emitted the RHS bare through `IsExprConstruct`'s display, with no
precedence handling, so a `Nested`-stripped AST drifted.
This drift is invisible to a stable-string round trip — `IsExpr(a,
DistinctFrom(Or(b,c)))` and `Or(IsExpr(a, DistinctFrom(b)), c)` print to the
same string `a IS DISTINCT FROM b OR c` — which is why the round-trip fuzzer
never flagged it despite generating the construct. The bug is real: the two
ASTs are distinct and the first does not reparse to itself.
Handle `DistinctFrom` in the `IsExpr` print arm (where the precedence
helpers are in scope) and parenthesize its RHS with `left_edge` (the RHS is
parsed fresh at `IS`, walking its left spine), matching the rest of the
model. The bare-keyword constructs (`NULL`/`TRUE`/`FALSE`/`UNKNOWN`) still
go through `IsExprConstruct`'s display. Parser-produced RHSs are wrapped in
`Expr::Nested` (`ATOM`), so the datadriven suites are unchanged.
Tests: adds `is_distinct_from_rhs_reparenthesized_after_nested_stripped` to
`sqlparser_common.rs`, which checks the round trip structurally (the
stable-string collision makes a string check insufficient).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>1 parent e7a2693 commit 3f73b8a
2 files changed
Lines changed: 60 additions & 1 deletion
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
246 | 246 | | |
247 | 247 | | |
248 | 248 | | |
249 | | - | |
| 249 | + | |
| 250 | + | |
| 251 | + | |
| 252 | + | |
| 253 | + | |
| 254 | + | |
| 255 | + | |
| 256 | + | |
| 257 | + | |
| 258 | + | |
| 259 | + | |
250 | 260 | | |
251 | 261 | | |
252 | 262 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
891 | 891 | | |
892 | 892 | | |
893 | 893 | | |
| 894 | + | |
| 895 | + | |
| 896 | + | |
| 897 | + | |
| 898 | + | |
| 899 | + | |
| 900 | + | |
| 901 | + | |
| 902 | + | |
| 903 | + | |
| 904 | + | |
| 905 | + | |
| 906 | + | |
| 907 | + | |
| 908 | + | |
| 909 | + | |
| 910 | + | |
| 911 | + | |
| 912 | + | |
| 913 | + | |
| 914 | + | |
| 915 | + | |
| 916 | + | |
| 917 | + | |
| 918 | + | |
| 919 | + | |
| 920 | + | |
| 921 | + | |
| 922 | + | |
| 923 | + | |
| 924 | + | |
| 925 | + | |
| 926 | + | |
| 927 | + | |
| 928 | + | |
| 929 | + | |
| 930 | + | |
| 931 | + | |
| 932 | + | |
| 933 | + | |
| 934 | + | |
| 935 | + | |
| 936 | + | |
| 937 | + | |
| 938 | + | |
| 939 | + | |
| 940 | + | |
| 941 | + | |
| 942 | + | |
0 commit comments