You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
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):
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.
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.
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.
Not caught by the parity suite (no pgvector/geometry write tests).
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[...]).
Phase 2.3: Extension-aware type system #27 (extension-aware type system) — UI type-picker concern; coordinate pgvector handling so detect + read + write are consistent.
Summary
src/binding.rs::bind_pg_stringis 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_stringruns these three branches (in this order, before the UUID/array/TEXT fallbacks):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.is_raw_sql_function(line 561) — if the trimmed uppercase string starts withST_+ contains(, or one of the legacyGEOMFROMTEXT(/GEOMFROMWKB(/POINTFROMTEXT(/POINTFROMWKB(prefixes, the string is inlined verbatim as the SQL fragment (sql: s.to_string(), no param). This letsST_GeomFromText('POINT(1 2)', 4326)be sent raw.is_wkt_geometry(line 568) — if the trimmed uppercase string starts withPOINT(/LINESTRING(/POLYGON(/MULTI*/GEOMETRYCOLLECTION(/GEOMETRY(, emitsST_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 nobind_pg_vector_string, nois_raw_sql_function, nois_wkt_geometry.Consequences
[1,2,3]matches the plugin's array-literal heuristic and becomesARRAY[1, 2, 3]. PostgreSQL rejects this for avectorcolumn (no cast) → server error. The builtin would emit'[1,2,3]'::vector.ST_GeomFromText('POINT(1 2)', 4326)reaches the plain TEXT fallback and is bound as$Ntext. The function is never executed server-side; the literal text of the function is stored instead of the geometry.POINT(1 2)is not UUID-shaped or array-shaped, so it hits the TEXT fallback and is bound as bare$Ntext. Stored as the WKT string, not converted to a geometry.Impact
null) is tracked in extract.rs silently decodes ~40 built-in PostgreSQL types to null (BIT, MACADDR8, geometric, FTS, system IDs, REG*, pgvector, ltree, composite/domain/multirange) #82; this is the write side.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), thenis_raw_sql_functionandis_wkt_geometryafter the temporal step and before the UUID-shape check. Portbind_pg_vector_string,is_raw_sql_function,is_wkt_geometryfrom the builtin'shelpers.rs. Add unit tests inbinding_tests.rs:[1,2,3]for avectorcolumn →'[1,2,3]'::vector(notARRAY[...]).ST_GeomFromText(...)→ inlined verbatim.POINT(1 2)→ST_GeomFromText($N).Related
null); this issue is the write-side counterpart. Both should land together for full pgvector parity.TabularisDB/tabularisbinding.rs::bind_pg_string+helpers.rs::{bind_pg_vector_string, is_raw_sql_function, is_wkt_geometry}.