fix: refuse TABLESAMPLE rather than returning every row - #866
fix: refuse TABLESAMPLE rather than returning every row#866OffgridwithJD wants to merge 1 commit into
Conversation
Co-authored-by: Cursor <cursoragent@cursor.com>
|
Review of the fix and the suite. I did not run the branch itself; both findings The hook coverage is complete — verified, not assumedThe claim that these three call sites are the whole surface holds. Every hook the and every place an RTE is read to decide on a columnar path: Those are exactly the three the PR patches. The remaining hooks do not create
|
|
Follow-up: I said I would measure the premise rather than take it from the header. The premise holds. The heap control samples (1030 of 10000), the columnar table One thing worth adding to the PR: A stale plan-node name in the headerThe header says: What I observe is:
With the premise confirmed and the hook coverage verified complete, the two Reviewed as OffgridwithJD. Not approving -- same account as the author. |
jdatcmd
left a comment
There was a problem hiding this comment.
Reviewed adversarially at 55fed91. Approving. This is the best-built PR in the current batch and I want to say why before the one finding: it asserts SQLSTATE instead of message text, states the reason in the file ("a grep for 'not supported' is also satisfied by a dozen unrelated errors, and by a connection failure"), and carries two controls rather than one.
I ran the removal proof the PR does not carry, and all three guards are load-bearing
Each guard reverted alone, on pg18_assert, 8 checks every arm:
| mutation | reds | which arms |
|---|---|---|
| baseline | 0 | — |
revert the SetRelPathlist guard |
4 | sum, SYSTEM, projected, grouped |
revert the CreateUpperPaths guard |
3 | count(*), sum, SYSTEM |
revert the TryGroupAggPath guard |
1 | grouped |
Every guard has at least one arm that reddens, and the signatures differ — count(*) reds under the upper-paths guard but not the pathlist guard, and grouped TABLESAMPLE is the only arm pinning TryGroupAggPath at all. That last row is worth keeping in mind if anyone ever trims this suite: delete that one arm and a whole hook goes unguarded.
Worth pasting into the PR body. A reviewer should not be the first person to find out whether each half of a three-part fix is tested.
One attack of mine that failed, reported because a negative result is evidence too
I went looking for a fourth planner hook left unguarded. There isn't one. PgColumnarPlanCustomPath and PgColumnarPlanAggPath have no tablesample check and correctly do not need one — they are plan-time callbacks over a path already chosen, so they cannot introduce the Sample Scan replacement. All three path-adding hooks are guarded. My first sweep said otherwise and that was my analysis window being too small, not a hole in the PR.
MINOR: sqlstate() has no unparsed bucket
if [ -n "$code" ]; then printf '%s\n' "$code"; else printf '00000\n'; fiWhen the helper cannot extract a code it returns 00000 — success, a real outcome, rather than "I could not tell". That is the parser-with-no-unparsed-bucket shape: every parse failure becomes a plausible answer.
It fails safe for the five 0A000 arms, which go red. It does not fail safe for the two controls:
control: an unsampled count reports success, so the probe is not stuck on 0A000
control: the same TABLESAMPLE on a heap table raises nothing
Both pass whenever the probe cannot parse — including against a server that never answered, which is the exact case the file's own comment says it wants to exclude. A third bucket fixes it:
if [ -n "$code" ]; then printf '%s\n' "$code"
elif printf '%s' "$out" | grep -q '^ERROR'; then printf 'UNPARSED\n'
else printf '00000\n'; fiThen a control asserting 00000 means "the statement succeeded" rather than "nothing matched my regex".
Not blocking: the five arms that carry the fix are proved falsifiable above, and the controls are belt-and-braces on top of them. Worth fixing before the next suite copies the helper, which is how expect_error spread to eleven files.
CI 12 of 12, MERGEABLE/CLEAN.
Summary
rte->tablesampleis set, soTABLESAMPLEreaches the AM sample callbacks.0A000. The custom scan and vectorized aggregate paths used to replace Sample Scan and return every row.Test coverage
test/tablesample.shMade with Cursor