Skip to content

Commit

Permalink
Merge branch 'apache:main' into tomers_branch
Browse files Browse the repository at this point in the history
  • Loading branch information
tomershaniii committed Oct 21, 2024
2 parents edce476 + 45c5d69 commit 3880697
Show file tree
Hide file tree
Showing 11 changed files with 813 additions and 50 deletions.
244 changes: 233 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,221 @@ impl fmt::Display for ColumnOptionDef {
}
}

/// Identity is a column option for defining an identity or autoincrement column in a `CREATE 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 IdentityPropertyKind {
/// An identity property declared via the `AUTOINCREMENT` key word
/// Example:
/// ```sql
/// AUTOINCREMENT(100, 1) NOORDER
/// AUTOINCREMENT START 100 INCREMENT 1 ORDER
/// ```
/// [Snowflake]: https://docs.snowflake.com/en/sql-reference/sql/create-table
Autoincrement(IdentityProperty),
/// An identity property declared via the `IDENTITY` key word
/// Example, [MS SQL Server] or [Snowflake]:
/// ```sql
/// IDENTITY(100, 1)
/// ```
/// [Snowflake]
/// ```sql
/// IDENTITY(100, 1) ORDER
/// IDENTITY START 100 INCREMENT 1 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
Identity(IdentityProperty),
}

impl fmt::Display for IdentityPropertyKind {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let (command, property) = match self {
IdentityPropertyKind::Identity(property) => ("IDENTITY", property),
IdentityPropertyKind::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(())
}
}

#[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<IdentityPropertyFormatKind>,
pub order: Option<IdentityPropertyOrder>,
}

/// 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 IdentityPropertyFormatKind {
/// A parameters of identity column declared like parameters of function call
/// Example:
/// ```sql
/// (100, 1)
/// ```
/// [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
FunctionCall(IdentityParameters),
/// A parameters of identity column declared with keywords `START` and `INCREMENT`
/// Example:
/// ```sql
/// START 100 INCREMENT 1
/// ```
/// [Snowflake]: https://docs.snowflake.com/en/sql-reference/sql/create-table
StartAndIncrement(IdentityParameters),
}

impl fmt::Display for IdentityPropertyFormatKind {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
IdentityPropertyFormatKind::FunctionCall(parameters) => {
write!(f, "({}, {})", parameters.seed, parameters.increment)
}
IdentityPropertyFormatKind::StartAndIncrement(parameters) => {
write!(
f,
" START {} INCREMENT {}",
parameters.seed, parameters.increment
)
}
}
}
}
#[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 {
/// The identity column option specifies how values are generated for the auto-incremented column, either in increasing or decreasing order.
/// Syntax
/// ```sql
/// ORDER | NOORDER
/// ```
/// [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 IdentityPropertyOrder {
Order,
NoOrder,
}

impl fmt::Display for IdentityPropertyOrder {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
IdentityPropertyOrder::Order => write!(f, " ORDER"),
IdentityPropertyOrder::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),
}

impl fmt::Display for ColumnPolicy {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}, {}", self.seed, self.increment)
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(())
}
}

#[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 {
/// This flag indicates that the column policy option is declared using the `WITH` prefix.
/// Example
/// ```sql
/// WITH PROJECTION POLICY sample_policy
/// ```
/// [Snowflake]: https://docs.snowflake.com/en/sql-reference/sql/create-table
pub with: bool,
pub policy_name: Ident,
pub using_columns: Option<Vec<Ident>>,
}

/// 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 {
/// This flag indicates that the tags option is declared using the `WITH` prefix.
/// Example:
/// ```sql
/// WITH TAG (A = 'Tag A')
/// ```
/// [Snowflake]: https://docs.snowflake.com/en/sql-reference/sql/create-table
pub with: bool,
pub tags: Vec<Tag>,
}

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

Expand Down Expand Up @@ -1180,16 +1384,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(IdentityPropertyKind),
/// 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 +1512,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
17 changes: 11 additions & 6 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, IdentityParameters, IdentityProperty, IdentityPropertyFormatKind,
IdentityPropertyKind, IdentityPropertyOrder, 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 Expand Up @@ -668,6 +669,9 @@ pub enum Expr {
},
/// CONVERT a value to a different data type or character encoding. e.g. `CONVERT(foo USING utf8mb4)`
Convert {
/// CONVERT (false) or TRY_CONVERT (true)
/// <https://learn.microsoft.com/en-us/sql/t-sql/functions/try-convert-transact-sql?view=sql-server-ver16>
is_try: bool,
/// The expression to convert
expr: Box<Expr>,
/// The target data type
Expand Down Expand Up @@ -1370,13 +1374,14 @@ impl fmt::Display for Expr {
}
}
Expr::Convert {
is_try,
expr,
target_before_value,
data_type,
charset,
styles,
} => {
write!(f, "CONVERT(")?;
write!(f, "{}CONVERT(", if *is_try { "TRY_" } else { "" })?;
if let Some(data_type) = data_type {
if let Some(charset) = charset {
write!(f, "{expr}, {data_type} CHARACTER SET {charset}")
Expand Down
4 changes: 4 additions & 0 deletions src/dialect/generic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,4 +107,8 @@ impl Dialect for GenericDialect {
fn supports_asc_desc_in_column_definition(&self) -> bool {
true
}

fn supports_try_convert(&self) -> bool {
true
}
}
31 changes: 30 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,
) -> Result<Option<Result<Option<ColumnOption>, ParserError>>, ParserError> {
// return None to fall back to the default behavior
Ok(None)
}

/// Decide the lexical Precedence of operators.
///
/// Uses (APPROXIMATELY) <https://www.postgresql.org/docs/7.0/operators.htm#AEN2026> as a reference
Expand Down Expand Up @@ -561,6 +574,22 @@ pub trait Dialect: Debug + Any {
fn supports_asc_desc_in_column_definition(&self) -> bool {
false
}

/// Returns true if this dialect supports treating the equals operator `=` within a `SelectItem`
/// as an alias assignment operator, rather than a boolean expression.
/// For example: the following statements are equivalent for such a dialect:
/// ```sql
/// SELECT col_alias = col FROM tbl;
/// SELECT col_alias AS col FROM tbl;
/// ```
fn supports_eq_alias_assigment(&self) -> bool {
false
}

/// Returns true if this dialect supports the `TRY_CONVERT` function
fn supports_try_convert(&self) -> bool {
false
}
}

/// This represents the operators for which precedence must be defined
Expand Down
Loading

0 comments on commit 3880697

Please sign in to comment.