Skip to content

Commit 55d8e29

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 0dc41fa commit 55d8e29

File tree

1 file changed

+254
-4
lines changed

1 file changed

+254
-4
lines changed

tests/sqlparser_common.rs

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

10725+
let supported_dialects = all_dialects_where(|d| d.supports_is_json_predicate());
10726+
let unsupported_dialects = all_dialects_where(|d| !d.supports_is_json_predicate());
10727+
1072510728
let sql = "SELECT f from foo where field is 0";
10726-
let res = parse_sql_statements(sql);
10729+
let res = supported_dialects.parse_sql_statements(sql);
10730+
assert_eq!(
10731+
ParserError::ParserError(
10732+
"Expected: [NOT] NULL | TRUE | FALSE | DISTINCT | [NOT] JSON [VALUE | SCALAR | ARRAY | OBJECT] [WITH | WITHOUT UNIQUE [KEYS]] | [form] NORMALIZED FROM after IS, found: 0"
10733+
.to_string()
10734+
),
10735+
res.unwrap_err()
10736+
);
10737+
let res = unsupported_dialects.parse_sql_statements(sql);
1072710738
assert_eq!(
1072810739
ParserError::ParserError(
1072910740
"Expected: [NOT] NULL | TRUE | FALSE | DISTINCT | [form] NORMALIZED FROM after IS, found: 0"
@@ -10733,7 +10744,15 @@ fn parse_is_boolean() {
1073310744
);
1073410745

1073510746
let sql = "SELECT s, s IS XYZ NORMALIZED FROM foo";
10736-
let res = parse_sql_statements(sql);
10747+
let res = supported_dialects.parse_sql_statements(sql);
10748+
assert_eq!(
10749+
ParserError::ParserError(
10750+
"Expected: [NOT] NULL | TRUE | FALSE | DISTINCT | [NOT] JSON [VALUE | SCALAR | ARRAY | OBJECT] [WITH | WITHOUT UNIQUE [KEYS]] | [form] NORMALIZED FROM after IS, found: XYZ"
10751+
.to_string()
10752+
),
10753+
res.unwrap_err()
10754+
);
10755+
let res = unsupported_dialects.parse_sql_statements(sql);
1073710756
assert_eq!(
1073810757
ParserError::ParserError(
1073910758
"Expected: [NOT] NULL | TRUE | FALSE | DISTINCT | [form] NORMALIZED FROM after IS, found: XYZ"
@@ -10743,7 +10762,15 @@ fn parse_is_boolean() {
1074310762
);
1074410763

1074510764
let sql = "SELECT s, s IS NFKC FROM foo";
10746-
let res = parse_sql_statements(sql);
10765+
let res = supported_dialects.parse_sql_statements(sql);
10766+
assert_eq!(
10767+
ParserError::ParserError(
10768+
"Expected: [NOT] NULL | TRUE | FALSE | DISTINCT | [NOT] JSON [VALUE | SCALAR | ARRAY | OBJECT] [WITH | WITHOUT UNIQUE [KEYS]] | [form] NORMALIZED FROM after IS, found: FROM"
10769+
.to_string()
10770+
),
10771+
res.unwrap_err()
10772+
);
10773+
let res = unsupported_dialects.parse_sql_statements(sql);
1074710774
assert_eq!(
1074810775
ParserError::ParserError(
1074910776
"Expected: [NOT] NULL | TRUE | FALSE | DISTINCT | [form] NORMALIZED FROM after IS, found: FROM"
@@ -10753,7 +10780,15 @@ fn parse_is_boolean() {
1075310780
);
1075410781

1075510782
let sql = "SELECT s, s IS TRIM(' NFKC ') FROM foo";
10756-
let res = parse_sql_statements(sql);
10783+
let res = supported_dialects.parse_sql_statements(sql);
10784+
assert_eq!(
10785+
ParserError::ParserError(
10786+
"Expected: [NOT] NULL | TRUE | FALSE | DISTINCT | [NOT] JSON [VALUE | SCALAR | ARRAY | OBJECT] [WITH | WITHOUT UNIQUE [KEYS]] | [form] NORMALIZED FROM after IS, found: TRIM"
10787+
.to_string()
10788+
),
10789+
res.unwrap_err()
10790+
);
10791+
let res = unsupported_dialects.parse_sql_statements(sql);
1075710792
assert_eq!(
1075810793
ParserError::ParserError(
1075910794
"Expected: [NOT] NULL | TRUE | FALSE | DISTINCT | [form] NORMALIZED FROM after IS, found: TRIM"
@@ -10763,6 +10798,221 @@ fn parse_is_boolean() {
1076310798
);
1076410799
}
1076510800

10801+
#[test]
10802+
fn parse_is_json_predicate() {
10803+
use self::Expr::*;
10804+
10805+
let supported_dialects = all_dialects_where(|d| d.supports_is_json_predicate());
10806+
10807+
let sql = "a IS JSON";
10808+
assert_eq!(
10809+
IsJson {
10810+
expr: Box::new(Identifier(Ident::new("a"))),
10811+
kind: None,
10812+
unique_keys: None,
10813+
negated: false,
10814+
},
10815+
supported_dialects.verified_expr(sql)
10816+
);
10817+
10818+
let sql = "a IS NOT JSON";
10819+
assert_eq!(
10820+
IsJson {
10821+
expr: Box::new(Identifier(Ident::new("a"))),
10822+
kind: None,
10823+
unique_keys: None,
10824+
negated: true,
10825+
},
10826+
supported_dialects.verified_expr(sql)
10827+
);
10828+
10829+
let sql = "a IS JSON VALUE";
10830+
assert_eq!(
10831+
IsJson {
10832+
expr: Box::new(Identifier(Ident::new("a"))),
10833+
kind: Some(JsonPredicateType::Value),
10834+
unique_keys: None,
10835+
negated: false,
10836+
},
10837+
supported_dialects.verified_expr(sql)
10838+
);
10839+
10840+
let sql = "a IS JSON SCALAR";
10841+
assert_eq!(
10842+
IsJson {
10843+
expr: Box::new(Identifier(Ident::new("a"))),
10844+
kind: Some(JsonPredicateType::Scalar),
10845+
unique_keys: None,
10846+
negated: false,
10847+
},
10848+
supported_dialects.verified_expr(sql)
10849+
);
10850+
10851+
let sql = "a IS JSON ARRAY";
10852+
assert_eq!(
10853+
IsJson {
10854+
expr: Box::new(Identifier(Ident::new("a"))),
10855+
kind: Some(JsonPredicateType::Array),
10856+
unique_keys: None,
10857+
negated: false,
10858+
},
10859+
supported_dialects.verified_expr(sql)
10860+
);
10861+
10862+
let sql = "a IS JSON OBJECT";
10863+
assert_eq!(
10864+
IsJson {
10865+
expr: Box::new(Identifier(Ident::new("a"))),
10866+
kind: Some(JsonPredicateType::Object),
10867+
unique_keys: None,
10868+
negated: false,
10869+
},
10870+
supported_dialects.verified_expr(sql)
10871+
);
10872+
10873+
let sql = "a IS JSON WITH UNIQUE KEYS";
10874+
assert_eq!(
10875+
IsJson {
10876+
expr: Box::new(Identifier(Ident::new("a"))),
10877+
kind: None,
10878+
unique_keys: Some(JsonKeyUniqueness::WithUniqueKeys),
10879+
negated: false,
10880+
},
10881+
supported_dialects.verified_expr(sql)
10882+
);
10883+
10884+
let sql = "a IS JSON WITHOUT UNIQUE KEYS";
10885+
assert_eq!(
10886+
IsJson {
10887+
expr: Box::new(Identifier(Ident::new("a"))),
10888+
kind: None,
10889+
unique_keys: Some(JsonKeyUniqueness::WithoutUniqueKeys),
10890+
negated: false,
10891+
},
10892+
supported_dialects.verified_expr(sql)
10893+
);
10894+
10895+
let sql = "a IS NOT JSON OBJECT WITHOUT UNIQUE KEYS";
10896+
assert_eq!(
10897+
IsJson {
10898+
expr: Box::new(Identifier(Ident::new("a"))),
10899+
kind: Some(JsonPredicateType::Object),
10900+
unique_keys: Some(JsonKeyUniqueness::WithoutUniqueKeys),
10901+
negated: true,
10902+
},
10903+
supported_dialects.verified_expr(sql)
10904+
);
10905+
10906+
supported_dialects.expr_parses_to("a IS JSON WITH UNIQUE", "a IS JSON WITH UNIQUE KEYS");
10907+
supported_dialects.expr_parses_to("a IS JSON WITHOUT UNIQUE", "a IS JSON WITHOUT UNIQUE KEYS");
10908+
10909+
assert_matches!(
10910+
supported_dialects.verified_expr("NOT a IS JSON"),
10911+
Expr::UnaryOp {
10912+
op: UnaryOperator::Not,
10913+
expr
10914+
} if matches!(&*expr, Expr::IsJson { .. })
10915+
);
10916+
}
10917+
10918+
#[test]
10919+
fn parse_is_json_predicate_unsupported_dialects() {
10920+
let unsupported_dialects = all_dialects_where(|d| !d.supports_is_json_predicate());
10921+
assert!(!unsupported_dialects.dialects.is_empty());
10922+
10923+
for sql in ["SELECT a IS JSON FROM t", "SELECT a IS NOT JSON FROM t"] {
10924+
let err = unsupported_dialects.parse_sql_statements(sql).unwrap_err();
10925+
let ParserError::ParserError(msg) = err else {
10926+
panic!("Expected ParserError::ParserError for `{sql}`, got: {err:?}");
10927+
};
10928+
assert!(
10929+
msg.contains("[NOT] NULL | TRUE | FALSE | DISTINCT | [form] NORMALIZED FROM after IS"),
10930+
"Unexpected error hint for unsupported dialects in `{sql}`: {msg}"
10931+
);
10932+
assert!(
10933+
!msg.contains("[NOT] JSON [VALUE | SCALAR | ARRAY | OBJECT]"),
10934+
"Unsupported dialects should not advertise JSON IS-predicate syntax in `{sql}`: {msg}"
10935+
);
10936+
assert!(
10937+
msg.contains("found: JSON"),
10938+
"Expected parser to fail at JSON token for unsupported dialects in `{sql}`: {msg}"
10939+
);
10940+
}
10941+
}
10942+
10943+
#[test]
10944+
fn parse_is_json_predicate_negative() {
10945+
let supported_dialects = all_dialects_where(|d| d.supports_is_json_predicate());
10946+
10947+
let cases = [
10948+
(
10949+
"SELECT * FROM t WHERE a IS JSON WITH FROM",
10950+
&["Expected: UNIQUE", "found: FROM"][..],
10951+
),
10952+
(
10953+
"SELECT * FROM t WHERE a IS JSON WITH KEYS",
10954+
&["Expected: UNIQUE", "found: KEYS"][..],
10955+
),
10956+
(
10957+
"SELECT * FROM t WHERE a IS JSON WITHOUT FROM",
10958+
&["Expected: UNIQUE", "found: FROM"][..],
10959+
),
10960+
(
10961+
"SELECT * FROM t WHERE a IS JSON WITHOUT KEYS",
10962+
&["Expected: UNIQUE", "found: KEYS"][..],
10963+
),
10964+
(
10965+
"SELECT * FROM t WHERE a IS NOT JSON WITH FROM",
10966+
&["Expected: UNIQUE", "found: FROM"][..],
10967+
),
10968+
(
10969+
"SELECT * FROM t WHERE a IS JSON VALUE ARRAY",
10970+
&["Expected: end of statement", "found: ARRAY"][..],
10971+
),
10972+
(
10973+
"SELECT * FROM t WHERE a IS JSON OBJECT VALUE",
10974+
&["Expected: end of statement", "found: VALUE"][..],
10975+
),
10976+
(
10977+
"SELECT * FROM t WHERE a IS JSON WITH UNIQUE EXTRA",
10978+
&["Expected: end of statement", "found: EXTRA"][..],
10979+
),
10980+
(
10981+
"SELECT * FROM t WHERE a IS JSON WITH UNIQUE KEYS EXTRA",
10982+
&["Expected: end of statement", "found: EXTRA"][..],
10983+
),
10984+
(
10985+
"SELECT * FROM t WHERE a IS JSON WITHOUT UNIQUE EXTRA",
10986+
&["Expected: end of statement", "found: EXTRA"][..],
10987+
),
10988+
(
10989+
"SELECT * FROM t WHERE a IS JSON WITHOUT UNIQUE KEYS EXTRA",
10990+
&["Expected: end of statement", "found: EXTRA"][..],
10991+
),
10992+
(
10993+
"SELECT * FROM t WHERE a IS JSON WITH UNIQUE KEYS WITH UNIQUE KEYS",
10994+
&["Expected: end of statement", "found: WITH"][..],
10995+
),
10996+
(
10997+
"SELECT * FROM t WHERE a IS JSON WITHOUT UNIQUE KEYS WITHOUT UNIQUE KEYS",
10998+
&["Expected: end of statement", "found: WITHOUT"][..],
10999+
),
11000+
];
11001+
11002+
for (sql, expected_fragments) in cases {
11003+
let err = supported_dialects.parse_sql_statements(sql).unwrap_err();
11004+
let ParserError::ParserError(msg) = err else {
11005+
panic!("Expected ParserError::ParserError for `{sql}`, got: {err:?}");
11006+
};
11007+
for fragment in expected_fragments {
11008+
assert!(
11009+
msg.contains(fragment),
11010+
"Expected parser diagnostic for `{sql}` to contain `{fragment}`, got: {msg}"
11011+
);
11012+
}
11013+
}
11014+
}
11015+
1076611016
#[test]
1076711017
fn parse_discard() {
1076811018
let sql = "DISCARD ALL";

0 commit comments

Comments
 (0)