Skip to content

Commit fbfaa1e

Browse files
authored
Merge branch 'apache:main' into tomers_branch
2 parents edce476 + 45c5d69 commit fbfaa1e

File tree

11 files changed

+813
-50
lines changed

11 files changed

+813
-50
lines changed

src/ast/ddl.rs

+233-11
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ use sqlparser_derive::{Visit, VisitMut};
3131
use crate::ast::value::escape_single_quote_string;
3232
use crate::ast::{
3333
display_comma_separated, display_separated, DataType, Expr, Ident, MySQLColumnPosition,
34-
ObjectName, OrderByExpr, ProjectionSelect, SequenceOptions, SqlOption, Value,
34+
ObjectName, OrderByExpr, ProjectionSelect, SequenceOptions, SqlOption, Tag, Value,
3535
};
3636
use crate::keywords::Keyword;
3737
use crate::tokenizer::Token;
@@ -1096,17 +1096,221 @@ impl fmt::Display for ColumnOptionDef {
10961096
}
10971097
}
10981098

1099+
/// Identity is a column option for defining an identity or autoincrement column in a `CREATE TABLE` statement.
1100+
/// Syntax
1101+
/// ```sql
1102+
/// { IDENTITY | AUTOINCREMENT } [ (seed , increment) | START num INCREMENT num ] [ ORDER | NOORDER ]
1103+
/// ```
1104+
/// [MS SQL Server]: https://learn.microsoft.com/en-us/sql/t-sql/statements/create-table-transact-sql-identity-property
1105+
/// [Snowflake]: https://docs.snowflake.com/en/sql-reference/sql/create-table
1106+
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1107+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1108+
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1109+
pub enum IdentityPropertyKind {
1110+
/// An identity property declared via the `AUTOINCREMENT` key word
1111+
/// Example:
1112+
/// ```sql
1113+
/// AUTOINCREMENT(100, 1) NOORDER
1114+
/// AUTOINCREMENT START 100 INCREMENT 1 ORDER
1115+
/// ```
1116+
/// [Snowflake]: https://docs.snowflake.com/en/sql-reference/sql/create-table
1117+
Autoincrement(IdentityProperty),
1118+
/// An identity property declared via the `IDENTITY` key word
1119+
/// Example, [MS SQL Server] or [Snowflake]:
1120+
/// ```sql
1121+
/// IDENTITY(100, 1)
1122+
/// ```
1123+
/// [Snowflake]
1124+
/// ```sql
1125+
/// IDENTITY(100, 1) ORDER
1126+
/// IDENTITY START 100 INCREMENT 1 NOORDER
1127+
/// ```
1128+
/// [MS SQL Server]: https://learn.microsoft.com/en-us/sql/t-sql/statements/create-table-transact-sql-identity-property
1129+
/// [Snowflake]: https://docs.snowflake.com/en/sql-reference/sql/create-table
1130+
Identity(IdentityProperty),
1131+
}
1132+
1133+
impl fmt::Display for IdentityPropertyKind {
1134+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1135+
let (command, property) = match self {
1136+
IdentityPropertyKind::Identity(property) => ("IDENTITY", property),
1137+
IdentityPropertyKind::Autoincrement(property) => ("AUTOINCREMENT", property),
1138+
};
1139+
write!(f, "{command}")?;
1140+
if let Some(parameters) = &property.parameters {
1141+
write!(f, "{parameters}")?;
1142+
}
1143+
if let Some(order) = &property.order {
1144+
write!(f, "{order}")?;
1145+
}
1146+
Ok(())
1147+
}
1148+
}
1149+
10991150
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
11001151
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
11011152
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
11021153
pub struct IdentityProperty {
1154+
pub parameters: Option<IdentityPropertyFormatKind>,
1155+
pub order: Option<IdentityPropertyOrder>,
1156+
}
1157+
1158+
/// A format of parameters of identity column.
1159+
///
1160+
/// It is [Snowflake] specific.
1161+
/// Syntax
1162+
/// ```sql
1163+
/// (seed , increment) | START num INCREMENT num
1164+
/// ```
1165+
/// [MS SQL Server] uses one way of representing these parameters.
1166+
/// Syntax
1167+
/// ```sql
1168+
/// (seed , increment)
1169+
/// ```
1170+
/// [MS SQL Server]: https://learn.microsoft.com/en-us/sql/t-sql/statements/create-table-transact-sql-identity-property
1171+
/// [Snowflake]: https://docs.snowflake.com/en/sql-reference/sql/create-table
1172+
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1173+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1174+
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1175+
pub enum IdentityPropertyFormatKind {
1176+
/// A parameters of identity column declared like parameters of function call
1177+
/// Example:
1178+
/// ```sql
1179+
/// (100, 1)
1180+
/// ```
1181+
/// [MS SQL Server]: https://learn.microsoft.com/en-us/sql/t-sql/statements/create-table-transact-sql-identity-property
1182+
/// [Snowflake]: https://docs.snowflake.com/en/sql-reference/sql/create-table
1183+
FunctionCall(IdentityParameters),
1184+
/// A parameters of identity column declared with keywords `START` and `INCREMENT`
1185+
/// Example:
1186+
/// ```sql
1187+
/// START 100 INCREMENT 1
1188+
/// ```
1189+
/// [Snowflake]: https://docs.snowflake.com/en/sql-reference/sql/create-table
1190+
StartAndIncrement(IdentityParameters),
1191+
}
1192+
1193+
impl fmt::Display for IdentityPropertyFormatKind {
1194+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1195+
match self {
1196+
IdentityPropertyFormatKind::FunctionCall(parameters) => {
1197+
write!(f, "({}, {})", parameters.seed, parameters.increment)
1198+
}
1199+
IdentityPropertyFormatKind::StartAndIncrement(parameters) => {
1200+
write!(
1201+
f,
1202+
" START {} INCREMENT {}",
1203+
parameters.seed, parameters.increment
1204+
)
1205+
}
1206+
}
1207+
}
1208+
}
1209+
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1210+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1211+
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1212+
pub struct IdentityParameters {
11031213
pub seed: Expr,
11041214
pub increment: Expr,
11051215
}
11061216

1107-
impl fmt::Display for IdentityProperty {
1217+
/// The identity column option specifies how values are generated for the auto-incremented column, either in increasing or decreasing order.
1218+
/// Syntax
1219+
/// ```sql
1220+
/// ORDER | NOORDER
1221+
/// ```
1222+
/// [Snowflake]: https://docs.snowflake.com/en/sql-reference/sql/create-table
1223+
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1224+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1225+
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1226+
pub enum IdentityPropertyOrder {
1227+
Order,
1228+
NoOrder,
1229+
}
1230+
1231+
impl fmt::Display for IdentityPropertyOrder {
1232+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1233+
match self {
1234+
IdentityPropertyOrder::Order => write!(f, " ORDER"),
1235+
IdentityPropertyOrder::NoOrder => write!(f, " NOORDER"),
1236+
}
1237+
}
1238+
}
1239+
1240+
/// Column policy that identify a security policy of access to a column.
1241+
/// Syntax
1242+
/// ```sql
1243+
/// [ WITH ] MASKING POLICY <policy_name> [ USING ( <col_name> , <cond_col1> , ... ) ]
1244+
/// [ WITH ] PROJECTION POLICY <policy_name>
1245+
/// ```
1246+
/// [Snowflake]: https://docs.snowflake.com/en/sql-reference/sql/create-table
1247+
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1248+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1249+
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1250+
pub enum ColumnPolicy {
1251+
MaskingPolicy(ColumnPolicyProperty),
1252+
ProjectionPolicy(ColumnPolicyProperty),
1253+
}
1254+
1255+
impl fmt::Display for ColumnPolicy {
11081256
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1109-
write!(f, "{}, {}", self.seed, self.increment)
1257+
let (command, property) = match self {
1258+
ColumnPolicy::MaskingPolicy(property) => ("MASKING POLICY", property),
1259+
ColumnPolicy::ProjectionPolicy(property) => ("PROJECTION POLICY", property),
1260+
};
1261+
if property.with {
1262+
write!(f, "WITH ")?;
1263+
}
1264+
write!(f, "{command} {}", property.policy_name)?;
1265+
if let Some(using_columns) = &property.using_columns {
1266+
write!(f, " USING ({})", display_comma_separated(using_columns))?;
1267+
}
1268+
Ok(())
1269+
}
1270+
}
1271+
1272+
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1273+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1274+
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1275+
pub struct ColumnPolicyProperty {
1276+
/// This flag indicates that the column policy option is declared using the `WITH` prefix.
1277+
/// Example
1278+
/// ```sql
1279+
/// WITH PROJECTION POLICY sample_policy
1280+
/// ```
1281+
/// [Snowflake]: https://docs.snowflake.com/en/sql-reference/sql/create-table
1282+
pub with: bool,
1283+
pub policy_name: Ident,
1284+
pub using_columns: Option<Vec<Ident>>,
1285+
}
1286+
1287+
/// Tags option of column
1288+
/// Syntax
1289+
/// ```sql
1290+
/// [ WITH ] TAG ( <tag_name> = '<tag_value>' [ , <tag_name> = '<tag_value>' , ... ] )
1291+
/// ```
1292+
/// [Snowflake]: https://docs.snowflake.com/en/sql-reference/sql/create-table
1293+
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1294+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1295+
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1296+
pub struct TagsColumnOption {
1297+
/// This flag indicates that the tags option is declared using the `WITH` prefix.
1298+
/// Example:
1299+
/// ```sql
1300+
/// WITH TAG (A = 'Tag A')
1301+
/// ```
1302+
/// [Snowflake]: https://docs.snowflake.com/en/sql-reference/sql/create-table
1303+
pub with: bool,
1304+
pub tags: Vec<Tag>,
1305+
}
1306+
1307+
impl fmt::Display for TagsColumnOption {
1308+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1309+
if self.with {
1310+
write!(f, "WITH ")?;
1311+
}
1312+
write!(f, "TAG ({})", display_comma_separated(&self.tags))?;
1313+
Ok(())
11101314
}
11111315
}
11121316

@@ -1180,16 +1384,32 @@ pub enum ColumnOption {
11801384
/// [1]: https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#view_column_option_list
11811385
/// [2]: https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#column_option_list
11821386
Options(Vec<SqlOption>),
1183-
/// MS SQL Server specific: Creates an identity column in a table.
1387+
/// Creates an identity or an autoincrement column in a table.
11841388
/// Syntax
11851389
/// ```sql
1186-
/// IDENTITY [ (seed , increment) ]
1390+
/// { IDENTITY | AUTOINCREMENT } [ (seed , increment) | START num INCREMENT num ] [ ORDER | NOORDER ]
11871391
/// ```
11881392
/// [MS SQL Server]: https://learn.microsoft.com/en-us/sql/t-sql/statements/create-table-transact-sql-identity-property
1189-
Identity(Option<IdentityProperty>),
1393+
/// [Snowflake]: https://docs.snowflake.com/en/sql-reference/sql/create-table
1394+
Identity(IdentityPropertyKind),
11901395
/// SQLite specific: ON CONFLICT option on column definition
11911396
/// <https://www.sqlite.org/lang_conflict.html>
11921397
OnConflict(Keyword),
1398+
/// Snowflake specific: an option of specifying security masking or projection policy to set on a column.
1399+
/// Syntax:
1400+
/// ```sql
1401+
/// [ WITH ] MASKING POLICY <policy_name> [ USING ( <col_name> , <cond_col1> , ... ) ]
1402+
/// [ WITH ] PROJECTION POLICY <policy_name>
1403+
/// ```
1404+
/// [Snowflake]: https://docs.snowflake.com/en/sql-reference/sql/create-table
1405+
Policy(ColumnPolicy),
1406+
/// Snowflake specific: Specifies the tag name and the tag string value.
1407+
/// Syntax:
1408+
/// ```sql
1409+
/// [ WITH ] TAG ( <tag_name> = '<tag_value>' [ , <tag_name> = '<tag_value>' , ... ] )
1410+
/// ```
1411+
/// [Snowflake]: https://docs.snowflake.com/en/sql-reference/sql/create-table
1412+
Tags(TagsColumnOption),
11931413
}
11941414

11951415
impl fmt::Display for ColumnOption {
@@ -1292,16 +1512,18 @@ impl fmt::Display for ColumnOption {
12921512
write!(f, "OPTIONS({})", display_comma_separated(options))
12931513
}
12941514
Identity(parameters) => {
1295-
write!(f, "IDENTITY")?;
1296-
if let Some(parameters) = parameters {
1297-
write!(f, "({parameters})")?;
1298-
}
1299-
Ok(())
1515+
write!(f, "{parameters}")
13001516
}
13011517
OnConflict(keyword) => {
13021518
write!(f, "ON CONFLICT {:?}", keyword)?;
13031519
Ok(())
13041520
}
1521+
Policy(parameters) => {
1522+
write!(f, "{parameters}")
1523+
}
1524+
Tags(tags) => {
1525+
write!(f, "{tags}")
1526+
}
13051527
}
13061528
}
13071529
}

src/ast/mod.rs

+11-6
Original file line numberDiff line numberDiff line change
@@ -40,11 +40,12 @@ pub use self::data_type::{
4040
pub use self::dcl::{AlterRoleOperation, ResetConfig, RoleOption, SetConfigValue, Use};
4141
pub use self::ddl::{
4242
AlterColumnOperation, AlterIndexOperation, AlterPolicyOperation, AlterTableOperation,
43-
ClusteredBy, ColumnDef, ColumnOption, ColumnOptionDef, ConstraintCharacteristics, Deduplicate,
44-
DeferrableInitial, GeneratedAs, GeneratedExpressionMode, IdentityProperty, IndexOption,
45-
IndexType, KeyOrIndexDisplay, Owner, Partition, ProcedureParam, ReferentialAction,
46-
TableConstraint, UserDefinedTypeCompositeAttributeDef, UserDefinedTypeRepresentation,
47-
ViewColumnDef,
43+
ClusteredBy, ColumnDef, ColumnOption, ColumnOptionDef, ColumnPolicy, ColumnPolicyProperty,
44+
ConstraintCharacteristics, Deduplicate, DeferrableInitial, GeneratedAs,
45+
GeneratedExpressionMode, IdentityParameters, IdentityProperty, IdentityPropertyFormatKind,
46+
IdentityPropertyKind, IdentityPropertyOrder, IndexOption, IndexType, KeyOrIndexDisplay, Owner,
47+
Partition, ProcedureParam, ReferentialAction, TableConstraint, TagsColumnOption,
48+
UserDefinedTypeCompositeAttributeDef, UserDefinedTypeRepresentation, ViewColumnDef,
4849
};
4950
pub use self::dml::{CreateIndex, CreateTable, Delete, Insert};
5051
pub use self::operator::{BinaryOperator, UnaryOperator};
@@ -668,6 +669,9 @@ pub enum Expr {
668669
},
669670
/// CONVERT a value to a different data type or character encoding. e.g. `CONVERT(foo USING utf8mb4)`
670671
Convert {
672+
/// CONVERT (false) or TRY_CONVERT (true)
673+
/// <https://learn.microsoft.com/en-us/sql/t-sql/functions/try-convert-transact-sql?view=sql-server-ver16>
674+
is_try: bool,
671675
/// The expression to convert
672676
expr: Box<Expr>,
673677
/// The target data type
@@ -1370,13 +1374,14 @@ impl fmt::Display for Expr {
13701374
}
13711375
}
13721376
Expr::Convert {
1377+
is_try,
13731378
expr,
13741379
target_before_value,
13751380
data_type,
13761381
charset,
13771382
styles,
13781383
} => {
1379-
write!(f, "CONVERT(")?;
1384+
write!(f, "{}CONVERT(", if *is_try { "TRY_" } else { "" })?;
13801385
if let Some(data_type) = data_type {
13811386
if let Some(charset) = charset {
13821387
write!(f, "{expr}, {data_type} CHARACTER SET {charset}")

src/dialect/generic.rs

+4
Original file line numberDiff line numberDiff line change
@@ -107,4 +107,8 @@ impl Dialect for GenericDialect {
107107
fn supports_asc_desc_in_column_definition(&self) -> bool {
108108
true
109109
}
110+
111+
fn supports_try_convert(&self) -> bool {
112+
true
113+
}
110114
}

src/dialect/mod.rs

+30-1
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ pub use self::postgresql::PostgreSqlDialect;
4949
pub use self::redshift::RedshiftSqlDialect;
5050
pub use self::snowflake::SnowflakeDialect;
5151
pub use self::sqlite::SQLiteDialect;
52-
use crate::ast::{Expr, Statement};
52+
use crate::ast::{ColumnOption, Expr, Statement};
5353
pub use crate::keywords;
5454
use crate::keywords::Keyword;
5555
use crate::parser::{Parser, ParserError};
@@ -478,6 +478,19 @@ pub trait Dialect: Debug + Any {
478478
None
479479
}
480480

481+
/// Dialect-specific column option parser override
482+
///
483+
/// This method is called to parse the next column option.
484+
///
485+
/// If `None` is returned, falls back to the default behavior.
486+
fn parse_column_option(
487+
&self,
488+
_parser: &mut Parser,
489+
) -> Option<Result<Option<ColumnOption>, ParserError>> {
490+
// return None to fall back to the default behavior
491+
None
492+
}
493+
481494
/// Decide the lexical Precedence of operators.
482495
///
483496
/// Uses (APPROXIMATELY) <https://www.postgresql.org/docs/7.0/operators.htm#AEN2026> as a reference
@@ -561,6 +574,22 @@ pub trait Dialect: Debug + Any {
561574
fn supports_asc_desc_in_column_definition(&self) -> bool {
562575
false
563576
}
577+
578+
/// Returns true if this dialect supports treating the equals operator `=` within a `SelectItem`
579+
/// as an alias assignment operator, rather than a boolean expression.
580+
/// For example: the following statements are equivalent for such a dialect:
581+
/// ```sql
582+
/// SELECT col_alias = col FROM tbl;
583+
/// SELECT col_alias AS col FROM tbl;
584+
/// ```
585+
fn supports_eq_alias_assigment(&self) -> bool {
586+
false
587+
}
588+
589+
/// Returns true if this dialect supports the `TRY_CONVERT` function
590+
fn supports_try_convert(&self) -> bool {
591+
false
592+
}
564593
}
565594

566595
/// This represents the operators for which precedence must be defined

0 commit comments

Comments
 (0)