@@ -38,6 +38,7 @@ use crate::ast::*;
3838use crate::dialect::*;
3939use crate::keywords::{Keyword, ALL_KEYWORDS};
4040use crate::tokenizer::*;
41+ use sqlparser::parser::ParserState::ColumnDefinition;
4142
4243mod alter;
4344
@@ -275,6 +276,12 @@ enum ParserState {
275276 /// PRIOR expressions while still allowing prior as an identifier name
276277 /// in other contexts.
277278 ConnectBy,
279+ /// The state when parsing column definitions. This state prohibits
280+ /// NOT NULL as an alias for IS NOT NULL. For example:
281+ /// ```sql
282+ /// CREATE TABLE foo (abc BIGINT NOT NULL);
283+ /// ```
284+ ColumnDefinition,
278285}
279286
280287/// A SQL Parser
@@ -3578,6 +3585,11 @@ impl<'a> Parser<'a> {
35783585 let negated = self.parse_keyword(Keyword::NOT);
35793586 let regexp = self.parse_keyword(Keyword::REGEXP);
35803587 let rlike = self.parse_keyword(Keyword::RLIKE);
3588+ let null = if !self.in_column_definition_state() {
3589+ self.parse_keyword(Keyword::NULL)
3590+ } else {
3591+ false
3592+ };
35813593 if regexp || rlike {
35823594 Ok(Expr::RLike {
35833595 negated,
@@ -3587,6 +3599,8 @@ impl<'a> Parser<'a> {
35873599 ),
35883600 regexp,
35893601 })
3602+ } else if negated && null {
3603+ Ok(Expr::IsNotNull(Box::new(expr)))
35903604 } else if self.parse_keyword(Keyword::IN) {
35913605 self.parse_in(expr, negated)
35923606 } else if self.parse_keyword(Keyword::BETWEEN) {
@@ -3624,6 +3638,9 @@ impl<'a> Parser<'a> {
36243638 self.expected("IN or BETWEEN after NOT", self.peek_token())
36253639 }
36263640 }
3641+ Keyword::NOTNULL if dialect.supports_notnull_operator() => {
3642+ Ok(Expr::IsNotNull(Box::new(expr)))
3643+ }
36273644 Keyword::MEMBER => {
36283645 if self.parse_keyword(Keyword::OF) {
36293646 self.expect_token(&Token::LParen)?;
@@ -7742,6 +7759,15 @@ impl<'a> Parser<'a> {
77427759 return option;
77437760 }
77447761
7762+ self.with_state(
7763+ ColumnDefinition,
7764+ |parser| -> Result<Option<ColumnOption>, ParserError> {
7765+ parser.parse_optional_column_option_inner()
7766+ },
7767+ )
7768+ }
7769+
7770+ fn parse_optional_column_option_inner(&mut self) -> Result<Option<ColumnOption>, ParserError> {
77457771 if self.parse_keywords(&[Keyword::CHARACTER, Keyword::SET]) {
77467772 Ok(Some(ColumnOption::CharacterSet(
77477773 self.parse_object_name(false)?,
@@ -7757,15 +7783,19 @@ impl<'a> Parser<'a> {
77577783 } else if self.parse_keyword(Keyword::NULL) {
77587784 Ok(Some(ColumnOption::Null))
77597785 } else if self.parse_keyword(Keyword::DEFAULT) {
7760- Ok(Some(ColumnOption::Default(self.parse_expr()?)))
7786+ Ok(Some(ColumnOption::Default(
7787+ self.parse_column_option_expr()?,
7788+ )))
77617789 } else if dialect_of!(self is ClickHouseDialect| GenericDialect)
77627790 && self.parse_keyword(Keyword::MATERIALIZED)
77637791 {
7764- Ok(Some(ColumnOption::Materialized(self.parse_expr()?)))
7792+ Ok(Some(ColumnOption::Materialized(
7793+ self.parse_column_option_expr()?,
7794+ )))
77657795 } else if dialect_of!(self is ClickHouseDialect| GenericDialect)
77667796 && self.parse_keyword(Keyword::ALIAS)
77677797 {
7768- Ok(Some(ColumnOption::Alias(self.parse_expr ()?)))
7798+ Ok(Some(ColumnOption::Alias(self.parse_column_option_expr ()?)))
77697799 } else if dialect_of!(self is ClickHouseDialect| GenericDialect)
77707800 && self.parse_keyword(Keyword::EPHEMERAL)
77717801 {
@@ -7774,7 +7804,9 @@ impl<'a> Parser<'a> {
77747804 if matches!(self.peek_token().token, Token::Comma | Token::RParen) {
77757805 Ok(Some(ColumnOption::Ephemeral(None)))
77767806 } else {
7777- Ok(Some(ColumnOption::Ephemeral(Some(self.parse_expr()?))))
7807+ Ok(Some(ColumnOption::Ephemeral(Some(
7808+ self.parse_column_option_expr()?,
7809+ ))))
77787810 }
77797811 } else if self.parse_keywords(&[Keyword::PRIMARY, Keyword::KEY]) {
77807812 let characteristics = self.parse_constraint_characteristics()?;
@@ -7817,7 +7849,8 @@ impl<'a> Parser<'a> {
78177849 }))
78187850 } else if self.parse_keyword(Keyword::CHECK) {
78197851 self.expect_token(&Token::LParen)?;
7820- let expr = self.parse_expr()?;
7852+ // since `CHECK` requires parentheses, we can parse the inner expression in ParserState::Normal
7853+ let expr: Expr = self.with_state(ParserState::Normal, |p| p.parse_expr())?;
78217854 self.expect_token(&Token::RParen)?;
78227855 Ok(Some(ColumnOption::Check(expr)))
78237856 } else if self.parse_keyword(Keyword::AUTO_INCREMENT)
@@ -7851,7 +7884,7 @@ impl<'a> Parser<'a> {
78517884 } else if self.parse_keywords(&[Keyword::ON, Keyword::UPDATE])
78527885 && dialect_of!(self is MySqlDialect | GenericDialect)
78537886 {
7854- let expr = self.parse_expr ()?;
7887+ let expr = self.parse_column_option_expr ()?;
78557888 Ok(Some(ColumnOption::OnUpdate(expr)))
78567889 } else if self.parse_keyword(Keyword::GENERATED) {
78577890 self.parse_optional_column_option_generated()
@@ -7869,7 +7902,9 @@ impl<'a> Parser<'a> {
78697902 } else if self.parse_keyword(Keyword::SRID)
78707903 && dialect_of!(self is MySqlDialect | GenericDialect)
78717904 {
7872- Ok(Some(ColumnOption::Srid(Box::new(self.parse_expr()?))))
7905+ Ok(Some(ColumnOption::Srid(Box::new(
7906+ self.parse_column_option_expr()?,
7907+ ))))
78737908 } else if self.parse_keyword(Keyword::IDENTITY)
78747909 && dialect_of!(self is MsSqlDialect | GenericDialect)
78757910 {
@@ -7909,6 +7944,31 @@ impl<'a> Parser<'a> {
79097944 }
79107945 }
79117946
7947+ /// When parsing some column option expressions we need to revert to [ParserState::Normal] since
7948+ /// `NOT NULL` is allowed as an alias for `IS NOT NULL`.
7949+ /// In those cases we use this helper instead of calling [Parser::parse_expr] directly.
7950+ ///
7951+ /// For example, consider these `CREATE TABLE` statements:
7952+ /// ```sql
7953+ /// CREATE TABLE foo (abc BOOL DEFAULT (42 NOT NULL) NOT NULL);
7954+ /// ```
7955+ /// vs
7956+ /// ```sql
7957+ /// CREATE TABLE foo (abc BOOL NOT NULL);
7958+ /// ```
7959+ ///
7960+ /// In the first we should parse the inner portion of `(42 NOT NULL)` as [Expr::IsNotNull],
7961+ /// whereas is both statements that trailing `NOT NULL` should only be parsed as a
7962+ /// [ColumnOption::NotNull].
7963+ fn parse_column_option_expr(&mut self) -> Result<Expr, ParserError> {
7964+ if self.peek_token_ref().token == Token::LParen {
7965+ let expr: Expr = self.with_state(ParserState::Normal, |p| p.parse_prefix())?;
7966+ Ok(expr)
7967+ } else {
7968+ Ok(self.parse_expr()?)
7969+ }
7970+ }
7971+
79127972 pub(crate) fn parse_tag(&mut self) -> Result<Tag, ParserError> {
79137973 let name = self.parse_object_name(false)?;
79147974 self.expect_token(&Token::Eq)?;
@@ -7953,7 +8013,7 @@ impl<'a> Parser<'a> {
79538013 }))
79548014 } else if self.parse_keywords(&[Keyword::ALWAYS, Keyword::AS]) {
79558015 if self.expect_token(&Token::LParen).is_ok() {
7956- let expr = self.parse_expr()?;
8016+ let expr: Expr = self.with_state(ParserState::Normal, |p| p. parse_expr() )?;
79578017 self.expect_token(&Token::RParen)?;
79588018 let (gen_as, expr_mode) = if self.parse_keywords(&[Keyword::STORED]) {
79598019 Ok((
@@ -16532,6 +16592,10 @@ impl<'a> Parser<'a> {
1653216592 Ok(None)
1653316593 }
1653416594 }
16595+
16596+ pub(crate) fn in_column_definition_state(&self) -> bool {
16597+ matches!(self.state, ColumnDefinition)
16598+ }
1653516599}
1653616600
1653716601fn maybe_prefixed_expr(expr: Expr, prefix: Option<Ident>) -> Expr {
@@ -17267,4 +17331,28 @@ mod tests {
1726717331
1726817332 assert!(Parser::parse_sql(&MySqlDialect {}, sql).is_err());
1726917333 }
17334+
17335+ #[test]
17336+ fn test_parse_not_null_in_column_options() {
17337+ let canonical = concat!(
17338+ "CREATE TABLE foo (",
17339+ "abc INT DEFAULT (42 IS NOT NULL) NOT NULL,",
17340+ " def INT,",
17341+ " def_null BOOL GENERATED ALWAYS AS (def IS NOT NULL) STORED,",
17342+ " CHECK (abc IS NOT NULL)",
17343+ ")"
17344+ );
17345+ all_dialects().verified_stmt(canonical);
17346+ all_dialects().one_statement_parses_to(
17347+ concat!(
17348+ "CREATE TABLE foo (",
17349+ "abc INT DEFAULT (42 NOT NULL) NOT NULL,",
17350+ " def INT,",
17351+ " def_null BOOL GENERATED ALWAYS AS (def NOT NULL) STORED,",
17352+ " CHECK (abc NOT NULL)",
17353+ ")"
17354+ ),
17355+ canonical,
17356+ );
17357+ }
1727017358}
0 commit comments