Skip to content

Commit d0102b2

Browse files
committed
Merge branch 'main' into solontsev/pg-create-server
# Conflicts: # tests/sqlparser_postgres.rs
2 parents d0c7c7e + 9020385 commit d0102b2

19 files changed

+1234
-104
lines changed

src/ast/ddl.rs

Lines changed: 36 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -67,8 +67,11 @@ impl fmt::Display for ReplicaIdentity {
6767
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
6868
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
6969
pub enum AlterTableOperation {
70-
/// `ADD <table_constraint>`
71-
AddConstraint(TableConstraint),
70+
/// `ADD <table_constraint> [NOT VALID]`
71+
AddConstraint {
72+
constraint: TableConstraint,
73+
not_valid: bool,
74+
},
7275
/// `ADD [COLUMN] [IF NOT EXISTS] <column_def>`
7376
AddColumn {
7477
/// `[COLUMN]`.
@@ -344,6 +347,10 @@ pub enum AlterTableOperation {
344347
equals: bool,
345348
value: ValueWithSpan,
346349
},
350+
/// `VALIDATE CONSTRAINT <name>`
351+
ValidateConstraint {
352+
name: Ident,
353+
},
347354
}
348355

349356
/// An `ALTER Policy` (`Statement::AlterPolicy`) operation
@@ -494,7 +501,16 @@ impl fmt::Display for AlterTableOperation {
494501
display_separated(new_partitions, " "),
495502
ine = if *if_not_exists { " IF NOT EXISTS" } else { "" }
496503
),
497-
AlterTableOperation::AddConstraint(c) => write!(f, "ADD {c}"),
504+
AlterTableOperation::AddConstraint {
505+
not_valid,
506+
constraint,
507+
} => {
508+
write!(f, "ADD {constraint}")?;
509+
if *not_valid {
510+
write!(f, " NOT VALID")?;
511+
}
512+
Ok(())
513+
}
498514
AlterTableOperation::AddColumn {
499515
column_keyword,
500516
if_not_exists,
@@ -772,6 +788,9 @@ impl fmt::Display for AlterTableOperation {
772788
AlterTableOperation::ReplicaIdentity { identity } => {
773789
write!(f, "REPLICA IDENTITY {identity}")
774790
}
791+
AlterTableOperation::ValidateConstraint { name } => {
792+
write!(f, "VALIDATE CONSTRAINT {name}")
793+
}
775794
}
776795
}
777796
}
@@ -893,7 +912,10 @@ pub enum AlterColumnOperation {
893912
data_type: DataType,
894913
/// PostgreSQL specific
895914
using: Option<Expr>,
915+
/// Set to true if the statement includes the `SET DATA TYPE` keywords
916+
had_set: bool,
896917
},
918+
897919
/// `ADD GENERATED { ALWAYS | BY DEFAULT } AS IDENTITY [ ( sequence_options ) ]`
898920
///
899921
/// Note: this is a PostgreSQL-specific operation.
@@ -914,12 +936,19 @@ impl fmt::Display for AlterColumnOperation {
914936
AlterColumnOperation::DropDefault => {
915937
write!(f, "DROP DEFAULT")
916938
}
917-
AlterColumnOperation::SetDataType { data_type, using } => {
939+
AlterColumnOperation::SetDataType {
940+
data_type,
941+
using,
942+
had_set,
943+
} => {
944+
if *had_set {
945+
write!(f, "SET DATA ")?;
946+
}
947+
write!(f, "TYPE {data_type}")?;
918948
if let Some(expr) = using {
919-
write!(f, "SET DATA TYPE {data_type} USING {expr}")
920-
} else {
921-
write!(f, "SET DATA TYPE {data_type}")
949+
write!(f, " USING {expr}")?;
922950
}
951+
Ok(())
923952
}
924953
AlterColumnOperation::AddGenerated {
925954
generated_as,

src/ast/mod.rs

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -996,7 +996,7 @@ pub enum Expr {
996996
data_type: DataType,
997997
/// The value of the constant.
998998
/// Hint: you can unwrap the string value using `value.into_string()`.
999-
value: Value,
999+
value: ValueWithSpan,
10001000
},
10011001
/// Scalar function call e.g. `LEFT(foo, 5)`
10021002
Function(Function),
@@ -1124,6 +1124,8 @@ pub enum Expr {
11241124
/// [Databricks](https://docs.databricks.com/en/sql/language-manual/sql-ref-lambda-functions.html)
11251125
/// [DuckDb](https://duckdb.org/docs/sql/functions/lambda.html)
11261126
Lambda(LambdaFunction),
1127+
/// Checks membership of a value in a JSON array
1128+
MemberOf(MemberOf),
11271129
}
11281130

11291131
impl Expr {
@@ -1912,6 +1914,7 @@ impl fmt::Display for Expr {
19121914
}
19131915
Expr::Prior(expr) => write!(f, "PRIOR {expr}"),
19141916
Expr::Lambda(lambda) => write!(f, "{lambda}"),
1917+
Expr::MemberOf(member_of) => write!(f, "{member_of}"),
19151918
}
19161919
}
19171920
}
@@ -9900,6 +9903,27 @@ impl fmt::Display for NullInclusion {
99009903
}
99019904
}
99029905

9906+
/// Checks membership of a value in a JSON array
9907+
///
9908+
/// Syntax:
9909+
/// ```sql
9910+
/// <value> MEMBER OF(<array>)
9911+
/// ```
9912+
/// [MySQL](https://dev.mysql.com/doc/refman/8.4/en/json-search-functions.html#operator_member-of)
9913+
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
9914+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
9915+
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
9916+
pub struct MemberOf {
9917+
pub value: Box<Expr>,
9918+
pub array: Box<Expr>,
9919+
}
9920+
9921+
impl fmt::Display for MemberOf {
9922+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
9923+
write!(f, "{} MEMBER OF({})", self.value, self.array)
9924+
}
9925+
}
9926+
99039927
#[cfg(test)]
99049928
mod tests {
99059929
use crate::tokenizer::Location;

src/ast/query.rs

Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2684,6 +2684,79 @@ pub enum PipeOperator {
26842684
/// Syntax: `|> TABLESAMPLE SYSTEM (10 PERCENT)
26852685
/// See more at <https://cloud.google.com/bigquery/docs/reference/standard-sql/pipe-syntax#tablesample_pipe_operator>
26862686
TableSample { sample: Box<TableSample> },
2687+
/// Renames columns in the input table.
2688+
///
2689+
/// Syntax: `|> RENAME old_name AS new_name, ...`
2690+
///
2691+
/// See more at <https://cloud.google.com/bigquery/docs/reference/standard-sql/pipe-syntax#rename_pipe_operator>
2692+
Rename { mappings: Vec<IdentWithAlias> },
2693+
/// Combines the input table with one or more tables using UNION.
2694+
///
2695+
/// Syntax: `|> UNION [ALL|DISTINCT] (<query>), (<query>), ...`
2696+
///
2697+
/// See more at <https://cloud.google.com/bigquery/docs/reference/standard-sql/pipe-syntax#union_pipe_operator>
2698+
Union {
2699+
set_quantifier: SetQuantifier,
2700+
queries: Vec<Query>,
2701+
},
2702+
/// Returns only the rows that are present in both the input table and the specified tables.
2703+
///
2704+
/// Syntax: `|> INTERSECT [DISTINCT] (<query>), (<query>), ...`
2705+
///
2706+
/// See more at <https://cloud.google.com/bigquery/docs/reference/standard-sql/pipe-syntax#intersect_pipe_operator>
2707+
Intersect {
2708+
set_quantifier: SetQuantifier,
2709+
queries: Vec<Query>,
2710+
},
2711+
/// Returns only the rows that are present in the input table but not in the specified tables.
2712+
///
2713+
/// Syntax: `|> EXCEPT DISTINCT (<query>), (<query>), ...`
2714+
///
2715+
/// See more at <https://cloud.google.com/bigquery/docs/reference/standard-sql/pipe-syntax#except_pipe_operator>
2716+
Except {
2717+
set_quantifier: SetQuantifier,
2718+
queries: Vec<Query>,
2719+
},
2720+
/// Calls a table function or procedure that returns a table.
2721+
///
2722+
/// Syntax: `|> CALL function_name(args) [AS alias]`
2723+
///
2724+
/// See more at <https://cloud.google.com/bigquery/docs/reference/standard-sql/pipe-syntax#call_pipe_operator>
2725+
Call {
2726+
function: Function,
2727+
alias: Option<Ident>,
2728+
},
2729+
/// Pivots data from rows to columns.
2730+
///
2731+
/// Syntax: `|> PIVOT(aggregate_function(column) FOR pivot_column IN (value1, value2, ...)) [AS alias]`
2732+
///
2733+
/// See more at <https://cloud.google.com/bigquery/docs/reference/standard-sql/pipe-syntax#pivot_pipe_operator>
2734+
Pivot {
2735+
aggregate_functions: Vec<ExprWithAlias>,
2736+
value_column: Vec<Ident>,
2737+
value_source: PivotValueSource,
2738+
alias: Option<Ident>,
2739+
},
2740+
/// The `UNPIVOT` pipe operator transforms columns into rows.
2741+
///
2742+
/// Syntax:
2743+
/// ```sql
2744+
/// |> UNPIVOT(value_column FOR name_column IN (column1, column2, ...)) [alias]
2745+
/// ```
2746+
///
2747+
/// See more at <https://cloud.google.com/bigquery/docs/reference/standard-sql/pipe-syntax#unpivot_pipe_operator>
2748+
Unpivot {
2749+
value_column: Ident,
2750+
name_column: Ident,
2751+
unpivot_columns: Vec<Ident>,
2752+
alias: Option<Ident>,
2753+
},
2754+
/// Joins the input table with another table.
2755+
///
2756+
/// Syntax: `|> [JOIN_TYPE] JOIN <table> [alias] ON <condition>` or `|> [JOIN_TYPE] JOIN <table> [alias] USING (<columns>)`
2757+
///
2758+
/// See more at <https://cloud.google.com/bigquery/docs/reference/standard-sql/pipe-syntax#join_pipe_operator>
2759+
Join(Join),
26872760
}
26882761

26892762
impl fmt::Display for PipeOperator {
@@ -2739,7 +2812,87 @@ impl fmt::Display for PipeOperator {
27392812
PipeOperator::TableSample { sample } => {
27402813
write!(f, "{sample}")
27412814
}
2815+
PipeOperator::Rename { mappings } => {
2816+
write!(f, "RENAME {}", display_comma_separated(mappings))
2817+
}
2818+
PipeOperator::Union {
2819+
set_quantifier,
2820+
queries,
2821+
} => Self::fmt_set_operation(f, "UNION", set_quantifier, queries),
2822+
PipeOperator::Intersect {
2823+
set_quantifier,
2824+
queries,
2825+
} => Self::fmt_set_operation(f, "INTERSECT", set_quantifier, queries),
2826+
PipeOperator::Except {
2827+
set_quantifier,
2828+
queries,
2829+
} => Self::fmt_set_operation(f, "EXCEPT", set_quantifier, queries),
2830+
PipeOperator::Call { function, alias } => {
2831+
write!(f, "CALL {function}")?;
2832+
Self::fmt_optional_alias(f, alias)
2833+
}
2834+
PipeOperator::Pivot {
2835+
aggregate_functions,
2836+
value_column,
2837+
value_source,
2838+
alias,
2839+
} => {
2840+
write!(
2841+
f,
2842+
"PIVOT({} FOR {} IN ({}))",
2843+
display_comma_separated(aggregate_functions),
2844+
Expr::CompoundIdentifier(value_column.to_vec()),
2845+
value_source
2846+
)?;
2847+
Self::fmt_optional_alias(f, alias)
2848+
}
2849+
PipeOperator::Unpivot {
2850+
value_column,
2851+
name_column,
2852+
unpivot_columns,
2853+
alias,
2854+
} => {
2855+
write!(
2856+
f,
2857+
"UNPIVOT({} FOR {} IN ({}))",
2858+
value_column,
2859+
name_column,
2860+
display_comma_separated(unpivot_columns)
2861+
)?;
2862+
Self::fmt_optional_alias(f, alias)
2863+
}
2864+
PipeOperator::Join(join) => write!(f, "{join}"),
2865+
}
2866+
}
2867+
}
2868+
2869+
impl PipeOperator {
2870+
/// Helper function to format optional alias for pipe operators
2871+
fn fmt_optional_alias(f: &mut fmt::Formatter<'_>, alias: &Option<Ident>) -> fmt::Result {
2872+
if let Some(alias) = alias {
2873+
write!(f, " AS {alias}")?;
27422874
}
2875+
Ok(())
2876+
}
2877+
2878+
/// Helper function to format set operations (UNION, INTERSECT, EXCEPT) with queries
2879+
fn fmt_set_operation(
2880+
f: &mut fmt::Formatter<'_>,
2881+
operation: &str,
2882+
set_quantifier: &SetQuantifier,
2883+
queries: &[Query],
2884+
) -> fmt::Result {
2885+
write!(f, "{operation}")?;
2886+
match set_quantifier {
2887+
SetQuantifier::None => {}
2888+
_ => {
2889+
write!(f, " {set_quantifier}")?;
2890+
}
2891+
}
2892+
write!(f, " ")?;
2893+
let parenthesized_queries: Vec<String> =
2894+
queries.iter().map(|query| format!("({query})")).collect();
2895+
write!(f, "{}", display_comma_separated(&parenthesized_queries))
27432896
}
27442897
}
27452898

src/ast/spans.rs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -925,6 +925,7 @@ impl Spanned for AlterColumnOperation {
925925
AlterColumnOperation::SetDataType {
926926
data_type: _,
927927
using,
928+
had_set: _,
928929
} => using.as_ref().map_or(Span::empty(), |u| u.span()),
929930
AlterColumnOperation::AddGenerated { .. } => Span::empty(),
930931
}
@@ -1075,7 +1076,10 @@ impl Spanned for CreateTableOptions {
10751076
impl Spanned for AlterTableOperation {
10761077
fn span(&self) -> Span {
10771078
match self {
1078-
AlterTableOperation::AddConstraint(table_constraint) => table_constraint.span(),
1079+
AlterTableOperation::AddConstraint {
1080+
constraint,
1081+
not_valid: _,
1082+
} => constraint.span(),
10791083
AlterTableOperation::AddColumn {
10801084
column_keyword: _,
10811085
if_not_exists: _,
@@ -1196,6 +1200,7 @@ impl Spanned for AlterTableOperation {
11961200
AlterTableOperation::AutoIncrement { value, .. } => value.span(),
11971201
AlterTableOperation::Lock { .. } => Span::empty(),
11981202
AlterTableOperation::ReplicaIdentity { .. } => Span::empty(),
1203+
AlterTableOperation::ValidateConstraint { name } => name.span,
11991204
}
12001205
}
12011206
}
@@ -1411,7 +1416,6 @@ impl Spanned for AssignmentTarget {
14111416
/// f.e. `IS NULL <expr>` reports as `<expr>::span`.
14121417
///
14131418
/// Missing spans:
1414-
/// - [Expr::TypedString] # missing span for data_type
14151419
/// - [Expr::MatchAgainst] # MySQL specific
14161420
/// - [Expr::RLike] # MySQL specific
14171421
/// - [Expr::Struct] # BigQuery specific
@@ -1620,6 +1624,7 @@ impl Spanned for Expr {
16201624
Expr::OuterJoin(expr) => expr.span(),
16211625
Expr::Prior(expr) => expr.span(),
16221626
Expr::Lambda(_) => Span::empty(),
1627+
Expr::MemberOf(member_of) => member_of.value.span().union(&member_of.array.span()),
16231628
}
16241629
}
16251630
}

src/dialect/generic.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,10 @@ impl Dialect for GenericDialect {
5252
true
5353
}
5454

55+
fn supports_left_associative_joins_without_parens(&self) -> bool {
56+
true
57+
}
58+
5559
fn supports_connect_by(&self) -> bool {
5660
true
5761
}
@@ -108,6 +112,10 @@ impl Dialect for GenericDialect {
108112
true
109113
}
110114

115+
fn supports_from_first_select(&self) -> bool {
116+
true
117+
}
118+
111119
fn supports_asc_desc_in_column_definition(&self) -> bool {
112120
true
113121
}

0 commit comments

Comments
 (0)