From 9be43e11cff752a0225ec375dbc273dd8c1b7e79 Mon Sep 17 00:00:00 2001 From: Jakob Truelsen Date: Mon, 11 Aug 2025 15:40:20 +0200 Subject: [PATCH 1/3] skip opclasses in indexes --- src/alter.rs | 4 +--- src/create.rs | 23 +++++++++++++++++++++-- src/keywords.rs | 6 ++++++ src/lib.rs | 14 ++++++++++++++ src/span.rs | 2 +- 5 files changed, 43 insertions(+), 6 deletions(-) diff --git a/src/alter.rs b/src/alter.rs index bfa1d9e..af239a3 100644 --- a/src/alter.rs +++ b/src/alter.rs @@ -756,9 +756,7 @@ fn parse_alter_table<'a>( match parser.token { Token::Ident(_, Keyword::DEFAULT) => { let drop_default_span = parser.consume().join_span(&set_span); - AlterColumnAction::DropDefault { - drop_default_span, - } + AlterColumnAction::DropDefault { drop_default_span } } Token::Ident(_, Keyword::NOT) => { let drop_not_null_span = set_span.join_span( diff --git a/src/create.rs b/src/create.rs index 15f7756..2fe2eb7 100644 --- a/src/create.rs +++ b/src/create.rs @@ -1033,12 +1033,31 @@ fn parse_create_index<'a>( gist_span.join_span(&using_span), )); } + let l_paren_span = parser.consume_token(Token::LParen)?; let mut column_names = Vec::new(); - column_names.push(parser.consume_plain_identifier()?); - while parser.skip_token(Token::Comma).is_some() { + loop { column_names.push(parser.consume_plain_identifier()?); + if let Token::Ident( + _, + Keyword::TEXT_PATTERN_OPS + | Keyword::VARCHAR_PATTERN_OPS + | Keyword::BPCHAR_PATTERN_OPS + | Keyword::INT8_OPS + | Keyword::INT4_OPS + | Keyword::INT2_OPS, + ) = &parser.token + { + let range = parser.consume(); + if !parser.options.dialect.is_postgresql() { + parser.err("Opclasses not supporetd", &range); + } + } + if parser.skip_token(Token::Comma).is_none() { + break; + } } + let r_paren_span = parser.consume_token(Token::RParen)?; let mut where_ = None; diff --git a/src/keywords.rs b/src/keywords.rs index 7158236..15dc976 100644 --- a/src/keywords.rs +++ b/src/keywords.rs @@ -128,6 +128,7 @@ BODY BOOL BOOLEAN BOTH +BPCHAR_PATTERN_OPS BTREE BY BYTE @@ -389,9 +390,12 @@ INSTR INT INT1 INT2 +INT2_OPS INT3 INT4 +INT4_OPS INT8 +INT8_OPS INTEGER INTERSECT INTERSECTA @@ -844,6 +848,7 @@ TEMPORARY TEMPTABLE TERMINATED TEXT +TEXT_PATTERN_OPS THAN THEN THREADS @@ -909,6 +914,7 @@ VALUE VALUES VARBINARY VARCHAR +VARCHAR_PATTERN_OPS VARCHAR2 VARCHARACTER VARIABLES diff --git a/src/lib.rs b/src/lib.rs index 659d4c8..2ed81a3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -288,6 +288,7 @@ pub fn test_parse_delete_sql_with_schema() { parse_statement(sql, &mut issues, &options); assert!(issues.is_ok(), "{}", issues); } + #[test] pub fn parse_create_index_sql_with_schema() { let sql = "CREATE INDEX `idx_test` ON test_schema.test(`col_test`)"; @@ -301,6 +302,19 @@ pub fn parse_create_index_sql_with_schema() { assert!(issues.is_ok(), "{}", issues); } +#[test] +pub fn parse_create_index_sql_with_opclass() { + let sql = "CREATE INDEX idx_test ON test(path text_pattern_ops)"; + let options = ParseOptions::new() + .dialect(SQLDialect::PostgreSQL) + .arguments(SQLArguments::Dollar) + .warn_unquoted_identifiers(false); + + let mut issues = Issues::new(sql); + parse_statement(sql, &mut issues, &options); + assert!(issues.is_ok(), "{}", issues); +} + #[test] pub fn parse_drop_index_sql_with_schema() { let sql = "DROP INDEX `idx_test` ON test_schema.test"; diff --git a/src/span.rs b/src/span.rs index 1ec02ec..af53270 100644 --- a/src/span.rs +++ b/src/span.rs @@ -122,7 +122,7 @@ impl Spanned for (bool, S) { } } -impl Spanned for (& str, S) { +impl Spanned for (&str, S) { fn span(&self) -> Span { self.1.span() } From 7984b3adf4bf1f1576aad472edc0fa368a068455 Mon Sep 17 00:00:00 2001 From: Jakob Truelsen Date: Mon, 11 Aug 2025 15:40:31 +0200 Subject: [PATCH 2/3] Add starts with function --- src/expression.rs | 2 ++ src/keywords.rs | 1 + 2 files changed, 3 insertions(+) diff --git a/src/expression.rs b/src/expression.rs index fa4eb1c..7cb144e 100644 --- a/src/expression.rs +++ b/src/expression.rs @@ -174,6 +174,7 @@ pub enum Function<'a> { SoundEx, Space, Sqrt, + StartsWith, StrCmp, Strftime, StrToDate, @@ -600,6 +601,7 @@ fn parse_function<'a>( Token::Ident(_, Keyword::VALUES) => Function::Value, Token::Ident(_, Keyword::LEAD) => Function::Lead, Token::Ident(_, Keyword::LAG) => Function::Lag, + Token::Ident(_, Keyword::STARTS_WITH) => Function::StartsWith, //https://mariadb.com/kb/en/control-flow-functions/ Token::Ident(_, Keyword::IFNULL) => Function::IfNull, diff --git a/src/keywords.rs b/src/keywords.rs index 15dc976..5568639 100644 --- a/src/keywords.rs +++ b/src/keywords.rs @@ -806,6 +806,7 @@ STAGE START STARTING STARTS +STARTS_WITH STATEMENT STATS_AUTO_RECALC STATS_PERSISTENT From 4f1b8dd0599278685144cac73822c09ed382b6c0 Mon Sep 17 00:00:00 2001 From: Jakob Truelsen Date: Mon, 11 Aug 2025 15:40:51 +0200 Subject: [PATCH 3/3] bump version --- Cargo.lock | 2 +- Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 063ba19..625a8f9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,4 +4,4 @@ version = 4 [[package]] name = "sql-parse" -version = "0.25.0" +version = "0.26.0" diff --git a/Cargo.toml b/Cargo.toml index dfe2d03..04ceccf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sql-parse" -version = "0.25.0" +version = "0.26.0" edition = "2021" authors = ["Jakob Truelsen "] keywords = [ "mysql", "postgresql", "sql", "lexer", "parser" ]