Skip to content

Commit b42f58d

Browse files
committed
Merge remote-tracking branch 'origin/main'
2 parents 16f7d6c + b9365b3 commit b42f58d

File tree

8 files changed

+293
-45
lines changed

8 files changed

+293
-45
lines changed

src/ast/ddl.rs

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,11 @@ use sqlparser_derive::{Visit, VisitMut};
3030

3131
use crate::ast::value::escape_single_quote_string;
3232
use crate::ast::{
33-
display_comma_separated, display_separated, CommentDef, CreateFunctionBody,
33+
display_comma_separated, display_separated, ArgMode, CommentDef, CreateFunctionBody,
3434
CreateFunctionUsing, DataType, Expr, FunctionBehavior, FunctionCalledOnNull,
35-
FunctionDeterminismSpecifier, FunctionParallel, Ident, MySQLColumnPosition, ObjectName,
36-
OperateFunctionArg, OrderByExpr, ProjectionSelect, SequenceOptions, SqlOption, Tag, Value,
37-
ValueWithSpan,
35+
FunctionDeterminismSpecifier, FunctionParallel, Ident, IndexColumn, MySQLColumnPosition,
36+
ObjectName, OperateFunctionArg, OrderByExpr, ProjectionSelect, SequenceOptions, SqlOption, Tag,
37+
Value, ValueWithSpan,
3838
};
3939
use crate::keywords::Keyword;
4040
use crate::tokenizer::Token;
@@ -979,7 +979,7 @@ pub enum TableConstraint {
979979
/// [1]: IndexType
980980
index_type: Option<IndexType>,
981981
/// Identifiers of the columns that are unique.
982-
columns: Vec<Ident>,
982+
columns: Vec<IndexColumn>,
983983
index_options: Vec<IndexOption>,
984984
characteristics: Option<ConstraintCharacteristics>,
985985
/// Optional Postgres nulls handling: `[ NULLS [ NOT ] DISTINCT ]`
@@ -1015,7 +1015,7 @@ pub enum TableConstraint {
10151015
/// [1]: IndexType
10161016
index_type: Option<IndexType>,
10171017
/// Identifiers of the columns that form the primary key.
1018-
columns: Vec<Ident>,
1018+
columns: Vec<IndexColumn>,
10191019
index_options: Vec<IndexOption>,
10201020
characteristics: Option<ConstraintCharacteristics>,
10211021
},
@@ -1060,7 +1060,7 @@ pub enum TableConstraint {
10601060
/// [1]: IndexType
10611061
index_type: Option<IndexType>,
10621062
/// Referred column identifier list.
1063-
columns: Vec<Ident>,
1063+
columns: Vec<IndexColumn>,
10641064
},
10651065
/// MySQLs [fulltext][1] definition. Since the [`SPATIAL`][2] definition is exactly the same,
10661066
/// and MySQL displays both the same way, it is part of this definition as well.
@@ -1083,7 +1083,7 @@ pub enum TableConstraint {
10831083
/// Optional index name.
10841084
opt_index_name: Option<Ident>,
10851085
/// Referred column identifier list.
1086-
columns: Vec<Ident>,
1086+
columns: Vec<IndexColumn>,
10871087
},
10881088
}
10891089

@@ -1367,11 +1367,16 @@ impl fmt::Display for NullsDistinctOption {
13671367
pub struct ProcedureParam {
13681368
pub name: Ident,
13691369
pub data_type: DataType,
1370+
pub mode: Option<ArgMode>,
13701371
}
13711372

13721373
impl fmt::Display for ProcedureParam {
13731374
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1374-
write!(f, "{} {}", self.name, self.data_type)
1375+
if let Some(mode) = &self.mode {
1376+
write!(f, "{mode} {} {}", self.name, self.data_type)
1377+
} else {
1378+
write!(f, "{} {}", self.name, self.data_type)
1379+
}
13751380
}
13761381
}
13771382

src/ast/spans.rs

Lines changed: 21 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -28,16 +28,17 @@ use super::{
2828
ConstraintCharacteristics, CopySource, CreateIndex, CreateTable, CreateTableOptions, Cte,
2929
Delete, DoUpdate, ExceptSelectItem, ExcludeSelectItem, Expr, ExprWithAlias, Fetch, FromTable,
3030
Function, FunctionArg, FunctionArgExpr, FunctionArgumentClause, FunctionArgumentList,
31-
FunctionArguments, GroupByExpr, HavingBound, IfStatement, IlikeSelectItem, Insert, Interpolate,
32-
InterpolateExpr, Join, JoinConstraint, JoinOperator, JsonPath, JsonPathElem, LateralView,
33-
LimitClause, MatchRecognizePattern, Measure, NamedParenthesizedList, NamedWindowDefinition,
34-
ObjectName, ObjectNamePart, Offset, OnConflict, OnConflictAction, OnInsert, OpenStatement,
35-
OrderBy, OrderByExpr, OrderByKind, Partition, PivotValueSource, ProjectionSelect, Query,
36-
RaiseStatement, RaiseStatementValue, ReferentialAction, RenameSelectItem, ReplaceSelectElement,
37-
ReplaceSelectItem, Select, SelectInto, SelectItem, SetExpr, SqlOption, Statement, Subscript,
38-
SymbolDefinition, TableAlias, TableAliasColumnDef, TableConstraint, TableFactor, TableObject,
39-
TableOptionsClustered, TableWithJoins, UpdateTableFromKind, Use, Value, Values, ViewColumnDef,
40-
WhileStatement, WildcardAdditionalOptions, With, WithFill,
31+
FunctionArguments, GroupByExpr, HavingBound, IfStatement, IlikeSelectItem, IndexColumn, Insert,
32+
Interpolate, InterpolateExpr, Join, JoinConstraint, JoinOperator, JsonPath, JsonPathElem,
33+
LateralView, LimitClause, MatchRecognizePattern, Measure, NamedParenthesizedList,
34+
NamedWindowDefinition, ObjectName, ObjectNamePart, Offset, OnConflict, OnConflictAction,
35+
OnInsert, OpenStatement, OrderBy, OrderByExpr, OrderByKind, Partition, PivotValueSource,
36+
ProjectionSelect, Query, RaiseStatement, RaiseStatementValue, ReferentialAction,
37+
RenameSelectItem, ReplaceSelectElement, ReplaceSelectItem, Select, SelectInto, SelectItem,
38+
SetExpr, SqlOption, Statement, Subscript, SymbolDefinition, TableAlias, TableAliasColumnDef,
39+
TableConstraint, TableFactor, TableObject, TableOptionsClustered, TableWithJoins,
40+
UpdateTableFromKind, Use, Value, Values, ViewColumnDef, WhileStatement,
41+
WildcardAdditionalOptions, With, WithFill,
4142
};
4243

4344
/// Given an iterator of spans, return the [Span::union] of all spans.
@@ -650,7 +651,7 @@ impl Spanned for TableConstraint {
650651
name.iter()
651652
.map(|i| i.span)
652653
.chain(index_name.iter().map(|i| i.span))
653-
.chain(columns.iter().map(|i| i.span))
654+
.chain(columns.iter().map(|i| i.span()))
654655
.chain(characteristics.iter().map(|i| i.span())),
655656
),
656657
TableConstraint::PrimaryKey {
@@ -664,7 +665,7 @@ impl Spanned for TableConstraint {
664665
name.iter()
665666
.map(|i| i.span)
666667
.chain(index_name.iter().map(|i| i.span))
667-
.chain(columns.iter().map(|i| i.span))
668+
.chain(columns.iter().map(|i| i.span()))
668669
.chain(characteristics.iter().map(|i| i.span())),
669670
),
670671
TableConstraint::ForeignKey {
@@ -700,7 +701,7 @@ impl Spanned for TableConstraint {
700701
} => union_spans(
701702
name.iter()
702703
.map(|i| i.span)
703-
.chain(columns.iter().map(|i| i.span)),
704+
.chain(columns.iter().map(|i| i.span())),
704705
),
705706
TableConstraint::FulltextOrSpatial {
706707
fulltext: _,
@@ -711,7 +712,7 @@ impl Spanned for TableConstraint {
711712
opt_index_name
712713
.iter()
713714
.map(|i| i.span)
714-
.chain(columns.iter().map(|i| i.span)),
715+
.chain(columns.iter().map(|i| i.span())),
715716
),
716717
}
717718
}
@@ -745,6 +746,12 @@ impl Spanned for CreateIndex {
745746
}
746747
}
747748

749+
impl Spanned for IndexColumn {
750+
fn span(&self) -> Span {
751+
self.column.span()
752+
}
753+
}
754+
748755
impl Spanned for CaseStatement {
749756
fn span(&self) -> Span {
750757
let CaseStatement {

src/parser/mod.rs

Lines changed: 54 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -6868,9 +6868,7 @@ impl<'a> Parser<'a> {
68686868
None
68696869
};
68706870

6871-
self.expect_token(&Token::LParen)?;
6872-
let columns = self.parse_comma_separated(Parser::parse_create_index_expr)?;
6873-
self.expect_token(&Token::RParen)?;
6871+
let columns = self.parse_parenthesized_index_column_list()?;
68746872

68756873
let include = if self.parse_keyword(Keyword::INCLUDE) {
68766874
self.expect_token(&Token::LParen)?;
@@ -7626,9 +7624,22 @@ impl<'a> Parser<'a> {
76267624
}
76277625

76287626
pub fn parse_procedure_param(&mut self) -> Result<ProcedureParam, ParserError> {
7627+
let mode = if self.parse_keyword(Keyword::IN) {
7628+
Some(ArgMode::In)
7629+
} else if self.parse_keyword(Keyword::OUT) {
7630+
Some(ArgMode::Out)
7631+
} else if self.parse_keyword(Keyword::INOUT) {
7632+
Some(ArgMode::InOut)
7633+
} else {
7634+
None
7635+
};
76297636
let name = self.parse_identifier()?;
76307637
let data_type = self.parse_data_type()?;
7631-
Ok(ProcedureParam { name, data_type })
7638+
Ok(ProcedureParam {
7639+
name,
7640+
data_type,
7641+
mode,
7642+
})
76327643
}
76337644

76347645
pub fn parse_column_def(&mut self) -> Result<ColumnDef, ParserError> {
@@ -8070,7 +8081,7 @@ impl<'a> Parser<'a> {
80708081
let index_name = self.parse_optional_ident()?;
80718082
let index_type = self.parse_optional_using_then_index_type()?;
80728083

8073-
let columns = self.parse_parenthesized_column_list(Mandatory, false)?;
8084+
let columns = self.parse_parenthesized_index_column_list()?;
80748085
let index_options = self.parse_index_options()?;
80758086
let characteristics = self.parse_constraint_characteristics()?;
80768087
Ok(Some(TableConstraint::Unique {
@@ -8092,7 +8103,7 @@ impl<'a> Parser<'a> {
80928103
let index_name = self.parse_optional_ident()?;
80938104
let index_type = self.parse_optional_using_then_index_type()?;
80948105

8095-
let columns = self.parse_parenthesized_column_list(Mandatory, false)?;
8106+
let columns = self.parse_parenthesized_index_column_list()?;
80968107
let index_options = self.parse_index_options()?;
80978108
let characteristics = self.parse_constraint_characteristics()?;
80988109
Ok(Some(TableConstraint::PrimaryKey {
@@ -8170,7 +8181,7 @@ impl<'a> Parser<'a> {
81708181
};
81718182

81728183
let index_type = self.parse_optional_using_then_index_type()?;
8173-
let columns = self.parse_parenthesized_column_list(Mandatory, false)?;
8184+
let columns = self.parse_parenthesized_index_column_list()?;
81748185

81758186
Ok(Some(TableConstraint::Index {
81768187
display_as_key,
@@ -8199,7 +8210,7 @@ impl<'a> Parser<'a> {
81998210

82008211
let opt_index_name = self.parse_optional_ident()?;
82018212

8202-
let columns = self.parse_parenthesized_column_list(Mandatory, false)?;
8213+
let columns = self.parse_parenthesized_index_column_list()?;
82038214

82048215
Ok(Some(TableConstraint::FulltextOrSpatial {
82058216
fulltext,
@@ -10601,6 +10612,14 @@ impl<'a> Parser<'a> {
1060110612
self.parse_parenthesized_column_list_inner(optional, allow_empty, |p| p.parse_identifier())
1060210613
}
1060310614

10615+
/// Parses a parenthesized comma-separated list of index columns, which can be arbitrary
10616+
/// expressions with ordering information (and an opclass in some dialects).
10617+
fn parse_parenthesized_index_column_list(&mut self) -> Result<Vec<IndexColumn>, ParserError> {
10618+
self.parse_parenthesized_column_list_inner(Mandatory, false, |p| {
10619+
p.parse_create_index_expr()
10620+
})
10621+
}
10622+
1060410623
/// Parses a parenthesized comma-separated list of qualified, possibly quoted identifiers.
1060510624
/// For example: `(db1.sc1.tbl1.col1, db1.sc1.tbl1."col 2", ...)`
1060610625
pub fn parse_parenthesized_qualified_column_list(
@@ -15017,7 +15036,8 @@ impl<'a> Parser<'a> {
1501715036

1501815037
/// Parse a FETCH clause
1501915038
pub fn parse_fetch(&mut self) -> Result<Fetch, ParserError> {
15020-
self.expect_one_of_keywords(&[Keyword::FIRST, Keyword::NEXT])?;
15039+
let _ = self.parse_one_of_keywords(&[Keyword::FIRST, Keyword::NEXT]);
15040+
1502115041
let (quantity, percent) = if self
1502215042
.parse_one_of_keywords(&[Keyword::ROW, Keyword::ROWS])
1502315043
.is_some()
@@ -15026,16 +15046,16 @@ impl<'a> Parser<'a> {
1502615046
} else {
1502715047
let quantity = Expr::Value(self.parse_value()?);
1502815048
let percent = self.parse_keyword(Keyword::PERCENT);
15029-
self.expect_one_of_keywords(&[Keyword::ROW, Keyword::ROWS])?;
15049+
let _ = self.parse_one_of_keywords(&[Keyword::ROW, Keyword::ROWS]);
1503015050
(Some(quantity), percent)
1503115051
};
15052+
1503215053
let with_ties = if self.parse_keyword(Keyword::ONLY) {
1503315054
false
15034-
} else if self.parse_keywords(&[Keyword::WITH, Keyword::TIES]) {
15035-
true
1503615055
} else {
15037-
return self.expected("one of ONLY or WITH TIES", self.peek_token());
15056+
self.parse_keywords(&[Keyword::WITH, Keyword::TIES])
1503815057
};
15058+
1503915059
Ok(Fetch {
1504015060
with_ties,
1504115061
percent,
@@ -16527,6 +16547,20 @@ mod tests {
1652716547
}};
1652816548
}
1652916549

16550+
fn mk_expected_col(name: &str) -> IndexColumn {
16551+
IndexColumn {
16552+
column: OrderByExpr {
16553+
expr: Expr::Identifier(name.into()),
16554+
options: OrderByOptions {
16555+
asc: None,
16556+
nulls_first: None,
16557+
},
16558+
with_fill: None,
16559+
},
16560+
operator_class: None,
16561+
}
16562+
}
16563+
1653016564
let dialect =
1653116565
TestedDialects::new(vec![Box::new(GenericDialect {}), Box::new(MySqlDialect {})]);
1653216566

@@ -16537,7 +16571,7 @@ mod tests {
1653716571
display_as_key: false,
1653816572
name: None,
1653916573
index_type: None,
16540-
columns: vec![Ident::new("c1")],
16574+
columns: vec![mk_expected_col("c1")],
1654116575
}
1654216576
);
1654316577

@@ -16548,7 +16582,7 @@ mod tests {
1654816582
display_as_key: true,
1654916583
name: None,
1655016584
index_type: None,
16551-
columns: vec![Ident::new("c1")],
16585+
columns: vec![mk_expected_col("c1")],
1655216586
}
1655316587
);
1655416588

@@ -16559,7 +16593,7 @@ mod tests {
1655916593
display_as_key: false,
1656016594
name: Some(Ident::with_quote('\'', "index")),
1656116595
index_type: None,
16562-
columns: vec![Ident::new("c1"), Ident::new("c2")],
16596+
columns: vec![mk_expected_col("c1"), mk_expected_col("c2")],
1656316597
}
1656416598
);
1656516599

@@ -16570,7 +16604,7 @@ mod tests {
1657016604
display_as_key: false,
1657116605
name: None,
1657216606
index_type: Some(IndexType::BTree),
16573-
columns: vec![Ident::new("c1")],
16607+
columns: vec![mk_expected_col("c1")],
1657416608
}
1657516609
);
1657616610

@@ -16581,7 +16615,7 @@ mod tests {
1658116615
display_as_key: false,
1658216616
name: None,
1658316617
index_type: Some(IndexType::Hash),
16584-
columns: vec![Ident::new("c1")],
16618+
columns: vec![mk_expected_col("c1")],
1658516619
}
1658616620
);
1658716621

@@ -16592,7 +16626,7 @@ mod tests {
1659216626
display_as_key: false,
1659316627
name: Some(Ident::new("idx_name")),
1659416628
index_type: Some(IndexType::BTree),
16595-
columns: vec![Ident::new("c1")],
16629+
columns: vec![mk_expected_col("c1")],
1659616630
}
1659716631
);
1659816632

@@ -16603,7 +16637,7 @@ mod tests {
1660316637
display_as_key: false,
1660416638
name: Some(Ident::new("idx_name")),
1660516639
index_type: Some(IndexType::Hash),
16606-
columns: vec![Ident::new("c1")],
16640+
columns: vec![mk_expected_col("c1")],
1660716641
}
1660816642
);
1660916643
}

src/test_utils.rs

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -448,3 +448,47 @@ pub fn call(function: &str, args: impl IntoIterator<Item = Expr>) -> Expr {
448448
within_group: vec![],
449449
})
450450
}
451+
452+
/// Gets the first index column (mysql calls it a key part) of the first index found in a
453+
/// [`Statement::CreateIndex`], [`Statement::CreateTable`], or [`Statement::AlterTable`].
454+
pub fn index_column(stmt: Statement) -> Expr {
455+
match stmt {
456+
Statement::CreateIndex(CreateIndex { columns, .. }) => {
457+
columns.first().unwrap().column.expr.clone()
458+
}
459+
Statement::CreateTable(CreateTable { constraints, .. }) => {
460+
match constraints.first().unwrap() {
461+
TableConstraint::Index { columns, .. } => {
462+
columns.first().unwrap().column.expr.clone()
463+
}
464+
TableConstraint::Unique { columns, .. } => {
465+
columns.first().unwrap().column.expr.clone()
466+
}
467+
TableConstraint::PrimaryKey { columns, .. } => {
468+
columns.first().unwrap().column.expr.clone()
469+
}
470+
TableConstraint::FulltextOrSpatial { columns, .. } => {
471+
columns.first().unwrap().column.expr.clone()
472+
}
473+
_ => panic!("Expected an index, unique, primary, full text, or spatial constraint (foreign key does not support general key part expressions)"),
474+
}
475+
}
476+
Statement::AlterTable { operations, .. } => match operations.first().unwrap() {
477+
AlterTableOperation::AddConstraint(TableConstraint::Index { columns, .. }) => {
478+
columns.first().unwrap().column.expr.clone()
479+
}
480+
AlterTableOperation::AddConstraint(TableConstraint::Unique { columns, .. }) => {
481+
columns.first().unwrap().column.expr.clone()
482+
}
483+
AlterTableOperation::AddConstraint(TableConstraint::PrimaryKey { columns, .. }) => {
484+
columns.first().unwrap().column.expr.clone()
485+
}
486+
AlterTableOperation::AddConstraint(TableConstraint::FulltextOrSpatial {
487+
columns,
488+
..
489+
}) => columns.first().unwrap().column.expr.clone(),
490+
_ => panic!("Expected an index, unique, primary, full text, or spatial constraint (foreign key does not support general key part expressions)"),
491+
},
492+
_ => panic!("Expected CREATE INDEX, ALTER TABLE, or CREATE TABLE, got: {stmt:?}"),
493+
}
494+
}

0 commit comments

Comments
 (0)