Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
195 changes: 184 additions & 11 deletions src/ast/ddl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ use sqlparser_derive::{Visit, VisitMut};
use crate::ast::value::escape_single_quote_string;
use crate::ast::{
display_comma_separated, display_separated, DataType, Expr, Ident, MySQLColumnPosition,
ObjectName, OrderByExpr, ProjectionSelect, SequenceOptions, SqlOption, Value,
ObjectName, OrderByExpr, ProjectionSelect, SequenceOptions, SqlOption, Tag, Value,
};
use crate::keywords::Keyword;
use crate::tokenizer::Token;
Expand Down Expand Up @@ -1096,17 +1096,172 @@ impl fmt::Display for ColumnOptionDef {
}
}

/// Identity is a column option for defining an identity or autoincrement column in a creating table statement.
/// Syntax
/// ```sql
/// { IDENTITY | AUTOINCREMENT } [ (seed , increment) | START num INCREMENT num ] [ ORDER | NOORDER ]
/// ```
/// [MS SQL Server]: https://learn.microsoft.com/en-us/sql/t-sql/statements/create-table-transact-sql-identity-property
/// [Snowflake]: https://docs.snowflake.com/en/sql-reference/sql/create-table
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub enum Identity {
Autoincrement(IdentityProperty),
Identity(IdentityProperty),
}

#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub struct IdentityProperty {
pub parameters: Option<IdentityFormat>,
pub order: Option<IdentityOrder>,
}

/// A format of parameters of identity column.
///
/// It is [Snowflake] specific.
/// Syntax
/// ```sql
/// (seed , increment) | START num INCREMENT num
/// ```
/// [MS SQL Server] uses one way of representing these parameters.
/// Syntax
/// ```sql
/// (seed , increment)
/// ```
/// [MS SQL Server]: https://learn.microsoft.com/en-us/sql/t-sql/statements/create-table-transact-sql-identity-property
/// [Snowflake]: https://docs.snowflake.com/en/sql-reference/sql/create-table
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub enum IdentityFormat {
FunctionCall(IdentityParameters),
StartAndIncrement(IdentityParameters),
}

#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub struct IdentityParameters {
pub seed: Expr,
pub increment: Expr,
}

impl fmt::Display for IdentityProperty {
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub enum IdentityOrder {
Order,
NoOrder,
}

impl fmt::Display for Identity {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let (command, property) = match self {
Identity::Identity(property) => ("IDENTITY", property),
Identity::Autoincrement(property) => ("AUTOINCREMENT", property),
};
write!(f, "{command}")?;
if let Some(parameters) = &property.parameters {
write!(f, "{parameters}")?;
}
if let Some(order) = &property.order {
write!(f, "{order}")?;
}
Ok(())
}
}

impl fmt::Display for IdentityFormat {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
IdentityFormat::FunctionCall(parameters) => {
write!(f, "({}, {})", parameters.seed, parameters.increment)
}
IdentityFormat::StartAndIncrement(parameters) => {
write!(
f,
" START {} INCREMENT {}",
parameters.seed, parameters.increment
)
}
}
}
}

impl fmt::Display for IdentityOrder {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
IdentityOrder::Order => write!(f, " ORDER"),
IdentityOrder::NoOrder => write!(f, " NOORDER"),
}
}
}

/// Column policy that identify a security policy of access to a column.
/// Syntax
/// ```sql
/// [ WITH ] MASKING POLICY <policy_name> [ USING ( <col_name> , <cond_col1> , ... ) ]
/// [ WITH ] PROJECTION POLICY <policy_name>
/// ```
/// [Snowflake]: https://docs.snowflake.com/en/sql-reference/sql/create-table
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub enum ColumnPolicy {
MaskingPolicy(ColumnPolicyProperty),
ProjectionPolicy(ColumnPolicyProperty),
}

#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub struct ColumnPolicyProperty {
pub with: bool,
pub policy_name: Ident,
pub using_columns: Option<Vec<Ident>>,
}

impl fmt::Display for ColumnPolicy {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let (command, property) = match self {
ColumnPolicy::MaskingPolicy(property) => ("MASKING POLICY", property),
ColumnPolicy::ProjectionPolicy(property) => ("PROJECTION POLICY", property),
};
if property.with {
write!(f, "WITH ")?;
}
write!(f, "{command} {}", property.policy_name)?;
if let Some(using_columns) = &property.using_columns {
write!(f, " USING ({})", display_comma_separated(using_columns))?;
}
Ok(())
}
}

/// Tags option of column
/// Syntax
/// ```sql
/// [ WITH ] TAG ( <tag_name> = '<tag_value>' [ , <tag_name> = '<tag_value>' , ... ] )
/// ```
/// [Snowflake]: https://docs.snowflake.com/en/sql-reference/sql/create-table
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub struct TagsColumnOption {
pub with: bool,
pub tags: Vec<Tag>,
}

impl fmt::Display for TagsColumnOption {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}, {}", self.seed, self.increment)
if self.with {
write!(f, "WITH ")?;
}
write!(f, "TAG ({})", display_comma_separated(&self.tags))?;
Ok(())
}
}

Expand Down Expand Up @@ -1180,16 +1335,32 @@ pub enum ColumnOption {
/// [1]: https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#view_column_option_list
/// [2]: https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#column_option_list
Options(Vec<SqlOption>),
/// MS SQL Server specific: Creates an identity column in a table.
/// Creates an identity or an autoincrement column in a table.
/// Syntax
/// ```sql
/// IDENTITY [ (seed , increment) ]
/// { IDENTITY | AUTOINCREMENT } [ (seed , increment) | START num INCREMENT num ] [ ORDER | NOORDER ]
/// ```
/// [MS SQL Server]: https://learn.microsoft.com/en-us/sql/t-sql/statements/create-table-transact-sql-identity-property
Identity(Option<IdentityProperty>),
/// [Snowflake]: https://docs.snowflake.com/en/sql-reference/sql/create-table
Identity(Identity),
/// SQLite specific: ON CONFLICT option on column definition
/// <https://www.sqlite.org/lang_conflict.html>
OnConflict(Keyword),
/// Snowflake specific: an option of specifying security masking or projection policy to set on a column.
/// Syntax:
/// ```sql
/// [ WITH ] MASKING POLICY <policy_name> [ USING ( <col_name> , <cond_col1> , ... ) ]
/// [ WITH ] PROJECTION POLICY <policy_name>
/// ```
/// [Snowflake]: https://docs.snowflake.com/en/sql-reference/sql/create-table
Policy(ColumnPolicy),
/// Snowflake specific: Specifies the tag name and the tag string value.
/// Syntax:
/// ```sql
/// [ WITH ] TAG ( <tag_name> = '<tag_value>' [ , <tag_name> = '<tag_value>' , ... ] )
/// ```
/// [Snowflake]: https://docs.snowflake.com/en/sql-reference/sql/create-table
Tags(TagsColumnOption),
}

impl fmt::Display for ColumnOption {
Expand Down Expand Up @@ -1292,16 +1463,18 @@ impl fmt::Display for ColumnOption {
write!(f, "OPTIONS({})", display_comma_separated(options))
}
Identity(parameters) => {
write!(f, "IDENTITY")?;
if let Some(parameters) = parameters {
write!(f, "({parameters})")?;
}
Ok(())
write!(f, "{parameters}")
}
OnConflict(keyword) => {
write!(f, "ON CONFLICT {:?}", keyword)?;
Ok(())
}
Policy(parameters) => {
write!(f, "{parameters}")
}
Tags(tags) => {
write!(f, "{tags}")
}
}
}
}
Expand Down
11 changes: 6 additions & 5 deletions src/ast/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,12 @@ pub use self::data_type::{
pub use self::dcl::{AlterRoleOperation, ResetConfig, RoleOption, SetConfigValue, Use};
pub use self::ddl::{
AlterColumnOperation, AlterIndexOperation, AlterPolicyOperation, AlterTableOperation,
ClusteredBy, ColumnDef, ColumnOption, ColumnOptionDef, ConstraintCharacteristics, Deduplicate,
DeferrableInitial, GeneratedAs, GeneratedExpressionMode, IdentityProperty, IndexOption,
IndexType, KeyOrIndexDisplay, Owner, Partition, ProcedureParam, ReferentialAction,
TableConstraint, UserDefinedTypeCompositeAttributeDef, UserDefinedTypeRepresentation,
ViewColumnDef,
ClusteredBy, ColumnDef, ColumnOption, ColumnOptionDef, ColumnPolicy, ColumnPolicyProperty,
ConstraintCharacteristics, Deduplicate, DeferrableInitial, GeneratedAs,
GeneratedExpressionMode, Identity, IdentityFormat, IdentityOrder, IdentityParameters,
IdentityProperty, IndexOption, IndexType, KeyOrIndexDisplay, Owner, Partition, ProcedureParam,
ReferentialAction, TableConstraint, TagsColumnOption, UserDefinedTypeCompositeAttributeDef,
UserDefinedTypeRepresentation, ViewColumnDef,
};
pub use self::dml::{CreateIndex, CreateTable, Delete, Insert};
pub use self::operator::{BinaryOperator, UnaryOperator};
Expand Down
15 changes: 14 additions & 1 deletion src/dialect/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ pub use self::postgresql::PostgreSqlDialect;
pub use self::redshift::RedshiftSqlDialect;
pub use self::snowflake::SnowflakeDialect;
pub use self::sqlite::SQLiteDialect;
use crate::ast::{Expr, Statement};
use crate::ast::{ColumnOption, Expr, Statement};
pub use crate::keywords;
use crate::keywords::Keyword;
use crate::parser::{Parser, ParserError};
Expand Down Expand Up @@ -478,6 +478,19 @@ pub trait Dialect: Debug + Any {
None
}

/// Dialect-specific column option parser override
///
/// This method is called to parse the next column option.
///
/// If `None` is returned, falls back to the default behavior.
fn parse_column_option(
&self,
_parser: &mut Parser,
) -> Option<Result<Option<ColumnOption>, ParserError>> {
// return None to fall back to the default behavior
None
}

/// Decide the lexical Precedence of operators.
///
/// Uses (APPROXIMATELY) <https://www.postgresql.org/docs/7.0/operators.htm#AEN2026> as a reference
Expand Down
Loading