Skip to content

Commit c0e0131

Browse files
test(parser): expand IS JSON coverage across dialect and error paths
Add integration coverage for supported IS JSON forms and unsupported-dialect failures for both IS JSON and IS NOT JSON. Tighten malformed-case assertions with token-specific diagnostics, including junk tails and duplicate WITH/WITHOUT UNIQUE KEYS clauses.
1 parent 3bb0d60 commit c0e0131

1 file changed

Lines changed: 254 additions & 4 deletions

File tree

tests/sqlparser_common.rs

Lines changed: 254 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10838,8 +10838,19 @@ fn parse_is_boolean() {
1083810838
verified_stmt("SELECT f FROM foo WHERE field IS UNKNOWN");
1083910839
verified_stmt("SELECT f FROM foo WHERE field IS NOT UNKNOWN");
1084010840

10841+
let supported_dialects = all_dialects_where(|d| d.supports_is_json_predicate());
10842+
let unsupported_dialects = all_dialects_where(|d| !d.supports_is_json_predicate());
10843+
1084110844
let sql = "SELECT f from foo where field is 0";
10842-
let res = parse_sql_statements(sql);
10845+
let res = supported_dialects.parse_sql_statements(sql);
10846+
assert_eq!(
10847+
ParserError::ParserError(
10848+
"Expected: [NOT] NULL | TRUE | FALSE | DISTINCT | [NOT] JSON [VALUE | SCALAR | ARRAY | OBJECT] [WITH | WITHOUT UNIQUE [KEYS]] | [form] NORMALIZED FROM after IS, found: 0"
10849+
.to_string()
10850+
),
10851+
res.unwrap_err()
10852+
);
10853+
let res = unsupported_dialects.parse_sql_statements(sql);
1084310854
assert_eq!(
1084410855
ParserError::ParserError(
1084510856
"Expected: [NOT] NULL | TRUE | FALSE | DISTINCT | [form] NORMALIZED FROM after IS, found: 0"
@@ -10849,7 +10860,15 @@ fn parse_is_boolean() {
1084910860
);
1085010861

1085110862
let sql = "SELECT s, s IS XYZ NORMALIZED FROM foo";
10852-
let res = parse_sql_statements(sql);
10863+
let res = supported_dialects.parse_sql_statements(sql);
10864+
assert_eq!(
10865+
ParserError::ParserError(
10866+
"Expected: [NOT] NULL | TRUE | FALSE | DISTINCT | [NOT] JSON [VALUE | SCALAR | ARRAY | OBJECT] [WITH | WITHOUT UNIQUE [KEYS]] | [form] NORMALIZED FROM after IS, found: XYZ"
10867+
.to_string()
10868+
),
10869+
res.unwrap_err()
10870+
);
10871+
let res = unsupported_dialects.parse_sql_statements(sql);
1085310872
assert_eq!(
1085410873
ParserError::ParserError(
1085510874
"Expected: [NOT] NULL | TRUE | FALSE | DISTINCT | [form] NORMALIZED FROM after IS, found: XYZ"
@@ -10859,7 +10878,15 @@ fn parse_is_boolean() {
1085910878
);
1086010879

1086110880
let sql = "SELECT s, s IS NFKC FROM foo";
10862-
let res = parse_sql_statements(sql);
10881+
let res = supported_dialects.parse_sql_statements(sql);
10882+
assert_eq!(
10883+
ParserError::ParserError(
10884+
"Expected: [NOT] NULL | TRUE | FALSE | DISTINCT | [NOT] JSON [VALUE | SCALAR | ARRAY | OBJECT] [WITH | WITHOUT UNIQUE [KEYS]] | [form] NORMALIZED FROM after IS, found: FROM"
10885+
.to_string()
10886+
),
10887+
res.unwrap_err()
10888+
);
10889+
let res = unsupported_dialects.parse_sql_statements(sql);
1086310890
assert_eq!(
1086410891
ParserError::ParserError(
1086510892
"Expected: [NOT] NULL | TRUE | FALSE | DISTINCT | [form] NORMALIZED FROM after IS, found: FROM"
@@ -10869,7 +10896,15 @@ fn parse_is_boolean() {
1086910896
);
1087010897

1087110898
let sql = "SELECT s, s IS TRIM(' NFKC ') FROM foo";
10872-
let res = parse_sql_statements(sql);
10899+
let res = supported_dialects.parse_sql_statements(sql);
10900+
assert_eq!(
10901+
ParserError::ParserError(
10902+
"Expected: [NOT] NULL | TRUE | FALSE | DISTINCT | [NOT] JSON [VALUE | SCALAR | ARRAY | OBJECT] [WITH | WITHOUT UNIQUE [KEYS]] | [form] NORMALIZED FROM after IS, found: TRIM"
10903+
.to_string()
10904+
),
10905+
res.unwrap_err()
10906+
);
10907+
let res = unsupported_dialects.parse_sql_statements(sql);
1087310908
assert_eq!(
1087410909
ParserError::ParserError(
1087510910
"Expected: [NOT] NULL | TRUE | FALSE | DISTINCT | [form] NORMALIZED FROM after IS, found: TRIM"
@@ -10879,6 +10914,221 @@ fn parse_is_boolean() {
1087910914
);
1088010915
}
1088110916

10917+
#[test]
10918+
fn parse_is_json_predicate() {
10919+
use self::Expr::*;
10920+
10921+
let supported_dialects = all_dialects_where(|d| d.supports_is_json_predicate());
10922+
10923+
let sql = "a IS JSON";
10924+
assert_eq!(
10925+
IsJson {
10926+
expr: Box::new(Identifier(Ident::new("a"))),
10927+
kind: None,
10928+
unique_keys: None,
10929+
negated: false,
10930+
},
10931+
supported_dialects.verified_expr(sql)
10932+
);
10933+
10934+
let sql = "a IS NOT JSON";
10935+
assert_eq!(
10936+
IsJson {
10937+
expr: Box::new(Identifier(Ident::new("a"))),
10938+
kind: None,
10939+
unique_keys: None,
10940+
negated: true,
10941+
},
10942+
supported_dialects.verified_expr(sql)
10943+
);
10944+
10945+
let sql = "a IS JSON VALUE";
10946+
assert_eq!(
10947+
IsJson {
10948+
expr: Box::new(Identifier(Ident::new("a"))),
10949+
kind: Some(JsonPredicateType::Value),
10950+
unique_keys: None,
10951+
negated: false,
10952+
},
10953+
supported_dialects.verified_expr(sql)
10954+
);
10955+
10956+
let sql = "a IS JSON SCALAR";
10957+
assert_eq!(
10958+
IsJson {
10959+
expr: Box::new(Identifier(Ident::new("a"))),
10960+
kind: Some(JsonPredicateType::Scalar),
10961+
unique_keys: None,
10962+
negated: false,
10963+
},
10964+
supported_dialects.verified_expr(sql)
10965+
);
10966+
10967+
let sql = "a IS JSON ARRAY";
10968+
assert_eq!(
10969+
IsJson {
10970+
expr: Box::new(Identifier(Ident::new("a"))),
10971+
kind: Some(JsonPredicateType::Array),
10972+
unique_keys: None,
10973+
negated: false,
10974+
},
10975+
supported_dialects.verified_expr(sql)
10976+
);
10977+
10978+
let sql = "a IS JSON OBJECT";
10979+
assert_eq!(
10980+
IsJson {
10981+
expr: Box::new(Identifier(Ident::new("a"))),
10982+
kind: Some(JsonPredicateType::Object),
10983+
unique_keys: None,
10984+
negated: false,
10985+
},
10986+
supported_dialects.verified_expr(sql)
10987+
);
10988+
10989+
let sql = "a IS JSON WITH UNIQUE KEYS";
10990+
assert_eq!(
10991+
IsJson {
10992+
expr: Box::new(Identifier(Ident::new("a"))),
10993+
kind: None,
10994+
unique_keys: Some(JsonKeyUniqueness::WithUniqueKeys),
10995+
negated: false,
10996+
},
10997+
supported_dialects.verified_expr(sql)
10998+
);
10999+
11000+
let sql = "a IS JSON WITHOUT UNIQUE KEYS";
11001+
assert_eq!(
11002+
IsJson {
11003+
expr: Box::new(Identifier(Ident::new("a"))),
11004+
kind: None,
11005+
unique_keys: Some(JsonKeyUniqueness::WithoutUniqueKeys),
11006+
negated: false,
11007+
},
11008+
supported_dialects.verified_expr(sql)
11009+
);
11010+
11011+
let sql = "a IS NOT JSON OBJECT WITHOUT UNIQUE KEYS";
11012+
assert_eq!(
11013+
IsJson {
11014+
expr: Box::new(Identifier(Ident::new("a"))),
11015+
kind: Some(JsonPredicateType::Object),
11016+
unique_keys: Some(JsonKeyUniqueness::WithoutUniqueKeys),
11017+
negated: true,
11018+
},
11019+
supported_dialects.verified_expr(sql)
11020+
);
11021+
11022+
supported_dialects.expr_parses_to("a IS JSON WITH UNIQUE", "a IS JSON WITH UNIQUE KEYS");
11023+
supported_dialects.expr_parses_to("a IS JSON WITHOUT UNIQUE", "a IS JSON WITHOUT UNIQUE KEYS");
11024+
11025+
assert_matches!(
11026+
supported_dialects.verified_expr("NOT a IS JSON"),
11027+
Expr::UnaryOp {
11028+
op: UnaryOperator::Not,
11029+
expr
11030+
} if matches!(&*expr, Expr::IsJson { .. })
11031+
);
11032+
}
11033+
11034+
#[test]
11035+
fn parse_is_json_predicate_unsupported_dialects() {
11036+
let unsupported_dialects = all_dialects_where(|d| !d.supports_is_json_predicate());
11037+
assert!(!unsupported_dialects.dialects.is_empty());
11038+
11039+
for sql in ["SELECT a IS JSON FROM t", "SELECT a IS NOT JSON FROM t"] {
11040+
let err = unsupported_dialects.parse_sql_statements(sql).unwrap_err();
11041+
let ParserError::ParserError(msg) = err else {
11042+
panic!("Expected ParserError::ParserError for `{sql}`, got: {err:?}");
11043+
};
11044+
assert!(
11045+
msg.contains("[NOT] NULL | TRUE | FALSE | DISTINCT | [form] NORMALIZED FROM after IS"),
11046+
"Unexpected error hint for unsupported dialects in `{sql}`: {msg}"
11047+
);
11048+
assert!(
11049+
!msg.contains("[NOT] JSON [VALUE | SCALAR | ARRAY | OBJECT]"),
11050+
"Unsupported dialects should not advertise JSON IS-predicate syntax in `{sql}`: {msg}"
11051+
);
11052+
assert!(
11053+
msg.contains("found: JSON"),
11054+
"Expected parser to fail at JSON token for unsupported dialects in `{sql}`: {msg}"
11055+
);
11056+
}
11057+
}
11058+
11059+
#[test]
11060+
fn parse_is_json_predicate_negative() {
11061+
let supported_dialects = all_dialects_where(|d| d.supports_is_json_predicate());
11062+
11063+
let cases = [
11064+
(
11065+
"SELECT * FROM t WHERE a IS JSON WITH FROM",
11066+
&["Expected: UNIQUE", "found: FROM"][..],
11067+
),
11068+
(
11069+
"SELECT * FROM t WHERE a IS JSON WITH KEYS",
11070+
&["Expected: UNIQUE", "found: KEYS"][..],
11071+
),
11072+
(
11073+
"SELECT * FROM t WHERE a IS JSON WITHOUT FROM",
11074+
&["Expected: UNIQUE", "found: FROM"][..],
11075+
),
11076+
(
11077+
"SELECT * FROM t WHERE a IS JSON WITHOUT KEYS",
11078+
&["Expected: UNIQUE", "found: KEYS"][..],
11079+
),
11080+
(
11081+
"SELECT * FROM t WHERE a IS NOT JSON WITH FROM",
11082+
&["Expected: UNIQUE", "found: FROM"][..],
11083+
),
11084+
(
11085+
"SELECT * FROM t WHERE a IS JSON VALUE ARRAY",
11086+
&["Expected: end of statement", "found: ARRAY"][..],
11087+
),
11088+
(
11089+
"SELECT * FROM t WHERE a IS JSON OBJECT VALUE",
11090+
&["Expected: end of statement", "found: VALUE"][..],
11091+
),
11092+
(
11093+
"SELECT * FROM t WHERE a IS JSON WITH UNIQUE EXTRA",
11094+
&["Expected: end of statement", "found: EXTRA"][..],
11095+
),
11096+
(
11097+
"SELECT * FROM t WHERE a IS JSON WITH UNIQUE KEYS EXTRA",
11098+
&["Expected: end of statement", "found: EXTRA"][..],
11099+
),
11100+
(
11101+
"SELECT * FROM t WHERE a IS JSON WITHOUT UNIQUE EXTRA",
11102+
&["Expected: end of statement", "found: EXTRA"][..],
11103+
),
11104+
(
11105+
"SELECT * FROM t WHERE a IS JSON WITHOUT UNIQUE KEYS EXTRA",
11106+
&["Expected: end of statement", "found: EXTRA"][..],
11107+
),
11108+
(
11109+
"SELECT * FROM t WHERE a IS JSON WITH UNIQUE KEYS WITH UNIQUE KEYS",
11110+
&["Expected: end of statement", "found: WITH"][..],
11111+
),
11112+
(
11113+
"SELECT * FROM t WHERE a IS JSON WITHOUT UNIQUE KEYS WITHOUT UNIQUE KEYS",
11114+
&["Expected: end of statement", "found: WITHOUT"][..],
11115+
),
11116+
];
11117+
11118+
for (sql, expected_fragments) in cases {
11119+
let err = supported_dialects.parse_sql_statements(sql).unwrap_err();
11120+
let ParserError::ParserError(msg) = err else {
11121+
panic!("Expected ParserError::ParserError for `{sql}`, got: {err:?}");
11122+
};
11123+
for fragment in expected_fragments {
11124+
assert!(
11125+
msg.contains(fragment),
11126+
"Expected parser diagnostic for `{sql}` to contain `{fragment}`, got: {msg}"
11127+
);
11128+
}
11129+
}
11130+
}
11131+
1088211132
#[test]
1088311133
fn parse_discard() {
1088411134
let sql = "DISCARD ALL";

0 commit comments

Comments
 (0)