Conversation
EnRaiha
force-pushed
the
fix/issue306-vector-array-coercion
branch
from
September 17, 2026 02:16
aa4ec43 to
e3e1295
Compare
ARRAY[0.1, 0.2, 0.3] folds its literals to Decimal. extract_vector_floats kept Float and Integer, dropped the rest, and reported "got 0 elements" as XX000. - accept Float, Integer, Decimal, and numeric String elements - reject a non-numeric element by index and type - refuse non-finite values - preserve BadRequest at the binary_tuple wrap sites, so a client value error never surfaces as XX000
Error::BadRequest fell into the bridge's catch-all and reached the client as XX000. A client value error is not an internal fault. - ErrorCode::BadRequest mirrors the crate error across the Data Plane and the cluster wire (appended variant, existing slots untouched) - pgwire renders it 42601, the code the direct path already assigns - write-abort treats it as not established: the same code can be raised after an earlier step of a multi-step plan applied
…t-image doors Two strict-encoder wrap sites still moved a client value error into ErrorCode::Internal while the sibling sites preserved it. Mirror the sibling arm so a bad value keeps its 42601 on every path, and pin both directions: the abort classifier never treats a bad request as definitely-unapplied, and the cluster wire round-trips it verbatim.
…ct pass The collect pass encodes strict post-images, so a client value error can surface there. It was folded into ErrorCode::Internal; preserve it like the sibling doors so the client keeps 42601.
EnRaiha
force-pushed
the
fix/issue306-vector-array-coercion
branch
from
September 17, 2026 04:38
e3e1295 to
654b7cc
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
ARRAY[0.1, 0.2, 0.3]folds its literals toDecimalin the planner. Strict element coercion keptFloatandInteger, dropped every other element, and reported the literal as having 0 elements — and that mismatch surfaced asXX000, an internal error, for what is a client value problem. A non-numeric element was equally opaque: no element index, no type, and the same internal class.This PR fixes the coercion and the class. Elements of every numeric shape are read; a bad element is refused by index and type; and a client value error keeps its
BadRequestclass across the Data Plane boundary instead of degrading toXX000.Behaviour changes
INSERT … ARRAY[0.1, 0.2, 0.3]intoVECTOR(3), strict schemaXX000, "got 0 elements"ARRAY[0.1, 'nope', 0.3]XX00042601, naming the element index and its typeARRAY[NaN]/ARRAY[Inf]XX00042601Closes #306.
Root cause
extract_vector_floatsinstrict_format/coerce.rsmatchedValue::FloatandValue::Integeronly. The planner's literal folding producesDecimal, so a literalARRAY[0.1, 0.2, 0.3]contributed zero elements and the column reportedgot 0 elements.crate::Error::BadRequesthad no mirror in the bridge'sErrorCodeenum, so the conversion fell through the catch-all toErrorCode::Internal { detail }— every client value error crossed the Data Plane boundary asXX000, even though the direct (single-node) path already assigned42601.handlers/convert.rs,point/update/post_image.rs), the update-from-join collect pass, and two doors found by the audit rounds (below) had the same fold-into-Internalshape.What changed
Commit
0fd44a626— coercion:extract_vector_floatsreadsFloat,Integer,Decimal, and numericStringelements; a non-numeric element is rejected with its index and type; non-finite values are refused with the value.binary_tuplewrap sites (stored_body.rs,stage_write/body.rs×2,stage_upsert.rs) preserveBadRequestinstead of wrapping it.Commit
ddefcaa0f— wire coverage:document_strict_inserts_a_decimal_array_literal_into_a_vector_column(the filed case)document_strict_reports_a_non_numeric_element_by_index_and_type(message names the element; SQLSTATE pinned)Commit
6c29ac9fd— the bridge:ErrorCode::BadRequest { detail }added to the bridge envelope enum with the same doc-comment pattern as its siblings, and preserved inFrom<crate::Error>.DataPlaneErrorCode, appended variant; the enum's own doc says variants are appended, never reordered) with both round-trip conversions.42601(the code the direct path already assigns). The node-abort classifier treats it as not established: the same code can be raised after an earlier step of a multi-step plan applied, so refusal-without-apply is not provable from the code alone.Fixes from the audit rounds:
f912fb2b1: two more doors preservedBadRequest—handlers/convert.rs(CONVERT row encode) andpoint/update/post_image.rs(strict re-encode). Tests added: the abort classifier coversBadRequest; the cluster wire round-trips it verbatim.e3e129563: the update-from-join collect pass (handlers/update_from_join.rs), which encodes strict post-images, preserved it too.Regression proof
On base
main, without this change: the filed case reportsexpected VECTOR(3), got 0 elements (SQLSTATE XX000), and the bad-element case finds no element message. With this change both pass, and the bad-element SQLSTATE is asserted as42601.Tested
cargo nextest run -p nodedb --test wire -E 'test(cases::engine_surface_document_strict)'— 2 new cases passerror_from_data_plane,data_plane_error_wire,write_abort, and the sqlstate/error-code unit testssql_convert_column_defs,sql_typeguard_default_gate,sql_typeguard_defaults)cargo fmt --all -- --check— cleancargo clippy -p nodedb -p nodedb-cluster --lib -- -D warnings— cleanReview
A separate, read-only parity audit ran over this branch before submission. It found the same defect class on further sites and asked for two tests; all are fixed and verified here.
BadRequestintoInternal(handlers/convert.rs,point/update/post_image.rs)f912fb2b1)e3e129563)Notes
RUST_MIN_STACK=16M. The same abort reproduces on an unrelated branch with no native-path changes, so it is a host property, not this change. CI runs them at the repository default.Commits
0fd44a626—fix(strict-format): coerce ARRAY vector literals into a strict VECTORddefcaa0f— ARRAY vector literal wire coverage6c29ac9fd—fix(bridge): carry a bad request across the Data Plane boundaryf912fb2b1—fix(executor): keep a bad request out of XX000 on the convert and post-image doorse3e129563—fix(executor): keep a bad request typed on the update-from-join collect pass