Skip to content

Support CREATE VECTOR INDEX - #2437

Open
moshap-firebolt wants to merge 4 commits into
apache:mainfrom
moshap-firebolt:bigquery-create-vector-index
Open

moshap-firebolt wants to merge 4 commits into
apache:mainfrom
moshap-firebolt:bigquery-create-vector-index

Conversation

@moshap-firebolt

@moshap-firebolt moshap-firebolt commented Aug 12, 2026 •

Copy link
Copy Markdown
Contributor

CREATE VECTOR INDEX creates an index for nearest-neighbor search over an embedding column in BigQuery, SQL Server and TiDB, but no dialect parsed it:

CREATE VECTOR INDEX idx ON t(embedding) OPTIONS(index_type = 'IVF', distance_type = 'COSINE')
-- Expected: an object type after CREATE, found: VECTOR

VECTOR becomes a keyword and a modifier on CREATE INDEX, like UNIQUE, so the statement reuses CreateIndex and its existing trailers (USING, INCLUDE, WITH, expression targets). CreateIndex gains vector, or_replace, options (BigQuery OPTIONS(...)), storing (BigQuery STORING(...)) and filegroup (SQL Server ON <filegroup>). A vector index accepts WITH (...) in every dialect, for SQL Server. Plain CREATE INDEX is unchanged.

Oracle's mandatory ORGANIZATION clause and MariaDB's bare M = ... 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's OPTIONS/STORING, SQL Server's bracket names, WITH (...) and ON [PRIMARY], and TiDB's distance-function target with USING HNSW.

This PR was prepared with AI assistance (Claude).

Dialects: BigQuery, MsSql, MySQL, Generic

@LucaCappelletti94 LucaCappelletti94 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

@moshap-firebolt
moshap-firebolt force-pushed the bigquery-create-vector-index branch from 1e9b099 to 8c5ccd7 Compare August 18, 2026 18:51
@moshap-firebolt moshap-firebolt changed the title BigQuery: support CREATE VECTOR INDEX Support CREATE VECTOR INDEX Aug 18, 2026
@moshap-firebolt
moshap-firebolt force-pushed the bigquery-create-vector-index branch 2 times, most recently from de8c8a1 to 1e9b099 Compare August 18, 2026 19:31
@moshap-firebolt moshap-firebolt changed the title Support CREATE VECTOR INDEX BigQuery: support CREATE VECTOR INDEX Aug 18, 2026
@moshap-firebolt
moshap-firebolt force-pushed the bigquery-create-vector-index branch from b6aa124 to dd1de78 Compare August 19, 2026 00:27
@moshap-firebolt moshap-firebolt changed the title BigQuery: support CREATE VECTOR INDEX Support CREATE VECTOR INDEX Aug 19, 2026
@moshap-firebolt

Copy link
Copy Markdown
Contributor Author

@LucaCappelletti94 - done, added tests demonstrating different syntaxes. Note - didn't implement full blown Oracle's one.

@moshap-firebolt
moshap-firebolt force-pushed the bigquery-create-vector-index branch from dd1de78 to e30e003 Compare August 24, 2026 21:35

@LucaCappelletti94 LucaCappelletti94 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment thread tests/sqlparser_oracle.rs
Comment on lines +543 to +551
#[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)");
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Suggested change
#[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)");
}

Comment thread src/keywords.rs
VARYING,
VAR_POP,
VAR_SAMP,
VERBOSE,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

VECTOR likely should be a keyword

Suggested change
VECTOR,
VERBOSE,

Comment thread src/parser/mod.rs Outdated
Comment on lines +5314 to +5317
} else if matches!(
&self.peek_token_ref().token,
Token::Word(w) if w.keyword == Keyword::NoKeyword && w.value.eq_ignore_ascii_case("VECTOR")
) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After adding the keyword, you can now replace this with:

Suggested change
} 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) {

Comment thread tests/sqlparser_mssql.rs
// (`METRIC` / `TYPE` / `MAXDOP`).
ms().verified_stmt(
"CREATE VECTOR INDEX vec_idx ON [dbo].[articles]([title_vector]) WITH (METRIC = 'cosine', TYPE = 'DiskANN', MAXDOP = 8)",
);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The ON syntax from SQL Server CREATE VECTOR INDEX grammar still does not parse, here is a red test for it:

Suggested change
);
);
ms().verified_stmt(
"CREATE VECTOR INDEX vec_idx ON [dbo].[articles]([title_vector]) WITH (METRIC = 'cosine', TYPE = 'DiskANN', MAXDOP = 8) ON [PRIMARY]",
);

@LucaCappelletti94 LucaCappelletti94 added MySQL SQL Server BigQuery Oracle waiting on contributor The review needs further refinements by its author labels Sep 22, 2026
moshap-firebolt and others added 4 commits October 29, 2026 16:38
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]>
@moshap-firebolt
moshap-firebolt force-pushed the bigquery-create-vector-index branch from e30e003 to cd6a0a8 Compare October 30, 2026 19:33
@codecov-commenter

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 67.44186% with 14 lines in your changes missing coverage. Please review.
✅ Project coverage is 82.58%. Comparing base (50813ee) to head (cd6a0a8).
⚠️ Report is 5 commits behind head on main.

Files with missing lines Patch % Lines
src/ast/spans.rs 0.00% 6 Missing ⚠️
src/parser/mod.rs 80.76% 0 Missing and 5 partials ⚠️
src/ast/ddl.rs 72.72% 0 Missing and 3 partials ⚠️
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.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

BigQuery MySQL Oracle SQL Server waiting on contributor The review needs further refinements by its author

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants