Reject a tuple whose column count disagrees with the relation - #103
Reject a tuple whose column count disagrees with the relation#103lukashes wants to merge 1 commit into
Conversation
📊 Benchmark ResultsCurrent run is the minimum over 3 passes, compared against the base branch (
Summary: 🟢 1 faster · ➡️ 10 neutral · ⚪ 2 ignored (sub-μs) Thresholds: <1μs ignore · 1–20μs 15% · 20–50μs 10% · ≥50μs 5%. Measured on a shared CI runner — treat small deltas as noise. Informational only; this check never fails the build. |
|
Parking this: the value is questionable. The guard catches our own decoder bug (a cursor desync), but internal fragility already fails fast — under ReleaseSafe (the release Docker image) an out-of-bounds read panics and the process restarts. In production the guard adds nothing. It also hurts diagnostics: a ReleaseSafe panic gives a stack trace next to the bug, while the guard catches the symptom far away in the converter and turns it into a crash loop with an unhelpful message. Data is only at risk under ReleaseFast on the load stand, which is a test tool. If that matters, building the load stand with ReleaseSafe is cleaner than a runtime guard. |
|
Moved to v0.4.0. The release Docker image builds with ReleaseSafe, so on the GA artifact the unguarded path panics and restarts instead of corrupting data: the guard is a diagnosability upgrade there, not a safety fix. The UB exposure is limited to ReleaseFast builds (load stand), which check-gaps monitors. Needs a rebase before merging: #114 rewrote the same converter functions (convert() takes lsn and lost the io parameter, buildMetadata moved into the struct and now allocates meta.lsn). Note for the rebase: freeMetadata must free the new lsn string too, or the error path leaks it. |
Closes #98.
Problem
tupleToRowDataindexesrel_info.columns[i]for every tuple column without checking the two agree in length. A decoded tuple that is wider than the registered relation reads past the columns slice: a panic under ReleaseSafe (release Docker image), undefined behavior under ReleaseFast (load stand), where it can silently corrupt the event sent to Kafka.Solution
tupleToRowDatawithtuple.columns.len == rel_info.columns.lenand returnerror.ColumnCountMismatchotherwise. pgoutput always sends one TupleData column per live relation column (non-identity columns in a key tuple come through as null, not dropped), so an inequality is a real desync, and the error propagates toConversionFailed, which fails the process for the supervisor to restart.convertbuilt the event metadata before the row, so a failing row build leaked the three metadata strings (the event'sdatais undefined, so it can't be deinit'd). Metadata now has anerrdefer, and UPDATE frees the already-built new row if the old row fails.Test
Unit test: a registered 2-column relation with a 1-column INSERT tuple returns
error.ColumnCountMismatchand leaks nothing. Integration and e2e (real pgoutput INSERT/UPDATE/DELETE) stay green, confirming the strict check does not reject valid streams.