Skip to content

Commit 187eae9

Browse files
committed
merge upstream/main
2 parents e9a35be + 3fa7114 commit 187eae9

36 files changed

+2003
-653
lines changed

README.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -159,9 +159,9 @@ $ cargo run --features json_example --example cli FILENAME.sql [--dialectname]
159159

160160
## Users
161161

162-
This parser is currently being used by the [DataFusion] query engine, [LocustDB],
163-
[Ballista], [GlueSQL], [Opteryx], [Polars], [PRQL], [Qrlew], [JumpWire], [ParadeDB], [CipherStash Proxy],
164-
and [GreptimeDB].
162+
This parser is currently being used by the [DataFusion] query engine,
163+
[LocustDB], [Ballista], [GlueSQL], [Opteryx], [Polars], [PRQL], [Qrlew],
164+
[JumpWire], [ParadeDB], [CipherStash Proxy], [Readyset] and [GreptimeDB].
165165

166166
If your project is using sqlparser-rs feel free to make a PR to add it
167167
to this list.
@@ -282,3 +282,4 @@ licensed as above, without any additional terms or conditions.
282282
[`GenericDialect`]: https://docs.rs/sqlparser/latest/sqlparser/dialect/struct.GenericDialect.html
283283
[CipherStash Proxy]: https://github.com/cipherstash/proxy
284284
[GreptimeDB]: https://github.com/GreptimeTeam/greptimedb
285+
[Readyset]: https://github.com/readysettech/readyset

src/ast/ddl.rs

Lines changed: 63 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -457,6 +457,12 @@ pub enum AlterTableOperation {
457457
},
458458
/// Remove the clustering key from the table.
459459
DropClusteringKey,
460+
/// Redshift `ALTER SORTKEY (column_list)`
461+
/// <https://docs.aws.amazon.com/redshift/latest/dg/r_ALTER_TABLE.html>
462+
AlterSortKey {
463+
/// Column references in the sort key.
464+
columns: Vec<Expr>,
465+
},
460466
/// Suspend background reclustering operations.
461467
SuspendRecluster,
462468
/// Resume background reclustering operations.
@@ -993,6 +999,10 @@ impl fmt::Display for AlterTableOperation {
993999
write!(f, "DROP CLUSTERING KEY")?;
9941000
Ok(())
9951001
}
1002+
AlterTableOperation::AlterSortKey { columns } => {
1003+
write!(f, "ALTER SORTKEY({})", display_comma_separated(columns))?;
1004+
Ok(())
1005+
}
9961006
AlterTableOperation::SuspendRecluster => {
9971007
write!(f, "SUSPEND RECLUSTER")?;
9981008
Ok(())
@@ -2040,7 +2050,7 @@ impl fmt::Display for ColumnOption {
20402050
Ok(())
20412051
}
20422052
Unique(constraint) => {
2043-
write!(f, "UNIQUE")?;
2053+
write!(f, "UNIQUE{:>}", constraint.index_type_display)?;
20442054
if let Some(characteristics) = &constraint.characteristics {
20452055
write!(f, " {characteristics}")?;
20462056
}
@@ -3032,6 +3042,15 @@ pub struct CreateTable {
30323042
/// Snowflake "REQUIRE USER" clause for dybamic tables
30333043
/// <https://docs.snowflake.com/en/sql-reference/sql/create-dynamic-table>
30343044
pub require_user: bool,
3045+
/// Redshift `DISTSTYLE` option
3046+
/// <https://docs.aws.amazon.com/redshift/latest/dg/r_CREATE_TABLE_NEW.html>
3047+
pub diststyle: Option<DistStyle>,
3048+
/// Redshift `DISTKEY` option
3049+
/// <https://docs.aws.amazon.com/redshift/latest/dg/r_CREATE_TABLE_NEW.html>
3050+
pub distkey: Option<Expr>,
3051+
/// Redshift `SORTKEY` option
3052+
/// <https://docs.aws.amazon.com/redshift/latest/dg/r_CREATE_TABLE_NEW.html>
3053+
pub sortkey: Option<Vec<Expr>>,
30353054
}
30363055

30373056
impl fmt::Display for CreateTable {
@@ -3330,6 +3349,15 @@ impl fmt::Display for CreateTable {
33303349
if self.strict {
33313350
write!(f, " STRICT")?;
33323351
}
3352+
if let Some(diststyle) = &self.diststyle {
3353+
write!(f, " DISTSTYLE {diststyle}")?;
3354+
}
3355+
if let Some(distkey) = &self.distkey {
3356+
write!(f, " DISTKEY({distkey})")?;
3357+
}
3358+
if let Some(sortkey) = &self.sortkey {
3359+
write!(f, " SORTKEY({})", display_comma_separated(sortkey))?;
3360+
}
33333361
if let Some(query) = &self.query {
33343362
write!(f, " AS {query}")?;
33353363
}
@@ -3417,6 +3445,34 @@ impl fmt::Display for PartitionBoundValue {
34173445
}
34183446
}
34193447

3448+
/// Redshift distribution style for `CREATE TABLE`.
3449+
///
3450+
/// See [Redshift](https://docs.aws.amazon.com/redshift/latest/dg/r_CREATE_TABLE_NEW.html)
3451+
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3452+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3453+
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3454+
pub enum DistStyle {
3455+
/// `DISTSTYLE AUTO`
3456+
Auto,
3457+
/// `DISTSTYLE EVEN`
3458+
Even,
3459+
/// `DISTSTYLE KEY`
3460+
Key,
3461+
/// `DISTSTYLE ALL`
3462+
All,
3463+
}
3464+
3465+
impl fmt::Display for DistStyle {
3466+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3467+
match self {
3468+
DistStyle::Auto => write!(f, "AUTO"),
3469+
DistStyle::Even => write!(f, "EVEN"),
3470+
DistStyle::Key => write!(f, "KEY"),
3471+
DistStyle::All => write!(f, "ALL"),
3472+
}
3473+
}
3474+
}
3475+
34203476
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
34213477
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
34223478
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
@@ -4259,6 +4315,9 @@ pub struct CreateView {
42594315
pub if_not_exists: bool,
42604316
/// if true, has SQLite `TEMP` or `TEMPORARY` clause <https://www.sqlite.org/lang_createview.html>
42614317
pub temporary: bool,
4318+
/// Snowflake: `COPY GRANTS` clause
4319+
/// <https://docs.snowflake.com/en/sql-reference/sql/create-view>
4320+
pub copy_grants: bool,
42624321
/// if not None, has Clickhouse `TO` clause, specify the table into which to insert results
42634322
/// <https://clickhouse.com/docs/en/sql-reference/statements/create/view#materialized-view>
42644323
pub to: Option<ObjectName>,
@@ -4302,6 +4361,9 @@ impl fmt::Display for CreateView {
43024361
.map(|to| format!(" TO {to}"))
43034362
.unwrap_or_default()
43044363
)?;
4364+
if self.copy_grants {
4365+
write!(f, " COPY GRANTS")?;
4366+
}
43054367
if !self.columns.is_empty() {
43064368
write!(f, " ({})", display_comma_separated(&self.columns))?;
43074369
}

src/ast/dml.rs

Lines changed: 53 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,8 @@ use super::{
3333
display_comma_separated, helpers::attached_token::AttachedToken, query::InputFormatClause,
3434
Assignment, Expr, FromTable, Ident, InsertAliases, MysqlInsertPriority, ObjectName, OnInsert,
3535
OptimizerHint, OrderByExpr, Query, SelectInto, SelectItem, Setting, SqliteOnConflict,
36-
TableFactor, TableObject, TableWithJoins, UpdateTableFromKind, Values,
36+
TableAliasWithoutColumns, TableFactor, TableObject, TableWithJoins, UpdateTableFromKind,
37+
Values,
3738
};
3839

3940
/// INSERT statement.
@@ -43,11 +44,11 @@ use super::{
4344
pub struct Insert {
4445
/// Token for the `INSERT` keyword (or its substitutes)
4546
pub insert_token: AttachedToken,
46-
/// A query optimizer hint
47+
/// Query optimizer hints
4748
///
4849
/// [MySQL](https://dev.mysql.com/doc/refman/8.4/en/optimizer-hints.html)
4950
/// [Oracle](https://docs.oracle.com/en/database/oracle/oracle-database/21/sqlrf/Comments.html#GUID-D316D545-89E2-4D54-977F-FC97815CD62E)
50-
pub optimizer_hint: Option<OptimizerHint>,
51+
pub optimizer_hints: Vec<OptimizerHint>,
5152
/// Only for Sqlite
5253
pub or: Option<SqliteOnConflict>,
5354
/// Only for mysql
@@ -56,10 +57,11 @@ pub struct Insert {
5657
pub into: bool,
5758
/// TABLE
5859
pub table: TableObject,
59-
/// table_name as foo (for PostgreSQL)
60-
pub table_alias: Option<Ident>,
60+
/// `table_name as foo` (for PostgreSQL)
61+
/// `table_name foo` (for Oracle)
62+
pub table_alias: Option<TableAliasWithoutColumns>,
6163
/// COLUMNS
62-
pub columns: Vec<Ident>,
64+
pub columns: Vec<ObjectName>,
6365
/// Overwrite (Hive)
6466
pub overwrite: bool,
6567
/// A SQL query that specifies what to insert
@@ -77,6 +79,9 @@ pub struct Insert {
7779
pub on: Option<OnInsert>,
7880
/// RETURNING
7981
pub returning: Option<Vec<SelectItem>>,
82+
/// OUTPUT (MSSQL)
83+
/// See <https://learn.microsoft.com/en-us/sql/t-sql/queries/output-clause-transact-sql>
84+
pub output: Option<OutputClause>,
8085
/// Only for mysql
8186
pub replace_into: bool,
8287
/// Only for mysql
@@ -125,15 +130,20 @@ pub struct Insert {
125130
impl Display for Insert {
126131
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
127132
// SQLite OR conflict has a special format: INSERT OR ... INTO table_name
128-
let table_name = if let Some(alias) = &self.table_alias {
129-
format!("{0} AS {alias}", self.table)
133+
let table_name = if let Some(table_alias) = &self.table_alias {
134+
format!(
135+
"{table} {as_keyword}{alias}",
136+
table = self.table,
137+
as_keyword = if table_alias.explicit { "AS " } else { "" },
138+
alias = table_alias.alias
139+
)
130140
} else {
131141
self.table.to_string()
132142
};
133143

134144
if let Some(on_conflict) = self.or {
135145
f.write_str("INSERT")?;
136-
if let Some(hint) = self.optimizer_hint.as_ref() {
146+
for hint in &self.optimizer_hints {
137147
write!(f, " {hint}")?;
138148
}
139149
write!(f, " {on_conflict} INTO {table_name} ")?;
@@ -147,7 +157,7 @@ impl Display for Insert {
147157
"INSERT"
148158
}
149159
)?;
150-
if let Some(hint) = self.optimizer_hint.as_ref() {
160+
for hint in &self.optimizer_hints {
151161
write!(f, " {hint}")?;
152162
}
153163
if let Some(priority) = self.priority {
@@ -196,6 +206,11 @@ impl Display for Insert {
196206
SpaceOrNewline.fmt(f)?;
197207
}
198208

209+
if let Some(output) = &self.output {
210+
write!(f, "{output}")?;
211+
SpaceOrNewline.fmt(f)?;
212+
}
213+
199214
if let Some(settings) = &self.settings {
200215
write!(f, "SETTINGS {}", display_comma_separated(settings))?;
201216
SpaceOrNewline.fmt(f)?;
@@ -267,11 +282,11 @@ impl Display for Insert {
267282
pub struct Delete {
268283
/// Token for the `DELETE` keyword
269284
pub delete_token: AttachedToken,
270-
/// A query optimizer hint
285+
/// Query optimizer hints
271286
///
272287
/// [MySQL](https://dev.mysql.com/doc/refman/8.4/en/optimizer-hints.html)
273288
/// [Oracle](https://docs.oracle.com/en/database/oracle/oracle-database/21/sqlrf/Comments.html#GUID-D316D545-89E2-4D54-977F-FC97815CD62E)
274-
pub optimizer_hint: Option<OptimizerHint>,
289+
pub optimizer_hints: Vec<OptimizerHint>,
275290
/// Multi tables delete are supported in mysql
276291
pub tables: Vec<ObjectName>,
277292
/// FROM
@@ -282,6 +297,9 @@ pub struct Delete {
282297
pub selection: Option<Expr>,
283298
/// RETURNING
284299
pub returning: Option<Vec<SelectItem>>,
300+
/// OUTPUT (MSSQL)
301+
/// See <https://learn.microsoft.com/en-us/sql/t-sql/queries/output-clause-transact-sql>
302+
pub output: Option<OutputClause>,
285303
/// ORDER BY (MySQL)
286304
pub order_by: Vec<OrderByExpr>,
287305
/// LIMIT (MySQL)
@@ -291,7 +309,7 @@ pub struct Delete {
291309
impl Display for Delete {
292310
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
293311
f.write_str("DELETE")?;
294-
if let Some(hint) = self.optimizer_hint.as_ref() {
312+
for hint in &self.optimizer_hints {
295313
f.write_str(" ")?;
296314
hint.fmt(f)?;
297315
}
@@ -307,6 +325,10 @@ impl Display for Delete {
307325
indented_list(f, from)?;
308326
}
309327
}
328+
if let Some(output) = &self.output {
329+
SpaceOrNewline.fmt(f)?;
330+
write!(f, "{output}")?;
331+
}
310332
if let Some(using) = &self.using {
311333
SpaceOrNewline.fmt(f)?;
312334
f.write_str("USING")?;
@@ -345,11 +367,11 @@ impl Display for Delete {
345367
pub struct Update {
346368
/// Token for the `UPDATE` keyword
347369
pub update_token: AttachedToken,
348-
/// A query optimizer hint
370+
/// Query optimizer hints
349371
///
350372
/// [MySQL](https://dev.mysql.com/doc/refman/8.4/en/optimizer-hints.html)
351373
/// [Oracle](https://docs.oracle.com/en/database/oracle/oracle-database/21/sqlrf/Comments.html#GUID-D316D545-89E2-4D54-977F-FC97815CD62E)
352-
pub optimizer_hint: Option<OptimizerHint>,
374+
pub optimizer_hints: Vec<OptimizerHint>,
353375
/// TABLE
354376
pub table: TableWithJoins,
355377
/// Column assignments
@@ -360,6 +382,9 @@ pub struct Update {
360382
pub selection: Option<Expr>,
361383
/// RETURNING
362384
pub returning: Option<Vec<SelectItem>>,
385+
/// OUTPUT (MSSQL)
386+
/// See <https://learn.microsoft.com/en-us/sql/t-sql/queries/output-clause-transact-sql>
387+
pub output: Option<OutputClause>,
363388
/// SQLite-specific conflict resolution clause
364389
pub or: Option<SqliteOnConflict>,
365390
/// LIMIT
@@ -368,11 +393,12 @@ pub struct Update {
368393

369394
impl Display for Update {
370395
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
371-
f.write_str("UPDATE ")?;
372-
if let Some(hint) = self.optimizer_hint.as_ref() {
373-
hint.fmt(f)?;
396+
f.write_str("UPDATE")?;
397+
for hint in &self.optimizer_hints {
374398
f.write_str(" ")?;
399+
hint.fmt(f)?;
375400
}
401+
f.write_str(" ")?;
376402
if let Some(or) = &self.or {
377403
or.fmt(f)?;
378404
f.write_str(" ")?;
@@ -388,6 +414,10 @@ impl Display for Update {
388414
f.write_str("SET")?;
389415
indented_list(f, &self.assignments)?;
390416
}
417+
if let Some(output) = &self.output {
418+
SpaceOrNewline.fmt(f)?;
419+
write!(f, "{output}")?;
420+
}
391421
if let Some(UpdateTableFromKind::AfterSet(from)) = &self.from {
392422
SpaceOrNewline.fmt(f)?;
393423
f.write_str("FROM")?;
@@ -419,10 +449,10 @@ impl Display for Update {
419449
pub struct Merge {
420450
/// The `MERGE` token that starts the statement.
421451
pub merge_token: AttachedToken,
422-
/// A query optimizer hint
452+
/// Query optimizer hints
423453
///
424454
/// [Oracle](https://docs.oracle.com/en/database/oracle/oracle-database/21/sqlrf/Comments.html#GUID-D316D545-89E2-4D54-977F-FC97815CD62E)
425-
pub optimizer_hint: Option<OptimizerHint>,
455+
pub optimizer_hints: Vec<OptimizerHint>,
426456
/// optional INTO keyword
427457
pub into: bool,
428458
/// Specifies the table to merge
@@ -440,7 +470,7 @@ pub struct Merge {
440470
impl Display for Merge {
441471
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
442472
f.write_str("MERGE")?;
443-
if let Some(hint) = self.optimizer_hint.as_ref() {
473+
for hint in &self.optimizer_hints {
444474
write!(f, " {hint}")?;
445475
}
446476
if self.into {
@@ -709,11 +739,11 @@ impl Display for MergeUpdateExpr {
709739
}
710740
}
711741

712-
/// A `OUTPUT` Clause in the end of a `MERGE` Statement
742+
/// An `OUTPUT` clause on `MERGE`, `INSERT`, `UPDATE`, or `DELETE` (MSSQL).
713743
///
714744
/// Example:
715745
/// OUTPUT $action, deleted.* INTO dbo.temp_products;
716-
/// [mssql](https://learn.microsoft.com/en-us/sql/t-sql/queries/output-clause-transact-sql)
746+
/// <https://learn.microsoft.com/en-us/sql/t-sql/queries/output-clause-transact-sql>
717747
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
718748
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
719749
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]

0 commit comments

Comments
 (0)