From 354024cbcffc0a700c02ddc840ba552cd54efe64 Mon Sep 17 00:00:00 2001 From: Alexey Gordeev Date: Thu, 16 Dec 2021 14:12:18 +0500 Subject: [PATCH 1/3] Removing Recheck and Filter Condition's columns from Bitmap Heap Scan output list when using ORCA. The changes introduced in PR #12176 revealed a problem with excessive Bitmap Heap Scan's targetlist which includes Recheck and Filter Condition's columns (introduced in old 97edf9b). Memory tuple binding generated based on targetlist with different count of attrs may point to different offsets and so, to some garbage or out of range memory area. See issue #12796 for more. Additional regression test shows how to reproduce a bug before fix. A couple of tests was modified, because there is no need of projection in them started from this patch. --- .../translate/CTranslatorDXLToPlStmt.cpp | 4 + .../data/dxl/minidump/BitmapIndexScan.mdp | 9 +- .../dxl/minidump/BitmapTableScan-Basic.mdp | 92 ++++------ .../gporca/data/dxl/minidump/GinIndex.mdp | 6 +- .../dxl/minidump/GinIndexPathOpfamily.mdp | 6 +- .../dxl/minidump/GinIndexSearchModeAll.mdp | 6 +- ...ist-AOCOTable-NonLossy-BitmapIndexPlan.mdp | 78 ++++---- .../gpopt/translate/CTranslatorExprToDXL.h | 8 - .../src/translate/CTranslatorExprToDXL.cpp | 58 ------ src/test/regress/expected/gporca.out | 59 ++++++ .../regress/expected/gporca_optimizer.out | 72 +++++++- .../output/qp_gist_indexes2_optimizer.source | 168 +++++++++--------- src/test/regress/sql/gporca.sql | 29 +++ 13 files changed, 312 insertions(+), 283 deletions(-) diff --git a/src/backend/gpopt/translate/CTranslatorDXLToPlStmt.cpp b/src/backend/gpopt/translate/CTranslatorDXLToPlStmt.cpp index c8ad4cefd3ac..6a7871323045 100644 --- a/src/backend/gpopt/translate/CTranslatorDXLToPlStmt.cpp +++ b/src/backend/gpopt/translate/CTranslatorDXLToPlStmt.cpp @@ -3608,6 +3608,10 @@ CTranslatorDXLToPlStmt::TranslateDXLCTEProducerToSharedScan( child_plan = materialize_plan; } + // targetlist mismatch leads to different tuple bindings, see #12796 + if (list_length(child_plan->targetlist) != list_length(plan->targetlist)) + elog(ERROR, "Shared Scan and child plan targetlist mismatch."); + InitializeSpoolingInfo(child_plan, cte_id); plan->lefttree = child_plan; diff --git a/src/backend/gporca/data/dxl/minidump/BitmapIndexScan.mdp b/src/backend/gporca/data/dxl/minidump/BitmapIndexScan.mdp index 9646bd7ecdb1..5227ad97c41f 100644 --- a/src/backend/gporca/data/dxl/minidump/BitmapIndexScan.mdp +++ b/src/backend/gporca/data/dxl/minidump/BitmapIndexScan.mdp @@ -556,14 +556,7 @@ see sql/BitmapIndexScan.sql - - - - - - - - + diff --git a/src/backend/gporca/data/dxl/minidump/BitmapTableScan-Basic.mdp b/src/backend/gporca/data/dxl/minidump/BitmapTableScan-Basic.mdp index aa84a4e622ac..8013f6d7096f 100644 --- a/src/backend/gporca/data/dxl/minidump/BitmapTableScan-Basic.mdp +++ b/src/backend/gporca/data/dxl/minidump/BitmapTableScan-Basic.mdp @@ -242,7 +242,7 @@ - + @@ -252,71 +252,53 @@ - - + + - + - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + diff --git a/src/backend/gporca/data/dxl/minidump/GinIndex.mdp b/src/backend/gporca/data/dxl/minidump/GinIndex.mdp index 00e82e4953df..2351608c7dc0 100644 --- a/src/backend/gporca/data/dxl/minidump/GinIndex.mdp +++ b/src/backend/gporca/data/dxl/minidump/GinIndex.mdp @@ -283,11 +283,7 @@ - - - - - + diff --git a/src/backend/gporca/data/dxl/minidump/GinIndexPathOpfamily.mdp b/src/backend/gporca/data/dxl/minidump/GinIndexPathOpfamily.mdp index 34b7e9047c84..b710e84e5071 100644 --- a/src/backend/gporca/data/dxl/minidump/GinIndexPathOpfamily.mdp +++ b/src/backend/gporca/data/dxl/minidump/GinIndexPathOpfamily.mdp @@ -283,11 +283,7 @@ - - - - - + diff --git a/src/backend/gporca/data/dxl/minidump/GinIndexSearchModeAll.mdp b/src/backend/gporca/data/dxl/minidump/GinIndexSearchModeAll.mdp index 3f4c74de1f5f..b419013c3b30 100644 --- a/src/backend/gporca/data/dxl/minidump/GinIndexSearchModeAll.mdp +++ b/src/backend/gporca/data/dxl/minidump/GinIndexSearchModeAll.mdp @@ -283,11 +283,7 @@ - - - - - + diff --git a/src/backend/gporca/data/dxl/minidump/Gist-AOCOTable-NonLossy-BitmapIndexPlan.mdp b/src/backend/gporca/data/dxl/minidump/Gist-AOCOTable-NonLossy-BitmapIndexPlan.mdp index 0383166b612b..6677750cb190 100644 --- a/src/backend/gporca/data/dxl/minidump/Gist-AOCOTable-NonLossy-BitmapIndexPlan.mdp +++ b/src/backend/gporca/data/dxl/minidump/Gist-AOCOTable-NonLossy-BitmapIndexPlan.mdp @@ -272,7 +272,7 @@ Gather Motion 3:1 (slice1; segments: 3) (cost=0.00..0.00 rows=1 width=4) - + @@ -282,65 +282,47 @@ Gather Motion 3:1 (slice1; segments: 3) (cost=0.00..0.00 rows=1 width=4) - - + + + + + + - + - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + diff --git a/src/backend/gporca/libgpopt/include/gpopt/translate/CTranslatorExprToDXL.h b/src/backend/gporca/libgpopt/include/gpopt/translate/CTranslatorExprToDXL.h index b14675ac38c7..e3c84b7a8612 100644 --- a/src/backend/gporca/libgpopt/include/gpopt/translate/CTranslatorExprToDXL.h +++ b/src/backend/gporca/libgpopt/include/gpopt/translate/CTranslatorExprToDXL.h @@ -785,14 +785,6 @@ class CTranslatorExprToDXL // helper to find subplan type from a correlated join expression static EdxlSubPlanType Edxlsubplantype(CExpression *pexprCorrelatedNLJoin); - // add used columns in the bitmap re-check and the remaining scalar filter condition to the - // required output column - static void AddBitmapFilterColumns( - CMemoryPool *mp, CPhysicalScan *pop, CExpression *pexprRecheckCond, - CExpression *pexprScalar, - CColRefSet *pcrsReqdOutput // append the required column reference - ); - public: // ctor CTranslatorExprToDXL(CMemoryPool *mp, CMDAccessor *md_accessor, diff --git a/src/backend/gporca/libgpopt/src/translate/CTranslatorExprToDXL.cpp b/src/backend/gporca/libgpopt/src/translate/CTranslatorExprToDXL.cpp index 9cadf9f02a89..f11824df674c 100644 --- a/src/backend/gporca/libgpopt/src/translate/CTranslatorExprToDXL.cpp +++ b/src/backend/gporca/libgpopt/src/translate/CTranslatorExprToDXL.cpp @@ -943,59 +943,6 @@ CTranslatorExprToDXL::PdxlnBitmapTableScan( ); } - -//--------------------------------------------------------------------------- -// @function: -// CTranslatorExprToDXL::AddBitmapFilterColumns -// -// @doc: -// Add used columns in the bitmap recheck and the remaining scalar filter -// condition to the required output column -//--------------------------------------------------------------------------- -void -CTranslatorExprToDXL::AddBitmapFilterColumns( - CMemoryPool *mp, CPhysicalScan *pop, CExpression *pexprRecheckCond, - CExpression *pexprScalar, - CColRefSet *pcrsReqdOutput // append the required column reference -) -{ - GPOS_ASSERT(NULL != pop); - GPOS_ASSERT(COperator::EopPhysicalDynamicBitmapTableScan == pop->Eopid() || - COperator::EopPhysicalBitmapTableScan == pop->Eopid()); - GPOS_ASSERT(NULL != pcrsReqdOutput); - - // compute what additional columns are required in the output of the (Dynamic) Bitmap Table Scan - CColRefSet *pcrsAdditional = GPOS_NEW(mp) CColRefSet(mp); - - if (NULL != pexprRecheckCond) - { - // add the columns used in the recheck condition - pcrsAdditional->Include(pexprRecheckCond->DeriveUsedColumns()); - } - - if (NULL != pexprScalar) - { - // add the columns used in the filter condition - pcrsAdditional->Include(pexprScalar->DeriveUsedColumns()); - } - - CColRefSet *pcrsBitmap = GPOS_NEW(mp) CColRefSet(mp); - pcrsBitmap->Include(pop->PdrgpcrOutput()); - - // only keep the columns that are in the table associated with the bitmap - pcrsAdditional->Intersection(pcrsBitmap); - - if (0 < pcrsAdditional->Size()) - { - pcrsReqdOutput->Include(pcrsAdditional); - } - - // clean up - pcrsAdditional->Release(); - pcrsBitmap->Release(); -} - - //--------------------------------------------------------------------------- // @function: // CTranslatorExprToDXL::PdxlnBitmapTableScan @@ -1056,9 +1003,6 @@ CTranslatorExprToDXL::PdxlnBitmapTableScan( CDXLNode(m_mp, GPOS_NEW(m_mp) CDXLScalarRecheckCondFilter(m_mp), pdxlnRecheckCond); - AddBitmapFilterColumns(m_mp, pop, pexprRecheckCond, pexprScalar, - pcrsOutput); - CDXLNode *proj_list_dxlnode = PdxlnProjList(pcrsOutput, colref_array); // translate bitmap access path @@ -1262,8 +1206,6 @@ CTranslatorExprToDXL::PdxlnDynamicBitmapTableScan( // build projection list CColRefSet *pcrsOutput = pexprScan->Prpp()->PcrsRequired(); - AddBitmapFilterColumns(m_mp, pop, pexprRecheckCond, pexprScalar, - pcrsOutput); CDXLNode *proj_list_dxlnode = PdxlnProjList(pcrsOutput, colref_array); pdxlnScan->AddChild(proj_list_dxlnode); diff --git a/src/test/regress/expected/gporca.out b/src/test/regress/expected/gporca.out index ede86088eb29..6c5013d890db 100644 --- a/src/test/regress/expected/gporca.out +++ b/src/test/regress/expected/gporca.out @@ -14165,6 +14165,65 @@ select count(*) from (select trim(regexp_split_to_table((a)::text, ','::text)) f (1 row) reset optimizer_trace_fallback; +-- Test Bitmap Heap Scan's targetlist contains only necessary attrs, not +-- including ones from Recheck and Filter conditions. +create table material_bitmapscan(i int, j int, k timestamp, l timestamp) +with(appendonly=true) distributed replicated; +create index material_bitmapscan_idx on material_bitmapscan using btree(k); +insert into material_bitmapscan +select i, mod(i, 10), + timestamp '2021-06-01' + interval '1' day * mod(i, 30), + timestamp '2021-06-01' + interval '1' day * mod(i, 30) +from generate_series(1, 10000) i; +-- Bitmap Heap Scan should not contain 'material_bitmapscan.k' and +-- 'material_bitmapscan.l' at the Output list. +explain (costs off, verbose) with mat as( + select i, j from material_bitmapscan + where i = 2 and j = 2 + and k = timestamp '2021-06-03' and l = timestamp '2021-06-03' +) +select m1.i +from mat m1 join mat m2 on m1.j = m2.j; + QUERY PLAN +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + Gather Motion 1:1 (slice1; segments: 1) + Output: material_bitmapscan.i + -> Hash Join + Output: material_bitmapscan.i + Hash Cond: (material_bitmapscan.j = m2.j) + -> Bitmap Heap Scan on orca.material_bitmapscan + Output: material_bitmapscan.i, material_bitmapscan.j + Recheck Cond: (material_bitmapscan.k = 'Thu Jun 03 00:00:00 2021'::timestamp without time zone) + Filter: ((material_bitmapscan.i = 2) AND (material_bitmapscan.j = 2) AND (material_bitmapscan.l = 'Thu Jun 03 00:00:00 2021'::timestamp without time zone)) + -> Bitmap Index Scan on material_bitmapscan_idx + Index Cond: (material_bitmapscan.k = 'Thu Jun 03 00:00:00 2021'::timestamp without time zone) + -> Hash + Output: m2.j + -> Subquery Scan on m2 + Output: m2.j + -> Bitmap Heap Scan on orca.material_bitmapscan material_bitmapscan_1 + Output: material_bitmapscan_1.i, material_bitmapscan_1.j + Recheck Cond: (material_bitmapscan_1.k = 'Thu Jun 03 00:00:00 2021'::timestamp without time zone) + Filter: ((material_bitmapscan_1.i = 2) AND (material_bitmapscan_1.j = 2) AND (material_bitmapscan_1.l = 'Thu Jun 03 00:00:00 2021'::timestamp without time zone)) + -> Bitmap Index Scan on material_bitmapscan_idx + Index Cond: (material_bitmapscan_1.k = 'Thu Jun 03 00:00:00 2021'::timestamp without time zone) + Optimizer: Postgres query optimizer + Settings: optimizer=off +(23 rows) + +-- There should be one row without any memory access errors. +with mat as( + select i, j from material_bitmapscan + where i = 2 and j = 2 + and k = timestamp '2021-06-03' and l = timestamp '2021-06-03' +) +select m1.i +from mat m1 join mat m2 on m1.j = m2.j; + i +--- + 2 +(1 row) + -- start_ignore DROP SCHEMA orca CASCADE; NOTICE: drop cascades to 167 other objects diff --git a/src/test/regress/expected/gporca_optimizer.out b/src/test/regress/expected/gporca_optimizer.out index 373b58147682..189522135385 100644 --- a/src/test/regress/expected/gporca_optimizer.out +++ b/src/test/regress/expected/gporca_optimizer.out @@ -13706,9 +13706,9 @@ and first_id in (select first_id from mat_w); -> Shared Scan (share slice:id 1:0) (cost=0.00..387.98 rows=4 width=1) Output: share0_ref1.first_id -> Materialize (cost=0.00..387.98 rows=4 width=1) - Output: material_test.first_id, material_test.second_id + Output: material_test.first_id -> Bitmap Heap Scan on orca.material_test (cost=0.00..387.98 rows=4 width=4) - Output: material_test.first_id, material_test.second_id + Output: material_test.first_id Recheck Cond: (material_test.second_id = ANY ('{1,2,3,4}'::integer[])) -> Bitmap Index Scan on material_test_idx (cost=0.00..0.00 rows=0 width=0) Index Cond: (material_test.second_id = ANY ('{1,2,3,4}'::integer[])) @@ -13729,7 +13729,7 @@ and first_id in (select first_id from mat_w); -> Shared Scan (share slice:id 1:0) (cost=0.00..431.00 rows=4 width=4) Output: share0_ref2.first_id Optimizer: Pivotal Optimizer (GPORCA) - Settings: enable_seqscan=on, optimizer=on + Settings: optimizer=on (31 rows) with mat_w as ( @@ -14419,6 +14419,72 @@ select count(*) from (select trim(regexp_split_to_table((a)::text, ','::text)) f (1 row) reset optimizer_trace_fallback; +-- Test Bitmap Heap Scan's targetlist contains only necessary attrs, not +-- including ones from Recheck and Filter conditions. +create table material_bitmapscan(i int, j int, k timestamp, l timestamp) +with(appendonly=true) distributed replicated; +create index material_bitmapscan_idx on material_bitmapscan using btree(k); +insert into material_bitmapscan +select i, mod(i, 10), + timestamp '2021-06-01' + interval '1' day * mod(i, 30), + timestamp '2021-06-01' + interval '1' day * mod(i, 30) +from generate_series(1, 10000) i; +-- Bitmap Heap Scan should not contain 'material_bitmapscan.k' and +-- 'material_bitmapscan.l' at the Output list. +explain (costs off, verbose) with mat as( + select i, j from material_bitmapscan + where i = 2 and j = 2 + and k = timestamp '2021-06-03' and l = timestamp '2021-06-03' +) +select m1.i +from mat m1 join mat m2 on m1.j = m2.j; + QUERY PLAN +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + Gather Motion 1:1 (slice1; segments: 1) + Output: share0_ref3.i + -> Sequence + Output: share0_ref3.i + -> Shared Scan (share slice:id 1:0) + Output: share0_ref1.i, share0_ref1.j + -> Materialize + Output: material_bitmapscan.i, material_bitmapscan.j + -> Bitmap Heap Scan on orca.material_bitmapscan + Output: material_bitmapscan.i, material_bitmapscan.j + Recheck Cond: (material_bitmapscan.k = 'Thu Jun 03 00:00:00 2021'::timestamp without time zone) + Filter: ((material_bitmapscan.i = 2) AND (material_bitmapscan.j = 2) AND (material_bitmapscan.l = 'Thu Jun 03 00:00:00 2021'::timestamp without time zone)) + -> Bitmap Index Scan on material_bitmapscan_idx + Index Cond: (material_bitmapscan.k = 'Thu Jun 03 00:00:00 2021'::timestamp without time zone) + -> Hash Join + Output: share0_ref3.i + Hash Cond: (share0_ref3.j = share0_ref2.j) + -> Result + Output: share0_ref3.i, share0_ref3.j + Filter: (share0_ref3.j = 2) + -> Shared Scan (share slice:id 1:0) + Output: share0_ref3.i, share0_ref3.j + -> Hash + Output: share0_ref2.j + -> Result + Output: share0_ref2.j + Filter: (share0_ref2.j = 2) + -> Shared Scan (share slice:id 1:0) + Output: share0_ref2.i, share0_ref2.j + Optimizer: Pivotal Optimizer (GPORCA) +(30 rows) + +-- There should be one row without any memory access errors. +with mat as( + select i, j from material_bitmapscan + where i = 2 and j = 2 + and k = timestamp '2021-06-03' and l = timestamp '2021-06-03' +) +select m1.i +from mat m1 join mat m2 on m1.j = m2.j; + i +--- + 2 +(1 row) + -- start_ignore DROP SCHEMA orca CASCADE; NOTICE: drop cascades to 167 other objects diff --git a/src/test/regress/output/qp_gist_indexes2_optimizer.source b/src/test/regress/output/qp_gist_indexes2_optimizer.source index b44abee0e528..e0cea0868236 100644 --- a/src/test/regress/output/qp_gist_indexes2_optimizer.source +++ b/src/test/regress/output/qp_gist_indexes2_optimizer.source @@ -1286,19 +1286,18 @@ SELECT id FROM GistTable1 EXPLAIN (COSTS OFF) SELECT id FROM GistTable1 WHERE property ~= '( (1,2), (3,4) )' ORDER BY id; - QUERY PLAN ------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------ Gather Motion 3:1 (slice1; segments: 3) Merge Key: id - -> Result - -> Sort - Sort Key: id - -> Bitmap Heap Scan on gisttable1 - Recheck Cond: (property ~= '(3,4),(1,2)'::box) - -> Bitmap Index Scan on propertyboxindex - Index Cond: (property ~= '(3,4),(1,2)'::box) - Optimizer: Pivotal Optimizer (GPORCA) version 2.74.0 -(10 rows) + -> Sort + Sort Key: id + -> Bitmap Heap Scan on gisttable1 + Recheck Cond: (property ~= '(3,4),(1,2)'::box) + -> Bitmap Index Scan on propertyboxindex + Index Cond: (property ~= '(3,4),(1,2)'::box) + Optimizer: Pivotal Optimizer (GPORCA) +(9 rows) REINDEX INDEX propertyBoxIndex; SELECT id FROM GistTable1 @@ -1314,19 +1313,18 @@ SELECT id FROM GistTable1 EXPLAIN (COSTS OFF) SELECT id FROM GistTable1 WHERE property ~= '( (1,2), (3,4) )' ORDER BY id; - QUERY PLAN ------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------ Gather Motion 3:1 (slice1; segments: 3) Merge Key: id - -> Result - -> Sort - Sort Key: id - -> Bitmap Heap Scan on gisttable1 - Recheck Cond: (property ~= '(3,4),(1,2)'::box) - -> Bitmap Index Scan on propertyboxindex - Index Cond: (property ~= '(3,4),(1,2)'::box) - Optimizer: Pivotal Optimizer (GPORCA) version 2.74.0 -(10 rows) + -> Sort + Sort Key: id + -> Bitmap Heap Scan on gisttable1 + Recheck Cond: (property ~= '(3,4),(1,2)'::box) + -> Bitmap Index Scan on propertyboxindex + Index Cond: (property ~= '(3,4),(1,2)'::box) + Optimizer: Pivotal Optimizer (GPORCA) +(9 rows) DROP INDEX propertyBoxIndex; -- Obviously, this shouldn't use the index now that the index is gone. @@ -1912,19 +1910,18 @@ SELECT id FROM GistTable1 EXPLAIN (COSTS OFF) SELECT id FROM GistTable1 WHERE property ~= '( (1,2), (3,4) )' ORDER BY id; - QUERY PLAN ------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------ Gather Motion 3:1 (slice1; segments: 3) Merge Key: id - -> Result - -> Sort - Sort Key: id - -> Bitmap Heap Scan on gisttable1 - Recheck Cond: (property ~= '(3,4),(1,2)'::box) - -> Bitmap Index Scan on propertyboxindex - Index Cond: (property ~= '(3,4),(1,2)'::box) - Optimizer: Pivotal Optimizer (GPORCA) version 2.74.0 -(10 rows) + -> Sort + Sort Key: id + -> Bitmap Heap Scan on gisttable1 + Recheck Cond: (property ~= '(3,4),(1,2)'::box) + -> Bitmap Index Scan on propertyboxindex + Index Cond: (property ~= '(3,4),(1,2)'::box) + Optimizer: Pivotal Optimizer (GPORCA) +(9 rows) REINDEX INDEX propertyBoxIndex; SELECT id FROM GistTable1 @@ -1940,19 +1937,18 @@ SELECT id FROM GistTable1 EXPLAIN (COSTS OFF) SELECT id FROM GistTable1 WHERE property ~= '( (1,2), (3,4) )' ORDER BY id; - QUERY PLAN ------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------ Gather Motion 3:1 (slice1; segments: 3) Merge Key: id - -> Result - -> Sort - Sort Key: id - -> Bitmap Heap Scan on gisttable1 - Recheck Cond: (property ~= '(3,4),(1,2)'::box) - -> Bitmap Index Scan on propertyboxindex - Index Cond: (property ~= '(3,4),(1,2)'::box) - Optimizer: Pivotal Optimizer (GPORCA) version 2.74.0 -(10 rows) + -> Sort + Sort Key: id + -> Bitmap Heap Scan on gisttable1 + Recheck Cond: (property ~= '(3,4),(1,2)'::box) + -> Bitmap Index Scan on propertyboxindex + Index Cond: (property ~= '(3,4),(1,2)'::box) + Optimizer: Pivotal Optimizer (GPORCA) +(9 rows) DROP INDEX propertyBoxIndex; -- Obviously, this shouldn't use the index now that the index is gone. @@ -2538,19 +2534,18 @@ SELECT id FROM GistTable1 EXPLAIN (COSTS OFF) SELECT id FROM GistTable1 WHERE property ~= '( (1,2), (3,4) )' ORDER BY id; - QUERY PLAN ------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------ Gather Motion 3:1 (slice1; segments: 3) Merge Key: id - -> Result - -> Sort - Sort Key: id - -> Bitmap Heap Scan on gisttable1 - Recheck Cond: (property ~= '(3,4),(1,2)'::box) - -> Bitmap Index Scan on propertyboxindex - Index Cond: (property ~= '(3,4),(1,2)'::box) - Optimizer: Pivotal Optimizer (GPORCA) version 2.74.0 -(10 rows) + -> Sort + Sort Key: id + -> Bitmap Heap Scan on gisttable1 + Recheck Cond: (property ~= '(3,4),(1,2)'::box) + -> Bitmap Index Scan on propertyboxindex + Index Cond: (property ~= '(3,4),(1,2)'::box) + Optimizer: Pivotal Optimizer (GPORCA) +(9 rows) REINDEX INDEX propertyBoxIndex; SELECT id FROM GistTable1 @@ -2566,19 +2561,18 @@ SELECT id FROM GistTable1 EXPLAIN (COSTS OFF) SELECT id FROM GistTable1 WHERE property ~= '( (1,2), (3,4) )' ORDER BY id; - QUERY PLAN ------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------ Gather Motion 3:1 (slice1; segments: 3) Merge Key: id - -> Result - -> Sort - Sort Key: id - -> Bitmap Heap Scan on gisttable1 - Recheck Cond: (property ~= '(3,4),(1,2)'::box) - -> Bitmap Index Scan on propertyboxindex - Index Cond: (property ~= '(3,4),(1,2)'::box) - Optimizer: Pivotal Optimizer (GPORCA) version 2.74.0 -(10 rows) + -> Sort + Sort Key: id + -> Bitmap Heap Scan on gisttable1 + Recheck Cond: (property ~= '(3,4),(1,2)'::box) + -> Bitmap Index Scan on propertyboxindex + Index Cond: (property ~= '(3,4),(1,2)'::box) + Optimizer: Pivotal Optimizer (GPORCA) +(9 rows) DROP INDEX propertyBoxIndex; -- Obviously, this shouldn't use the index now that the index is gone. @@ -3164,19 +3158,18 @@ SELECT id FROM GistTable1 EXPLAIN (COSTS OFF) SELECT id FROM GistTable1 WHERE property ~= '( (1,2), (3,4) )' ORDER BY id; - QUERY PLAN ----------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------ Gather Motion 3:1 (slice1; segments: 3) Merge Key: id - -> Result - -> Sort - Sort Key: id - -> Bitmap Heap Scan on gisttable1 - Recheck Cond: (property ~= '(3,4),(1,2)'::box) - -> Bitmap Index Scan on propertyboxindex - Index Cond: (property ~= '(3,4),(1,2)'::box) - Optimizer: Pivotal Optimizer (GPORCA) version 2.74.0 -(10 rows) + -> Sort + Sort Key: id + -> Bitmap Heap Scan on gisttable1 + Recheck Cond: (property ~= '(3,4),(1,2)'::box) + -> Bitmap Index Scan on propertyboxindex + Index Cond: (property ~= '(3,4),(1,2)'::box) + Optimizer: Pivotal Optimizer (GPORCA) +(9 rows) REINDEX INDEX propertyBoxIndex; SELECT id FROM GistTable1 @@ -3192,19 +3185,18 @@ SELECT id FROM GistTable1 EXPLAIN (COSTS OFF) SELECT id FROM GistTable1 WHERE property ~= '( (1,2), (3,4) )' ORDER BY id; - QUERY PLAN ------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------ Gather Motion 3:1 (slice1; segments: 3) Merge Key: id - -> Result - -> Sort - Sort Key: id - -> Bitmap Heap Scan on gisttable1 - Recheck Cond: (property ~= '(3,4),(1,2)'::box) - -> Bitmap Index Scan on propertyboxindex - Index Cond: (property ~= '(3,4),(1,2)'::box) - Optimizer: Pivotal Optimizer (GPORCA) version 2.74.0 -(10 rows) + -> Sort + Sort Key: id + -> Bitmap Heap Scan on gisttable1 + Recheck Cond: (property ~= '(3,4),(1,2)'::box) + -> Bitmap Index Scan on propertyboxindex + Index Cond: (property ~= '(3,4),(1,2)'::box) + Optimizer: Pivotal Optimizer (GPORCA) +(9 rows) DROP INDEX propertyBoxIndex; -- Obviously, this shouldn't use the index now that the index is gone. diff --git a/src/test/regress/sql/gporca.sql b/src/test/regress/sql/gporca.sql index 3394153b0aca..b7894535b833 100644 --- a/src/test/regress/sql/gporca.sql +++ b/src/test/regress/sql/gporca.sql @@ -3170,6 +3170,35 @@ select * from (select trim(regexp_split_to_table((a)::text, ','::text)) from nes select count(*) from (select trim(regexp_split_to_table((a)::text, ','::text)) from nested_srf)a; reset optimizer_trace_fallback; + +-- Test Bitmap Heap Scan's targetlist contains only necessary attrs, not +-- including ones from Recheck and Filter conditions. +create table material_bitmapscan(i int, j int, k timestamp, l timestamp) +with(appendonly=true) distributed replicated; +create index material_bitmapscan_idx on material_bitmapscan using btree(k); +insert into material_bitmapscan +select i, mod(i, 10), + timestamp '2021-06-01' + interval '1' day * mod(i, 30), + timestamp '2021-06-01' + interval '1' day * mod(i, 30) +from generate_series(1, 10000) i; +-- Bitmap Heap Scan should not contain 'material_bitmapscan.k' and +-- 'material_bitmapscan.l' at the Output list. +explain (costs off, verbose) with mat as( + select i, j from material_bitmapscan + where i = 2 and j = 2 + and k = timestamp '2021-06-03' and l = timestamp '2021-06-03' +) +select m1.i +from mat m1 join mat m2 on m1.j = m2.j; +-- There should be one row without any memory access errors. +with mat as( + select i, j from material_bitmapscan + where i = 2 and j = 2 + and k = timestamp '2021-06-03' and l = timestamp '2021-06-03' +) +select m1.i +from mat m1 join mat m2 on m1.j = m2.j; + -- start_ignore DROP SCHEMA orca CASCADE; -- end_ignore From a0ffdd8bf4fc53fdc29f0e5ccae07b5db1635c7e Mon Sep 17 00:00:00 2001 From: Alexey Gordeev Date: Thu, 16 Dec 2021 18:01:59 +0500 Subject: [PATCH 2/3] Natively raise exception in case of targetlist mismatch. --- src/backend/gpopt/translate/CTranslatorDXLToPlStmt.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/backend/gpopt/translate/CTranslatorDXLToPlStmt.cpp b/src/backend/gpopt/translate/CTranslatorDXLToPlStmt.cpp index 6a7871323045..bd9896909018 100644 --- a/src/backend/gpopt/translate/CTranslatorDXLToPlStmt.cpp +++ b/src/backend/gpopt/translate/CTranslatorDXLToPlStmt.cpp @@ -3610,7 +3610,8 @@ CTranslatorDXLToPlStmt::TranslateDXLCTEProducerToSharedScan( // targetlist mismatch leads to different tuple bindings, see #12796 if (list_length(child_plan->targetlist) != list_length(plan->targetlist)) - elog(ERROR, "Shared Scan and child plan targetlist mismatch."); + GPOS_RAISE(gpdxl::ExmaDXL, gpdxl::ExmiDXL2PlStmtConversion, + GPOS_WSZ_LIT("Shared Scan and child plan targetlist mismatch.")); InitializeSpoolingInfo(child_plan, cte_id); From 0131ee24f279b3bd21de33fec880633925af5c28 Mon Sep 17 00:00:00 2001 From: Alexey Gordeev Date: Tue, 21 Dec 2021 18:12:25 +0500 Subject: [PATCH 3/3] Commenting. mdp comment plan update. --- .../translate/CTranslatorDXLToPlStmt.cpp | 4 +++- ...ist-AOCOTable-NonLossy-BitmapIndexPlan.mdp | 21 +++++++++---------- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/src/backend/gpopt/translate/CTranslatorDXLToPlStmt.cpp b/src/backend/gpopt/translate/CTranslatorDXLToPlStmt.cpp index bd9896909018..edfd676f78f0 100644 --- a/src/backend/gpopt/translate/CTranslatorDXLToPlStmt.cpp +++ b/src/backend/gpopt/translate/CTranslatorDXLToPlStmt.cpp @@ -3608,7 +3608,9 @@ CTranslatorDXLToPlStmt::TranslateDXLCTEProducerToSharedScan( child_plan = materialize_plan; } - // targetlist mismatch leads to different tuple bindings, see #12796 + // Targetlist mismatch leads to different tuple bindings, see #12796. + // We assume targetlist's equivalence. In case of inequality one list + // is a subset of another, so it safe to compare only length. if (list_length(child_plan->targetlist) != list_length(plan->targetlist)) GPOS_RAISE(gpdxl::ExmaDXL, gpdxl::ExmiDXL2PlStmtConversion, GPOS_WSZ_LIT("Shared Scan and child plan targetlist mismatch.")); diff --git a/src/backend/gporca/data/dxl/minidump/Gist-AOCOTable-NonLossy-BitmapIndexPlan.mdp b/src/backend/gporca/data/dxl/minidump/Gist-AOCOTable-NonLossy-BitmapIndexPlan.mdp index 6677750cb190..55de927bb1cf 100644 --- a/src/backend/gporca/data/dxl/minidump/Gist-AOCOTable-NonLossy-BitmapIndexPlan.mdp +++ b/src/backend/gporca/data/dxl/minidump/Gist-AOCOTable-NonLossy-BitmapIndexPlan.mdp @@ -16,18 +16,17 @@ EXPLAIN SELECT id FROM aoco_gist_tbl WHERE b ~= '( (1,2), (3,4) )' ORDER BY id; - QUERY PLAN -Gather Motion 3:1 (slice1; segments: 3) (cost=0.00..0.00 rows=1 width=4) + QUERY PLAN + Gather Motion 3:1 (slice1; segments: 3) (cost=0.00..391.30 rows=1 width=4) Merge Key: id - -> Result (cost=0.00..0.00 rows=1 width=4) - -> Sort (cost=0.00..0.00 rows=1 width=4) - Sort Key: id - -> Bitmap Table Scan on aoco_gist_tbl (cost=0.00..0.00 rows=1 width=4) - Recheck Cond: b ~= '(3,4),(1,2)'::box - -> Bitmap Index Scan on boxindex (cost=0.00..0.00 rows=0 width=0) - Index Cond: b ~= '(3,4),(1,2)'::box - Optimizer status: PQO version 2.65.1 -(10 rows) + -> Sort (cost=0.00..391.30 rows=1 width=4) + Sort Key: id + -> Bitmap Heap Scan on aoco_gist_tbl (cost=0.00..391.30 rows=1 width=4) + Recheck Cond: (b ~= '(3,4),(1,2)'::box) + -> Bitmap Index Scan on boxindex (cost=0.00..0.00 rows=0 width=0) + Index Cond: (b ~= '(3,4),(1,2)'::box) + Optimizer: Pivotal Optimizer (GPORCA) +(9 rows) -->