Skip to content

Commit 0d4967c

Browse files
committed
Merge remote-tracking branch 'origin/main' into fix-mysql-drop-index-error
2 parents aec0d2e + 394a534 commit 0d4967c

File tree

8 files changed

+180
-30
lines changed

8 files changed

+180
-30
lines changed

src/ast/ddl.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,7 @@ pub enum AlterTableOperation {
139139
},
140140
/// `DROP [ COLUMN ] [ IF EXISTS ] <column_name> [ CASCADE ]`
141141
DropColumn {
142+
has_column_keyword: bool,
142143
column_name: Ident,
143144
if_exists: bool,
144145
drop_behavior: Option<DropBehavior>,
@@ -615,12 +616,14 @@ impl fmt::Display for AlterTableOperation {
615616
AlterTableOperation::DropForeignKey { name } => write!(f, "DROP FOREIGN KEY {name}"),
616617
AlterTableOperation::DropIndex { name } => write!(f, "DROP INDEX {name}"),
617618
AlterTableOperation::DropColumn {
619+
has_column_keyword,
618620
column_name,
619621
if_exists,
620622
drop_behavior,
621623
} => write!(
622624
f,
623-
"DROP COLUMN {}{}{}",
625+
"DROP {}{}{}{}",
626+
if *has_column_keyword { "COLUMN " } else { "" },
624627
if *if_exists { "IF EXISTS " } else { "" },
625628
column_name,
626629
match drop_behavior {

src/ast/mod.rs

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3416,6 +3416,9 @@ pub enum Statement {
34163416
purge: bool,
34173417
/// MySQL-specific "TEMPORARY" keyword
34183418
temporary: bool,
3419+
/// MySQL-specific drop index syntax, which requires table specification
3420+
/// See <https://dev.mysql.com/doc/refman/8.4/en/drop-index.html>
3421+
table: Option<ObjectName>,
34193422
},
34203423
/// ```sql
34213424
/// DROP FUNCTION
@@ -5264,17 +5267,24 @@ impl fmt::Display for Statement {
52645267
restrict,
52655268
purge,
52665269
temporary,
5267-
} => write!(
5268-
f,
5269-
"DROP {}{}{} {}{}{}{}",
5270-
if *temporary { "TEMPORARY " } else { "" },
5271-
object_type,
5272-
if *if_exists { " IF EXISTS" } else { "" },
5273-
display_comma_separated(names),
5274-
if *cascade { " CASCADE" } else { "" },
5275-
if *restrict { " RESTRICT" } else { "" },
5276-
if *purge { " PURGE" } else { "" }
5277-
),
5270+
table,
5271+
} => {
5272+
write!(
5273+
f,
5274+
"DROP {}{}{} {}{}{}{}",
5275+
if *temporary { "TEMPORARY " } else { "" },
5276+
object_type,
5277+
if *if_exists { " IF EXISTS" } else { "" },
5278+
display_comma_separated(names),
5279+
if *cascade { " CASCADE" } else { "" },
5280+
if *restrict { " RESTRICT" } else { "" },
5281+
if *purge { " PURGE" } else { "" },
5282+
)?;
5283+
if let Some(table_name) = table.as_ref() {
5284+
write!(f, " ON {}", table_name)?;
5285+
};
5286+
Ok(())
5287+
}
52785288
Statement::DropFunction {
52795289
if_exists,
52805290
func_desc,

src/ast/query.rs

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1559,7 +1559,7 @@ impl fmt::Display for TableSampleBucket {
15591559
}
15601560
impl fmt::Display for TableSample {
15611561
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1562-
write!(f, " {}", self.modifier)?;
1562+
write!(f, "{}", self.modifier)?;
15631563
if let Some(name) = &self.name {
15641564
write!(f, " {}", name)?;
15651565
}
@@ -1862,7 +1862,7 @@ impl fmt::Display for TableFactor {
18621862
write!(f, " WITH ORDINALITY")?;
18631863
}
18641864
if let Some(TableSampleKind::BeforeTableAlias(sample)) = sample {
1865-
write!(f, "{sample}")?;
1865+
write!(f, " {sample}")?;
18661866
}
18671867
if let Some(alias) = alias {
18681868
write!(f, " AS {alias}")?;
@@ -1877,7 +1877,7 @@ impl fmt::Display for TableFactor {
18771877
write!(f, "{version}")?;
18781878
}
18791879
if let Some(TableSampleKind::AfterTableAlias(sample)) = sample {
1880-
write!(f, "{sample}")?;
1880+
write!(f, " {sample}")?;
18811881
}
18821882
Ok(())
18831883
}
@@ -2680,6 +2680,10 @@ pub enum PipeOperator {
26802680
full_table_exprs: Vec<ExprWithAliasAndOrderBy>,
26812681
group_by_expr: Vec<ExprWithAliasAndOrderBy>,
26822682
},
2683+
/// Selects a random sample of rows from the input table.
2684+
/// Syntax: `|> TABLESAMPLE SYSTEM (10 PERCENT)
2685+
/// See more at <https://cloud.google.com/bigquery/docs/reference/standard-sql/pipe-syntax#tablesample_pipe_operator>
2686+
TableSample { sample: Box<TableSample> },
26832687
}
26842688

26852689
impl fmt::Display for PipeOperator {
@@ -2731,6 +2735,10 @@ impl fmt::Display for PipeOperator {
27312735
PipeOperator::OrderBy { exprs } => {
27322736
write!(f, "ORDER BY {}", display_comma_separated(exprs.as_slice()))
27332737
}
2738+
2739+
PipeOperator::TableSample { sample } => {
2740+
write!(f, "{}", sample)
2741+
}
27342742
}
27352743
}
27362744
}

src/ast/spans.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1091,6 +1091,7 @@ impl Spanned for AlterTableOperation {
10911091
drop_behavior: _,
10921092
} => name.span,
10931093
AlterTableOperation::DropColumn {
1094+
has_column_keyword: _,
10941095
column_name,
10951096
if_exists: _,
10961097
drop_behavior: _,

src/parser/mod.rs

Lines changed: 35 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5289,11 +5289,17 @@ impl<'a> Parser<'a> {
52895289
|parser: &mut Parser| -> Result<OperateFunctionArg, ParserError> {
52905290
let name = parser.parse_identifier()?;
52915291
let data_type = parser.parse_data_type()?;
5292+
let default_expr = if parser.consume_token(&Token::Eq) {
5293+
Some(parser.parse_expr()?)
5294+
} else {
5295+
None
5296+
};
5297+
52925298
Ok(OperateFunctionArg {
52935299
mode: None,
52945300
name: Some(name),
52955301
data_type,
5296-
default_expr: None,
5302+
default_expr,
52975303
})
52985304
};
52995305
self.expect_token(&Token::LParen)?;
@@ -6271,6 +6277,11 @@ impl<'a> Parser<'a> {
62716277
loc
62726278
);
62736279
}
6280+
let table = if self.parse_keyword(Keyword::ON) {
6281+
Some(self.parse_object_name(false)?)
6282+
} else {
6283+
None
6284+
};
62746285
Ok(Statement::Drop {
62756286
object_type,
62766287
if_exists,
@@ -6279,6 +6290,7 @@ impl<'a> Parser<'a> {
62796290
restrict,
62806291
purge,
62816292
temporary,
6293+
table,
62826294
})
62836295
}
62846296

@@ -8633,11 +8645,12 @@ impl<'a> Parser<'a> {
86338645
} else if self.parse_keywords(&[Keyword::CLUSTERING, Keyword::KEY]) {
86348646
AlterTableOperation::DropClusteringKey
86358647
} else {
8636-
let _ = self.parse_keyword(Keyword::COLUMN); // [ COLUMN ]
8648+
let has_column_keyword = self.parse_keyword(Keyword::COLUMN); // [ COLUMN ]
86378649
let if_exists = self.parse_keywords(&[Keyword::IF, Keyword::EXISTS]);
86388650
let column_name = self.parse_identifier()?;
86398651
let drop_behavior = self.parse_optional_drop_behavior();
86408652
AlterTableOperation::DropColumn {
8653+
has_column_keyword,
86418654
column_name,
86428655
if_exists,
86438656
drop_behavior,
@@ -10123,7 +10136,13 @@ impl<'a> Parser<'a> {
1012310136
}
1012410137
if self.parse_keywords(&[Keyword::GROUPING, Keyword::SETS]) {
1012510138
self.expect_token(&Token::LParen)?;
10126-
let result = self.parse_comma_separated(|p| p.parse_tuple(true, true))?;
10139+
let result = self.parse_comma_separated(|p| {
10140+
if p.peek_token_ref().token == Token::LParen {
10141+
p.parse_tuple(true, true)
10142+
} else {
10143+
Ok(vec![p.parse_expr()?])
10144+
}
10145+
})?;
1012710146
self.expect_token(&Token::RParen)?;
1012810147
modifiers.push(GroupByWithModifier::GroupingSets(Expr::GroupingSets(
1012910148
result,
@@ -11072,6 +11091,7 @@ impl<'a> Parser<'a> {
1107211091
Keyword::LIMIT,
1107311092
Keyword::AGGREGATE,
1107411093
Keyword::ORDER,
11094+
Keyword::TABLESAMPLE,
1107511095
])?;
1107611096
match kw {
1107711097
Keyword::SELECT => {
@@ -11134,6 +11154,10 @@ impl<'a> Parser<'a> {
1113411154
let exprs = self.parse_comma_separated(Parser::parse_order_by_expr)?;
1113511155
pipe_operators.push(PipeOperator::OrderBy { exprs })
1113611156
}
11157+
Keyword::TABLESAMPLE => {
11158+
let sample = self.parse_table_sample(TableSampleModifier::TableSample)?;
11159+
pipe_operators.push(PipeOperator::TableSample { sample });
11160+
}
1113711161
unhandled => {
1113811162
return Err(ParserError::ParserError(format!(
1113911163
"`expect_one_of_keywords` further up allowed unhandled keyword: {unhandled:?}"
@@ -12778,7 +12802,13 @@ impl<'a> Parser<'a> {
1277812802
} else {
1277912803
return Ok(None);
1278012804
};
12805+
self.parse_table_sample(modifier).map(Some)
12806+
}
1278112807

12808+
fn parse_table_sample(
12809+
&mut self,
12810+
modifier: TableSampleModifier,
12811+
) -> Result<Box<TableSample>, ParserError> {
1278212812
let name = match self.parse_one_of_keywords(&[
1278312813
Keyword::BERNOULLI,
1278412814
Keyword::ROW,
@@ -12860,14 +12890,14 @@ impl<'a> Parser<'a> {
1286012890
None
1286112891
};
1286212892

12863-
Ok(Some(Box::new(TableSample {
12893+
Ok(Box::new(TableSample {
1286412894
modifier,
1286512895
name,
1286612896
quantity,
1286712897
seed,
1286812898
bucket,
1286912899
offset,
12870-
})))
12900+
}))
1287112901
}
1287212902

1287312903
fn parse_table_sample_seed(

tests/sqlparser_common.rs

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2822,6 +2822,38 @@ fn parse_group_by_special_grouping_sets() {
28222822
}
28232823
}
28242824

2825+
#[test]
2826+
fn parse_group_by_grouping_sets_single_values() {
2827+
let sql = "SELECT a, b, SUM(c) FROM tab1 GROUP BY a, b GROUPING SETS ((a, b), a, (b), c, ())";
2828+
let canonical =
2829+
"SELECT a, b, SUM(c) FROM tab1 GROUP BY a, b GROUPING SETS ((a, b), (a), (b), (c), ())";
2830+
match all_dialects().one_statement_parses_to(sql, canonical) {
2831+
Statement::Query(query) => {
2832+
let group_by = &query.body.as_select().unwrap().group_by;
2833+
assert_eq!(
2834+
group_by,
2835+
&GroupByExpr::Expressions(
2836+
vec![
2837+
Expr::Identifier(Ident::new("a")),
2838+
Expr::Identifier(Ident::new("b"))
2839+
],
2840+
vec![GroupByWithModifier::GroupingSets(Expr::GroupingSets(vec![
2841+
vec![
2842+
Expr::Identifier(Ident::new("a")),
2843+
Expr::Identifier(Ident::new("b"))
2844+
],
2845+
vec![Expr::Identifier(Ident::new("a"))],
2846+
vec![Expr::Identifier(Ident::new("b"))],
2847+
vec![Expr::Identifier(Ident::new("c"))],
2848+
vec![]
2849+
]))]
2850+
)
2851+
);
2852+
}
2853+
_ => unreachable!(),
2854+
}
2855+
}
2856+
28252857
#[test]
28262858
fn parse_select_having() {
28272859
let sql = "SELECT foo FROM bar GROUP BY foo HAVING COUNT(*) > 1";
@@ -4926,17 +4958,18 @@ fn parse_alter_table_drop_column() {
49264958
check_one("DROP COLUMN IF EXISTS is_active CASCADE");
49274959
check_one("DROP COLUMN IF EXISTS is_active RESTRICT");
49284960
one_statement_parses_to(
4929-
"ALTER TABLE tab DROP IF EXISTS is_active CASCADE",
4961+
"ALTER TABLE tab DROP COLUMN IF EXISTS is_active CASCADE",
49304962
"ALTER TABLE tab DROP COLUMN IF EXISTS is_active CASCADE",
49314963
);
49324964
one_statement_parses_to(
49334965
"ALTER TABLE tab DROP is_active CASCADE",
4934-
"ALTER TABLE tab DROP COLUMN is_active CASCADE",
4966+
"ALTER TABLE tab DROP is_active CASCADE",
49354967
);
49364968

49374969
fn check_one(constraint_text: &str) {
49384970
match alter_table_op(verified_stmt(&format!("ALTER TABLE tab {constraint_text}"))) {
49394971
AlterTableOperation::DropColumn {
4972+
has_column_keyword: true,
49404973
column_name,
49414974
if_exists,
49424975
drop_behavior,
@@ -15157,6 +15190,11 @@ fn parse_pipeline_operator() {
1515715190
dialects.verified_stmt("SELECT * FROM users |> ORDER BY id DESC");
1515815191
dialects.verified_stmt("SELECT * FROM users |> ORDER BY id DESC, name ASC");
1515915192

15193+
// tablesample pipe operator
15194+
dialects.verified_stmt("SELECT * FROM tbl |> TABLESAMPLE BERNOULLI (50)");
15195+
dialects.verified_stmt("SELECT * FROM tbl |> TABLESAMPLE SYSTEM (50 PERCENT)");
15196+
dialects.verified_stmt("SELECT * FROM tbl |> TABLESAMPLE SYSTEM (50) REPEATABLE (10)");
15197+
1516015198
// many pipes
1516115199
dialects.verified_stmt(
1516215200
"SELECT * FROM CustomerOrders |> AGGREGATE SUM(cost) AS total_cost GROUP BY customer_id, state, item_type |> EXTEND COUNT(*) OVER (PARTITION BY customer_id) AS num_orders |> WHERE num_orders > 1 |> AGGREGATE AVG(total_cost) AS average GROUP BY state DESC, item_type ASC",

tests/sqlparser_mssql.rs

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -377,6 +377,46 @@ fn parse_create_function() {
377377
);
378378
}
379379

380+
#[test]
381+
fn parse_create_function_parameter_default_values() {
382+
let single_default_sql =
383+
"CREATE FUNCTION test_func(@param1 INT = 42) RETURNS INT AS BEGIN RETURN @param1; END";
384+
assert_eq!(
385+
ms().verified_stmt(single_default_sql),
386+
Statement::CreateFunction(CreateFunction {
387+
or_alter: false,
388+
or_replace: false,
389+
temporary: false,
390+
if_not_exists: false,
391+
name: ObjectName::from(vec![Ident::new("test_func")]),
392+
args: Some(vec![OperateFunctionArg {
393+
mode: None,
394+
name: Some(Ident::new("@param1")),
395+
data_type: DataType::Int(None),
396+
default_expr: Some(Expr::Value((number("42")).with_empty_span())),
397+
},]),
398+
return_type: Some(DataType::Int(None)),
399+
function_body: Some(CreateFunctionBody::AsBeginEnd(BeginEndStatements {
400+
begin_token: AttachedToken::empty(),
401+
statements: vec![Statement::Return(ReturnStatement {
402+
value: Some(ReturnStatementValue::Expr(Expr::Identifier(Ident::new(
403+
"@param1"
404+
)))),
405+
})],
406+
end_token: AttachedToken::empty(),
407+
})),
408+
behavior: None,
409+
called_on_null: None,
410+
parallel: None,
411+
using: None,
412+
language: None,
413+
determinism_specifier: None,
414+
options: None,
415+
remote_connection: None,
416+
}),
417+
);
418+
}
419+
380420
#[test]
381421
fn parse_mssql_apply_join() {
382422
let _ = ms_and_generic().verified_only_select(

0 commit comments

Comments
 (0)