@@ -15974,3 +15974,135 @@ fn parse_create_procedure_with_parameter_modes() {
1597415974 _ => unreachable!(),
1597515975 }
1597615976}
15977+
15978+ #[test]
15979+ fn parse_not_null_unsupported() {
15980+ // Only DuckDB and SQLite support `x NOT NULL` as an expression
15981+ // All other dialects fail to parse.
15982+ let sql = r#"WITH t AS (SELECT NULL AS x) SELECT x NOT NULL FROM t"#;
15983+ let dialects = all_dialects_except(|d| d.supports_not_null());
15984+ let res = dialects.parse_sql_statements(sql);
15985+ assert_eq!(
15986+ ParserError::ParserError("Expected: end of statement, found: NULL".to_string()),
15987+ res.unwrap_err()
15988+ );
15989+ }
15990+
15991+ #[test]
15992+ fn parse_not_null_supported() {
15993+ // DuckDB and SQLite support `x NOT NULL` as an expression
15994+ let sql = r#"WITH t AS (SELECT NULL AS x) SELECT x NOT NULL FROM t"#;
15995+ let dialects = all_dialects_where(|d| d.supports_not_null());
15996+ let stmt = dialects.one_statement_parses_to(sql, sql);
15997+ match stmt {
15998+ Statement::Query(qry) => match *qry.body {
15999+ SetExpr::Select(select) => {
16000+ assert_eq!(select.projection.len(), 1);
16001+ match select.projection.first().unwrap() {
16002+ UnnamedExpr(expr) => {
16003+ let fake_span = Span {
16004+ start: Location { line: 0, column: 0 },
16005+ end: Location { line: 0, column: 0 },
16006+ };
16007+ assert_eq!(
16008+ *expr,
16009+ Expr::NotNull {
16010+ expr: Box::new(Identifier(Ident {
16011+ value: "x".to_string(),
16012+ quote_style: None,
16013+ span: fake_span,
16014+ })),
16015+ one_word: false,
16016+ },
16017+ );
16018+ }
16019+ _ => unreachable!(),
16020+ }
16021+ }
16022+ _ => unreachable!(),
16023+ },
16024+ _ => unreachable!(),
16025+ }
16026+ }
16027+
16028+ #[test]
16029+ fn parse_notnull_unsupported() {
16030+ // Only Postgres, DuckDB, and SQLite support `x NOTNULL` as an expression
16031+ // All other dialects consider `x NOTNULL` like `x AS NOTNULL` and thus
16032+ // consider `NOTNULL` an alias for x.
16033+ let sql = r#"WITH t AS (SELECT NULL AS x) SELECT x NOTNULL FROM t"#;
16034+ let canonical = r#"WITH t AS (SELECT NULL AS x) SELECT x AS NOTNULL FROM t"#;
16035+ let dialects = all_dialects_except(|d| d.supports_notnull());
16036+ let stmt = dialects.one_statement_parses_to(sql, canonical);
16037+ match stmt {
16038+ Statement::Query(qry) => match *qry.body {
16039+ SetExpr::Select(select) => {
16040+ assert_eq!(select.projection.len(), 1);
16041+ match select.projection.first().unwrap() {
16042+ SelectItem::ExprWithAlias { expr, alias } => {
16043+ let fake_span = Span {
16044+ start: Location { line: 0, column: 0 },
16045+ end: Location { line: 0, column: 0 },
16046+ };
16047+ assert_eq!(
16048+ *expr,
16049+ Identifier(Ident {
16050+ value: "x".to_string(),
16051+ quote_style: None,
16052+ span: fake_span,
16053+ })
16054+ );
16055+ assert_eq!(
16056+ *alias,
16057+ Ident {
16058+ value: "NOTNULL".to_string(),
16059+ quote_style: None,
16060+ span: fake_span,
16061+ }
16062+ );
16063+ }
16064+ _ => unreachable!(),
16065+ }
16066+ }
16067+ _ => unreachable!(),
16068+ },
16069+ _ => unreachable!(),
16070+ }
16071+ }
16072+
16073+ #[test]
16074+ fn parse_notnull_supported() {
16075+ // DuckDB and SQLite support `x NOT NULL` as an expression
16076+ let sql = r#"WITH t AS (SELECT NULL AS x) SELECT x NOTNULL FROM t"#;
16077+ let dialects = all_dialects_where(|d| d.supports_notnull());
16078+ let stmt = dialects.one_statement_parses_to(sql, "");
16079+ match stmt {
16080+ Statement::Query(qry) => match *qry.body {
16081+ SetExpr::Select(select) => {
16082+ assert_eq!(select.projection.len(), 1);
16083+ match select.projection.first().unwrap() {
16084+ UnnamedExpr(expr) => {
16085+ let fake_span = Span {
16086+ start: Location { line: 0, column: 0 },
16087+ end: Location { line: 0, column: 0 },
16088+ };
16089+ assert_eq!(
16090+ *expr,
16091+ Expr::NotNull {
16092+ expr: Box::new(Identifier(Ident {
16093+ value: "x".to_string(),
16094+ quote_style: None,
16095+ span: fake_span,
16096+ })),
16097+ one_word: true,
16098+ },
16099+ );
16100+ }
16101+ _ => unreachable!(),
16102+ }
16103+ }
16104+ _ => unreachable!(),
16105+ },
16106+ _ => unreachable!(),
16107+ }
16108+ }
0 commit comments