Skip to content

Commit cd7b567

Browse files
committed
Merge branch 'main' into feature/1533-dereference-expr-2
2 parents 2778211 + fad2ddd commit cd7b567

File tree

17 files changed

+966
-120
lines changed

17 files changed

+966
-120
lines changed

src/ast/dml.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -505,8 +505,8 @@ impl Display for Insert {
505505
self.table_name.to_string()
506506
};
507507

508-
if let Some(action) = self.or {
509-
write!(f, "INSERT OR {action} INTO {table_name} ")?;
508+
if let Some(on_conflict) = self.or {
509+
write!(f, "INSERT {on_conflict} INTO {table_name} ")?;
510510
} else {
511511
write!(
512512
f,

src/ast/mod.rs

Lines changed: 82 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,8 @@ pub use self::query::{
6060
OrderBy, OrderByExpr, PivotValueSource, ProjectionSelect, Query, RenameSelectItem,
6161
RepetitionQuantifier, ReplaceSelectElement, ReplaceSelectItem, RowsPerMatch, Select,
6262
SelectInto, SelectItem, SetExpr, SetOperator, SetQuantifier, Setting, SymbolDefinition, Table,
63-
TableAlias, TableFactor, TableFunctionArgs, TableVersion, TableWithJoins, Top, TopQuantity,
64-
ValueTableMode, Values, WildcardAdditionalOptions, With, WithFill,
63+
TableAlias, TableAliasColumnDef, TableFactor, TableFunctionArgs, TableVersion, TableWithJoins,
64+
Top, TopQuantity, ValueTableMode, Values, WildcardAdditionalOptions, With, WithFill,
6565
};
6666

6767
pub use self::trigger::{
@@ -2396,6 +2396,8 @@ pub enum Statement {
23962396
selection: Option<Expr>,
23972397
/// RETURNING
23982398
returning: Option<Vec<SelectItem>>,
2399+
/// SQLite-specific conflict resolution clause
2400+
or: Option<SqliteOnConflict>,
23992401
},
24002402
/// ```sql
24012403
/// DELETE
@@ -3167,7 +3169,7 @@ pub enum Statement {
31673169
/// KILL [CONNECTION | QUERY | MUTATION]
31683170
/// ```
31693171
///
3170-
/// See <https://clickhouse.com/docs/ru/sql-reference/statements/kill/>
3172+
/// See <https://clickhouse.com/docs/en/sql-reference/statements/kill/>
31713173
/// See <https://dev.mysql.com/doc/refman/8.0/en/kill.html>
31723174
Kill {
31733175
modifier: Option<KillType>,
@@ -3338,6 +3340,13 @@ pub enum Statement {
33383340
/// See Postgres <https://www.postgresql.org/docs/current/sql-listen.html>
33393341
LISTEN { channel: Ident },
33403342
/// ```sql
3343+
/// UNLISTEN
3344+
/// ```
3345+
/// stop listening for a notification
3346+
///
3347+
/// See Postgres <https://www.postgresql.org/docs/current/sql-unlisten.html>
3348+
UNLISTEN { channel: Ident },
3349+
/// ```sql
33413350
/// NOTIFY channel [ , payload ]
33423351
/// ```
33433352
/// send a notification event together with an optional “payload” string to channel
@@ -3691,8 +3700,13 @@ impl fmt::Display for Statement {
36913700
from,
36923701
selection,
36933702
returning,
3703+
or,
36943704
} => {
3695-
write!(f, "UPDATE {table}")?;
3705+
write!(f, "UPDATE ")?;
3706+
if let Some(or) = or {
3707+
write!(f, "{or} ")?;
3708+
}
3709+
write!(f, "{table}")?;
36963710
if !assignments.is_empty() {
36973711
write!(f, " SET {}", display_comma_separated(assignments))?;
36983712
}
@@ -4941,6 +4955,10 @@ impl fmt::Display for Statement {
49414955
write!(f, "LISTEN {channel}")?;
49424956
Ok(())
49434957
}
4958+
Statement::UNLISTEN { channel } => {
4959+
write!(f, "UNLISTEN {channel}")?;
4960+
Ok(())
4961+
}
49444962
Statement::NOTIFY { channel, payload } => {
49454963
write!(f, "NOTIFY {channel}")?;
49464964
if let Some(payload) = payload {
@@ -5442,6 +5460,8 @@ pub enum FunctionArgOperator {
54425460
RightArrow,
54435461
/// function(arg1 := value1)
54445462
Assignment,
5463+
/// function(arg1 : value1)
5464+
Colon,
54455465
}
54465466

54475467
impl fmt::Display for FunctionArgOperator {
@@ -5450,6 +5470,7 @@ impl fmt::Display for FunctionArgOperator {
54505470
FunctionArgOperator::Equals => f.write_str("="),
54515471
FunctionArgOperator::RightArrow => f.write_str("=>"),
54525472
FunctionArgOperator::Assignment => f.write_str(":="),
5473+
FunctionArgOperator::Colon => f.write_str(":"),
54535474
}
54545475
}
54555476
}
@@ -5458,11 +5479,22 @@ impl fmt::Display for FunctionArgOperator {
54585479
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
54595480
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
54605481
pub enum FunctionArg {
5482+
/// `name` is identifier
5483+
///
5484+
/// Enabled when `Dialect::supports_named_fn_args_with_expr_name` returns 'false'
54615485
Named {
54625486
name: Ident,
54635487
arg: FunctionArgExpr,
54645488
operator: FunctionArgOperator,
54655489
},
5490+
/// `name` is arbitrary expression
5491+
///
5492+
/// Enabled when `Dialect::supports_named_fn_args_with_expr_name` returns 'true'
5493+
ExprNamed {
5494+
name: Expr,
5495+
arg: FunctionArgExpr,
5496+
operator: FunctionArgOperator,
5497+
},
54665498
Unnamed(FunctionArgExpr),
54675499
}
54685500

@@ -5474,6 +5506,11 @@ impl fmt::Display for FunctionArg {
54745506
arg,
54755507
operator,
54765508
} => write!(f, "{name} {operator} {arg}"),
5509+
FunctionArg::ExprNamed {
5510+
name,
5511+
arg,
5512+
operator,
5513+
} => write!(f, "{name} {operator} {arg}"),
54775514
FunctionArg::Unnamed(unnamed_arg) => write!(f, "{unnamed_arg}"),
54785515
}
54795516
}
@@ -5612,7 +5649,10 @@ impl fmt::Display for FunctionArgumentList {
56125649
}
56135650
write!(f, "{}", display_comma_separated(&self.args))?;
56145651
if !self.clauses.is_empty() {
5615-
write!(f, " {}", display_separated(&self.clauses, " "))?;
5652+
if !self.args.is_empty() {
5653+
write!(f, " ")?;
5654+
}
5655+
write!(f, "{}", display_separated(&self.clauses, " "))?;
56165656
}
56175657
Ok(())
56185658
}
@@ -5654,6 +5694,11 @@ pub enum FunctionArgumentClause {
56545694
///
56555695
/// [`GROUP_CONCAT`]: https://dev.mysql.com/doc/refman/8.0/en/aggregate-functions.html#function_group-concat
56565696
Separator(Value),
5697+
/// The json-null-clause to the [`JSON_ARRAY`]/[`JSON_OBJECT`] function in MSSQL.
5698+
///
5699+
/// [`JSON_ARRAY`]: <https://learn.microsoft.com/en-us/sql/t-sql/functions/json-array-transact-sql?view=sql-server-ver16>
5700+
/// [`JSON_OBJECT`]: <https://learn.microsoft.com/en-us/sql/t-sql/functions/json-object-transact-sql?view=sql-server-ver16>
5701+
JsonNullClause(JsonNullClause),
56575702
}
56585703

56595704
impl fmt::Display for FunctionArgumentClause {
@@ -5669,6 +5714,7 @@ impl fmt::Display for FunctionArgumentClause {
56695714
FunctionArgumentClause::OnOverflow(on_overflow) => write!(f, "{on_overflow}"),
56705715
FunctionArgumentClause::Having(bound) => write!(f, "{bound}"),
56715716
FunctionArgumentClause::Separator(sep) => write!(f, "SEPARATOR {sep}"),
5717+
FunctionArgumentClause::JsonNullClause(null_clause) => write!(f, "{null_clause}"),
56725718
}
56735719
}
56745720
}
@@ -6304,11 +6350,11 @@ impl fmt::Display for SqliteOnConflict {
63046350
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
63056351
use SqliteOnConflict::*;
63066352
match self {
6307-
Rollback => write!(f, "ROLLBACK"),
6308-
Abort => write!(f, "ABORT"),
6309-
Fail => write!(f, "FAIL"),
6310-
Ignore => write!(f, "IGNORE"),
6311-
Replace => write!(f, "REPLACE"),
6353+
Rollback => write!(f, "OR ROLLBACK"),
6354+
Abort => write!(f, "OR ABORT"),
6355+
Fail => write!(f, "OR FAIL"),
6356+
Ignore => write!(f, "OR IGNORE"),
6357+
Replace => write!(f, "OR REPLACE"),
63126358
}
63136359
}
63146360
}
@@ -7557,6 +7603,32 @@ impl fmt::Display for ShowStatementIn {
75577603
}
75587604
}
75597605

7606+
/// MSSQL's json null clause
7607+
///
7608+
/// ```plaintext
7609+
/// <json_null_clause> ::=
7610+
/// NULL ON NULL
7611+
/// | ABSENT ON NULL
7612+
/// ```
7613+
///
7614+
/// <https://learn.microsoft.com/en-us/sql/t-sql/functions/json-object-transact-sql?view=sql-server-ver16#json_null_clause>
7615+
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
7616+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
7617+
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
7618+
pub enum JsonNullClause {
7619+
NullOnNull,
7620+
AbsentOnNull,
7621+
}
7622+
7623+
impl Display for JsonNullClause {
7624+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
7625+
match self {
7626+
JsonNullClause::NullOnNull => write!(f, "NULL ON NULL"),
7627+
JsonNullClause::AbsentOnNull => write!(f, "ABSENT ON NULL"),
7628+
}
7629+
}
7630+
}
7631+
75607632
#[cfg(test)]
75617633
mod tests {
75627634
use super::*;

src/ast/query.rs

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1597,7 +1597,7 @@ impl fmt::Display for TableFactor {
15971597
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
15981598
pub struct TableAlias {
15991599
pub name: Ident,
1600-
pub columns: Vec<Ident>,
1600+
pub columns: Vec<TableAliasColumnDef>,
16011601
}
16021602

16031603
impl fmt::Display for TableAlias {
@@ -1610,6 +1610,41 @@ impl fmt::Display for TableAlias {
16101610
}
16111611
}
16121612

1613+
/// SQL column definition in a table expression alias.
1614+
/// Most of the time, the data type is not specified.
1615+
/// But some table-valued functions do require specifying the data type.
1616+
///
1617+
/// See <https://www.postgresql.org/docs/17/queries-table-expressions.html#QUERIES-TABLEFUNCTIONS>
1618+
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1619+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1620+
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1621+
pub struct TableAliasColumnDef {
1622+
/// Column name alias
1623+
pub name: Ident,
1624+
/// Some table-valued functions require specifying the data type in the alias.
1625+
pub data_type: Option<DataType>,
1626+
}
1627+
1628+
impl TableAliasColumnDef {
1629+
/// Create a new table alias column definition with only a name and no type
1630+
pub fn from_name<S: Into<String>>(name: S) -> Self {
1631+
TableAliasColumnDef {
1632+
name: Ident::new(name),
1633+
data_type: None,
1634+
}
1635+
}
1636+
}
1637+
1638+
impl fmt::Display for TableAliasColumnDef {
1639+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1640+
write!(f, "{}", self.name)?;
1641+
if let Some(ref data_type) = self.data_type {
1642+
write!(f, " {}", data_type)?;
1643+
}
1644+
Ok(())
1645+
}
1646+
}
1647+
16131648
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
16141649
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
16151650
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
@@ -1694,6 +1729,13 @@ impl fmt::Display for Join {
16941729
suffix(constraint)
16951730
),
16961731
JoinOperator::CrossJoin => write!(f, " CROSS JOIN {}", self.relation),
1732+
JoinOperator::Semi(constraint) => write!(
1733+
f,
1734+
" {}SEMI JOIN {}{}",
1735+
prefix(constraint),
1736+
self.relation,
1737+
suffix(constraint)
1738+
),
16971739
JoinOperator::LeftSemi(constraint) => write!(
16981740
f,
16991741
" {}LEFT SEMI JOIN {}{}",
@@ -1708,6 +1750,13 @@ impl fmt::Display for Join {
17081750
self.relation,
17091751
suffix(constraint)
17101752
),
1753+
JoinOperator::Anti(constraint) => write!(
1754+
f,
1755+
" {}ANTI JOIN {}{}",
1756+
prefix(constraint),
1757+
self.relation,
1758+
suffix(constraint)
1759+
),
17111760
JoinOperator::LeftAnti(constraint) => write!(
17121761
f,
17131762
" {}LEFT ANTI JOIN {}{}",
@@ -1746,10 +1795,14 @@ pub enum JoinOperator {
17461795
RightOuter(JoinConstraint),
17471796
FullOuter(JoinConstraint),
17481797
CrossJoin,
1798+
/// SEMI (non-standard)
1799+
Semi(JoinConstraint),
17491800
/// LEFT SEMI (non-standard)
17501801
LeftSemi(JoinConstraint),
17511802
/// RIGHT SEMI (non-standard)
17521803
RightSemi(JoinConstraint),
1804+
/// ANTI (non-standard)
1805+
Anti(JoinConstraint),
17531806
/// LEFT ANTI (non-standard)
17541807
LeftAnti(JoinConstraint),
17551808
/// RIGHT ANTI (non-standard)

src/dialect/duckdb.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,10 @@ impl Dialect for DuckDbDialect {
4747
true
4848
}
4949

50+
fn supports_named_fn_args_with_assignment_operator(&self) -> bool {
51+
true
52+
}
53+
5054
// DuckDB uses this syntax for `STRUCT`s.
5155
//
5256
// https://duckdb.org/docs/sql/data_types/struct.html#creating-structs

src/dialect/generic.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,10 @@ impl Dialect for GenericDialect {
120120
true
121121
}
122122

123+
fn supports_named_fn_args_with_assignment_operator(&self) -> bool {
124+
true
125+
}
126+
123127
fn support_period_map_access_key(&self) -> bool {
124128
true
125129
}

src/dialect/mod.rs

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -231,11 +231,34 @@ pub trait Dialect: Debug + Any {
231231
false
232232
}
233233

234-
/// Returns true if the dialect supports named arguments of the form FUN(a = '1', b = '2').
234+
/// Returns true if the dialect supports named arguments of the form `FUN(a = '1', b = '2')`.
235235
fn supports_named_fn_args_with_eq_operator(&self) -> bool {
236236
false
237237
}
238238

239+
/// Returns true if the dialect supports named arguments of the form `FUN(a : '1', b : '2')`.
240+
fn supports_named_fn_args_with_colon_operator(&self) -> bool {
241+
false
242+
}
243+
244+
/// Returns true if the dialect supports named arguments of the form `FUN(a := '1', b := '2')`.
245+
fn supports_named_fn_args_with_assignment_operator(&self) -> bool {
246+
false
247+
}
248+
249+
/// Returns true if the dialect supports named arguments of the form `FUN(a => '1', b => '2')`.
250+
fn supports_named_fn_args_with_rarrow_operator(&self) -> bool {
251+
true
252+
}
253+
254+
/// Returns true if dialect supports argument name as arbitrary expression.
255+
/// e.g. `FUN(LOWER('a'):'1', b:'2')`
256+
/// Such function arguments are represented in the AST by the `FunctionArg::ExprNamed` variant,
257+
/// otherwise use the `FunctionArg::Named` variant (compatible reason).
258+
fn supports_named_fn_args_with_expr_name(&self) -> bool {
259+
false
260+
}
261+
239262
/// Returns true if the dialect supports identifiers starting with a numeric
240263
/// prefix such as tables named `59901_user_login`
241264
fn supports_numeric_prefix(&self) -> bool {
@@ -610,13 +633,8 @@ pub trait Dialect: Debug + Any {
610633
false
611634
}
612635

613-
/// Returns true if the dialect supports the `LISTEN` statement
614-
fn supports_listen(&self) -> bool {
615-
false
616-
}
617-
618-
/// Returns true if the dialect supports the `NOTIFY` statement
619-
fn supports_notify(&self) -> bool {
636+
/// Returns true if the dialect supports the `LISTEN`, `UNLISTEN` and `NOTIFY` statements
637+
fn supports_listen_notify(&self) -> bool {
620638
false
621639
}
622640

src/dialect/mssql.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,4 +66,16 @@ impl Dialect for MsSqlDialect {
6666
fn supports_methods(&self) -> bool {
6767
true
6868
}
69+
70+
fn supports_named_fn_args_with_colon_operator(&self) -> bool {
71+
true
72+
}
73+
74+
fn supports_named_fn_args_with_expr_name(&self) -> bool {
75+
true
76+
}
77+
78+
fn supports_named_fn_args_with_rarrow_operator(&self) -> bool {
79+
false
80+
}
6981
}

0 commit comments

Comments
 (0)