Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions src/ast/ddl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,9 @@ use crate::ast::value::escape_single_quote_string;
use crate::ast::{
display_comma_separated, display_separated, CommentDef, CreateFunctionBody,
CreateFunctionUsing, DataType, Expr, FunctionBehavior, FunctionCalledOnNull,
FunctionDeterminismSpecifier, FunctionParallel, Ident, MySQLColumnPosition, ObjectName,
OperateFunctionArg, OrderByExpr, ProjectionSelect, SequenceOptions, SqlOption, Tag, Value,
ValueWithSpan,
FunctionDeterminismSpecifier, FunctionParallel, Ident, IndexColumn, MySQLColumnPosition,
ObjectName, OperateFunctionArg, OrderByExpr, ProjectionSelect, SequenceOptions, SqlOption, Tag,
Value, ValueWithSpan,
};
use crate::keywords::Keyword;
use crate::tokenizer::Token;
Expand Down Expand Up @@ -979,7 +979,7 @@ pub enum TableConstraint {
/// [1]: IndexType
index_type: Option<IndexType>,
/// Identifiers of the columns that are unique.
columns: Vec<Ident>,
columns: Vec<IndexColumn>,
index_options: Vec<IndexOption>,
characteristics: Option<ConstraintCharacteristics>,
/// Optional Postgres nulls handling: `[ NULLS [ NOT ] DISTINCT ]`
Expand Down Expand Up @@ -1015,7 +1015,7 @@ pub enum TableConstraint {
/// [1]: IndexType
index_type: Option<IndexType>,
/// Identifiers of the columns that form the primary key.
columns: Vec<Ident>,
columns: Vec<IndexColumn>,
index_options: Vec<IndexOption>,
characteristics: Option<ConstraintCharacteristics>,
},
Expand Down Expand Up @@ -1060,7 +1060,7 @@ pub enum TableConstraint {
/// [1]: IndexType
index_type: Option<IndexType>,
/// Referred column identifier list.
columns: Vec<Ident>,
columns: Vec<IndexColumn>,
},
/// MySQLs [fulltext][1] definition. Since the [`SPATIAL`][2] definition is exactly the same,
/// and MySQL displays both the same way, it is part of this definition as well.
Expand All @@ -1083,7 +1083,7 @@ pub enum TableConstraint {
/// Optional index name.
opt_index_name: Option<Ident>,
/// Referred column identifier list.
columns: Vec<Ident>,
columns: Vec<IndexColumn>,
},
}

Expand Down
35 changes: 21 additions & 14 deletions src/ast/spans.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,16 +28,17 @@ use super::{
ConstraintCharacteristics, CopySource, CreateIndex, CreateTable, CreateTableOptions, Cte,
Delete, DoUpdate, ExceptSelectItem, ExcludeSelectItem, Expr, ExprWithAlias, Fetch, FromTable,
Function, FunctionArg, FunctionArgExpr, FunctionArgumentClause, FunctionArgumentList,
FunctionArguments, GroupByExpr, HavingBound, IfStatement, IlikeSelectItem, Insert, Interpolate,
InterpolateExpr, Join, JoinConstraint, JoinOperator, JsonPath, JsonPathElem, LateralView,
LimitClause, MatchRecognizePattern, Measure, NamedParenthesizedList, NamedWindowDefinition,
ObjectName, ObjectNamePart, Offset, OnConflict, OnConflictAction, OnInsert, OpenStatement,
OrderBy, OrderByExpr, OrderByKind, Partition, PivotValueSource, ProjectionSelect, Query,
RaiseStatement, RaiseStatementValue, ReferentialAction, RenameSelectItem, ReplaceSelectElement,
ReplaceSelectItem, Select, SelectInto, SelectItem, SetExpr, SqlOption, Statement, Subscript,
SymbolDefinition, TableAlias, TableAliasColumnDef, TableConstraint, TableFactor, TableObject,
TableOptionsClustered, TableWithJoins, UpdateTableFromKind, Use, Value, Values, ViewColumnDef,
WhileStatement, WildcardAdditionalOptions, With, WithFill,
FunctionArguments, GroupByExpr, HavingBound, IfStatement, IlikeSelectItem, IndexColumn, Insert,
Interpolate, InterpolateExpr, Join, JoinConstraint, JoinOperator, JsonPath, JsonPathElem,
LateralView, LimitClause, MatchRecognizePattern, Measure, NamedParenthesizedList,
NamedWindowDefinition, ObjectName, ObjectNamePart, Offset, OnConflict, OnConflictAction,
OnInsert, OpenStatement, OrderBy, OrderByExpr, OrderByKind, Partition, PivotValueSource,
ProjectionSelect, Query, RaiseStatement, RaiseStatementValue, ReferentialAction,
RenameSelectItem, ReplaceSelectElement, ReplaceSelectItem, Select, SelectInto, SelectItem,
SetExpr, SqlOption, Statement, Subscript, SymbolDefinition, TableAlias, TableAliasColumnDef,
TableConstraint, TableFactor, TableObject, TableOptionsClustered, TableWithJoins,
UpdateTableFromKind, Use, Value, Values, ViewColumnDef, WhileStatement,
WildcardAdditionalOptions, With, WithFill,
};

/// Given an iterator of spans, return the [Span::union] of all spans.
Expand Down Expand Up @@ -650,7 +651,7 @@ impl Spanned for TableConstraint {
name.iter()
.map(|i| i.span)
.chain(index_name.iter().map(|i| i.span))
.chain(columns.iter().map(|i| i.span))
.chain(columns.iter().map(|i| i.span()))
.chain(characteristics.iter().map(|i| i.span())),
),
TableConstraint::PrimaryKey {
Expand All @@ -664,7 +665,7 @@ impl Spanned for TableConstraint {
name.iter()
.map(|i| i.span)
.chain(index_name.iter().map(|i| i.span))
.chain(columns.iter().map(|i| i.span))
.chain(columns.iter().map(|i| i.span()))
.chain(characteristics.iter().map(|i| i.span())),
),
TableConstraint::ForeignKey {
Expand Down Expand Up @@ -700,7 +701,7 @@ impl Spanned for TableConstraint {
} => union_spans(
name.iter()
.map(|i| i.span)
.chain(columns.iter().map(|i| i.span)),
.chain(columns.iter().map(|i| i.span())),
),
TableConstraint::FulltextOrSpatial {
fulltext: _,
Expand All @@ -711,7 +712,7 @@ impl Spanned for TableConstraint {
opt_index_name
.iter()
.map(|i| i.span)
.chain(columns.iter().map(|i| i.span)),
.chain(columns.iter().map(|i| i.span())),
),
}
}
Expand Down Expand Up @@ -745,6 +746,12 @@ impl Spanned for CreateIndex {
}
}

impl Spanned for IndexColumn {
fn span(&self) -> Span {
self.column.span()
}
}

impl Spanned for CaseStatement {
fn span(&self) -> Span {
let CaseStatement {
Expand Down
48 changes: 34 additions & 14 deletions src/parser/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6868,9 +6868,7 @@ impl<'a> Parser<'a> {
None
};

self.expect_token(&Token::LParen)?;
let columns = self.parse_comma_separated(Parser::parse_create_index_expr)?;
self.expect_token(&Token::RParen)?;
let columns = self.parse_parenthesized_index_column_list()?;

let include = if self.parse_keyword(Keyword::INCLUDE) {
self.expect_token(&Token::LParen)?;
Expand Down Expand Up @@ -8070,7 +8068,7 @@ impl<'a> Parser<'a> {
let index_name = self.parse_optional_ident()?;
let index_type = self.parse_optional_using_then_index_type()?;

let columns = self.parse_parenthesized_column_list(Mandatory, false)?;
let columns = self.parse_parenthesized_index_column_list()?;
let index_options = self.parse_index_options()?;
let characteristics = self.parse_constraint_characteristics()?;
Ok(Some(TableConstraint::Unique {
Expand All @@ -8092,7 +8090,7 @@ impl<'a> Parser<'a> {
let index_name = self.parse_optional_ident()?;
let index_type = self.parse_optional_using_then_index_type()?;

let columns = self.parse_parenthesized_column_list(Mandatory, false)?;
let columns = self.parse_parenthesized_index_column_list()?;
let index_options = self.parse_index_options()?;
let characteristics = self.parse_constraint_characteristics()?;
Ok(Some(TableConstraint::PrimaryKey {
Expand Down Expand Up @@ -8170,7 +8168,7 @@ impl<'a> Parser<'a> {
};

let index_type = self.parse_optional_using_then_index_type()?;
let columns = self.parse_parenthesized_column_list(Mandatory, false)?;
let columns = self.parse_parenthesized_index_column_list()?;

Ok(Some(TableConstraint::Index {
display_as_key,
Expand Down Expand Up @@ -8199,7 +8197,7 @@ impl<'a> Parser<'a> {

let opt_index_name = self.parse_optional_ident()?;

let columns = self.parse_parenthesized_column_list(Mandatory, false)?;
let columns = self.parse_parenthesized_index_column_list()?;

Ok(Some(TableConstraint::FulltextOrSpatial {
fulltext,
Expand Down Expand Up @@ -10601,6 +10599,14 @@ impl<'a> Parser<'a> {
self.parse_parenthesized_column_list_inner(optional, allow_empty, |p| p.parse_identifier())
}

/// Parses a parenthesized comma-separated list of index columns, which can be arbitrary
/// expressions with ordering information (and an opclass in some dialects).
fn parse_parenthesized_index_column_list(&mut self) -> Result<Vec<IndexColumn>, ParserError> {
self.parse_parenthesized_column_list_inner(Mandatory, false, |p| {
p.parse_create_index_expr()
})
}

/// Parses a parenthesized comma-separated list of qualified, possibly quoted identifiers.
/// For example: `(db1.sc1.tbl1.col1, db1.sc1.tbl1."col 2", ...)`
pub fn parse_parenthesized_qualified_column_list(
Expand Down Expand Up @@ -16527,6 +16533,20 @@ mod tests {
}};
}

fn mk_expected_col(name: &str) -> IndexColumn {
IndexColumn {
column: OrderByExpr {
expr: Expr::Identifier(name.into()),
options: OrderByOptions {
asc: None,
nulls_first: None,
},
with_fill: None,
},
operator_class: None,
}
}

let dialect =
TestedDialects::new(vec![Box::new(GenericDialect {}), Box::new(MySqlDialect {})]);

Expand All @@ -16537,7 +16557,7 @@ mod tests {
display_as_key: false,
name: None,
index_type: None,
columns: vec![Ident::new("c1")],
columns: vec![mk_expected_col("c1")],
}
);

Expand All @@ -16548,7 +16568,7 @@ mod tests {
display_as_key: true,
name: None,
index_type: None,
columns: vec![Ident::new("c1")],
columns: vec![mk_expected_col("c1")],
}
);

Expand All @@ -16559,7 +16579,7 @@ mod tests {
display_as_key: false,
name: Some(Ident::with_quote('\'', "index")),
index_type: None,
columns: vec![Ident::new("c1"), Ident::new("c2")],
columns: vec![mk_expected_col("c1"), mk_expected_col("c2")],
}
);

Expand All @@ -16570,7 +16590,7 @@ mod tests {
display_as_key: false,
name: None,
index_type: Some(IndexType::BTree),
columns: vec![Ident::new("c1")],
columns: vec![mk_expected_col("c1")],
}
);

Expand All @@ -16581,7 +16601,7 @@ mod tests {
display_as_key: false,
name: None,
index_type: Some(IndexType::Hash),
columns: vec![Ident::new("c1")],
columns: vec![mk_expected_col("c1")],
}
);

Expand All @@ -16592,7 +16612,7 @@ mod tests {
display_as_key: false,
name: Some(Ident::new("idx_name")),
index_type: Some(IndexType::BTree),
columns: vec![Ident::new("c1")],
columns: vec![mk_expected_col("c1")],
}
);

Expand All @@ -16603,7 +16623,7 @@ mod tests {
display_as_key: false,
name: Some(Ident::new("idx_name")),
index_type: Some(IndexType::Hash),
columns: vec![Ident::new("c1")],
columns: vec![mk_expected_col("c1")],
}
);
}
Expand Down
44 changes: 44 additions & 0 deletions src/test_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -448,3 +448,47 @@ pub fn call(function: &str, args: impl IntoIterator<Item = Expr>) -> Expr {
within_group: vec![],
})
}

/// Gets the first index column (mysql calls it a key part) of the first index found in a
/// [`Statement::CreateIndex`], [`Statement::CreateTable`], or [`Statement::AlterTable`].
pub fn index_column(stmt: Statement) -> Expr {
match stmt {
Statement::CreateIndex(CreateIndex { columns, .. }) => {
columns.first().unwrap().column.expr.clone()
}
Statement::CreateTable(CreateTable { constraints, .. }) => {
match constraints.first().unwrap() {
TableConstraint::Index { columns, .. } => {
columns.first().unwrap().column.expr.clone()
}
TableConstraint::Unique { columns, .. } => {
columns.first().unwrap().column.expr.clone()
}
TableConstraint::PrimaryKey { columns, .. } => {
columns.first().unwrap().column.expr.clone()
}
TableConstraint::FulltextOrSpatial { columns, .. } => {
columns.first().unwrap().column.expr.clone()
}
_ => panic!("Expected an index, unique, primary, full text, or spatial constraint (foreign key does not support general key part expressions)"),
}
}
Statement::AlterTable { operations, .. } => match operations.first().unwrap() {
AlterTableOperation::AddConstraint(TableConstraint::Index { columns, .. }) => {
columns.first().unwrap().column.expr.clone()
}
AlterTableOperation::AddConstraint(TableConstraint::Unique { columns, .. }) => {
columns.first().unwrap().column.expr.clone()
}
AlterTableOperation::AddConstraint(TableConstraint::PrimaryKey { columns, .. }) => {
columns.first().unwrap().column.expr.clone()
}
AlterTableOperation::AddConstraint(TableConstraint::FulltextOrSpatial {
columns,
..
}) => columns.first().unwrap().column.expr.clone(),
_ => panic!("Expected an index, unique, primary, full text, or spatial constraint (foreign key does not support general key part expressions)"),
},
_ => panic!("Expected CREATE INDEX, ALTER TABLE, or CREATE TABLE, got: {stmt:?}"),
}
}
Loading
Loading