Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[BACKPORT 2024.1][#21930] YSQL: Fix Bitmap Scans corrupted results fo…
…r rechecked text columns Summary: Original commit: 237dad5 / D35399 === Problem === Queries with recheck conditions on text columns had corrupted values: ```lang=sql create table test_recheck_text(a text); insert into test_recheck_text VALUES ('i'); create index on test_recheck_text(a ASC); /*+ BitmapScan(t) Set(yb_enable_bitmapscan true) */ SELECT * FROM test_recheck_text AS t WHERE a = 'i' AND a < 'j'; a ---------------------------------------------------------------------------- \x7F\x7F\x7F\x7F\x7F\x7F\x7F\x7F\x7F\x7F\x7F\x7F\x7F\x7F\x7F\x7F\x7F\x7F (1 row) ``` This is because of allocating parts of the tuple into a memory context that gets reset when evaluating recheck conditions. === Explanation === While implementing Bitmap Scans, I had copied two patterns that do not work well together: First, from `nodeBitmapHeapscan.c`: ```lang=c /* * If we are using lossy info, we have to recheck the qual * conditions at every tuple. */ if (tbmres->recheck) { econtext->ecxt_scantuple = slot; if (!ExecQualAndReset(node->bitmapqualorig, econtext)) { /* Fails recheck, so drop it and loop back for another */ InstrCountFiltered2(node, 1); ExecClearTuple(slot); continue; } } ``` second, from `ybSeqScan.c`: ```lang=c /* capture all fetch allocations in the short-lived context */ oldcontext = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory); ybFetchNext(ybScan->handle, slot, RelationGetRelid(node->ss.ss_currentRelation)); MemoryContextSwitchTo(oldcontext); ``` `nodeYbBitmapTablescan.c` had the following flow: ``` lang=c oldcontext = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory); ybFetchNext() // load tuple into ecxt_per_tuple_memory MemoryContextSwitchTo(oldcontext); ... if (node->recheck_required) { if (!ExecQualAndReset(node->recheck_local_quals, econtext)) // reset ecxt_per_tuple_memory!! ... } ``` `ybFetchNext` loaded any allocations associated with the tuple into `ecxt_per_tuple_memory`. Then `ExecQualAndReset` cleared it. These two operations clearly don't work well together, and explain the corrupted value of the query - the allocations associated with the tuple were freed before we could use them. The solution is to fetch the tuple into a longer-lived memory context OR change `ExecQualAndReset` to `ExecQual`. The first option is more desirable, because we can let the tuples themselves live longer while the intermediate results of `ExecQual` can be freed as soon as possible. Jira: DB-10845 Test Plan: ``` ./yb_build.sh --java-test 'org.yb.pgsql.TestPgRegressYbBitmapScans' ``` Reviewers: tnayak, amartsinchyk, mtakahara Reviewed By: tnayak Subscribers: yql Tags: #jenkins-ready Differential Revision: https://phorge.dev.yugabyte.com/D35631
- Loading branch information