Skip to content

binding.rs cannot write pgvector columns or PostGIS geometry (missing pgvector / raw-SQL-function / WKT branches in bind_pg_string) #83

Description

@aesslinger

Summary

src/binding.rs::bind_pg_string is missing three branches that the built-in driver runs in its value-binding cascade: pgvector (bind_pg_vector_string), raw-SQL-function passthrough (is_raw_sql_function), and WKT-geometry auto-wrapping (is_wkt_geometry). INSERT/UPDATE into pgvector columns or PostGIS geometry columns produces wrong SQL or wrong data.

Builtin behavior (upstream main)

src-tauri/src/drivers/postgres/binding.rs::bind_pg_string runs these three branches (in this order, before the UUID/array/TEXT fallbacks):

  1. pgvector (line 521) — options.column_type.and_then(|t| bind_pg_vector_string(s, t)). Validates the literal against a strict character allow-list and emits '<value>'::<type> inline (no param) — pgvector has no text→vector cast for a bound parameter.
  2. is_raw_sql_function (line 561) — if the trimmed uppercase string starts with ST_ + contains (, or one of the legacy GEOMFROMTEXT(/GEOMFROMWKB(/POINTFROMTEXT(/POINTFROMWKB( prefixes, the string is inlined verbatim as the SQL fragment (sql: s.to_string(), no param). This lets ST_GeomFromText('POINT(1 2)', 4326) be sent raw.
  3. is_wkt_geometry (line 568) — if the trimmed uppercase string starts with POINT(/LINESTRING(/POLYGON(/MULTI*/GEOMETRYCOLLECTION(/GEOMETRY(, emits ST_GeomFromText($N) with the WKT string bound as TEXT.

Plugin behavior (this repo)

src/binding.rs::bind_pg_string (lines 212-300) cascade: DEFAULT → blob → enum → boolean → numeric-string → temporal-string → UUID shape → array-literal ([...]) → TEXT fallback. There is no bind_pg_vector_string, no is_raw_sql_function, no is_wkt_geometry.

Consequences

  • pgvector column: a value [1,2,3] matches the plugin's array-literal heuristic and becomes ARRAY[1, 2, 3]. PostgreSQL rejects this for a vector column (no cast) → server error. The builtin would emit '[1,2,3]'::vector.
  • Raw SQL function: ST_GeomFromText('POINT(1 2)', 4326) reaches the plain TEXT fallback and is bound as $N text. The function is never executed server-side; the literal text of the function is stored instead of the geometry.
  • WKT geometry: POINT(1 2) is not UUID-shaped or array-shaped, so it hits the TEXT fallback and is bound as bare $N text. Stored as the WKT string, not converted to a geometry.

Impact

Fix

Port the three branches into bind_pg_string (src/binding.rs) in the builtin's order: pgvector right after the DEFAULT sentinel (before blob — pgvector must run before the array-literal heuristic), then is_raw_sql_function and is_wkt_geometry after the temporal step and before the UUID-shape check. Port bind_pg_vector_string, is_raw_sql_function, is_wkt_geometry from the builtin's helpers.rs. Add unit tests in binding_tests.rs:

  • [1,2,3] for a vector column → '[1,2,3]'::vector (not ARRAY[...]).
  • ST_GeomFromText(...) → inlined verbatim.
  • POINT(1 2)ST_GeomFromText($N).

Related

Activity

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

Metadata

Metadata

Assignees

Labels

bugSomething isn't workingcapability-gapA builtin-only feature this plugin doesn't yet support

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions