diff --git a/src/ast/ddl.rs b/src/ast/ddl.rs index c6ab7ad10..c62f448c1 100644 --- a/src/ast/ddl.rs +++ b/src/ast/ddl.rs @@ -30,8 +30,9 @@ use sqlparser_derive::{Visit, VisitMut}; use crate::ast::value::escape_single_quote_string; use crate::ast::{ - display_comma_separated, display_separated, table_constraints::TableConstraint, ArgMode, - CommentDef, ConditionalStatements, CreateFunctionBody, CreateFunctionUsing, + display_comma_separated, display_separated, + table_constraints::{CheckConstraint, TableConstraint}, + ArgMode, CommentDef, ConditionalStatements, CreateFunctionBody, CreateFunctionUsing, CreateTableLikeKind, CreateTableOptions, DataType, Expr, FileFormat, FunctionBehavior, FunctionCalledOnNull, FunctionDeterminismSpecifier, FunctionParallel, HiveDistributionStyle, HiveFormat, HiveIOFormat, HiveRowFormat, Ident, InitializeKind, MySQLColumnPosition, @@ -1573,7 +1574,7 @@ pub enum ColumnOption { characteristics: Option, }, /// `CHECK ()` - Check(Expr), + Check(CheckConstraint), /// Dialect-specific options, such as: /// - MySQL's `AUTO_INCREMENT` or SQLite's `AUTOINCREMENT` /// - ... @@ -1642,6 +1643,12 @@ pub enum ColumnOption { Invisible, } +impl From for ColumnOption { + fn from(c: CheckConstraint) -> Self { + ColumnOption::Check(c) + } +} + impl fmt::Display for ColumnOption { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { use ColumnOption::*; @@ -1690,7 +1697,7 @@ impl fmt::Display for ColumnOption { } Ok(()) } - Check(expr) => write!(f, "CHECK ({expr})"), + Check(constraint) => write!(f, "{constraint}"), DialectSpecific(val) => write!(f, "{}", display_separated(val, " ")), CharacterSet(n) => write!(f, "CHARACTER SET {n}"), Collation(n) => write!(f, "COLLATE {n}"), diff --git a/src/ast/spans.rs b/src/ast/spans.rs index 0a303fcfd..24b758030 100644 --- a/src/ast/spans.rs +++ b/src/ast/spans.rs @@ -835,7 +835,7 @@ impl Spanned for ColumnOption { .chain(on_update.iter().map(|i| i.span())) .chain(characteristics.iter().map(|i| i.span())), ), - ColumnOption::Check(expr) => expr.span(), + ColumnOption::Check(constraint) => constraint.span(), ColumnOption::DialectSpecific(_) => Span::empty(), ColumnOption::CharacterSet(object_name) => object_name.span(), ColumnOption::Collation(object_name) => object_name.span(), diff --git a/src/parser/mod.rs b/src/parser/mod.rs index d1e9b1e78..387944412 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -8071,7 +8071,14 @@ impl<'a> Parser<'a> { // since `CHECK` requires parentheses, we can parse the inner expression in ParserState::Normal let expr: Expr = self.with_state(ParserState::Normal, |p| p.parse_expr())?; self.expect_token(&Token::RParen)?; - Ok(Some(ColumnOption::Check(expr))) + Ok(Some( + CheckConstraint { + name: None, // Column-level check constraints don't have names + expr: Box::new(expr), + enforced: None, // Could be extended later to support MySQL ENFORCED/NOT ENFORCED + } + .into(), + )) } else if self.parse_keyword(Keyword::AUTO_INCREMENT) && dialect_of!(self is MySqlDialect | GenericDialect) { diff --git a/tests/sqlparser_common.rs b/tests/sqlparser_common.rs index a1fd48d3e..bea199f10 100644 --- a/tests/sqlparser_common.rs +++ b/tests/sqlparser_common.rs @@ -3781,7 +3781,11 @@ fn parse_create_table() { }, ColumnOptionDef { name: None, - option: ColumnOption::Check(verified_expr("constrained > 0")), + option: ColumnOption::Check(CheckConstraint { + name: None, + expr: Box::new(verified_expr("constrained > 0")), + enforced: None, + }), }, ], },