Skip to content

Commit 3014f8c

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 580eca1 commit 3014f8c

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
@@ -10747,8 +10747,19 @@ fn parse_is_boolean() {
1074710747
verified_stmt("SELECT f FROM foo WHERE field IS UNKNOWN");
1074810748
verified_stmt("SELECT f FROM foo WHERE field IS NOT UNKNOWN");
1074910749

10750+
let supported_dialects = all_dialects_where(|d| d.supports_is_json_predicate());
10751+
let unsupported_dialects = all_dialects_where(|d| !d.supports_is_json_predicate());
10752+
1075010753
let sql = "SELECT f from foo where field is 0";
10751-
let res = parse_sql_statements(sql);
10754+
let res = supported_dialects.parse_sql_statements(sql);
10755+
assert_eq!(
10756+
ParserError::ParserError(
10757+
"Expected: [NOT] NULL | TRUE | FALSE | DISTINCT | [NOT] JSON [VALUE | SCALAR | ARRAY | OBJECT] [WITH | WITHOUT UNIQUE [KEYS]] | [form] NORMALIZED FROM after IS, found: 0"
10758+
.to_string()
10759+
),
10760+
res.unwrap_err()
10761+
);
10762+
let res = unsupported_dialects.parse_sql_statements(sql);
1075210763
assert_eq!(
1075310764
ParserError::ParserError(
1075410765
"Expected: [NOT] NULL | TRUE | FALSE | DISTINCT | [form] NORMALIZED FROM after IS, found: 0"
@@ -10758,7 +10769,15 @@ fn parse_is_boolean() {
1075810769
);
1075910770

1076010771
let sql = "SELECT s, s IS XYZ NORMALIZED FROM foo";
10761-
let res = parse_sql_statements(sql);
10772+
let res = supported_dialects.parse_sql_statements(sql);
10773+
assert_eq!(
10774+
ParserError::ParserError(
10775+
"Expected: [NOT] NULL | TRUE | FALSE | DISTINCT | [NOT] JSON [VALUE | SCALAR | ARRAY | OBJECT] [WITH | WITHOUT UNIQUE [KEYS]] | [form] NORMALIZED FROM after IS, found: XYZ"
10776+
.to_string()
10777+
),
10778+
res.unwrap_err()
10779+
);
10780+
let res = unsupported_dialects.parse_sql_statements(sql);
1076210781
assert_eq!(
1076310782
ParserError::ParserError(
1076410783
"Expected: [NOT] NULL | TRUE | FALSE | DISTINCT | [form] NORMALIZED FROM after IS, found: XYZ"
@@ -10768,7 +10787,15 @@ fn parse_is_boolean() {
1076810787
);
1076910788

1077010789
let sql = "SELECT s, s IS NFKC FROM foo";
10771-
let res = parse_sql_statements(sql);
10790+
let res = supported_dialects.parse_sql_statements(sql);
10791+
assert_eq!(
10792+
ParserError::ParserError(
10793+
"Expected: [NOT] NULL | TRUE | FALSE | DISTINCT | [NOT] JSON [VALUE | SCALAR | ARRAY | OBJECT] [WITH | WITHOUT UNIQUE [KEYS]] | [form] NORMALIZED FROM after IS, found: FROM"
10794+
.to_string()
10795+
),
10796+
res.unwrap_err()
10797+
);
10798+
let res = unsupported_dialects.parse_sql_statements(sql);
1077210799
assert_eq!(
1077310800
ParserError::ParserError(
1077410801
"Expected: [NOT] NULL | TRUE | FALSE | DISTINCT | [form] NORMALIZED FROM after IS, found: FROM"
@@ -10778,7 +10805,15 @@ fn parse_is_boolean() {
1077810805
);
1077910806

1078010807
let sql = "SELECT s, s IS TRIM(' NFKC ') FROM foo";
10781-
let res = parse_sql_statements(sql);
10808+
let res = supported_dialects.parse_sql_statements(sql);
10809+
assert_eq!(
10810+
ParserError::ParserError(
10811+
"Expected: [NOT] NULL | TRUE | FALSE | DISTINCT | [NOT] JSON [VALUE | SCALAR | ARRAY | OBJECT] [WITH | WITHOUT UNIQUE [KEYS]] | [form] NORMALIZED FROM after IS, found: TRIM"
10812+
.to_string()
10813+
),
10814+
res.unwrap_err()
10815+
);
10816+
let res = unsupported_dialects.parse_sql_statements(sql);
1078210817
assert_eq!(
1078310818
ParserError::ParserError(
1078410819
"Expected: [NOT] NULL | TRUE | FALSE | DISTINCT | [form] NORMALIZED FROM after IS, found: TRIM"
@@ -10788,6 +10823,221 @@ fn parse_is_boolean() {
1078810823
);
1078910824
}
1079010825

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

0 commit comments

Comments
 (0)