Skip to content

fix: bind hybrid search tsv_lang as a parameter with regconfig cast - #333

Open
Vladislav Nechakhin (vladislav-nechakhin) wants to merge 2 commits into
mainfrom
open-swe/bind-tsv-lang-as-parameter
Open

Vladislav Nechakhin (vladislav-nechakhin) wants to merge 2 commits into
mainfrom
open-swe/bind-tsv-lang-as-parameter

Conversation

@vladislav-nechakhin

Copy link
Copy Markdown

The two AsyncPGVectorStore statements that interpolate hybrid_search_config.tsv_lang into SQL as a quoted literal now bind it as a SQLAlchemy parameter with an explicit regconfig cast, so the value is always treated as data by PostgreSQL:

  • Write path: to_tsvector((:tsv_lang)::regconfig, :tsv_content) in aadd_embeddings
  • Search path: plainto_tsquery((:tsv_lang)::regconfig, :fts_query) in the hybrid sparse query

Behavior

  • Unchanged: when tsv_lang is unset (None or ""), both calls keep their one-argument forms and PostgreSQL applies default_text_search_config. No default is substituted.
  • Unchanged: stored tsvector values are identical for any valid language, so no migration or reindex is needed.
  • Changed: an invalid or nonexistent tsv_lang now surfaces a PostgreSQL error at query time (e.g. invalid name syntax, SQLSTATE 42602, or "text search configuration ... does not exist") instead of being spliced into the statement text.

The cast is wrapped as (:tsv_lang)::regconfig — the literal :tsv_lang::regconfig is not parsed as a bind parameter by SQLAlchemy text(), so the parentheses are required.

Testing

New database-backed tests in tests/unit_tests/v2/test_async_pg_vectorstore_tsv_lang.py cover the valid language (pg_catalog.english), the unset branch (None and ""), and the reported payload, asserting the raised error's SQLSTATE is 42602 (an invalid regconfig literal inside the bound parameter) rather than a statement syntax error. Existing hybrid search tests are unchanged and pass.

Follow-up (not in this PR): validating tsv_lang in HybridSearchConfig.__post_init__ so a bad value fails at construction instead of at query time.

Made by Open SWE · openai:gpt-6-astra (low)

References

Interpolating the hybrid search language into to_tsvector and
plainto_tsquery as a quoted literal required the value to be a valid
text search configuration name. Bind it as a SQLAlchemy parameter with
an explicit regconfig cast instead, so the value is always treated as
data by PostgreSQL. Unset languages keep the one-argument function
forms, so default_text_search_config still applies.

Invalid configuration values now surface a PostgreSQL error at query
time rather than being spliced into the statement.

Co-authored-by: open-swe[bot] <open-swe@users.noreply.github.com>
@ccurme
ccurme (ccurme) marked this pull request as ready for review September 16, 2026 16:20
The hybrid search index expression also interpolated the language as a
quoted literal, and DDL cannot take a bound parameter. Resolve the
language with quote_literal over a regconfig cast before splicing it,
so invalid values are rejected by PostgreSQL and the DDL only ever
receives the canonical literal.

Co-authored-by: open-swe[bot] <open-swe@users.noreply.github.com>

This branch has not been deployed

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant