Skip to content

Commit 2f95334

Browse files
Merge branch 'main' into gin_trgm_ops
2 parents c30853d + cad4923 commit 2f95334

File tree

16 files changed

+692
-203
lines changed

16 files changed

+692
-203
lines changed

src/ast/data_type.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -328,10 +328,15 @@ pub enum DataType {
328328
/// [MySQL]: https://dev.mysql.com/doc/refman/9.1/en/bit-type.html
329329
/// [MSSQL]: https://learn.microsoft.com/en-us/sql/t-sql/data-types/bit-transact-sql?view=sql-server-ver16
330330
Bit(Option<u64>),
331-
/// Variable-length bit string e.g. [Postgres]
331+
/// `BIT VARYING(n)`: Variable-length bit string e.g. [Postgres]
332332
///
333333
/// [Postgres]: https://www.postgresql.org/docs/current/datatype-bit.html
334334
BitVarying(Option<u64>),
335+
/// `VARBIT(n)`: Variable-length bit string. [Postgres] alias for `BIT VARYING`
336+
///
337+
/// [Postgres]: https://www.postgresql.org/docs/current/datatype.html
338+
VarBit(Option<u64>),
339+
///
335340
/// Custom type such as enums
336341
Custom(ObjectName, Vec<String>),
337342
/// Arrays
@@ -550,6 +555,7 @@ impl fmt::Display for DataType {
550555
DataType::BitVarying(size) => {
551556
format_type_with_optional_length(f, "BIT VARYING", size, false)
552557
}
558+
DataType::VarBit(size) => format_type_with_optional_length(f, "VARBIT", size, false),
553559
DataType::Array(ty) => match ty {
554560
ArrayElemTypeDef::None => write!(f, "ARRAY"),
555561
ArrayElemTypeDef::SquareBracket(t, None) => write!(f, "{t}[]"),

src/ast/helpers/stmt_data_loading.rs

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ pub enum DataLoadingOptionType {
5858
STRING,
5959
BOOLEAN,
6060
ENUM,
61+
NUMBER,
6162
}
6263

6364
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
@@ -128,12 +129,9 @@ impl fmt::Display for DataLoadingOption {
128129
DataLoadingOptionType::STRING => {
129130
write!(f, "{}='{}'", self.option_name, self.value)?;
130131
}
131-
DataLoadingOptionType::ENUM => {
132-
// single quote is omitted
133-
write!(f, "{}={}", self.option_name, self.value)?;
134-
}
135-
DataLoadingOptionType::BOOLEAN => {
136-
// single quote is omitted
132+
DataLoadingOptionType::ENUM
133+
| DataLoadingOptionType::BOOLEAN
134+
| DataLoadingOptionType::NUMBER => {
137135
write!(f, "{}={}", self.option_name, self.value)?;
138136
}
139137
}

src/ast/mod.rs

Lines changed: 90 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -2505,24 +2505,30 @@ pub enum Statement {
25052505
values: Vec<Option<String>>,
25062506
},
25072507
/// ```sql
2508-
/// COPY INTO
2508+
/// COPY INTO <table> | <location>
25092509
/// ```
2510-
/// See <https://docs.snowflake.com/en/sql-reference/sql/copy-into-table>
2510+
/// See:
2511+
/// <https://docs.snowflake.com/en/sql-reference/sql/copy-into-table>
2512+
/// <https://docs.snowflake.com/en/sql-reference/sql/copy-into-location>
2513+
///
25112514
/// Copy Into syntax available for Snowflake is different than the one implemented in
25122515
/// Postgres. Although they share common prefix, it is reasonable to implement them
25132516
/// in different enums. This can be refactored later once custom dialects
25142517
/// are allowed to have custom Statements.
25152518
CopyIntoSnowflake {
2519+
kind: CopyIntoSnowflakeKind,
25162520
into: ObjectName,
2517-
from_stage: ObjectName,
2518-
from_stage_alias: Option<Ident>,
2521+
from_obj: Option<ObjectName>,
2522+
from_obj_alias: Option<Ident>,
25192523
stage_params: StageParamsObject,
25202524
from_transformations: Option<Vec<StageLoadSelectItem>>,
2525+
from_query: Option<Box<Query>>,
25212526
files: Option<Vec<String>>,
25222527
pattern: Option<String>,
25232528
file_format: DataLoadingOptions,
25242529
copy_options: DataLoadingOptions,
25252530
validation_mode: Option<String>,
2531+
partition: Option<Box<Expr>>,
25262532
},
25272533
/// ```sql
25282534
/// CLOSE
@@ -3011,6 +3017,12 @@ pub enum Statement {
30113017
show_options: ShowStatementOptions,
30123018
},
30133019
/// ```sql
3020+
/// SHOW OBJECTS LIKE 'line%' IN mydb.public
3021+
/// ```
3022+
/// Snowflake-specific statement
3023+
/// <https://docs.snowflake.com/en/sql-reference/sql/show-objects>
3024+
ShowObjects(ShowObjects),
3025+
/// ```sql
30143026
/// SHOW TABLES
30153027
/// ```
30163028
ShowTables {
@@ -4704,6 +4716,17 @@ impl fmt::Display for Statement {
47044716
)?;
47054717
Ok(())
47064718
}
4719+
Statement::ShowObjects(ShowObjects {
4720+
terse,
4721+
show_options,
4722+
}) => {
4723+
write!(
4724+
f,
4725+
"SHOW {terse}OBJECTS{show_options}",
4726+
terse = if *terse { "TERSE " } else { "" },
4727+
)?;
4728+
Ok(())
4729+
}
47074730
Statement::ShowTables {
47084731
terse,
47094732
history,
@@ -5055,60 +5078,69 @@ impl fmt::Display for Statement {
50555078
Ok(())
50565079
}
50575080
Statement::CopyIntoSnowflake {
5081+
kind,
50585082
into,
5059-
from_stage,
5060-
from_stage_alias,
5083+
from_obj,
5084+
from_obj_alias,
50615085
stage_params,
50625086
from_transformations,
5087+
from_query,
50635088
files,
50645089
pattern,
50655090
file_format,
50665091
copy_options,
50675092
validation_mode,
5093+
partition,
50685094
} => {
50695095
write!(f, "COPY INTO {}", into)?;
5070-
if from_transformations.is_none() {
5071-
// Standard data load
5072-
write!(f, " FROM {}{}", from_stage, stage_params)?;
5073-
if from_stage_alias.as_ref().is_some() {
5074-
write!(f, " AS {}", from_stage_alias.as_ref().unwrap())?;
5075-
}
5076-
} else {
5096+
if let Some(from_transformations) = from_transformations {
50775097
// Data load with transformation
5078-
write!(
5079-
f,
5080-
" FROM (SELECT {} FROM {}{}",
5081-
display_separated(from_transformations.as_ref().unwrap(), ", "),
5082-
from_stage,
5083-
stage_params,
5084-
)?;
5085-
if from_stage_alias.as_ref().is_some() {
5086-
write!(f, " AS {}", from_stage_alias.as_ref().unwrap())?;
5098+
if let Some(from_stage) = from_obj {
5099+
write!(
5100+
f,
5101+
" FROM (SELECT {} FROM {}{}",
5102+
display_separated(from_transformations, ", "),
5103+
from_stage,
5104+
stage_params
5105+
)?;
5106+
}
5107+
if let Some(from_obj_alias) = from_obj_alias {
5108+
write!(f, " AS {}", from_obj_alias)?;
50875109
}
50885110
write!(f, ")")?;
5111+
} else if let Some(from_obj) = from_obj {
5112+
// Standard data load
5113+
write!(f, " FROM {}{}", from_obj, stage_params)?;
5114+
if let Some(from_obj_alias) = from_obj_alias {
5115+
write!(f, " AS {from_obj_alias}")?;
5116+
}
5117+
} else if let Some(from_query) = from_query {
5118+
// Data unload from query
5119+
write!(f, " FROM ({from_query})")?;
50895120
}
5090-
if files.is_some() {
5091-
write!(
5092-
f,
5093-
" FILES = ('{}')",
5094-
display_separated(files.as_ref().unwrap(), "', '")
5095-
)?;
5121+
5122+
if let Some(files) = files {
5123+
write!(f, " FILES = ('{}')", display_separated(files, "', '"))?;
50965124
}
5097-
if pattern.is_some() {
5098-
write!(f, " PATTERN = '{}'", pattern.as_ref().unwrap())?;
5125+
if let Some(pattern) = pattern {
5126+
write!(f, " PATTERN = '{}'", pattern)?;
5127+
}
5128+
if let Some(partition) = partition {
5129+
write!(f, " PARTITION BY {partition}")?;
50995130
}
51005131
if !file_format.options.is_empty() {
51015132
write!(f, " FILE_FORMAT=({})", file_format)?;
51025133
}
51035134
if !copy_options.options.is_empty() {
5104-
write!(f, " COPY_OPTIONS=({})", copy_options)?;
5135+
match kind {
5136+
CopyIntoSnowflakeKind::Table => {
5137+
write!(f, " COPY_OPTIONS=({})", copy_options)?
5138+
}
5139+
CopyIntoSnowflakeKind::Location => write!(f, " {copy_options}")?,
5140+
}
51055141
}
5106-
if validation_mode.is_some() {
5107-
write!(
5108-
f,
5109-
" VALIDATION_MODE = {}",
5110-
validation_mode.as_ref().unwrap()
5111-
)?;
5142+
if let Some(validation_mode) = validation_mode {
5143+
write!(f, " VALIDATION_MODE = {}", validation_mode)?;
51125144
}
51135145
Ok(())
51145146
}
@@ -8335,6 +8367,14 @@ impl fmt::Display for ShowStatementIn {
83358367
}
83368368
}
83378369

8370+
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
8371+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
8372+
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
8373+
pub struct ShowObjects {
8374+
pub terse: bool,
8375+
pub show_options: ShowStatementOptions,
8376+
}
8377+
83388378
/// MSSQL's json null clause
83398379
///
83408380
/// ```plaintext
@@ -8550,6 +8590,19 @@ impl Display for StorageSerializationPolicy {
85508590
}
85518591
}
85528592

8593+
/// Variants of the Snowflake `COPY INTO` statement
8594+
#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
8595+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
8596+
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
8597+
pub enum CopyIntoSnowflakeKind {
8598+
/// Loads data from files to a table
8599+
/// See: <https://docs.snowflake.com/en/sql-reference/sql/copy-into-table>
8600+
Table,
8601+
/// Unloads data from a table or query to external files
8602+
/// See: <https://docs.snowflake.com/en/sql-reference/sql/copy-into-location>
8603+
Location,
8604+
}
8605+
85538606
#[cfg(test)]
85548607
mod tests {
85558608
use super::*;

src/ast/spans.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -333,15 +333,18 @@ impl Spanned for Statement {
333333
} => source.span(),
334334
Statement::CopyIntoSnowflake {
335335
into: _,
336-
from_stage: _,
337-
from_stage_alias: _,
336+
from_obj: _,
337+
from_obj_alias: _,
338338
stage_params: _,
339339
from_transformations: _,
340340
files: _,
341341
pattern: _,
342342
file_format: _,
343343
copy_options: _,
344344
validation_mode: _,
345+
kind: _,
346+
from_query: _,
347+
partition: _,
345348
} => Span::empty(),
346349
Statement::Close { cursor } => match cursor {
347350
CloseCursor::All => Span::empty(),
@@ -493,6 +496,7 @@ impl Spanned for Statement {
493496
Statement::DropConnector { .. } => Span::empty(),
494497
Statement::ShowDatabases { .. } => Span::empty(),
495498
Statement::ShowSchemas { .. } => Span::empty(),
499+
Statement::ShowObjects { .. } => Span::empty(),
496500
Statement::ShowViews { .. } => Span::empty(),
497501
Statement::LISTEN { .. } => Span::empty(),
498502
Statement::NOTIFY { .. } => Span::empty(),

src/dialect/duckdb.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,4 +80,9 @@ impl Dialect for DuckDbDialect {
8080
fn supports_load_extension(&self) -> bool {
8181
true
8282
}
83+
84+
// See DuckDB <https://duckdb.org/docs/sql/data_types/array.html#defining-an-array-field>
85+
fn supports_array_typedef_size(&self) -> bool {
86+
true
87+
}
8388
}

src/dialect/generic.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,4 +143,8 @@ impl Dialect for GenericDialect {
143143
fn supports_string_escape_constant(&self) -> bool {
144144
true
145145
}
146+
147+
fn supports_array_typedef_size(&self) -> bool {
148+
true
149+
}
146150
}

src/dialect/mod.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -881,6 +881,21 @@ pub trait Dialect: Debug + Any {
881881
fn supports_table_hints(&self) -> bool {
882882
false
883883
}
884+
885+
/// Returns true if this dialect requires a whitespace character after `--` to start a single line comment.
886+
///
887+
/// MySQL: <https://dev.mysql.com/doc/refman/8.4/en/ansi-diff-comments.html>
888+
/// e.g. UPDATE account SET balance=balance--1
889+
// WHERE account_id=5752 ^^^ will be interpreted as two minus signs instead of a comment
890+
fn requires_single_line_comment_whitespace(&self) -> bool {
891+
false
892+
}
893+
894+
/// Returns true if the dialect supports size definition for array types.
895+
/// For example: ```CREATE TABLE my_table (my_array INT[3])```.
896+
fn supports_array_typedef_size(&self) -> bool {
897+
false
898+
}
884899
}
885900

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

src/dialect/mysql.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,10 @@ impl Dialect for MySqlDialect {
125125
fn supports_table_hints(&self) -> bool {
126126
true
127127
}
128+
129+
fn requires_single_line_comment_whitespace(&self) -> bool {
130+
true
131+
}
128132
}
129133

130134
/// `LOCK TABLES`

src/dialect/postgresql.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,11 @@ impl Dialect for PostgreSqlDialect {
253253
fn supports_numeric_literal_underscores(&self) -> bool {
254254
true
255255
}
256+
257+
/// See: <https://www.postgresql.org/docs/current/arrays.html#ARRAYS-DECLARATION>
258+
fn supports_array_typedef_size(&self) -> bool {
259+
true
260+
}
256261
}
257262

258263
pub fn parse_create(parser: &mut Parser) -> Option<Result<Statement, ParserError>> {

0 commit comments

Comments
 (0)