mirror of
https://github.com/apache/datafusion-sqlparser-rs.git
synced 2025-07-07 17:04:59 +00:00
Merge remote-tracking branch 'origin/main'
This commit is contained in:
commit
09f85f5c45
30 changed files with 586 additions and 319 deletions
|
@ -63,7 +63,7 @@ $ cargo run --example cli - [--dialectname]
|
|||
};
|
||||
|
||||
let contents = if filename == "-" {
|
||||
println!("Parsing from stdin using {:?}", dialect);
|
||||
println!("Parsing from stdin using {dialect:?}");
|
||||
let mut buf = Vec::new();
|
||||
stdin()
|
||||
.read_to_end(&mut buf)
|
||||
|
|
|
@ -45,25 +45,24 @@ fn basic_queries(c: &mut Criterion) {
|
|||
|
||||
let large_statement = {
|
||||
let expressions = (0..1000)
|
||||
.map(|n| format!("FN_{}(COL_{})", n, n))
|
||||
.map(|n| format!("FN_{n}(COL_{n})"))
|
||||
.collect::<Vec<_>>()
|
||||
.join(", ");
|
||||
let tables = (0..1000)
|
||||
.map(|n| format!("TABLE_{}", n))
|
||||
.map(|n| format!("TABLE_{n}"))
|
||||
.collect::<Vec<_>>()
|
||||
.join(" JOIN ");
|
||||
let where_condition = (0..1000)
|
||||
.map(|n| format!("COL_{} = {}", n, n))
|
||||
.map(|n| format!("COL_{n} = {n}"))
|
||||
.collect::<Vec<_>>()
|
||||
.join(" OR ");
|
||||
let order_condition = (0..1000)
|
||||
.map(|n| format!("COL_{} DESC", n))
|
||||
.map(|n| format!("COL_{n} DESC"))
|
||||
.collect::<Vec<_>>()
|
||||
.join(", ");
|
||||
|
||||
format!(
|
||||
"SELECT {} FROM {} WHERE {} ORDER BY {}",
|
||||
expressions, tables, where_condition, order_condition
|
||||
"SELECT {expressions} FROM {tables} WHERE {where_condition} ORDER BY {order_condition}"
|
||||
)
|
||||
};
|
||||
|
||||
|
|
|
@ -666,7 +666,7 @@ impl fmt::Display for DataType {
|
|||
}
|
||||
DataType::Enum(vals, bits) => {
|
||||
match bits {
|
||||
Some(bits) => write!(f, "ENUM{}", bits),
|
||||
Some(bits) => write!(f, "ENUM{bits}"),
|
||||
None => write!(f, "ENUM"),
|
||||
}?;
|
||||
write!(f, "(")?;
|
||||
|
@ -714,16 +714,16 @@ impl fmt::Display for DataType {
|
|||
}
|
||||
// ClickHouse
|
||||
DataType::Nullable(data_type) => {
|
||||
write!(f, "Nullable({})", data_type)
|
||||
write!(f, "Nullable({data_type})")
|
||||
}
|
||||
DataType::FixedString(character_length) => {
|
||||
write!(f, "FixedString({})", character_length)
|
||||
write!(f, "FixedString({character_length})")
|
||||
}
|
||||
DataType::LowCardinality(data_type) => {
|
||||
write!(f, "LowCardinality({})", data_type)
|
||||
write!(f, "LowCardinality({data_type})")
|
||||
}
|
||||
DataType::Map(key_data_type, value_data_type) => {
|
||||
write!(f, "Map({}, {})", key_data_type, value_data_type)
|
||||
write!(f, "Map({key_data_type}, {value_data_type})")
|
||||
}
|
||||
DataType::Tuple(fields) => {
|
||||
write!(f, "Tuple({})", display_comma_separated(fields))
|
||||
|
@ -745,7 +745,7 @@ impl fmt::Display for DataType {
|
|||
DataType::NamedTable { name, columns } => {
|
||||
write!(f, "{} TABLE ({})", name, display_comma_separated(columns))
|
||||
}
|
||||
DataType::GeometricType(kind) => write!(f, "{}", kind),
|
||||
DataType::GeometricType(kind) => write!(f, "{kind}"),
|
||||
DataType::TsVector => write!(f, "TSVECTOR"),
|
||||
DataType::TsQuery => write!(f, "TSQUERY"),
|
||||
}
|
||||
|
@ -942,7 +942,7 @@ impl fmt::Display for CharacterLength {
|
|||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
CharacterLength::IntegerLength { length, unit } => {
|
||||
write!(f, "{}", length)?;
|
||||
write!(f, "{length}")?;
|
||||
if let Some(unit) = unit {
|
||||
write!(f, " {unit}")?;
|
||||
}
|
||||
|
@ -997,7 +997,7 @@ impl fmt::Display for BinaryLength {
|
|||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
BinaryLength::IntegerLength { length } => {
|
||||
write!(f, "{}", length)?;
|
||||
write!(f, "{length}")?;
|
||||
}
|
||||
BinaryLength::Max => {
|
||||
write!(f, "MAX")?;
|
||||
|
|
|
@ -173,7 +173,7 @@ impl fmt::Display for AlterRoleOperation {
|
|||
in_database,
|
||||
} => {
|
||||
if let Some(database_name) = in_database {
|
||||
write!(f, "IN DATABASE {} ", database_name)?;
|
||||
write!(f, "IN DATABASE {database_name} ")?;
|
||||
}
|
||||
|
||||
match config_value {
|
||||
|
@ -187,7 +187,7 @@ impl fmt::Display for AlterRoleOperation {
|
|||
in_database,
|
||||
} => {
|
||||
if let Some(database_name) = in_database {
|
||||
write!(f, "IN DATABASE {} ", database_name)?;
|
||||
write!(f, "IN DATABASE {database_name} ")?;
|
||||
}
|
||||
|
||||
match config_name {
|
||||
|
@ -218,15 +218,15 @@ impl fmt::Display for Use {
|
|||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.write_str("USE ")?;
|
||||
match self {
|
||||
Use::Catalog(name) => write!(f, "CATALOG {}", name),
|
||||
Use::Schema(name) => write!(f, "SCHEMA {}", name),
|
||||
Use::Database(name) => write!(f, "DATABASE {}", name),
|
||||
Use::Warehouse(name) => write!(f, "WAREHOUSE {}", name),
|
||||
Use::Role(name) => write!(f, "ROLE {}", name),
|
||||
Use::Catalog(name) => write!(f, "CATALOG {name}"),
|
||||
Use::Schema(name) => write!(f, "SCHEMA {name}"),
|
||||
Use::Database(name) => write!(f, "DATABASE {name}"),
|
||||
Use::Warehouse(name) => write!(f, "WAREHOUSE {name}"),
|
||||
Use::Role(name) => write!(f, "ROLE {name}"),
|
||||
Use::SecondaryRoles(secondary_roles) => {
|
||||
write!(f, "SECONDARY ROLES {}", secondary_roles)
|
||||
write!(f, "SECONDARY ROLES {secondary_roles}")
|
||||
}
|
||||
Use::Object(name) => write!(f, "{}", name),
|
||||
Use::Object(name) => write!(f, "{name}"),
|
||||
Use::Default => write!(f, "DEFAULT"),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -57,7 +57,7 @@ impl fmt::Display for ReplicaIdentity {
|
|||
ReplicaIdentity::None => f.write_str("NONE"),
|
||||
ReplicaIdentity::Full => f.write_str("FULL"),
|
||||
ReplicaIdentity::Default => f.write_str("DEFAULT"),
|
||||
ReplicaIdentity::Index(idx) => write!(f, "USING INDEX {}", idx),
|
||||
ReplicaIdentity::Index(idx) => write!(f, "USING INDEX {idx}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -450,7 +450,7 @@ pub enum Owner {
|
|||
impl fmt::Display for Owner {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
Owner::Ident(ident) => write!(f, "{}", ident),
|
||||
Owner::Ident(ident) => write!(f, "{ident}"),
|
||||
Owner::CurrentRole => write!(f, "CURRENT_ROLE"),
|
||||
Owner::CurrentUser => write!(f, "CURRENT_USER"),
|
||||
Owner::SessionUser => write!(f, "SESSION_USER"),
|
||||
|
@ -525,7 +525,7 @@ impl fmt::Display for AlterTableOperation {
|
|||
if *if_not_exists {
|
||||
write!(f, " IF NOT EXISTS")?;
|
||||
}
|
||||
write!(f, " {} ({})", name, query)
|
||||
write!(f, " {name} ({query})")
|
||||
}
|
||||
AlterTableOperation::Algorithm { equals, algorithm } => {
|
||||
write!(
|
||||
|
@ -540,7 +540,7 @@ impl fmt::Display for AlterTableOperation {
|
|||
if *if_exists {
|
||||
write!(f, " IF EXISTS")?;
|
||||
}
|
||||
write!(f, " {}", name)
|
||||
write!(f, " {name}")
|
||||
}
|
||||
AlterTableOperation::MaterializeProjection {
|
||||
if_exists,
|
||||
|
@ -551,9 +551,9 @@ impl fmt::Display for AlterTableOperation {
|
|||
if *if_exists {
|
||||
write!(f, " IF EXISTS")?;
|
||||
}
|
||||
write!(f, " {}", name)?;
|
||||
write!(f, " {name}")?;
|
||||
if let Some(partition) = partition {
|
||||
write!(f, " IN PARTITION {}", partition)?;
|
||||
write!(f, " IN PARTITION {partition}")?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
@ -566,9 +566,9 @@ impl fmt::Display for AlterTableOperation {
|
|||
if *if_exists {
|
||||
write!(f, " IF EXISTS")?;
|
||||
}
|
||||
write!(f, " {}", name)?;
|
||||
write!(f, " {name}")?;
|
||||
if let Some(partition) = partition {
|
||||
write!(f, " IN PARTITION {}", partition)?;
|
||||
write!(f, " IN PARTITION {partition}")?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
@ -1168,7 +1168,7 @@ impl fmt::Display for TableConstraint {
|
|||
write!(f, " ON UPDATE {action}")?;
|
||||
}
|
||||
if let Some(characteristics) = characteristics {
|
||||
write!(f, " {}", characteristics)?;
|
||||
write!(f, " {characteristics}")?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
@ -1308,7 +1308,7 @@ impl fmt::Display for IndexType {
|
|||
Self::SPGiST => write!(f, "SPGIST"),
|
||||
Self::BRIN => write!(f, "BRIN"),
|
||||
Self::Bloom => write!(f, "BLOOM"),
|
||||
Self::Custom(name) => write!(f, "{}", name),
|
||||
Self::Custom(name) => write!(f, "{name}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1426,17 +1426,41 @@ impl fmt::Display for ColumnDef {
|
|||
pub struct ViewColumnDef {
|
||||
pub name: Ident,
|
||||
pub data_type: Option<DataType>,
|
||||
pub options: Option<Vec<ColumnOption>>,
|
||||
pub options: Option<ColumnOptions>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
|
||||
pub enum ColumnOptions {
|
||||
CommaSeparated(Vec<ColumnOption>),
|
||||
SpaceSeparated(Vec<ColumnOption>),
|
||||
}
|
||||
|
||||
impl ColumnOptions {
|
||||
pub fn as_slice(&self) -> &[ColumnOption] {
|
||||
match self {
|
||||
ColumnOptions::CommaSeparated(options) => options.as_slice(),
|
||||
ColumnOptions::SpaceSeparated(options) => options.as_slice(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for ViewColumnDef {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{}", self.name)?;
|
||||
if let Some(data_type) = self.data_type.as_ref() {
|
||||
write!(f, " {}", data_type)?;
|
||||
write!(f, " {data_type}")?;
|
||||
}
|
||||
if let Some(options) = self.options.as_ref() {
|
||||
write!(f, " {}", display_comma_separated(options.as_slice()))?;
|
||||
match options {
|
||||
ColumnOptions::CommaSeparated(column_options) => {
|
||||
write!(f, " {}", display_comma_separated(column_options.as_slice()))?;
|
||||
}
|
||||
ColumnOptions::SpaceSeparated(column_options) => {
|
||||
write!(f, " {}", display_separated(column_options.as_slice(), " "))?
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
@ -1821,7 +1845,7 @@ impl fmt::Display for ColumnOption {
|
|||
} => {
|
||||
write!(f, "{}", if *is_primary { "PRIMARY KEY" } else { "UNIQUE" })?;
|
||||
if let Some(characteristics) = characteristics {
|
||||
write!(f, " {}", characteristics)?;
|
||||
write!(f, " {characteristics}")?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
@ -1843,7 +1867,7 @@ impl fmt::Display for ColumnOption {
|
|||
write!(f, " ON UPDATE {action}")?;
|
||||
}
|
||||
if let Some(characteristics) = characteristics {
|
||||
write!(f, " {}", characteristics)?;
|
||||
write!(f, " {characteristics}")?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
@ -1903,7 +1927,7 @@ impl fmt::Display for ColumnOption {
|
|||
write!(f, "{parameters}")
|
||||
}
|
||||
OnConflict(keyword) => {
|
||||
write!(f, "ON CONFLICT {:?}", keyword)?;
|
||||
write!(f, "ON CONFLICT {keyword:?}")?;
|
||||
Ok(())
|
||||
}
|
||||
Policy(parameters) => {
|
||||
|
|
|
@ -55,7 +55,7 @@ impl Display for IndexColumn {
|
|||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{}", self.column)?;
|
||||
if let Some(operator_class) = &self.operator_class {
|
||||
write!(f, " {}", operator_class)?;
|
||||
write!(f, " {operator_class}")?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
@ -266,7 +266,7 @@ impl Display for CreateTable {
|
|||
name = self.name,
|
||||
)?;
|
||||
if let Some(on_cluster) = &self.on_cluster {
|
||||
write!(f, " ON CLUSTER {}", on_cluster)?;
|
||||
write!(f, " ON CLUSTER {on_cluster}")?;
|
||||
}
|
||||
if !self.columns.is_empty() || !self.constraints.is_empty() {
|
||||
f.write_str(" (")?;
|
||||
|
@ -383,15 +383,15 @@ impl Display for CreateTable {
|
|||
match &self.table_options {
|
||||
options @ CreateTableOptions::With(_)
|
||||
| options @ CreateTableOptions::Plain(_)
|
||||
| options @ CreateTableOptions::TableProperties(_) => write!(f, " {}", options)?,
|
||||
| options @ CreateTableOptions::TableProperties(_) => write!(f, " {options}")?,
|
||||
_ => (),
|
||||
}
|
||||
|
||||
if let Some(primary_key) = &self.primary_key {
|
||||
write!(f, " PRIMARY KEY {}", primary_key)?;
|
||||
write!(f, " PRIMARY KEY {primary_key}")?;
|
||||
}
|
||||
if let Some(order_by) = &self.order_by {
|
||||
write!(f, " ORDER BY {}", order_by)?;
|
||||
write!(f, " ORDER BY {order_by}")?;
|
||||
}
|
||||
if let Some(inherits) = &self.inherits {
|
||||
write!(f, " INHERITS ({})", display_comma_separated(inherits))?;
|
||||
|
@ -403,7 +403,7 @@ impl Display for CreateTable {
|
|||
write!(f, " CLUSTER BY {cluster_by}")?;
|
||||
}
|
||||
if let options @ CreateTableOptions::Options(_) = &self.table_options {
|
||||
write!(f, " {}", options)?;
|
||||
write!(f, " {options}")?;
|
||||
}
|
||||
if let Some(external_volume) = self.external_volume.as_ref() {
|
||||
write!(f, " EXTERNAL_VOLUME = '{external_volume}'")?;
|
||||
|
|
|
@ -67,7 +67,7 @@ impl fmt::Display for KeyValueOptions {
|
|||
} else {
|
||||
f.write_str(" ")?;
|
||||
}
|
||||
write!(f, "{}", option)?;
|
||||
write!(f, "{option}")?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
|
|
192
src/ast/mod.rs
192
src/ast/mod.rs
|
@ -28,6 +28,7 @@ use helpers::{
|
|||
stmt_data_loading::{FileStagingCommand, StageLoadSelectItemKind},
|
||||
};
|
||||
|
||||
use core::cmp::Ordering;
|
||||
use core::ops::Deref;
|
||||
use core::{
|
||||
fmt::{self, Display},
|
||||
|
@ -60,13 +61,14 @@ pub use self::ddl::{
|
|||
AlterColumnOperation, AlterConnectorOwner, AlterIndexOperation, AlterPolicyOperation,
|
||||
AlterTableAlgorithm, AlterTableLock, AlterTableOperation, AlterType, AlterTypeAddValue,
|
||||
AlterTypeAddValuePosition, AlterTypeOperation, AlterTypeRename, AlterTypeRenameValue,
|
||||
ClusteredBy, ColumnDef, ColumnOption, ColumnOptionDef, ColumnPolicy, ColumnPolicyProperty,
|
||||
ConstraintCharacteristics, CreateConnector, CreateDomain, CreateFunction, Deduplicate,
|
||||
DeferrableInitial, DropBehavior, GeneratedAs, GeneratedExpressionMode, IdentityParameters,
|
||||
IdentityProperty, IdentityPropertyFormatKind, IdentityPropertyKind, IdentityPropertyOrder,
|
||||
IndexOption, IndexType, KeyOrIndexDisplay, NullsDistinctOption, Owner, Partition,
|
||||
ProcedureParam, ReferentialAction, ReplicaIdentity, TableConstraint, TagsColumnOption,
|
||||
UserDefinedTypeCompositeAttributeDef, UserDefinedTypeRepresentation, ViewColumnDef,
|
||||
ClusteredBy, ColumnDef, ColumnOption, ColumnOptionDef, ColumnOptions, ColumnPolicy,
|
||||
ColumnPolicyProperty, ConstraintCharacteristics, CreateConnector, CreateDomain, CreateFunction,
|
||||
Deduplicate, DeferrableInitial, DropBehavior, GeneratedAs, GeneratedExpressionMode,
|
||||
IdentityParameters, IdentityProperty, IdentityPropertyFormatKind, IdentityPropertyKind,
|
||||
IdentityPropertyOrder, IndexOption, IndexType, KeyOrIndexDisplay, NullsDistinctOption, Owner,
|
||||
Partition, ProcedureParam, ReferentialAction, ReplicaIdentity, TableConstraint,
|
||||
TagsColumnOption, UserDefinedTypeCompositeAttributeDef, UserDefinedTypeRepresentation,
|
||||
ViewColumnDef,
|
||||
};
|
||||
pub use self::dml::{CreateIndex, CreateTable, Delete, IndexColumn, Insert};
|
||||
pub use self::operator::{BinaryOperator, UnaryOperator};
|
||||
|
@ -172,7 +174,7 @@ fn format_statement_list(f: &mut fmt::Formatter, statements: &[Statement]) -> fm
|
|||
}
|
||||
|
||||
/// An identifier, decomposed into its value or character data and the quote style.
|
||||
#[derive(Debug, Clone, PartialOrd, Ord)]
|
||||
#[derive(Debug, Clone)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
|
||||
pub struct Ident {
|
||||
|
@ -214,6 +216,35 @@ impl core::hash::Hash for Ident {
|
|||
|
||||
impl Eq for Ident {}
|
||||
|
||||
impl PartialOrd for Ident {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
|
||||
impl Ord for Ident {
|
||||
fn cmp(&self, other: &Self) -> Ordering {
|
||||
let Ident {
|
||||
value,
|
||||
quote_style,
|
||||
// exhaustiveness check; we ignore spans in ordering
|
||||
span: _,
|
||||
} = self;
|
||||
|
||||
let Ident {
|
||||
value: other_value,
|
||||
quote_style: other_quote_style,
|
||||
// exhaustiveness check; we ignore spans in ordering
|
||||
span: _,
|
||||
} = other;
|
||||
|
||||
// First compare by value, then by quote_style
|
||||
value
|
||||
.cmp(other_value)
|
||||
.then_with(|| quote_style.cmp(other_quote_style))
|
||||
}
|
||||
}
|
||||
|
||||
impl Ident {
|
||||
/// Create a new identifier with the given value and no quotes and an empty span.
|
||||
pub fn new<S>(value: S) -> Self
|
||||
|
@ -326,7 +357,7 @@ impl ObjectNamePart {
|
|||
impl fmt::Display for ObjectNamePart {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
ObjectNamePart::Identifier(ident) => write!(f, "{}", ident),
|
||||
ObjectNamePart::Identifier(ident) => write!(f, "{ident}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1179,8 +1210,8 @@ pub enum AccessExpr {
|
|||
impl fmt::Display for AccessExpr {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
AccessExpr::Dot(expr) => write!(f, ".{}", expr),
|
||||
AccessExpr::Subscript(subscript) => write!(f, "[{}]", subscript),
|
||||
AccessExpr::Dot(expr) => write!(f, ".{expr}"),
|
||||
AccessExpr::Subscript(subscript) => write!(f, "[{subscript}]"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1382,12 +1413,12 @@ impl fmt::Display for Expr {
|
|||
match self {
|
||||
Expr::Identifier(s) => write!(f, "{s}"),
|
||||
Expr::Wildcard(_) => f.write_str("*"),
|
||||
Expr::QualifiedWildcard(prefix, _) => write!(f, "{}.*", prefix),
|
||||
Expr::QualifiedWildcard(prefix, _) => write!(f, "{prefix}.*"),
|
||||
Expr::CompoundIdentifier(s) => write!(f, "{}", display_separated(s, ".")),
|
||||
Expr::CompoundFieldAccess { root, access_chain } => {
|
||||
write!(f, "{}", root)?;
|
||||
write!(f, "{root}")?;
|
||||
for field in access_chain {
|
||||
write!(f, "{}", field)?;
|
||||
write!(f, "{field}")?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
@ -1516,7 +1547,7 @@ impl fmt::Display for Expr {
|
|||
} => {
|
||||
let not_ = if *negated { "NOT " } else { "" };
|
||||
if form.is_none() {
|
||||
write!(f, "{} IS {}NORMALIZED", expr, not_)
|
||||
write!(f, "{expr} IS {not_}NORMALIZED")
|
||||
} else {
|
||||
write!(
|
||||
f,
|
||||
|
@ -1838,7 +1869,7 @@ impl fmt::Display for Expr {
|
|||
}
|
||||
}
|
||||
Expr::Named { expr, name } => {
|
||||
write!(f, "{} AS {}", expr, name)
|
||||
write!(f, "{expr} AS {name}")
|
||||
}
|
||||
Expr::Dictionary(fields) => {
|
||||
write!(f, "{{{}}}", display_comma_separated(fields))
|
||||
|
@ -2394,7 +2425,7 @@ impl fmt::Display for ConditionalStatements {
|
|||
}
|
||||
Ok(())
|
||||
}
|
||||
ConditionalStatements::BeginEnd(bes) => write!(f, "{}", bes),
|
||||
ConditionalStatements::BeginEnd(bes) => write!(f, "{bes}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2914,9 +2945,7 @@ impl Display for Set {
|
|||
write!(
|
||||
f,
|
||||
"SET {modifier}ROLE {role_name}",
|
||||
modifier = context_modifier
|
||||
.map(|m| format!("{}", m))
|
||||
.unwrap_or_default()
|
||||
modifier = context_modifier.map(|m| format!("{m}")).unwrap_or_default()
|
||||
)
|
||||
}
|
||||
Self::SetSessionParam(kind) => write!(f, "SET {kind}"),
|
||||
|
@ -2949,7 +2978,7 @@ impl Display for Set {
|
|||
charset_name,
|
||||
collation_name,
|
||||
} => {
|
||||
write!(f, "SET NAMES {}", charset_name)?;
|
||||
write!(f, "SET NAMES {charset_name}")?;
|
||||
|
||||
if let Some(collation) = collation_name {
|
||||
f.write_str(" COLLATE ")?;
|
||||
|
@ -2972,7 +3001,7 @@ impl Display for Set {
|
|||
write!(
|
||||
f,
|
||||
"SET {}{}{} = {}",
|
||||
scope.map(|s| format!("{}", s)).unwrap_or_default(),
|
||||
scope.map(|s| format!("{s}")).unwrap_or_default(),
|
||||
if *hivevar { "HIVEVAR:" } else { "" },
|
||||
variable,
|
||||
display_comma_separated(values)
|
||||
|
@ -3914,6 +3943,7 @@ pub enum Statement {
|
|||
or_alter: bool,
|
||||
name: ObjectName,
|
||||
params: Option<Vec<ProcedureParam>>,
|
||||
language: Option<Ident>,
|
||||
body: ConditionalStatements,
|
||||
},
|
||||
/// ```sql
|
||||
|
@ -4214,7 +4244,7 @@ pub enum Statement {
|
|||
/// ```sql
|
||||
/// NOTIFY channel [ , payload ]
|
||||
/// ```
|
||||
/// send a notification event together with an optional “payload” string to channel
|
||||
/// send a notification event together with an optional "payload" string to channel
|
||||
///
|
||||
/// See Postgres <https://www.postgresql.org/docs/current/sql-notify.html>
|
||||
NOTIFY {
|
||||
|
@ -4373,7 +4403,7 @@ impl fmt::Display for Statement {
|
|||
write!(f, "{describe_alias} ")?;
|
||||
|
||||
if let Some(format) = hive_format {
|
||||
write!(f, "{} ", format)?;
|
||||
write!(f, "{format} ")?;
|
||||
}
|
||||
if *has_table_keyword {
|
||||
write!(f, "TABLE ")?;
|
||||
|
@ -4817,6 +4847,7 @@ impl fmt::Display for Statement {
|
|||
name,
|
||||
or_alter,
|
||||
params,
|
||||
language,
|
||||
body,
|
||||
} => {
|
||||
write!(
|
||||
|
@ -4832,6 +4863,10 @@ impl fmt::Display for Statement {
|
|||
}
|
||||
}
|
||||
|
||||
if let Some(language) = language {
|
||||
write!(f, " LANGUAGE {language}")?;
|
||||
}
|
||||
|
||||
write!(f, " AS {body}")
|
||||
}
|
||||
Statement::CreateMacro {
|
||||
|
@ -5204,7 +5239,7 @@ impl fmt::Display for Statement {
|
|||
if *only {
|
||||
write!(f, "ONLY ")?;
|
||||
}
|
||||
write!(f, "{name} ", name = name)?;
|
||||
write!(f, "{name} ")?;
|
||||
if let Some(cluster) = on_cluster {
|
||||
write!(f, "ON CLUSTER {cluster} ")?;
|
||||
}
|
||||
|
@ -5282,7 +5317,7 @@ impl fmt::Display for Statement {
|
|||
)?;
|
||||
if !session_params.options.is_empty() {
|
||||
if *set {
|
||||
write!(f, " {}", session_params)?;
|
||||
write!(f, " {session_params}")?;
|
||||
} else {
|
||||
let options = session_params
|
||||
.options
|
||||
|
@ -5316,7 +5351,7 @@ impl fmt::Display for Statement {
|
|||
if *purge { " PURGE" } else { "" },
|
||||
)?;
|
||||
if let Some(table_name) = table.as_ref() {
|
||||
write!(f, " ON {}", table_name)?;
|
||||
write!(f, " ON {table_name}")?;
|
||||
};
|
||||
Ok(())
|
||||
}
|
||||
|
@ -5571,7 +5606,7 @@ impl fmt::Display for Statement {
|
|||
} => {
|
||||
if *syntax_begin {
|
||||
if let Some(modifier) = *modifier {
|
||||
write!(f, "BEGIN {}", modifier)?;
|
||||
write!(f, "BEGIN {modifier}")?;
|
||||
} else {
|
||||
write!(f, "BEGIN")?;
|
||||
}
|
||||
|
@ -5607,7 +5642,7 @@ impl fmt::Display for Statement {
|
|||
if *end_syntax {
|
||||
write!(f, "END")?;
|
||||
if let Some(modifier) = *modifier {
|
||||
write!(f, " {}", modifier)?;
|
||||
write!(f, " {modifier}")?;
|
||||
}
|
||||
if *chain {
|
||||
write!(f, " AND CHAIN")?;
|
||||
|
@ -5706,7 +5741,7 @@ impl fmt::Display for Statement {
|
|||
write!(f, " GRANTED BY {grantor}")?;
|
||||
}
|
||||
if let Some(cascade) = cascade {
|
||||
write!(f, " {}", cascade)?;
|
||||
write!(f, " {cascade}")?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
@ -5885,13 +5920,13 @@ impl fmt::Display for Statement {
|
|||
if_not_exists = if *if_not_exists { "IF NOT EXISTS " } else { "" },
|
||||
)?;
|
||||
if !directory_table_params.options.is_empty() {
|
||||
write!(f, " DIRECTORY=({})", directory_table_params)?;
|
||||
write!(f, " DIRECTORY=({directory_table_params})")?;
|
||||
}
|
||||
if !file_format.options.is_empty() {
|
||||
write!(f, " FILE_FORMAT=({})", file_format)?;
|
||||
write!(f, " FILE_FORMAT=({file_format})")?;
|
||||
}
|
||||
if !copy_options.options.is_empty() {
|
||||
write!(f, " COPY_OPTIONS=({})", copy_options)?;
|
||||
write!(f, " COPY_OPTIONS=({copy_options})")?;
|
||||
}
|
||||
if comment.is_some() {
|
||||
write!(f, " COMMENT='{}'", comment.as_ref().unwrap())?;
|
||||
|
@ -5914,7 +5949,7 @@ impl fmt::Display for Statement {
|
|||
validation_mode,
|
||||
partition,
|
||||
} => {
|
||||
write!(f, "COPY INTO {}", into)?;
|
||||
write!(f, "COPY INTO {into}")?;
|
||||
if let Some(into_columns) = into_columns {
|
||||
write!(f, " ({})", display_comma_separated(into_columns))?;
|
||||
}
|
||||
|
@ -5930,12 +5965,12 @@ impl fmt::Display for Statement {
|
|||
)?;
|
||||
}
|
||||
if let Some(from_obj_alias) = from_obj_alias {
|
||||
write!(f, " AS {}", from_obj_alias)?;
|
||||
write!(f, " AS {from_obj_alias}")?;
|
||||
}
|
||||
write!(f, ")")?;
|
||||
} else if let Some(from_obj) = from_obj {
|
||||
// Standard data load
|
||||
write!(f, " FROM {}{}", from_obj, stage_params)?;
|
||||
write!(f, " FROM {from_obj}{stage_params}")?;
|
||||
if let Some(from_obj_alias) = from_obj_alias {
|
||||
write!(f, " AS {from_obj_alias}")?;
|
||||
}
|
||||
|
@ -5948,24 +5983,24 @@ impl fmt::Display for Statement {
|
|||
write!(f, " FILES = ('{}')", display_separated(files, "', '"))?;
|
||||
}
|
||||
if let Some(pattern) = pattern {
|
||||
write!(f, " PATTERN = '{}'", pattern)?;
|
||||
write!(f, " PATTERN = '{pattern}'")?;
|
||||
}
|
||||
if let Some(partition) = partition {
|
||||
write!(f, " PARTITION BY {partition}")?;
|
||||
}
|
||||
if !file_format.options.is_empty() {
|
||||
write!(f, " FILE_FORMAT=({})", file_format)?;
|
||||
write!(f, " FILE_FORMAT=({file_format})")?;
|
||||
}
|
||||
if !copy_options.options.is_empty() {
|
||||
match kind {
|
||||
CopyIntoSnowflakeKind::Table => {
|
||||
write!(f, " COPY_OPTIONS=({})", copy_options)?
|
||||
write!(f, " COPY_OPTIONS=({copy_options})")?
|
||||
}
|
||||
CopyIntoSnowflakeKind::Location => write!(f, " {copy_options}")?,
|
||||
}
|
||||
}
|
||||
if let Some(validation_mode) = validation_mode {
|
||||
write!(f, " VALIDATION_MODE = {}", validation_mode)?;
|
||||
write!(f, " VALIDATION_MODE = {validation_mode}")?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
@ -6011,10 +6046,10 @@ impl fmt::Display for Statement {
|
|||
} => {
|
||||
write!(f, "OPTIMIZE TABLE {name}")?;
|
||||
if let Some(on_cluster) = on_cluster {
|
||||
write!(f, " ON CLUSTER {on_cluster}", on_cluster = on_cluster)?;
|
||||
write!(f, " ON CLUSTER {on_cluster}")?;
|
||||
}
|
||||
if let Some(partition) = partition {
|
||||
write!(f, " {partition}", partition = partition)?;
|
||||
write!(f, " {partition}")?;
|
||||
}
|
||||
if *include_final {
|
||||
write!(f, " FINAL")?;
|
||||
|
@ -6141,7 +6176,7 @@ impl fmt::Display for SetAssignment {
|
|||
write!(
|
||||
f,
|
||||
"{}{} = {}",
|
||||
self.scope.map(|s| format!("{}", s)).unwrap_or_default(),
|
||||
self.scope.map(|s| format!("{s}")).unwrap_or_default(),
|
||||
self.name,
|
||||
self.value
|
||||
)
|
||||
|
@ -6870,7 +6905,7 @@ impl fmt::Display for GranteeName {
|
|||
match self {
|
||||
GranteeName::ObjectName(name) => name.fmt(f),
|
||||
GranteeName::UserHost { user, host } => {
|
||||
write!(f, "{}@{}", user, host)
|
||||
write!(f, "{user}@{host}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6885,6 +6920,12 @@ pub enum GrantObjects {
|
|||
AllSequencesInSchema { schemas: Vec<ObjectName> },
|
||||
/// Grant privileges on `ALL TABLES IN SCHEMA <schema_name> [, ...]`
|
||||
AllTablesInSchema { schemas: Vec<ObjectName> },
|
||||
/// Grant privileges on `FUTURE SCHEMAS IN DATABASE <database_name> [, ...]`
|
||||
FutureSchemasInDatabase { databases: Vec<ObjectName> },
|
||||
/// Grant privileges on `FUTURE TABLES IN SCHEMA <schema_name> [, ...]`
|
||||
FutureTablesInSchema { schemas: Vec<ObjectName> },
|
||||
/// Grant privileges on `FUTURE VIEWS IN SCHEMA <schema_name> [, ...]`
|
||||
FutureViewsInSchema { schemas: Vec<ObjectName> },
|
||||
/// Grant privileges on specific databases
|
||||
Databases(Vec<ObjectName>),
|
||||
/// Grant privileges on specific schemas
|
||||
|
@ -6953,6 +6994,27 @@ impl fmt::Display for GrantObjects {
|
|||
display_comma_separated(schemas)
|
||||
)
|
||||
}
|
||||
GrantObjects::FutureSchemasInDatabase { databases } => {
|
||||
write!(
|
||||
f,
|
||||
"FUTURE SCHEMAS IN DATABASE {}",
|
||||
display_comma_separated(databases)
|
||||
)
|
||||
}
|
||||
GrantObjects::FutureTablesInSchema { schemas } => {
|
||||
write!(
|
||||
f,
|
||||
"FUTURE TABLES IN SCHEMA {}",
|
||||
display_comma_separated(schemas)
|
||||
)
|
||||
}
|
||||
GrantObjects::FutureViewsInSchema { schemas } => {
|
||||
write!(
|
||||
f,
|
||||
"FUTURE VIEWS IN SCHEMA {}",
|
||||
display_comma_separated(schemas)
|
||||
)
|
||||
}
|
||||
GrantObjects::ResourceMonitors(objects) => {
|
||||
write!(f, "RESOURCE MONITOR {}", display_comma_separated(objects))
|
||||
}
|
||||
|
@ -7040,7 +7102,7 @@ pub enum AssignmentTarget {
|
|||
impl fmt::Display for AssignmentTarget {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
AssignmentTarget::ColumnName(column) => write!(f, "{}", column),
|
||||
AssignmentTarget::ColumnName(column) => write!(f, "{column}"),
|
||||
AssignmentTarget::Tuple(columns) => write!(f, "({})", display_comma_separated(columns)),
|
||||
}
|
||||
}
|
||||
|
@ -7285,8 +7347,8 @@ impl fmt::Display for FunctionArguments {
|
|||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
FunctionArguments::None => Ok(()),
|
||||
FunctionArguments::Subquery(query) => write!(f, "({})", query),
|
||||
FunctionArguments::List(args) => write!(f, "({})", args),
|
||||
FunctionArguments::Subquery(query) => write!(f, "({query})"),
|
||||
FunctionArguments::List(args) => write!(f, "({args})"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -7307,7 +7369,7 @@ pub struct FunctionArgumentList {
|
|||
impl fmt::Display for FunctionArgumentList {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
if let Some(duplicate_treatment) = self.duplicate_treatment {
|
||||
write!(f, "{} ", duplicate_treatment)?;
|
||||
write!(f, "{duplicate_treatment} ")?;
|
||||
}
|
||||
write!(f, "{}", display_comma_separated(&self.args))?;
|
||||
if !self.clauses.is_empty() {
|
||||
|
@ -7367,7 +7429,7 @@ impl fmt::Display for FunctionArgumentClause {
|
|||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
FunctionArgumentClause::IgnoreOrRespectNulls(null_treatment) => {
|
||||
write!(f, "{}", null_treatment)
|
||||
write!(f, "{null_treatment}")
|
||||
}
|
||||
FunctionArgumentClause::OrderBy(order_by) => {
|
||||
write!(f, "ORDER BY {}", display_comma_separated(order_by))
|
||||
|
@ -7823,12 +7885,12 @@ pub enum SqlOption {
|
|||
impl fmt::Display for SqlOption {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
SqlOption::Clustered(c) => write!(f, "{}", c),
|
||||
SqlOption::Clustered(c) => write!(f, "{c}"),
|
||||
SqlOption::Ident(ident) => {
|
||||
write!(f, "{}", ident)
|
||||
write!(f, "{ident}")
|
||||
}
|
||||
SqlOption::KeyValue { key: name, value } => {
|
||||
write!(f, "{} = {}", name, value)
|
||||
write!(f, "{name} = {value}")
|
||||
}
|
||||
SqlOption::Partition {
|
||||
column_name,
|
||||
|
@ -7868,7 +7930,7 @@ impl fmt::Display for SqlOption {
|
|||
SqlOption::NamedParenthesizedList(value) => {
|
||||
write!(f, "{} = ", value.key)?;
|
||||
if let Some(key) = &value.name {
|
||||
write!(f, "{}", key)?;
|
||||
write!(f, "{key}")?;
|
||||
}
|
||||
if !value.values.is_empty() {
|
||||
write!(f, "({})", display_comma_separated(&value.values))?
|
||||
|
@ -7925,7 +7987,7 @@ impl fmt::Display for AttachDuckDBDatabaseOption {
|
|||
AttachDuckDBDatabaseOption::ReadOnly(Some(true)) => write!(f, "READ_ONLY true"),
|
||||
AttachDuckDBDatabaseOption::ReadOnly(Some(false)) => write!(f, "READ_ONLY false"),
|
||||
AttachDuckDBDatabaseOption::ReadOnly(None) => write!(f, "READ_ONLY"),
|
||||
AttachDuckDBDatabaseOption::Type(t) => write!(f, "TYPE {}", t),
|
||||
AttachDuckDBDatabaseOption::Type(t) => write!(f, "TYPE {t}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -9448,10 +9510,10 @@ impl fmt::Display for ShowStatementIn {
|
|||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{}", self.clause)?;
|
||||
if let Some(parent_type) = &self.parent_type {
|
||||
write!(f, " {}", parent_type)?;
|
||||
write!(f, " {parent_type}")?;
|
||||
}
|
||||
if let Some(parent_name) = &self.parent_name {
|
||||
write!(f, " {}", parent_name)?;
|
||||
write!(f, " {parent_name}")?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
@ -9532,7 +9594,7 @@ impl fmt::Display for TableObject {
|
|||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
Self::TableName(table_name) => write!(f, "{table_name}"),
|
||||
Self::TableFunction(func) => write!(f, "FUNCTION {}", func),
|
||||
Self::TableFunction(func) => write!(f, "FUNCTION {func}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -9720,7 +9782,7 @@ pub struct ReturnStatement {
|
|||
impl fmt::Display for ReturnStatement {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match &self.value {
|
||||
Some(ReturnStatementValue::Expr(expr)) => write!(f, "RETURN {}", expr),
|
||||
Some(ReturnStatementValue::Expr(expr)) => write!(f, "RETURN {expr}"),
|
||||
None => write!(f, "RETURN"),
|
||||
}
|
||||
}
|
||||
|
@ -9771,6 +9833,8 @@ impl fmt::Display for NullInclusion {
|
|||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::tokenizer::Location;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
|
@ -10066,4 +10130,16 @@ mod tests {
|
|||
test_steps(OneOrManyWithParens::Many(vec![2]), vec![2], 3);
|
||||
test_steps(OneOrManyWithParens::Many(vec![3, 4]), vec![3, 4], 4);
|
||||
}
|
||||
|
||||
// Tests that the position in the code of an `Ident` does not affect its
|
||||
// ordering.
|
||||
#[test]
|
||||
fn test_ident_ord() {
|
||||
let mut a = Ident::with_span(Span::new(Location::new(1, 1), Location::new(1, 1)), "a");
|
||||
let mut b = Ident::with_span(Span::new(Location::new(2, 2), Location::new(2, 2)), "b");
|
||||
|
||||
assert!(a < b);
|
||||
std::mem::swap(&mut a.span, &mut b.span);
|
||||
assert!(a < b);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1047,7 +1047,7 @@ impl fmt::Display for ConnectBy {
|
|||
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
|
||||
pub struct Setting {
|
||||
pub key: Ident,
|
||||
pub value: Value,
|
||||
pub value: Expr,
|
||||
}
|
||||
|
||||
impl fmt::Display for Setting {
|
||||
|
@ -1183,7 +1183,7 @@ impl fmt::Display for TableIndexHints {
|
|||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{} {} ", self.hint_type, self.index_type)?;
|
||||
if let Some(for_clause) = &self.for_clause {
|
||||
write!(f, "FOR {} ", for_clause)?;
|
||||
write!(f, "FOR {for_clause} ")?;
|
||||
}
|
||||
write!(f, "({})", display_comma_separated(&self.index_names))
|
||||
}
|
||||
|
@ -1459,7 +1459,7 @@ impl fmt::Display for TableSampleQuantity {
|
|||
}
|
||||
write!(f, "{}", self.value)?;
|
||||
if let Some(unit) = &self.unit {
|
||||
write!(f, " {}", unit)?;
|
||||
write!(f, " {unit}")?;
|
||||
}
|
||||
if self.parenthesized {
|
||||
write!(f, ")")?;
|
||||
|
@ -1552,7 +1552,7 @@ impl fmt::Display for TableSampleBucket {
|
|||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "BUCKET {} OUT OF {}", self.bucket, self.total)?;
|
||||
if let Some(on) = &self.on {
|
||||
write!(f, " ON {}", on)?;
|
||||
write!(f, " ON {on}")?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
@ -1561,19 +1561,19 @@ impl fmt::Display for TableSample {
|
|||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{}", self.modifier)?;
|
||||
if let Some(name) = &self.name {
|
||||
write!(f, " {}", name)?;
|
||||
write!(f, " {name}")?;
|
||||
}
|
||||
if let Some(quantity) = &self.quantity {
|
||||
write!(f, " {}", quantity)?;
|
||||
write!(f, " {quantity}")?;
|
||||
}
|
||||
if let Some(seed) = &self.seed {
|
||||
write!(f, " {}", seed)?;
|
||||
write!(f, " {seed}")?;
|
||||
}
|
||||
if let Some(bucket) = &self.bucket {
|
||||
write!(f, " ({})", bucket)?;
|
||||
write!(f, " ({bucket})")?;
|
||||
}
|
||||
if let Some(offset) = &self.offset {
|
||||
write!(f, " OFFSET {}", offset)?;
|
||||
write!(f, " OFFSET {offset}")?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
@ -1651,7 +1651,7 @@ impl fmt::Display for RowsPerMatch {
|
|||
RowsPerMatch::AllRows(mode) => {
|
||||
write!(f, "ALL ROWS PER MATCH")?;
|
||||
if let Some(mode) = mode {
|
||||
write!(f, " {}", mode)?;
|
||||
write!(f, " {mode}")?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
@ -1777,7 +1777,7 @@ impl fmt::Display for MatchRecognizePattern {
|
|||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
use MatchRecognizePattern::*;
|
||||
match self {
|
||||
Symbol(symbol) => write!(f, "{}", symbol),
|
||||
Symbol(symbol) => write!(f, "{symbol}"),
|
||||
Exclude(symbol) => write!(f, "{{- {symbol} -}}"),
|
||||
Permute(symbols) => write!(f, "PERMUTE({})", display_comma_separated(symbols)),
|
||||
Concat(patterns) => write!(f, "{}", display_separated(patterns, " ")),
|
||||
|
@ -2148,7 +2148,7 @@ impl fmt::Display for TableAliasColumnDef {
|
|||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{}", self.name)?;
|
||||
if let Some(ref data_type) = self.data_type {
|
||||
write!(f, " {}", data_type)?;
|
||||
write!(f, " {data_type}")?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
@ -2398,7 +2398,7 @@ impl fmt::Display for OrderBy {
|
|||
write!(f, " {}", display_comma_separated(exprs))?;
|
||||
}
|
||||
OrderByKind::All(all) => {
|
||||
write!(f, " ALL{}", all)?;
|
||||
write!(f, " ALL{all}")?;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2429,7 +2429,7 @@ impl fmt::Display for OrderByExpr {
|
|||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{}{}", self.expr, self.options)?;
|
||||
if let Some(ref with_fill) = self.with_fill {
|
||||
write!(f, " {}", with_fill)?
|
||||
write!(f, " {with_fill}")?
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
@ -2452,13 +2452,13 @@ impl fmt::Display for WithFill {
|
|||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "WITH FILL")?;
|
||||
if let Some(ref from) = self.from {
|
||||
write!(f, " FROM {}", from)?;
|
||||
write!(f, " FROM {from}")?;
|
||||
}
|
||||
if let Some(ref to) = self.to {
|
||||
write!(f, " TO {}", to)?;
|
||||
write!(f, " TO {to}")?;
|
||||
}
|
||||
if let Some(ref step) = self.step {
|
||||
write!(f, " STEP {}", step)?;
|
||||
write!(f, " STEP {step}")?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
@ -2487,7 +2487,7 @@ impl fmt::Display for InterpolateExpr {
|
|||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{}", self.column)?;
|
||||
if let Some(ref expr) = self.expr {
|
||||
write!(f, " AS {}", expr)?;
|
||||
write!(f, " AS {expr}")?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
@ -2565,7 +2565,7 @@ impl fmt::Display for LimitClause {
|
|||
Ok(())
|
||||
}
|
||||
LimitClause::OffsetCommaLimit { offset, limit } => {
|
||||
write!(f, " LIMIT {}, {}", offset, limit)
|
||||
write!(f, " LIMIT {offset}, {limit}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2702,12 +2702,12 @@ impl fmt::Display for PipeOperator {
|
|||
write!(f, "DROP {}", display_comma_separated(columns.as_slice()))
|
||||
}
|
||||
PipeOperator::As { alias } => {
|
||||
write!(f, "AS {}", alias)
|
||||
write!(f, "AS {alias}")
|
||||
}
|
||||
PipeOperator::Limit { expr, offset } => {
|
||||
write!(f, "LIMIT {}", expr)?;
|
||||
write!(f, "LIMIT {expr}")?;
|
||||
if let Some(offset) = offset {
|
||||
write!(f, " OFFSET {}", offset)?;
|
||||
write!(f, " OFFSET {offset}")?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
@ -2730,14 +2730,14 @@ impl fmt::Display for PipeOperator {
|
|||
}
|
||||
|
||||
PipeOperator::Where { expr } => {
|
||||
write!(f, "WHERE {}", expr)
|
||||
write!(f, "WHERE {expr}")
|
||||
}
|
||||
PipeOperator::OrderBy { exprs } => {
|
||||
write!(f, "ORDER BY {}", display_comma_separated(exprs.as_slice()))
|
||||
}
|
||||
|
||||
PipeOperator::TableSample { sample } => {
|
||||
write!(f, "{}", sample)
|
||||
write!(f, "{sample}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3016,7 +3016,7 @@ pub enum FormatClause {
|
|||
impl fmt::Display for FormatClause {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
FormatClause::Identifier(ident) => write!(f, "FORMAT {}", ident),
|
||||
FormatClause::Identifier(ident) => write!(f, "FORMAT {ident}"),
|
||||
FormatClause::Null => write!(f, "FORMAT NULL"),
|
||||
}
|
||||
}
|
||||
|
@ -3078,9 +3078,9 @@ impl fmt::Display for ForClause {
|
|||
without_array_wrapper,
|
||||
} => {
|
||||
write!(f, "FOR JSON ")?;
|
||||
write!(f, "{}", for_json)?;
|
||||
write!(f, "{for_json}")?;
|
||||
if let Some(root) = root {
|
||||
write!(f, ", ROOT('{}')", root)?;
|
||||
write!(f, ", ROOT('{root}')")?;
|
||||
}
|
||||
if *include_null_values {
|
||||
write!(f, ", INCLUDE_NULL_VALUES")?;
|
||||
|
@ -3098,7 +3098,7 @@ impl fmt::Display for ForClause {
|
|||
r#type,
|
||||
} => {
|
||||
write!(f, "FOR XML ")?;
|
||||
write!(f, "{}", for_xml)?;
|
||||
write!(f, "{for_xml}")?;
|
||||
if *binary_base64 {
|
||||
write!(f, ", BINARY BASE64")?;
|
||||
}
|
||||
|
@ -3106,7 +3106,7 @@ impl fmt::Display for ForClause {
|
|||
write!(f, ", TYPE")?;
|
||||
}
|
||||
if let Some(root) = root {
|
||||
write!(f, ", ROOT('{}')", root)?;
|
||||
write!(f, ", ROOT('{root}')")?;
|
||||
}
|
||||
if *elements {
|
||||
write!(f, ", ELEMENTS")?;
|
||||
|
@ -3133,7 +3133,7 @@ impl fmt::Display for ForXml {
|
|||
ForXml::Raw(root) => {
|
||||
write!(f, "RAW")?;
|
||||
if let Some(root) = root {
|
||||
write!(f, "('{}')", root)?;
|
||||
write!(f, "('{root}')")?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
@ -3142,7 +3142,7 @@ impl fmt::Display for ForXml {
|
|||
ForXml::Path(root) => {
|
||||
write!(f, "PATH")?;
|
||||
if let Some(root) = root {
|
||||
write!(f, "('{}')", root)?;
|
||||
write!(f, "('{root}')")?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
@ -3205,7 +3205,7 @@ impl fmt::Display for JsonTableColumn {
|
|||
JsonTableColumn::Named(json_table_named_column) => {
|
||||
write!(f, "{json_table_named_column}")
|
||||
}
|
||||
JsonTableColumn::ForOrdinality(ident) => write!(f, "{} FOR ORDINALITY", ident),
|
||||
JsonTableColumn::ForOrdinality(ident) => write!(f, "{ident} FOR ORDINALITY"),
|
||||
JsonTableColumn::Nested(json_table_nested_column) => {
|
||||
write!(f, "{json_table_nested_column}")
|
||||
}
|
||||
|
@ -3271,10 +3271,10 @@ impl fmt::Display for JsonTableNamedColumn {
|
|||
self.path
|
||||
)?;
|
||||
if let Some(on_empty) = &self.on_empty {
|
||||
write!(f, " {} ON EMPTY", on_empty)?;
|
||||
write!(f, " {on_empty} ON EMPTY")?;
|
||||
}
|
||||
if let Some(on_error) = &self.on_error {
|
||||
write!(f, " {} ON ERROR", on_error)?;
|
||||
write!(f, " {on_error} ON ERROR")?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
@ -3296,7 +3296,7 @@ impl fmt::Display for JsonTableColumnErrorHandling {
|
|||
match self {
|
||||
JsonTableColumnErrorHandling::Null => write!(f, "NULL"),
|
||||
JsonTableColumnErrorHandling::Default(json_string) => {
|
||||
write!(f, "DEFAULT {}", json_string)
|
||||
write!(f, "DEFAULT {json_string}")
|
||||
}
|
||||
JsonTableColumnErrorHandling::Error => write!(f, "ERROR"),
|
||||
}
|
||||
|
@ -3429,12 +3429,12 @@ impl fmt::Display for XmlTableColumn {
|
|||
default,
|
||||
nullable,
|
||||
} => {
|
||||
write!(f, " {}", r#type)?;
|
||||
write!(f, " {type}")?;
|
||||
if let Some(p) = path {
|
||||
write!(f, " PATH {}", p)?;
|
||||
write!(f, " PATH {p}")?;
|
||||
}
|
||||
if let Some(d) = default {
|
||||
write!(f, " DEFAULT {}", d)?;
|
||||
write!(f, " DEFAULT {d}")?;
|
||||
}
|
||||
if !*nullable {
|
||||
write!(f, " NOT NULL")?;
|
||||
|
@ -3465,7 +3465,7 @@ impl fmt::Display for XmlPassingArgument {
|
|||
}
|
||||
write!(f, "{}", self.expr)?;
|
||||
if let Some(alias) = &self.alias {
|
||||
write!(f, " AS {}", alias)?;
|
||||
write!(f, " AS {alias}")?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
use crate::ast::query::SelectItemQualifiedWildcardKind;
|
||||
use crate::ast::{query::SelectItemQualifiedWildcardKind, ColumnOptions};
|
||||
use core::iter;
|
||||
|
||||
use crate::tokenizer::Span;
|
||||
|
@ -991,10 +991,13 @@ impl Spanned for ViewColumnDef {
|
|||
options,
|
||||
} = self;
|
||||
|
||||
union_spans(
|
||||
core::iter::once(name.span)
|
||||
.chain(options.iter().flat_map(|i| i.iter().map(|k| k.span()))),
|
||||
)
|
||||
name.span.union_opt(&options.as_ref().map(|o| o.span()))
|
||||
}
|
||||
}
|
||||
|
||||
impl Spanned for ColumnOptions {
|
||||
fn span(&self) -> Span {
|
||||
union_spans(self.as_slice().iter().map(|i| i.span()))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1055,7 +1058,9 @@ impl Spanned for CreateTableOptions {
|
|||
match self {
|
||||
CreateTableOptions::None => Span::empty(),
|
||||
CreateTableOptions::With(vec) => union_spans(vec.iter().map(|i| i.span())),
|
||||
CreateTableOptions::Options(vec) => union_spans(vec.iter().map(|i| i.span())),
|
||||
CreateTableOptions::Options(vec) => {
|
||||
union_spans(vec.as_slice().iter().map(|i| i.span()))
|
||||
}
|
||||
CreateTableOptions::Plain(vec) => union_spans(vec.iter().map(|i| i.span())),
|
||||
CreateTableOptions::TableProperties(vec) => union_spans(vec.iter().map(|i| i.span())),
|
||||
}
|
||||
|
|
|
@ -116,7 +116,6 @@ impl From<ValueWithSpan> for Value {
|
|||
derive(Visit, VisitMut),
|
||||
visit(with = "visit_value")
|
||||
)]
|
||||
|
||||
pub enum Value {
|
||||
/// Numeric literal
|
||||
#[cfg(not(feature = "bigdecimal"))]
|
||||
|
@ -551,16 +550,16 @@ impl fmt::Display for EscapeUnicodeStringLiteral<'_> {
|
|||
write!(f, r#"\\"#)?;
|
||||
}
|
||||
x if x.is_ascii() => {
|
||||
write!(f, "{}", c)?;
|
||||
write!(f, "{c}")?;
|
||||
}
|
||||
_ => {
|
||||
let codepoint = c as u32;
|
||||
// if the character fits in 32 bits, we can use the \XXXX format
|
||||
// otherwise, we need to use the \+XXXXXX format
|
||||
if codepoint <= 0xFFFF {
|
||||
write!(f, "\\{:04X}", codepoint)?;
|
||||
write!(f, "\\{codepoint:04X}")?;
|
||||
} else {
|
||||
write!(f, "\\+{:06X}", codepoint)?;
|
||||
write!(f, "\\+{codepoint:06X}")?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -926,10 +926,10 @@ mod tests {
|
|||
#[test]
|
||||
fn overflow() {
|
||||
let cond = (0..1000)
|
||||
.map(|n| format!("X = {}", n))
|
||||
.map(|n| format!("X = {n}"))
|
||||
.collect::<Vec<_>>()
|
||||
.join(" OR ");
|
||||
let sql = format!("SELECT x where {0}", cond);
|
||||
let sql = format!("SELECT x where {cond}");
|
||||
|
||||
let dialect = GenericDialect {};
|
||||
let tokens = Tokenizer::new(&dialect, sql.as_str()).tokenize().unwrap();
|
||||
|
|
|
@ -615,7 +615,7 @@ pub trait Dialect: Debug + Any {
|
|||
}
|
||||
|
||||
let token = parser.peek_token();
|
||||
debug!("get_next_precedence_full() {:?}", token);
|
||||
debug!("get_next_precedence_full() {token:?}");
|
||||
match token.token {
|
||||
Token::Word(w) if w.keyword == Keyword::OR => Ok(p!(Or)),
|
||||
Token::Word(w) if w.keyword == Keyword::AND => Ok(p!(And)),
|
||||
|
@ -1056,6 +1056,10 @@ pub trait Dialect: Debug + Any {
|
|||
fn supports_set_names(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn supports_space_separated_column_options(&self) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
/// This represents the operators for which precedence must be defined
|
||||
|
|
|
@ -104,7 +104,7 @@ impl Dialect for PostgreSqlDialect {
|
|||
|
||||
fn get_next_precedence(&self, parser: &Parser) -> Option<Result<u8, ParserError>> {
|
||||
let token = parser.peek_token();
|
||||
debug!("get_next_precedence() {:?}", token);
|
||||
debug!("get_next_precedence() {token:?}");
|
||||
|
||||
// we only return some custom value here when the behaviour (not merely the numeric value) differs
|
||||
// from the default implementation
|
||||
|
|
|
@ -360,6 +360,10 @@ impl Dialect for SnowflakeDialect {
|
|||
fn get_reserved_keywords_for_select_item_operator(&self) -> &[Keyword] {
|
||||
&RESERVED_KEYWORDS_FOR_SELECT_ITEM_OPERATOR
|
||||
}
|
||||
|
||||
fn supports_space_separated_column_options(&self) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_file_staging_command(kw: Keyword, parser: &mut Parser) -> Result<Statement, ParserError> {
|
||||
|
|
|
@ -395,6 +395,7 @@ define_keywords!(
|
|||
FUNCTION,
|
||||
FUNCTIONS,
|
||||
FUSION,
|
||||
FUTURE,
|
||||
GENERAL,
|
||||
GENERATE,
|
||||
GENERATED,
|
||||
|
|
|
@ -436,7 +436,7 @@ impl<'a> Parser<'a> {
|
|||
///
|
||||
/// See example on [`Parser::new()`] for an example
|
||||
pub fn try_with_sql(self, sql: &str) -> Result<Self, ParserError> {
|
||||
debug!("Parsing sql '{}'...", sql);
|
||||
debug!("Parsing sql '{sql}'...");
|
||||
let tokens = Tokenizer::new(self.dialect, sql)
|
||||
.with_unescape(self.options.unescape)
|
||||
.tokenize_with_location()?;
|
||||
|
@ -1226,10 +1226,10 @@ impl<'a> Parser<'a> {
|
|||
|
||||
expr = self.parse_compound_expr(expr, vec![])?;
|
||||
|
||||
debug!("prefix: {:?}", expr);
|
||||
debug!("prefix: {expr:?}");
|
||||
loop {
|
||||
let next_precedence = self.get_next_precedence()?;
|
||||
debug!("next precedence: {:?}", next_precedence);
|
||||
debug!("next precedence: {next_precedence:?}");
|
||||
|
||||
if precedence >= next_precedence {
|
||||
break;
|
||||
|
@ -1631,8 +1631,7 @@ impl<'a> Parser<'a> {
|
|||
Token::QuestionPipe => UnaryOperator::QuestionPipe,
|
||||
_ => {
|
||||
return Err(ParserError::ParserError(format!(
|
||||
"Unexpected token in unary operator parsing: {:?}",
|
||||
tok
|
||||
"Unexpected token in unary operator parsing: {tok:?}"
|
||||
)))
|
||||
}
|
||||
};
|
||||
|
@ -2771,7 +2770,7 @@ impl<'a> Parser<'a> {
|
|||
|
||||
if self.dialect.supports_dictionary_syntax() {
|
||||
self.prev_token(); // Put back the '{'
|
||||
return self.parse_duckdb_struct_literal();
|
||||
return self.parse_dictionary();
|
||||
}
|
||||
|
||||
self.expected("an expression", token)
|
||||
|
@ -3140,7 +3139,7 @@ impl<'a> Parser<'a> {
|
|||
Ok(fields)
|
||||
}
|
||||
|
||||
/// DuckDB specific: Parse a duckdb [dictionary]
|
||||
/// DuckDB and ClickHouse specific: Parse a duckdb [dictionary] or a clickhouse [map] setting
|
||||
///
|
||||
/// Syntax:
|
||||
///
|
||||
|
@ -3149,18 +3148,18 @@ impl<'a> Parser<'a> {
|
|||
/// ```
|
||||
///
|
||||
/// [dictionary]: https://duckdb.org/docs/sql/data_types/struct#creating-structs
|
||||
fn parse_duckdb_struct_literal(&mut self) -> Result<Expr, ParserError> {
|
||||
/// [map]: https://clickhouse.com/docs/operations/settings/settings#additional_table_filters
|
||||
fn parse_dictionary(&mut self) -> Result<Expr, ParserError> {
|
||||
self.expect_token(&Token::LBrace)?;
|
||||
|
||||
let fields =
|
||||
self.parse_comma_separated0(Self::parse_duckdb_dictionary_field, Token::RBrace)?;
|
||||
let fields = self.parse_comma_separated0(Self::parse_dictionary_field, Token::RBrace)?;
|
||||
|
||||
self.expect_token(&Token::RBrace)?;
|
||||
|
||||
Ok(Expr::Dictionary(fields))
|
||||
}
|
||||
|
||||
/// Parse a field for a duckdb [dictionary]
|
||||
/// Parse a field for a duckdb [dictionary] or a clickhouse [map] setting
|
||||
///
|
||||
/// Syntax
|
||||
///
|
||||
|
@ -3169,7 +3168,8 @@ impl<'a> Parser<'a> {
|
|||
/// ```
|
||||
///
|
||||
/// [dictionary]: https://duckdb.org/docs/sql/data_types/struct#creating-structs
|
||||
fn parse_duckdb_dictionary_field(&mut self) -> Result<DictionaryField, ParserError> {
|
||||
/// [map]: https://clickhouse.com/docs/operations/settings/settings#additional_table_filters
|
||||
fn parse_dictionary_field(&mut self) -> Result<DictionaryField, ParserError> {
|
||||
let key = self.parse_identifier()?;
|
||||
|
||||
self.expect_token(&Token::Colon)?;
|
||||
|
@ -10579,17 +10579,7 @@ impl<'a> Parser<'a> {
|
|||
/// Parses a column definition within a view.
|
||||
fn parse_view_column(&mut self) -> Result<ViewColumnDef, ParserError> {
|
||||
let name = self.parse_identifier()?;
|
||||
let options = if (dialect_of!(self is BigQueryDialect | GenericDialect)
|
||||
&& self.parse_keyword(Keyword::OPTIONS))
|
||||
|| (dialect_of!(self is SnowflakeDialect | GenericDialect)
|
||||
&& self.parse_keyword(Keyword::COMMENT))
|
||||
{
|
||||
self.prev_token();
|
||||
self.parse_optional_column_option()?
|
||||
.map(|option| vec![option])
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let options = self.parse_view_column_options()?;
|
||||
let data_type = if dialect_of!(self is ClickHouseDialect) {
|
||||
Some(self.parse_data_type()?)
|
||||
} else {
|
||||
|
@ -10602,6 +10592,25 @@ impl<'a> Parser<'a> {
|
|||
})
|
||||
}
|
||||
|
||||
fn parse_view_column_options(&mut self) -> Result<Option<ColumnOptions>, ParserError> {
|
||||
let mut options = Vec::new();
|
||||
loop {
|
||||
let option = self.parse_optional_column_option()?;
|
||||
if let Some(option) = option {
|
||||
options.push(option);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if options.is_empty() {
|
||||
Ok(None)
|
||||
} else if self.dialect.supports_space_separated_column_options() {
|
||||
Ok(Some(ColumnOptions::SpaceSeparated(options)))
|
||||
} else {
|
||||
Ok(Some(ColumnOptions::CommaSeparated(options)))
|
||||
}
|
||||
}
|
||||
|
||||
/// Parses a parenthesized comma-separated list of unqualified, possibly quoted identifiers.
|
||||
/// For example: `(col1, "col 2", ...)`
|
||||
pub fn parse_parenthesized_column_list(
|
||||
|
@ -11208,7 +11217,7 @@ impl<'a> Parser<'a> {
|
|||
let key_values = self.parse_comma_separated(|p| {
|
||||
let key = p.parse_identifier()?;
|
||||
p.expect_token(&Token::Eq)?;
|
||||
let value = p.parse_value()?.value;
|
||||
let value = p.parse_expr()?;
|
||||
Ok(Setting { key, value })
|
||||
})?;
|
||||
Some(key_values)
|
||||
|
@ -13650,7 +13659,7 @@ impl<'a> Parser<'a> {
|
|||
let ident = self.parse_identifier()?;
|
||||
if let GranteeName::ObjectName(namespace) = name {
|
||||
name = GranteeName::ObjectName(ObjectName::from(vec![Ident::new(
|
||||
format!("{}:{}", namespace, ident),
|
||||
format!("{namespace}:{ident}"),
|
||||
)]));
|
||||
};
|
||||
}
|
||||
|
@ -13687,6 +13696,33 @@ impl<'a> Parser<'a> {
|
|||
Some(GrantObjects::AllTablesInSchema {
|
||||
schemas: self.parse_comma_separated(|p| p.parse_object_name(false))?,
|
||||
})
|
||||
} else if self.parse_keywords(&[
|
||||
Keyword::FUTURE,
|
||||
Keyword::SCHEMAS,
|
||||
Keyword::IN,
|
||||
Keyword::DATABASE,
|
||||
]) {
|
||||
Some(GrantObjects::FutureSchemasInDatabase {
|
||||
databases: self.parse_comma_separated(|p| p.parse_object_name(false))?,
|
||||
})
|
||||
} else if self.parse_keywords(&[
|
||||
Keyword::FUTURE,
|
||||
Keyword::TABLES,
|
||||
Keyword::IN,
|
||||
Keyword::SCHEMA,
|
||||
]) {
|
||||
Some(GrantObjects::FutureTablesInSchema {
|
||||
schemas: self.parse_comma_separated(|p| p.parse_object_name(false))?,
|
||||
})
|
||||
} else if self.parse_keywords(&[
|
||||
Keyword::FUTURE,
|
||||
Keyword::VIEWS,
|
||||
Keyword::IN,
|
||||
Keyword::SCHEMA,
|
||||
]) {
|
||||
Some(GrantObjects::FutureViewsInSchema {
|
||||
schemas: self.parse_comma_separated(|p| p.parse_object_name(false))?,
|
||||
})
|
||||
} else if self.parse_keywords(&[
|
||||
Keyword::ALL,
|
||||
Keyword::SEQUENCES,
|
||||
|
@ -14620,7 +14656,7 @@ impl<'a> Parser<'a> {
|
|||
self.dialect
|
||||
.get_reserved_keywords_for_select_item_operator(),
|
||||
)
|
||||
.map(|keyword| Ident::new(format!("{:?}", keyword)));
|
||||
.map(|keyword| Ident::new(format!("{keyword:?}")));
|
||||
|
||||
match self.parse_wildcard_expr()? {
|
||||
Expr::QualifiedWildcard(prefix, token) => Ok(SelectItem::QualifiedWildcard(
|
||||
|
@ -15797,6 +15833,13 @@ impl<'a> Parser<'a> {
|
|||
pub fn parse_create_procedure(&mut self, or_alter: bool) -> Result<Statement, ParserError> {
|
||||
let name = self.parse_object_name(false)?;
|
||||
let params = self.parse_optional_procedure_parameters()?;
|
||||
|
||||
let language = if self.parse_keyword(Keyword::LANGUAGE) {
|
||||
Some(self.parse_identifier()?)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
self.expect_keyword_is(Keyword::AS)?;
|
||||
|
||||
let body = self.parse_conditional_statements(&[Keyword::END])?;
|
||||
|
@ -15805,6 +15848,7 @@ impl<'a> Parser<'a> {
|
|||
name,
|
||||
or_alter,
|
||||
params,
|
||||
language,
|
||||
body,
|
||||
})
|
||||
}
|
||||
|
|
|
@ -270,7 +270,7 @@ impl TestedDialects {
|
|||
tokenizer = tokenizer.with_unescape(options.unescape);
|
||||
}
|
||||
let tokens = tokenizer.tokenize().unwrap();
|
||||
assert_eq!(expected, tokens, "Tokenized differently for {:?}", dialect);
|
||||
assert_eq!(expected, tokens, "Tokenized differently for {dialect:?}");
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -366,6 +366,11 @@ pub fn number(n: &str) -> Value {
|
|||
Value::Number(n.parse().unwrap(), false)
|
||||
}
|
||||
|
||||
/// Creates a [Value::SingleQuotedString]
|
||||
pub fn single_quoted_string(s: impl Into<String>) -> Value {
|
||||
Value::SingleQuotedString(s.into())
|
||||
}
|
||||
|
||||
pub fn table_alias(name: impl Into<String>) -> Option<TableAlias> {
|
||||
Some(TableAlias {
|
||||
name: Ident::new(name),
|
||||
|
|
|
@ -1751,7 +1751,7 @@ impl<'a> Tokenizer<'a> {
|
|||
(None, Some(tok)) => Ok(Some(tok)),
|
||||
(None, None) => self.tokenizer_error(
|
||||
chars.location(),
|
||||
format!("Expected a valid binary operator after '{}'", prefix),
|
||||
format!("Expected a valid binary operator after '{prefix}'"),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
@ -1809,7 +1809,7 @@ impl<'a> Tokenizer<'a> {
|
|||
chars.next();
|
||||
|
||||
let mut temp = String::new();
|
||||
let end_delimiter = format!("${}$", value);
|
||||
let end_delimiter = format!("${value}$");
|
||||
|
||||
loop {
|
||||
match chars.next() {
|
||||
|
@ -2402,13 +2402,13 @@ fn take_char_from_hex_digits(
|
|||
location: chars.location(),
|
||||
})?;
|
||||
let digit = next_char.to_digit(16).ok_or_else(|| TokenizerError {
|
||||
message: format!("Invalid hex digit in escaped unicode string: {}", next_char),
|
||||
message: format!("Invalid hex digit in escaped unicode string: {next_char}"),
|
||||
location: chars.location(),
|
||||
})?;
|
||||
result = result * 16 + digit;
|
||||
}
|
||||
char::from_u32(result).ok_or_else(|| TokenizerError {
|
||||
message: format!("Invalid unicode character: {:x}", result),
|
||||
message: format!("Invalid unicode character: {result:x}"),
|
||||
location: chars.location(),
|
||||
})
|
||||
}
|
||||
|
@ -3504,7 +3504,7 @@ mod tests {
|
|||
}
|
||||
|
||||
fn check_unescape(s: &str, expected: Option<&str>) {
|
||||
let s = format!("'{}'", s);
|
||||
let s = format!("'{s}'");
|
||||
let mut state = State {
|
||||
peekable: s.chars().peekable(),
|
||||
line: 0,
|
||||
|
|
|
@ -355,14 +355,16 @@ fn parse_create_view_with_options() {
|
|||
ViewColumnDef {
|
||||
name: Ident::new("age"),
|
||||
data_type: None,
|
||||
options: Some(vec![ColumnOption::Options(vec![SqlOption::KeyValue {
|
||||
key: Ident::new("description"),
|
||||
value: Expr::Value(
|
||||
Value::DoubleQuotedString("field age".to_string()).with_span(
|
||||
Span::new(Location::new(1, 42), Location::new(1, 52))
|
||||
)
|
||||
),
|
||||
}])]),
|
||||
options: Some(ColumnOptions::CommaSeparated(vec![ColumnOption::Options(
|
||||
vec![SqlOption::KeyValue {
|
||||
key: Ident::new("description"),
|
||||
value: Expr::Value(
|
||||
Value::DoubleQuotedString("field age".to_string()).with_span(
|
||||
Span::new(Location::new(1, 42), Location::new(1, 52))
|
||||
)
|
||||
),
|
||||
}]
|
||||
)])),
|
||||
},
|
||||
],
|
||||
columns
|
||||
|
|
|
@ -28,7 +28,7 @@ use test_utils::*;
|
|||
use sqlparser::ast::Expr::{BinaryOp, Identifier};
|
||||
use sqlparser::ast::SelectItem::UnnamedExpr;
|
||||
use sqlparser::ast::TableFactor::Table;
|
||||
use sqlparser::ast::Value::Number;
|
||||
use sqlparser::ast::Value::Boolean;
|
||||
use sqlparser::ast::*;
|
||||
use sqlparser::dialect::ClickHouseDialect;
|
||||
use sqlparser::dialect::GenericDialect;
|
||||
|
@ -914,7 +914,7 @@ fn parse_create_view_with_fields_data_types() {
|
|||
}]),
|
||||
vec![]
|
||||
)),
|
||||
options: None
|
||||
options: None,
|
||||
},
|
||||
ViewColumnDef {
|
||||
name: "f".into(),
|
||||
|
@ -926,7 +926,7 @@ fn parse_create_view_with_fields_data_types() {
|
|||
}]),
|
||||
vec![]
|
||||
)),
|
||||
options: None
|
||||
options: None,
|
||||
},
|
||||
]
|
||||
);
|
||||
|
@ -965,38 +965,103 @@ fn parse_limit_by() {
|
|||
|
||||
#[test]
|
||||
fn parse_settings_in_query() {
|
||||
match clickhouse_and_generic()
|
||||
.verified_stmt(r#"SELECT * FROM t SETTINGS max_threads = 1, max_block_size = 10000"#)
|
||||
{
|
||||
Statement::Query(query) => {
|
||||
assert_eq!(
|
||||
query.settings,
|
||||
Some(vec![
|
||||
Setting {
|
||||
key: Ident::new("max_threads"),
|
||||
value: Number("1".parse().unwrap(), false)
|
||||
},
|
||||
Setting {
|
||||
key: Ident::new("max_block_size"),
|
||||
value: Number("10000".parse().unwrap(), false)
|
||||
},
|
||||
])
|
||||
);
|
||||
fn check_settings(sql: &str, expected: Vec<Setting>) {
|
||||
match clickhouse_and_generic().verified_stmt(sql) {
|
||||
Statement::Query(q) => {
|
||||
assert_eq!(q.settings, Some(expected));
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
|
||||
for (sql, expected_settings) in [
|
||||
(
|
||||
r#"SELECT * FROM t SETTINGS max_threads = 1, max_block_size = 10000"#,
|
||||
vec![
|
||||
Setting {
|
||||
key: Ident::new("max_threads"),
|
||||
value: Expr::value(number("1")),
|
||||
},
|
||||
Setting {
|
||||
key: Ident::new("max_block_size"),
|
||||
value: Expr::value(number("10000")),
|
||||
},
|
||||
],
|
||||
),
|
||||
(
|
||||
r#"SELECT * FROM t SETTINGS additional_table_filters = {'table_1': 'x != 2'}"#,
|
||||
vec![Setting {
|
||||
key: Ident::new("additional_table_filters"),
|
||||
value: Expr::Dictionary(vec![DictionaryField {
|
||||
key: Ident::with_quote('\'', "table_1"),
|
||||
value: Expr::value(single_quoted_string("x != 2")).into(),
|
||||
}]),
|
||||
}],
|
||||
),
|
||||
(
|
||||
r#"SELECT * FROM t SETTINGS additional_result_filter = 'x != 2', query_plan_optimize_lazy_materialization = false"#,
|
||||
vec![
|
||||
Setting {
|
||||
key: Ident::new("additional_result_filter"),
|
||||
value: Expr::value(single_quoted_string("x != 2")),
|
||||
},
|
||||
Setting {
|
||||
key: Ident::new("query_plan_optimize_lazy_materialization"),
|
||||
value: Expr::value(Boolean(false)),
|
||||
},
|
||||
],
|
||||
),
|
||||
] {
|
||||
check_settings(sql, expected_settings);
|
||||
}
|
||||
|
||||
let invalid_cases = vec![
|
||||
"SELECT * FROM t SETTINGS a",
|
||||
"SELECT * FROM t SETTINGS a=",
|
||||
"SELECT * FROM t SETTINGS a=1, b",
|
||||
"SELECT * FROM t SETTINGS a=1, b=",
|
||||
"SELECT * FROM t SETTINGS a=1, b=c",
|
||||
("SELECT * FROM t SETTINGS a", "Expected: =, found: EOF"),
|
||||
(
|
||||
"SELECT * FROM t SETTINGS a=",
|
||||
"Expected: an expression, found: EOF",
|
||||
),
|
||||
("SELECT * FROM t SETTINGS a=1, b", "Expected: =, found: EOF"),
|
||||
(
|
||||
"SELECT * FROM t SETTINGS a=1, b=",
|
||||
"Expected: an expression, found: EOF",
|
||||
),
|
||||
(
|
||||
"SELECT * FROM t SETTINGS a = {",
|
||||
"Expected: identifier, found: EOF",
|
||||
),
|
||||
(
|
||||
"SELECT * FROM t SETTINGS a = {'b'",
|
||||
"Expected: :, found: EOF",
|
||||
),
|
||||
(
|
||||
"SELECT * FROM t SETTINGS a = {'b': ",
|
||||
"Expected: an expression, found: EOF",
|
||||
),
|
||||
(
|
||||
"SELECT * FROM t SETTINGS a = {'b': 'c',}",
|
||||
"Expected: identifier, found: }",
|
||||
),
|
||||
(
|
||||
"SELECT * FROM t SETTINGS a = {'b': 'c', 'd'}",
|
||||
"Expected: :, found: }",
|
||||
),
|
||||
(
|
||||
"SELECT * FROM t SETTINGS a = {'b': 'c', 'd': }",
|
||||
"Expected: an expression, found: }",
|
||||
),
|
||||
(
|
||||
"SELECT * FROM t SETTINGS a = {ANY(b)}",
|
||||
"Expected: :, found: (",
|
||||
),
|
||||
];
|
||||
for sql in invalid_cases {
|
||||
clickhouse_and_generic()
|
||||
.parse_sql_statements(sql)
|
||||
.expect_err("Expected: SETTINGS key = value, found: ");
|
||||
for (sql, error_msg) in invalid_cases {
|
||||
assert_eq!(
|
||||
clickhouse_and_generic()
|
||||
.parse_sql_statements(sql)
|
||||
.unwrap_err(),
|
||||
ParserError(error_msg.to_string())
|
||||
);
|
||||
}
|
||||
}
|
||||
#[test]
|
||||
|
@ -1345,7 +1410,7 @@ fn parse_use() {
|
|||
for object_name in &valid_object_names {
|
||||
// Test single identifier without quotes
|
||||
assert_eq!(
|
||||
clickhouse().verified_stmt(&format!("USE {}", object_name)),
|
||||
clickhouse().verified_stmt(&format!("USE {object_name}")),
|
||||
Statement::Use(Use::Object(ObjectName::from(vec![Ident::new(
|
||||
object_name.to_string()
|
||||
)])))
|
||||
|
@ -1353,7 +1418,7 @@ fn parse_use() {
|
|||
for "e in "e_styles {
|
||||
// Test single identifier with different type of quotes
|
||||
assert_eq!(
|
||||
clickhouse().verified_stmt(&format!("USE {0}{1}{0}", quote, object_name)),
|
||||
clickhouse().verified_stmt(&format!("USE {quote}{object_name}{quote}")),
|
||||
Statement::Use(Use::Object(ObjectName::from(vec![Ident::with_quote(
|
||||
quote,
|
||||
object_name.to_string(),
|
||||
|
@ -1367,7 +1432,7 @@ fn parse_use() {
|
|||
fn test_query_with_format_clause() {
|
||||
let format_options = vec!["TabSeparated", "JSONCompact", "NULL"];
|
||||
for format in &format_options {
|
||||
let sql = format!("SELECT * FROM t FORMAT {}", format);
|
||||
let sql = format!("SELECT * FROM t FORMAT {format}");
|
||||
match clickhouse_and_generic().verified_stmt(&sql) {
|
||||
Statement::Query(query) => {
|
||||
if *format == "NULL" {
|
||||
|
@ -1550,11 +1615,11 @@ fn parse_select_table_function_settings() {
|
|||
settings: Some(vec![
|
||||
Setting {
|
||||
key: "s0".into(),
|
||||
value: Value::Number("3".parse().unwrap(), false),
|
||||
value: Expr::value(number("3")),
|
||||
},
|
||||
Setting {
|
||||
key: "s1".into(),
|
||||
value: Value::SingleQuotedString("s".into()),
|
||||
value: Expr::value(single_quoted_string("s")),
|
||||
},
|
||||
]),
|
||||
},
|
||||
|
@ -1575,11 +1640,11 @@ fn parse_select_table_function_settings() {
|
|||
settings: Some(vec![
|
||||
Setting {
|
||||
key: "s0".into(),
|
||||
value: Value::Number("3".parse().unwrap(), false),
|
||||
value: Expr::value(number("3")),
|
||||
},
|
||||
Setting {
|
||||
key: "s1".into(),
|
||||
value: Value::SingleQuotedString("s".into()),
|
||||
value: Expr::value(single_quoted_string("s")),
|
||||
},
|
||||
]),
|
||||
},
|
||||
|
@ -1589,7 +1654,6 @@ fn parse_select_table_function_settings() {
|
|||
"SELECT * FROM t(SETTINGS a=)",
|
||||
"SELECT * FROM t(SETTINGS a=1, b)",
|
||||
"SELECT * FROM t(SETTINGS a=1, b=)",
|
||||
"SELECT * FROM t(SETTINGS a=1, b=c)",
|
||||
];
|
||||
for sql in invalid_cases {
|
||||
clickhouse_and_generic()
|
||||
|
|
|
@ -3563,7 +3563,7 @@ fn test_double_value() {
|
|||
for (input, expected) in test_cases {
|
||||
for (i, expr) in input.iter().enumerate() {
|
||||
if let Statement::Query(query) =
|
||||
dialects.one_statement_parses_to(&format!("SELECT {}", expr), "")
|
||||
dialects.one_statement_parses_to(&format!("SELECT {expr}"), "")
|
||||
{
|
||||
if let SetExpr::Select(select) = *query.body {
|
||||
assert_eq!(expected[i], select.projection[0]);
|
||||
|
@ -4023,13 +4023,13 @@ fn parse_create_table_column_constraint_characteristics() {
|
|||
syntax
|
||||
};
|
||||
|
||||
let sql = format!("CREATE TABLE t (a int UNIQUE {})", syntax);
|
||||
let sql = format!("CREATE TABLE t (a int UNIQUE {syntax})");
|
||||
let expected_clause = if syntax.is_empty() {
|
||||
String::new()
|
||||
} else {
|
||||
format!(" {syntax}")
|
||||
};
|
||||
let expected = format!("CREATE TABLE t (a INT UNIQUE{})", expected_clause);
|
||||
let expected = format!("CREATE TABLE t (a INT UNIQUE{expected_clause})");
|
||||
let ast = one_statement_parses_to(&sql, &expected);
|
||||
|
||||
let expected_value = if deferrable.is_some() || initially.is_some() || enforced.is_some() {
|
||||
|
@ -7499,7 +7499,7 @@ fn parse_cte_in_data_modification_statements() {
|
|||
assert_eq!(query.with.unwrap().to_string(), "WITH x AS (SELECT 1)");
|
||||
assert!(matches!(*query.body, SetExpr::Update(_)));
|
||||
}
|
||||
other => panic!("Expected: UPDATE, got: {:?}", other),
|
||||
other => panic!("Expected: UPDATE, got: {other:?}"),
|
||||
}
|
||||
|
||||
match verified_stmt("WITH t (x) AS (SELECT 9) DELETE FROM q WHERE id IN (SELECT x FROM t)") {
|
||||
|
@ -7507,7 +7507,7 @@ fn parse_cte_in_data_modification_statements() {
|
|||
assert_eq!(query.with.unwrap().to_string(), "WITH t (x) AS (SELECT 9)");
|
||||
assert!(matches!(*query.body, SetExpr::Delete(_)));
|
||||
}
|
||||
other => panic!("Expected: DELETE, got: {:?}", other),
|
||||
other => panic!("Expected: DELETE, got: {other:?}"),
|
||||
}
|
||||
|
||||
match verified_stmt("WITH x AS (SELECT 42) INSERT INTO t SELECT foo FROM x") {
|
||||
|
@ -7515,7 +7515,7 @@ fn parse_cte_in_data_modification_statements() {
|
|||
assert_eq!(query.with.unwrap().to_string(), "WITH x AS (SELECT 42)");
|
||||
assert!(matches!(*query.body, SetExpr::Insert(_)));
|
||||
}
|
||||
other => panic!("Expected: INSERT, got: {:?}", other),
|
||||
other => panic!("Expected: INSERT, got: {other:?}"),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -7990,7 +7990,7 @@ fn parse_create_view_with_columns() {
|
|||
.map(|name| ViewColumnDef {
|
||||
name,
|
||||
data_type: None,
|
||||
options: None
|
||||
options: None,
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
);
|
||||
|
@ -9386,9 +9386,11 @@ fn parse_grant() {
|
|||
verified_stmt("GRANT SELECT ON VIEW view1 TO ROLE role1");
|
||||
verified_stmt("GRANT EXEC ON my_sp TO runner");
|
||||
verified_stmt("GRANT UPDATE ON my_table TO updater_role AS dbo");
|
||||
|
||||
all_dialects_where(|d| d.identifier_quote_style("none") == Some('['))
|
||||
.verified_stmt("GRANT SELECT ON [my_table] TO [public]");
|
||||
verified_stmt("GRANT SELECT ON FUTURE SCHEMAS IN DATABASE db1 TO ROLE role1");
|
||||
verified_stmt("GRANT SELECT ON FUTURE TABLES IN SCHEMA db1.sc1 TO ROLE role1");
|
||||
verified_stmt("GRANT SELECT ON FUTURE VIEWS IN SCHEMA db1.sc1 TO ROLE role1");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -10043,7 +10045,7 @@ fn parse_offset_and_limit() {
|
|||
#[test]
|
||||
fn parse_time_functions() {
|
||||
fn test_time_function(func_name: &'static str) {
|
||||
let sql = format!("SELECT {}()", func_name);
|
||||
let sql = format!("SELECT {func_name}()");
|
||||
let select = verified_only_select(&sql);
|
||||
let select_localtime_func_call_ast = Function {
|
||||
name: ObjectName::from(vec![Ident::new(func_name)]),
|
||||
|
@ -10065,7 +10067,7 @@ fn parse_time_functions() {
|
|||
);
|
||||
|
||||
// Validating Parenthesis
|
||||
let sql_without_parens = format!("SELECT {}", func_name);
|
||||
let sql_without_parens = format!("SELECT {func_name}");
|
||||
let mut ast_without_parens = select_localtime_func_call_ast;
|
||||
ast_without_parens.args = FunctionArguments::None;
|
||||
assert_eq!(
|
||||
|
@ -14306,7 +14308,7 @@ fn overflow() {
|
|||
let expr = std::iter::repeat_n("1", 1000)
|
||||
.collect::<Vec<_>>()
|
||||
.join(" + ");
|
||||
let sql = format!("SELECT {}", expr);
|
||||
let sql = format!("SELECT {expr}");
|
||||
|
||||
let mut statements = Parser::parse_sql(&GenericDialect {}, sql.as_str()).unwrap();
|
||||
let statement = statements.pop().unwrap();
|
||||
|
@ -14606,7 +14608,7 @@ fn test_conditional_statement_span() {
|
|||
else_block.unwrap().span()
|
||||
);
|
||||
}
|
||||
stmt => panic!("Unexpected statement: {:?}", stmt),
|
||||
stmt => panic!("Unexpected statement: {stmt:?}"),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -15380,6 +15382,36 @@ fn join_precedence() {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_create_procedure_with_language() {
|
||||
let sql = r#"CREATE PROCEDURE test_proc LANGUAGE sql AS BEGIN SELECT 1; END"#;
|
||||
match verified_stmt(sql) {
|
||||
Statement::CreateProcedure {
|
||||
or_alter,
|
||||
name,
|
||||
params,
|
||||
language,
|
||||
..
|
||||
} => {
|
||||
assert_eq!(or_alter, false);
|
||||
assert_eq!(name.to_string(), "test_proc");
|
||||
assert_eq!(params, Some(vec![]));
|
||||
assert_eq!(
|
||||
language,
|
||||
Some(Ident {
|
||||
value: "sql".into(),
|
||||
quote_style: None,
|
||||
span: Span {
|
||||
start: Location::empty(),
|
||||
end: Location::empty()
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_create_procedure_with_parameter_modes() {
|
||||
let sql = r#"CREATE PROCEDURE test_proc (IN a INTEGER, OUT b TEXT, INOUT c TIMESTAMP, d BOOL) AS BEGIN SELECT 1; END"#;
|
||||
|
|
|
@ -213,7 +213,7 @@ fn parse_use() {
|
|||
for object_name in &valid_object_names {
|
||||
// Test single identifier without quotes
|
||||
assert_eq!(
|
||||
databricks().verified_stmt(&format!("USE {}", object_name)),
|
||||
databricks().verified_stmt(&format!("USE {object_name}")),
|
||||
Statement::Use(Use::Object(ObjectName::from(vec![Ident::new(
|
||||
object_name.to_string()
|
||||
)])))
|
||||
|
@ -221,7 +221,7 @@ fn parse_use() {
|
|||
for "e in "e_styles {
|
||||
// Test single identifier with different type of quotes
|
||||
assert_eq!(
|
||||
databricks().verified_stmt(&format!("USE {0}{1}{0}", quote, object_name)),
|
||||
databricks().verified_stmt(&format!("USE {quote}{object_name}{quote}")),
|
||||
Statement::Use(Use::Object(ObjectName::from(vec![Ident::with_quote(
|
||||
quote,
|
||||
object_name.to_string(),
|
||||
|
@ -233,21 +233,21 @@ fn parse_use() {
|
|||
for "e in "e_styles {
|
||||
// Test single identifier with keyword and different type of quotes
|
||||
assert_eq!(
|
||||
databricks().verified_stmt(&format!("USE CATALOG {0}my_catalog{0}", quote)),
|
||||
databricks().verified_stmt(&format!("USE CATALOG {quote}my_catalog{quote}")),
|
||||
Statement::Use(Use::Catalog(ObjectName::from(vec![Ident::with_quote(
|
||||
quote,
|
||||
"my_catalog".to_string(),
|
||||
)])))
|
||||
);
|
||||
assert_eq!(
|
||||
databricks().verified_stmt(&format!("USE DATABASE {0}my_database{0}", quote)),
|
||||
databricks().verified_stmt(&format!("USE DATABASE {quote}my_database{quote}")),
|
||||
Statement::Use(Use::Database(ObjectName::from(vec![Ident::with_quote(
|
||||
quote,
|
||||
"my_database".to_string(),
|
||||
)])))
|
||||
);
|
||||
assert_eq!(
|
||||
databricks().verified_stmt(&format!("USE SCHEMA {0}my_schema{0}", quote)),
|
||||
databricks().verified_stmt(&format!("USE SCHEMA {quote}my_schema{quote}")),
|
||||
Statement::Use(Use::Schema(ObjectName::from(vec![Ident::with_quote(
|
||||
quote,
|
||||
"my_schema".to_string(),
|
||||
|
@ -357,6 +357,6 @@ fn data_type_timestamp_ntz() {
|
|||
}]
|
||||
);
|
||||
}
|
||||
s => panic!("Unexpected statement: {:?}", s),
|
||||
s => panic!("Unexpected statement: {s:?}"),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -368,7 +368,7 @@ fn test_duckdb_specific_int_types() {
|
|||
("HUGEINT", DataType::HugeInt),
|
||||
];
|
||||
for (dtype_string, data_type) in duckdb_dtypes {
|
||||
let sql = format!("SELECT 123::{}", dtype_string);
|
||||
let sql = format!("SELECT 123::{dtype_string}");
|
||||
let select = duckdb().verified_only_select(&sql);
|
||||
assert_eq!(
|
||||
&Expr::Cast {
|
||||
|
@ -792,7 +792,7 @@ fn parse_use() {
|
|||
for object_name in &valid_object_names {
|
||||
// Test single identifier without quotes
|
||||
assert_eq!(
|
||||
duckdb().verified_stmt(&format!("USE {}", object_name)),
|
||||
duckdb().verified_stmt(&format!("USE {object_name}")),
|
||||
Statement::Use(Use::Object(ObjectName::from(vec![Ident::new(
|
||||
object_name.to_string()
|
||||
)])))
|
||||
|
@ -800,7 +800,7 @@ fn parse_use() {
|
|||
for "e in "e_styles {
|
||||
// Test single identifier with different type of quotes
|
||||
assert_eq!(
|
||||
duckdb().verified_stmt(&format!("USE {0}{1}{0}", quote, object_name)),
|
||||
duckdb().verified_stmt(&format!("USE {quote}{object_name}{quote}")),
|
||||
Statement::Use(Use::Object(ObjectName::from(vec![Ident::with_quote(
|
||||
quote,
|
||||
object_name.to_string(),
|
||||
|
@ -812,7 +812,9 @@ fn parse_use() {
|
|||
for "e in "e_styles {
|
||||
// Test double identifier with different type of quotes
|
||||
assert_eq!(
|
||||
duckdb().verified_stmt(&format!("USE {0}CATALOG{0}.{0}my_schema{0}", quote)),
|
||||
duckdb().verified_stmt(&format!(
|
||||
"USE {quote}CATALOG{quote}.{quote}my_schema{quote}"
|
||||
)),
|
||||
Statement::Use(Use::Object(ObjectName::from(vec![
|
||||
Ident::with_quote(quote, "CATALOG"),
|
||||
Ident::with_quote(quote, "my_schema")
|
||||
|
|
|
@ -524,7 +524,7 @@ fn parse_use() {
|
|||
for object_name in &valid_object_names {
|
||||
// Test single identifier without quotes
|
||||
assert_eq!(
|
||||
hive().verified_stmt(&format!("USE {}", object_name)),
|
||||
hive().verified_stmt(&format!("USE {object_name}")),
|
||||
Statement::Use(Use::Object(ObjectName::from(vec![Ident::new(
|
||||
object_name.to_string()
|
||||
)])))
|
||||
|
@ -532,7 +532,7 @@ fn parse_use() {
|
|||
for "e in "e_styles {
|
||||
// Test single identifier with different type of quotes
|
||||
assert_eq!(
|
||||
hive().verified_stmt(&format!("USE {}{}{}", quote, object_name, quote)),
|
||||
hive().verified_stmt(&format!("USE {quote}{object_name}{quote}")),
|
||||
Statement::Use(Use::Object(ObjectName::from(vec![Ident::with_quote(
|
||||
quote,
|
||||
object_name.to_string(),
|
||||
|
|
|
@ -173,7 +173,8 @@ fn parse_create_procedure() {
|
|||
value: "test".into(),
|
||||
quote_style: None,
|
||||
span: Span::empty(),
|
||||
}])
|
||||
}]),
|
||||
language: None,
|
||||
}
|
||||
)
|
||||
}
|
||||
|
@ -1672,7 +1673,7 @@ fn parse_use() {
|
|||
for object_name in &valid_object_names {
|
||||
// Test single identifier without quotes
|
||||
assert_eq!(
|
||||
ms().verified_stmt(&format!("USE {}", object_name)),
|
||||
ms().verified_stmt(&format!("USE {object_name}")),
|
||||
Statement::Use(Use::Object(ObjectName::from(vec![Ident::new(
|
||||
object_name.to_string()
|
||||
)])))
|
||||
|
@ -1680,7 +1681,7 @@ fn parse_use() {
|
|||
for "e in "e_styles {
|
||||
// Test single identifier with different type of quotes
|
||||
assert_eq!(
|
||||
ms().verified_stmt(&format!("USE {}{}{}", quote, object_name, quote)),
|
||||
ms().verified_stmt(&format!("USE {quote}{object_name}{quote}")),
|
||||
Statement::Use(Use::Object(ObjectName::from(vec![Ident::with_quote(
|
||||
quote,
|
||||
object_name.to_string(),
|
||||
|
@ -2186,7 +2187,7 @@ fn parse_mssql_if_else() {
|
|||
"IF 1 = 1 BEGIN SET @A = 1; END ELSE SET @A = 2;"
|
||||
);
|
||||
}
|
||||
_ => panic!("Unexpected statements: {:?}", stmts),
|
||||
_ => panic!("Unexpected statements: {stmts:?}"),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2236,7 +2237,7 @@ fn test_mssql_if_statements_span() {
|
|||
Span::new(Location::new(1, 21), Location::new(1, 36))
|
||||
);
|
||||
}
|
||||
stmt => panic!("Unexpected statement: {:?}", stmt),
|
||||
stmt => panic!("Unexpected statement: {stmt:?}"),
|
||||
}
|
||||
|
||||
// Blocks
|
||||
|
@ -2257,7 +2258,7 @@ fn test_mssql_if_statements_span() {
|
|||
Span::new(Location::new(1, 32), Location::new(1, 57))
|
||||
);
|
||||
}
|
||||
stmt => panic!("Unexpected statement: {:?}", stmt),
|
||||
stmt => panic!("Unexpected statement: {stmt:?}"),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -593,7 +593,7 @@ fn parse_use() {
|
|||
for object_name in &valid_object_names {
|
||||
// Test single identifier without quotes
|
||||
assert_eq!(
|
||||
mysql_and_generic().verified_stmt(&format!("USE {}", object_name)),
|
||||
mysql_and_generic().verified_stmt(&format!("USE {object_name}")),
|
||||
Statement::Use(Use::Object(ObjectName::from(vec![Ident::new(
|
||||
object_name.to_string()
|
||||
)])))
|
||||
|
@ -601,8 +601,7 @@ fn parse_use() {
|
|||
for "e in "e_styles {
|
||||
// Test single identifier with different type of quotes
|
||||
assert_eq!(
|
||||
mysql_and_generic()
|
||||
.verified_stmt(&format!("USE {}{}{}", quote, object_name, quote)),
|
||||
mysql_and_generic().verified_stmt(&format!("USE {quote}{object_name}{quote}")),
|
||||
Statement::Use(Use::Object(ObjectName::from(vec![Ident::with_quote(
|
||||
quote,
|
||||
object_name.to_string(),
|
||||
|
@ -2263,11 +2262,11 @@ fn parse_qualified_identifiers_with_numeric_prefix() {
|
|||
Some(SelectItem::UnnamedExpr(Expr::CompoundIdentifier(parts))) => {
|
||||
assert_eq!(&[Ident::new("t"), Ident::new("15to29")], &parts[..]);
|
||||
}
|
||||
proj => panic!("Unexpected projection: {:?}", proj),
|
||||
proj => panic!("Unexpected projection: {proj:?}"),
|
||||
},
|
||||
body => panic!("Unexpected statement body: {:?}", body),
|
||||
body => panic!("Unexpected statement body: {body:?}"),
|
||||
},
|
||||
stmt => panic!("Unexpected statement: {:?}", stmt),
|
||||
stmt => panic!("Unexpected statement: {stmt:?}"),
|
||||
}
|
||||
|
||||
// Case 2: Qualified column name that starts with digits and on its own represents a number.
|
||||
|
@ -2277,11 +2276,11 @@ fn parse_qualified_identifiers_with_numeric_prefix() {
|
|||
Some(SelectItem::UnnamedExpr(Expr::CompoundIdentifier(parts))) => {
|
||||
assert_eq!(&[Ident::new("t"), Ident::new("15e29")], &parts[..]);
|
||||
}
|
||||
proj => panic!("Unexpected projection: {:?}", proj),
|
||||
proj => panic!("Unexpected projection: {proj:?}"),
|
||||
},
|
||||
body => panic!("Unexpected statement body: {:?}", body),
|
||||
body => panic!("Unexpected statement body: {body:?}"),
|
||||
},
|
||||
stmt => panic!("Unexpected statement: {:?}", stmt),
|
||||
stmt => panic!("Unexpected statement: {stmt:?}"),
|
||||
}
|
||||
|
||||
// Case 3: Unqualified, the same token is parsed as a number.
|
||||
|
@ -2295,11 +2294,11 @@ fn parse_qualified_identifiers_with_numeric_prefix() {
|
|||
Some(SelectItem::UnnamedExpr(Expr::Value(ValueWithSpan { value, .. }))) => {
|
||||
assert_eq!(&number("15e29"), value);
|
||||
}
|
||||
proj => panic!("Unexpected projection: {:?}", proj),
|
||||
proj => panic!("Unexpected projection: {proj:?}"),
|
||||
},
|
||||
body => panic!("Unexpected statement body: {:?}", body),
|
||||
body => panic!("Unexpected statement body: {body:?}"),
|
||||
},
|
||||
stmt => panic!("Unexpected statement: {:?}", stmt),
|
||||
stmt => panic!("Unexpected statement: {stmt:?}"),
|
||||
}
|
||||
|
||||
// Case 4: Quoted simple identifier.
|
||||
|
@ -2309,11 +2308,11 @@ fn parse_qualified_identifiers_with_numeric_prefix() {
|
|||
Some(SelectItem::UnnamedExpr(Expr::Identifier(name))) => {
|
||||
assert_eq!(&Ident::with_quote('`', "15e29"), name);
|
||||
}
|
||||
proj => panic!("Unexpected projection: {:?}", proj),
|
||||
proj => panic!("Unexpected projection: {proj:?}"),
|
||||
},
|
||||
body => panic!("Unexpected statement body: {:?}", body),
|
||||
body => panic!("Unexpected statement body: {body:?}"),
|
||||
},
|
||||
stmt => panic!("Unexpected statement: {:?}", stmt),
|
||||
stmt => panic!("Unexpected statement: {stmt:?}"),
|
||||
}
|
||||
|
||||
// Case 5: Quoted compound identifier.
|
||||
|
@ -2326,11 +2325,11 @@ fn parse_qualified_identifiers_with_numeric_prefix() {
|
|||
&parts[..]
|
||||
);
|
||||
}
|
||||
proj => panic!("Unexpected projection: {:?}", proj),
|
||||
proj => panic!("Unexpected projection: {proj:?}"),
|
||||
},
|
||||
body => panic!("Unexpected statement body: {:?}", body),
|
||||
body => panic!("Unexpected statement body: {body:?}"),
|
||||
},
|
||||
stmt => panic!("Unexpected statement: {:?}", stmt),
|
||||
stmt => panic!("Unexpected statement: {stmt:?}"),
|
||||
}
|
||||
|
||||
// Case 6: Multi-level compound identifiers.
|
||||
|
@ -2347,11 +2346,11 @@ fn parse_qualified_identifiers_with_numeric_prefix() {
|
|||
&parts[..]
|
||||
);
|
||||
}
|
||||
proj => panic!("Unexpected projection: {:?}", proj),
|
||||
proj => panic!("Unexpected projection: {proj:?}"),
|
||||
},
|
||||
body => panic!("Unexpected statement body: {:?}", body),
|
||||
body => panic!("Unexpected statement body: {body:?}"),
|
||||
},
|
||||
stmt => panic!("Unexpected statement: {:?}", stmt),
|
||||
stmt => panic!("Unexpected statement: {stmt:?}"),
|
||||
}
|
||||
|
||||
// Case 7: Multi-level compound quoted identifiers.
|
||||
|
@ -2368,11 +2367,11 @@ fn parse_qualified_identifiers_with_numeric_prefix() {
|
|||
&parts[..]
|
||||
);
|
||||
}
|
||||
proj => panic!("Unexpected projection: {:?}", proj),
|
||||
proj => panic!("Unexpected projection: {proj:?}"),
|
||||
},
|
||||
body => panic!("Unexpected statement body: {:?}", body),
|
||||
body => panic!("Unexpected statement body: {body:?}"),
|
||||
},
|
||||
stmt => panic!("Unexpected statement: {:?}", stmt),
|
||||
stmt => panic!("Unexpected statement: {stmt:?}"),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2535,12 +2535,12 @@ fn parse_create_indices_with_operator_classes() {
|
|||
for expected_operator_class in &operator_classes {
|
||||
let single_column_sql_statement = format!(
|
||||
"CREATE INDEX the_index_name ON users USING {expected_index_type} (concat_users_name(first_name, last_name){})",
|
||||
expected_operator_class.as_ref().map(|oc| format!(" {}", oc))
|
||||
expected_operator_class.as_ref().map(|oc| format!(" {oc}"))
|
||||
.unwrap_or_default()
|
||||
);
|
||||
let multi_column_sql_statement = format!(
|
||||
"CREATE INDEX the_index_name ON users USING {expected_index_type} (column_name,concat_users_name(first_name, last_name){})",
|
||||
expected_operator_class.as_ref().map(|oc| format!(" {}", oc))
|
||||
expected_operator_class.as_ref().map(|oc| format!(" {oc}"))
|
||||
.unwrap_or_default()
|
||||
);
|
||||
|
||||
|
@ -3273,7 +3273,7 @@ fn test_fn_arg_with_value_operator() {
|
|||
assert!(matches!(
|
||||
&args[..],
|
||||
&[FunctionArg::ExprNamed { operator: FunctionArgOperator::Value, .. }]
|
||||
), "Invalid function argument: {:?}", args);
|
||||
), "Invalid function argument: {args:?}");
|
||||
}
|
||||
other => panic!("Expected: JSON_OBJECT('name' VALUE 'value') to be parsed as a function, but got {other:?}"),
|
||||
}
|
||||
|
@ -5679,7 +5679,7 @@ fn parse_drop_trigger() {
|
|||
"DROP TRIGGER{} check_update ON table_name{}",
|
||||
if if_exists { " IF EXISTS" } else { "" },
|
||||
option
|
||||
.map(|o| format!(" {}", o))
|
||||
.map(|o| format!(" {o}"))
|
||||
.unwrap_or_else(|| "".to_string())
|
||||
);
|
||||
assert_eq!(
|
||||
|
@ -5773,8 +5773,7 @@ fn parse_trigger_related_functions() {
|
|||
// Now we parse the statements and check if they are parsed correctly.
|
||||
let mut statements = pg()
|
||||
.parse_sql_statements(&format!(
|
||||
"{}{}{}{}",
|
||||
sql_table_creation, sql_create_function, sql_create_trigger, sql_drop_trigger
|
||||
"{sql_table_creation}{sql_create_function}{sql_create_trigger}{sql_drop_trigger}"
|
||||
))
|
||||
.unwrap();
|
||||
|
||||
|
|
|
@ -2510,10 +2510,7 @@ fn test_snowflake_stage_object_names_into_location() {
|
|||
.zip(allowed_object_names.iter_mut())
|
||||
{
|
||||
let (formatted_name, object_name) = it;
|
||||
let sql = format!(
|
||||
"COPY INTO {} FROM 'gcs://mybucket/./../a.csv'",
|
||||
formatted_name
|
||||
);
|
||||
let sql = format!("COPY INTO {formatted_name} FROM 'gcs://mybucket/./../a.csv'");
|
||||
match snowflake().verified_stmt(&sql) {
|
||||
Statement::CopyIntoSnowflake { into, .. } => {
|
||||
assert_eq!(into.0, object_name.0)
|
||||
|
@ -2536,10 +2533,7 @@ fn test_snowflake_stage_object_names_into_table() {
|
|||
.zip(allowed_object_names.iter_mut())
|
||||
{
|
||||
let (formatted_name, object_name) = it;
|
||||
let sql = format!(
|
||||
"COPY INTO {} FROM 'gcs://mybucket/./../a.csv'",
|
||||
formatted_name
|
||||
);
|
||||
let sql = format!("COPY INTO {formatted_name} FROM 'gcs://mybucket/./../a.csv'");
|
||||
match snowflake().verified_stmt(&sql) {
|
||||
Statement::CopyIntoSnowflake { into, .. } => {
|
||||
assert_eq!(into.0, object_name.0)
|
||||
|
@ -3020,7 +3014,7 @@ fn parse_use() {
|
|||
for object_name in &valid_object_names {
|
||||
// Test single identifier without quotes
|
||||
assert_eq!(
|
||||
snowflake().verified_stmt(&format!("USE {}", object_name)),
|
||||
snowflake().verified_stmt(&format!("USE {object_name}")),
|
||||
Statement::Use(Use::Object(ObjectName::from(vec![Ident::new(
|
||||
object_name.to_string()
|
||||
)])))
|
||||
|
@ -3028,7 +3022,7 @@ fn parse_use() {
|
|||
for "e in "e_styles {
|
||||
// Test single identifier with different type of quotes
|
||||
assert_eq!(
|
||||
snowflake().verified_stmt(&format!("USE {}{}{}", quote, object_name, quote)),
|
||||
snowflake().verified_stmt(&format!("USE {quote}{object_name}{quote}")),
|
||||
Statement::Use(Use::Object(ObjectName::from(vec![Ident::with_quote(
|
||||
quote,
|
||||
object_name.to_string(),
|
||||
|
@ -3040,7 +3034,9 @@ fn parse_use() {
|
|||
for "e in "e_styles {
|
||||
// Test double identifier with different type of quotes
|
||||
assert_eq!(
|
||||
snowflake().verified_stmt(&format!("USE {0}CATALOG{0}.{0}my_schema{0}", quote)),
|
||||
snowflake().verified_stmt(&format!(
|
||||
"USE {quote}CATALOG{quote}.{quote}my_schema{quote}"
|
||||
)),
|
||||
Statement::Use(Use::Object(ObjectName::from(vec![
|
||||
Ident::with_quote(quote, "CATALOG"),
|
||||
Ident::with_quote(quote, "my_schema")
|
||||
|
@ -3059,35 +3055,37 @@ fn parse_use() {
|
|||
for "e in "e_styles {
|
||||
// Test single and double identifier with keyword and different type of quotes
|
||||
assert_eq!(
|
||||
snowflake().verified_stmt(&format!("USE DATABASE {0}my_database{0}", quote)),
|
||||
snowflake().verified_stmt(&format!("USE DATABASE {quote}my_database{quote}")),
|
||||
Statement::Use(Use::Database(ObjectName::from(vec![Ident::with_quote(
|
||||
quote,
|
||||
"my_database".to_string(),
|
||||
)])))
|
||||
);
|
||||
assert_eq!(
|
||||
snowflake().verified_stmt(&format!("USE SCHEMA {0}my_schema{0}", quote)),
|
||||
snowflake().verified_stmt(&format!("USE SCHEMA {quote}my_schema{quote}")),
|
||||
Statement::Use(Use::Schema(ObjectName::from(vec![Ident::with_quote(
|
||||
quote,
|
||||
"my_schema".to_string(),
|
||||
)])))
|
||||
);
|
||||
assert_eq!(
|
||||
snowflake().verified_stmt(&format!("USE SCHEMA {0}CATALOG{0}.{0}my_schema{0}", quote)),
|
||||
snowflake().verified_stmt(&format!(
|
||||
"USE SCHEMA {quote}CATALOG{quote}.{quote}my_schema{quote}"
|
||||
)),
|
||||
Statement::Use(Use::Schema(ObjectName::from(vec![
|
||||
Ident::with_quote(quote, "CATALOG"),
|
||||
Ident::with_quote(quote, "my_schema")
|
||||
])))
|
||||
);
|
||||
assert_eq!(
|
||||
snowflake().verified_stmt(&format!("USE ROLE {0}my_role{0}", quote)),
|
||||
snowflake().verified_stmt(&format!("USE ROLE {quote}my_role{quote}")),
|
||||
Statement::Use(Use::Role(ObjectName::from(vec![Ident::with_quote(
|
||||
quote,
|
||||
"my_role".to_string(),
|
||||
)])))
|
||||
);
|
||||
assert_eq!(
|
||||
snowflake().verified_stmt(&format!("USE WAREHOUSE {0}my_wh{0}", quote)),
|
||||
snowflake().verified_stmt(&format!("USE WAREHOUSE {quote}my_wh{quote}")),
|
||||
Statement::Use(Use::Warehouse(ObjectName::from(vec![Ident::with_quote(
|
||||
quote,
|
||||
"my_wh".to_string(),
|
||||
|
@ -3124,7 +3122,7 @@ fn view_comment_option_should_be_after_column_list() {
|
|||
"CREATE OR REPLACE VIEW v (a COMMENT 'a comment', b, c COMMENT 'c comment') COMMENT = 'Comment' AS SELECT a FROM t",
|
||||
"CREATE OR REPLACE VIEW v (a COMMENT 'a comment', b, c COMMENT 'c comment') WITH (foo = bar) COMMENT = 'Comment' AS SELECT a FROM t",
|
||||
] {
|
||||
snowflake_and_generic()
|
||||
snowflake()
|
||||
.verified_stmt(sql);
|
||||
}
|
||||
}
|
||||
|
@ -3133,7 +3131,7 @@ fn view_comment_option_should_be_after_column_list() {
|
|||
fn parse_view_column_descriptions() {
|
||||
let sql = "CREATE OR REPLACE VIEW v (a COMMENT 'Comment', b) AS SELECT a, b FROM table1";
|
||||
|
||||
match snowflake_and_generic().verified_stmt(sql) {
|
||||
match snowflake().verified_stmt(sql) {
|
||||
Statement::CreateView { name, columns, .. } => {
|
||||
assert_eq!(name.to_string(), "v");
|
||||
assert_eq!(
|
||||
|
@ -3142,7 +3140,9 @@ fn parse_view_column_descriptions() {
|
|||
ViewColumnDef {
|
||||
name: Ident::new("a"),
|
||||
data_type: None,
|
||||
options: Some(vec![ColumnOption::Comment("Comment".to_string())]),
|
||||
options: Some(ColumnOptions::SpaceSeparated(vec![ColumnOption::Comment(
|
||||
"Comment".to_string()
|
||||
)])),
|
||||
},
|
||||
ViewColumnDef {
|
||||
name: Ident::new("b"),
|
||||
|
@ -3627,7 +3627,7 @@ fn test_alter_session_followed_by_statement() {
|
|||
.unwrap();
|
||||
match stmts[..] {
|
||||
[Statement::AlterSession { .. }, Statement::Query { .. }] => {}
|
||||
_ => panic!("Unexpected statements: {:?}", stmts),
|
||||
_ => panic!("Unexpected statements: {stmts:?}"),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4165,3 +4165,10 @@ fn test_snowflake_fetch_clause_syntax() {
|
|||
canonical,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_snowflake_create_view_with_multiple_column_options() {
|
||||
let create_view_with_tag =
|
||||
r#"CREATE VIEW X (COL WITH TAG (pii='email') COMMENT 'foobar') AS SELECT * FROM Y"#;
|
||||
snowflake().verified_stmt(create_view_with_tag);
|
||||
}
|
||||
|
|
|
@ -324,7 +324,7 @@ fn parse_create_table_on_conflict_col() {
|
|||
Keyword::IGNORE,
|
||||
Keyword::REPLACE,
|
||||
] {
|
||||
let sql = format!("CREATE TABLE t1 (a INT, b INT ON CONFLICT {:?})", keyword);
|
||||
let sql = format!("CREATE TABLE t1 (a INT, b INT ON CONFLICT {keyword:?})");
|
||||
match sqlite_and_generic().verified_stmt(&sql) {
|
||||
Statement::CreateTable(CreateTable { columns, .. }) => {
|
||||
assert_eq!(
|
||||
|
@ -410,7 +410,7 @@ fn parse_window_function_with_filter() {
|
|||
"count",
|
||||
"user_defined_function",
|
||||
] {
|
||||
let sql = format!("SELECT {}(x) FILTER (WHERE y) OVER () FROM t", func_name);
|
||||
let sql = format!("SELECT {func_name}(x) FILTER (WHERE y) OVER () FROM t");
|
||||
let select = sqlite().verified_only_select(&sql);
|
||||
assert_eq!(select.to_string(), sql);
|
||||
assert_eq!(
|
||||
|
@ -444,7 +444,7 @@ fn parse_window_function_with_filter() {
|
|||
fn parse_attach_database() {
|
||||
let sql = "ATTACH DATABASE 'test.db' AS test";
|
||||
let verified_stmt = sqlite().verified_stmt(sql);
|
||||
assert_eq!(sql, format!("{}", verified_stmt));
|
||||
assert_eq!(sql, format!("{verified_stmt}"));
|
||||
match verified_stmt {
|
||||
Statement::AttachDatabase {
|
||||
schema_name,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue