Repository navigation
Support CREATE VECTOR INDEX - #2437
moshap-firebolt wants to merge 4 commits into
Conversation
LucaCappelletti94
left a comment
There was a problem hiding this comment.
At this time, this PR edits would suggest that CREATE VECTOR INDEX is a BigQuery-specific syntax, but it is not, as it is supported also by:
- Oracle SQL
- Microsoft SQL
- Therefore also Generic Dialect
Therefore, move the tests to sqlparser common and ensure that all dialects that support the syntax successfully parse it. It may be acceptable to maintainers that dialects that do not support the syntax also parse it given the current preference for permissive parsing. I suggest you also review the possible syntax variations that these other dialects may have on this syntax, so as to cover more of its variants completely.
1e9b099 to
8c5ccd7
Compare
CREATE VECTOR INDEXCREATE VECTOR INDEX
de8c8a1 to
1e9b099
Compare
CREATE VECTOR INDEXCREATE VECTOR INDEX
b6aa124 to
dd1de78
Compare
CREATE VECTOR INDEXCREATE VECTOR INDEX
|
@LucaCappelletti94 - done, added tests demonstrating different syntaxes. Note - didn't implement full blown Oracle's one. |
dd1de78 to
e30e003
Compare
LucaCappelletti94
left a comment
There was a problem hiding this comment.
I believe any Oracle support note should be removed at this time, given that its mandatory grammar is still unsupported.
Do recall to rebase on main to avoid this branch getting stale.
| #[test] | ||
| fn parse_oracle_create_vector_index() { | ||
| // Oracle's specialized clauses (ORGANIZATION / DISTANCE / WITH TARGET | ||
| // ACCURACY / PARAMETERS) are not yet parsed; the forms it shares with the | ||
| // common grammar — an expression target and an `INCLUDE` list — round-trip. | ||
| oracle().verified_stmt("CREATE VECTOR INDEX g_idx ON galaxies(embedding)"); | ||
| oracle().verified_stmt("CREATE VECTOR INDEX g_idx ON galaxies(VEC_DISTANCE(embedding))"); | ||
| oracle().verified_stmt("CREATE VECTOR INDEX g_idx ON galaxies(embedding) INCLUDE (id)"); | ||
| } |
There was a problem hiding this comment.
None of these inputs are valid Oracle statements, and the common test already covers permissive parsing of the shared prefix across every dialect. Since correct Oracle statements are not currently supported, it does not make sense to test for incorrect ones even though this implementation parses them without erroring out, which I am unsure whether that is desirable.
| #[test] | |
| fn parse_oracle_create_vector_index() { | |
| // Oracle's specialized clauses (ORGANIZATION / DISTANCE / WITH TARGET | |
| // ACCURACY / PARAMETERS) are not yet parsed; the forms it shares with the | |
| // common grammar — an expression target and an `INCLUDE` list — round-trip. | |
| oracle().verified_stmt("CREATE VECTOR INDEX g_idx ON galaxies(embedding)"); | |
| oracle().verified_stmt("CREATE VECTOR INDEX g_idx ON galaxies(VEC_DISTANCE(embedding))"); | |
| oracle().verified_stmt("CREATE VECTOR INDEX g_idx ON galaxies(embedding) INCLUDE (id)"); | |
| } |
| VARYING, | ||
| VAR_POP, | ||
| VAR_SAMP, | ||
| VERBOSE, |
There was a problem hiding this comment.
VECTOR likely should be a keyword
| VECTOR, | |
| VERBOSE, |
| } else if matches!( | ||
| &self.peek_token_ref().token, | ||
| Token::Word(w) if w.keyword == Keyword::NoKeyword && w.value.eq_ignore_ascii_case("VECTOR") | ||
| ) { |
There was a problem hiding this comment.
After adding the keyword, you can now replace this with:
| } else if matches!( | |
| &self.peek_token_ref().token, | |
| Token::Word(w) if w.keyword == Keyword::NoKeyword && w.value.eq_ignore_ascii_case("VECTOR") | |
| ) { | |
| } else if self.parse_keyword(Keyword::VECTOR) { |
| // (`METRIC` / `TYPE` / `MAXDOP`). | ||
| ms().verified_stmt( | ||
| "CREATE VECTOR INDEX vec_idx ON [dbo].[articles]([title_vector]) WITH (METRIC = 'cosine', TYPE = 'DiskANN', MAXDOP = 8)", | ||
| ); |
There was a problem hiding this comment.
The ON syntax from SQL Server CREATE VECTOR INDEX grammar still does not parse, here is a red test for it:
| ); | |
| ); | |
| ms().verified_stmt( | |
| "CREATE VECTOR INDEX vec_idx ON [dbo].[articles]([title_vector]) WITH (METRIC = 'cosine', TYPE = 'DiskANN', MAXDOP = 8) ON [PRIMARY]", | |
| ); |
BigQuery can create a vector index for approximate nearest-neighbor search over
an embedding column:
CREATE [OR REPLACE] VECTOR INDEX [IF NOT EXISTS] <name>
ON <table>(<column>)
OPTIONS(index_type = 'IVF', distance_type = 'COSINE', ...)
`VECTOR` is not a keyword, so `parse_create` previously failed with
`Expected: an object type after CREATE, found: VECTOR`.
- Add `vector`, `or_replace` and `options` fields to `CreateIndex`. `VECTOR` is
a modifier on `CREATE INDEX` (like `EXTERNAL` on `CREATE TABLE`), so it reuses
the existing node rather than a new statement variant. `Display` renders
`CREATE [OR REPLACE ]VECTOR INDEX ...` plus a trailing `OPTIONS(...)`.
- Parse the form in `parse_create` via a small `parse_create_vector_index`
helper; the `OPTIONS(...)` clause reuses `parse_options` / `SqlOption`, so it
parses and renders the same way as `CREATE TABLE` / `CREATE VIEW` OPTIONS.
- Plain `CREATE INDEX` is unchanged (all three fields default to false/empty).
- New test `parse_bigquery_create_vector_index` in `tests/sqlparser_bigquery.rs`
verifies the round-trip and covers `OR REPLACE`, `IF NOT EXISTS`, multi-part
names and the OPTIONS-less form.
Docs: https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#create_vector_index_statement
Co-authored-by: Claude Opus 4.8 <[email protected]>
Address review feedback that `CREATE VECTOR INDEX` is not BigQuery-specific (Oracle, SQL Server, MariaDB and TiDB also have it, hence Generic too). - Route the statement through `parse_create_index` instead of a separate BigQuery helper, so it inherits the standard index trailers (`USING`, `INCLUDE`, `WITH`, expression targets, index options) that cover the Oracle / SQL Server / TiDB variants, plus the BigQuery `OPTIONS(...)` clause. - Align `Display` order (OPTIONS after WITH) with parse order so `INCLUDE` + `OPTIONS` combinations round-trip. - Drop the BigQuery-specific doc-comment framing. - Move the test to `tests/sqlparser_common.rs` as `parse_create_vector_index`, running across all dialects and covering `OR REPLACE`, `IF NOT EXISTS`, schema-qualified names, `OPTIONS(...)`, the `INCLUDE` trailer, and an expression target. Co-authored-by: Claude Opus 4.8 <[email protected]>
Extend the shared `CREATE VECTOR INDEX` parsing to the trailers used by the other dialects, and add per-dialect tests: - `STORING(...)` covering-column clause (BigQuery); new `storing` field on `CreateIndex`, rendered after `INCLUDE`. - Accept a `WITH (...)` options clause on a vector index in every dialect (SQL Server `WITH (METRIC = ..., TYPE = ..., MAXDOP = ...)`), not only the dialects that enable it for a plain `CREATE INDEX`. Tests: - `tests/sqlparser_common.rs` — the generic core plus the shared trailers (`INCLUDE`, `STORING`, `WITH`, `USING`, expression targets) across all dialects. - `tests/sqlparser_bigquery.rs` — `OPTIONS(...)` with index_type / distance_type / JSON tuning keys, and `STORING(...)`. - `tests/sqlparser_mssql.rs` — bracket-quoted names with `WITH (...)`. - `tests/sqlparser_mysql.rs` — TiDB's distance-function target with `USING`. - `tests/sqlparser_oracle.rs` — the core, an expression target and an `INCLUDE` list (Oracle's `ORGANIZATION` / `DISTANCE` / `WITH TARGET ACCURACY` / `PARAMETERS` clauses are not yet parsed). Co-authored-by: Claude Opus 4.8 <[email protected]>
- Add `VECTOR` as a keyword and match it with `parse_keyword`. - Parse SQL Server's trailing `ON <filegroup>` on a vector index into a new `CreateIndex::filegroup` field. - Drop the Oracle tests: Oracle's mandatory clauses are still unsupported, and the common test covers the shared prefix. Co-authored-by: Claude Opus 5.5 <[email protected]>
e30e003 to
cd6a0a8
Compare
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #2437 +/- ##
==========================================
+ Coverage 82.54% 82.58% +0.04%
==========================================
Files 42 42
Lines 35553 35651 +98
Branches 35553 35651 +98
==========================================
+ Hits 29346 29443 +97
+ Misses 2672 2665 -7
- Partials 3535 3543 +8 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
CREATE VECTOR INDEXcreates an index for nearest-neighbor search over an embedding column in BigQuery, SQL Server and TiDB, but no dialect parsed it:VECTORbecomes a keyword and a modifier onCREATE INDEX, likeUNIQUE, so the statement reusesCreateIndexand its existing trailers (USING,INCLUDE,WITH, expression targets).CreateIndexgainsvector,or_replace,options(BigQueryOPTIONS(...)),storing(BigQuerySTORING(...)) andfilegroup(SQL ServerON <filegroup>). A vector index acceptsWITH (...)in every dialect, for SQL Server. PlainCREATE INDEXis unchanged.Oracle's mandatory
ORGANIZATIONclause and MariaDB's bareM = ...option need their own grammar and are left for a follow-up.Round-trip tests cover the shared form on all dialects in
sqlparser_common.rs, plus BigQuery'sOPTIONS/STORING, SQL Server's bracket names,WITH (...)andON [PRIMARY], and TiDB's distance-function target withUSING HNSW.This PR was prepared with AI assistance (Claude).
Dialects: BigQuery, MsSql, MySQL, Generic