Skip to content

Commit 09e7020

Browse files
committed
ORCA: allow partition table use the append node
In ORCA, both Dynamic Scan and Append operators can serve as scan methods for partitioned tables. Historically, ORCA initially supported the Append operator before switching to Dynamic Any Scan, with several iterations of changes in between. In current CBDB versions, Dynamic Scan is the default partitioned table scan operator. However, the vectorized executor in CBDB (closed-source) cannot support Dynamic Scan due to its multi-threaded architecture, which prohibits metadata reading during scanning. This commit reintroduces the Append operator as an alternative. The GUC `optimizer_disable_dynamic_table_scan` (default: off) now allows choosing between Dynamic Scan and Append operators. Important considerations when using Append operator: 1. **Row-level security unsupported on root partition table**: Append cannot be used with row-level security on partitioned tables. ORCA applies row-level security at the final stage, making it impossible to determine the root partition after generating Append plans. Dynamic Scan preserves root partition information, enabling runtime application of row-level security to child partitions. 2. **No index-only scan support**: This is a CBDB executor limitation. Only Dynamic Scan supports index-only scans for partitioned tables.
1 parent 5804930 commit 09e7020

32 files changed

Lines changed: 23101 additions & 48 deletions

src/backend/gpopt/config/CConfigParamMapping.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -301,15 +301,18 @@ CConfigParamMapping::SConfigMappingElem CConfigParamMapping::m_elements[] = {
301301
{EopttraceEnableUseDistributionInDQA,
302302
&optimizer_enable_use_distribution_in_dqa,
303303
false, // m_negate_param
304-
GPOS_WSZ_LIT(
305-
"Enable use the distribution key in DQA")},
304+
GPOS_WSZ_LIT("Enable use the distribution key in DQA")},
306305
{EopttraceDisableInnerHashJoin, &optimizer_enable_hashjoin,
307306
true, // m_negate_param
308307
GPOS_WSZ_LIT("Explore hash join alternatives")},
309308
{EopttraceDisableInnerNLJ, &optimizer_enable_nljoin,
310309
true, // m_negate_param
311310
GPOS_WSZ_LIT("Enable nested loop join alternatives")},
312311

312+
{EopttraceDisableDynamicTableScan, &optimizer_disable_dynamic_table_scan,
313+
false, // m_negate_param
314+
GPOS_WSZ_LIT(
315+
"Disable the dynamic seq/bitmap/index scan in partition table")},
313316
};
314317

315318
//---------------------------------------------------------------------------

src/backend/gpopt/translate/CTranslatorDXLToPlStmt.cpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3921,6 +3921,31 @@ CTranslatorDXLToPlStmt::TranslateDXLAppend(
39213921
GPOS_ASSERT(EdxlappendIndexFirstChild < arity);
39223922
append->appendplans = NIL;
39233923

3924+
// translate table descriptor into a range table entry
3925+
CDXLPhysicalAppend *phy_append_dxlop =
3926+
CDXLPhysicalAppend::Cast(append_dxlnode->GetOperator());
3927+
3928+
// If this append was create from a DynamicTableScan node in ORCA, it will
3929+
// contain the table descriptor of the root partitioned table. Add that to
3930+
// the range table in the PlStmt.
3931+
if (phy_append_dxlop->GetScanId() != gpos::ulong_max)
3932+
{
3933+
GPOS_ASSERT(nullptr != phy_append_dxlop->GetDXLTableDesc());
3934+
3935+
// translation context for column mappings in the base relation
3936+
CDXLTranslateContextBaseTable base_table_context(m_mp);
3937+
3938+
(void) ProcessDXLTblDescr(phy_append_dxlop->GetDXLTableDesc(),
3939+
&base_table_context);
3940+
3941+
OID oid_type =
3942+
CMDIdGPDB::CastMdid(m_md_accessor->PtMDType<IMDTypeInt4>()->MDId())
3943+
->Oid();
3944+
append->join_prune_paramids =
3945+
TranslateJoinPruneParamids(phy_append_dxlop->GetSelectorIds(),
3946+
oid_type, m_dxl_to_plstmt_context);
3947+
}
3948+
39243949
// translate children
39253950
CDXLTranslateContext child_context(m_mp, false,
39263951
output_context->GetColIdToParamIdMap());

src/backend/gpopt/translate/CTranslatorQueryToDXL.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -528,6 +528,11 @@ CTranslatorQueryToDXL::CheckRangeTable(Query *query)
528528
GPOS_RAISE(gpdxl::ExmaDXL, gpdxl::ExmiQuery2DXLUnsupportedFeature,
529529
GPOS_WSZ_LIT("TABLESAMPLE in the FROM clause"));
530530
}
531+
532+
if (rte->relkind == 'p' && query->hasRowSecurity && GPOS_FTRACE(EopttraceDisableDynamicTableScan)) {
533+
GPOS_RAISE(gpdxl::ExmaDXL, gpdxl::ExmiQuery2DXLUnsupportedFeature,
534+
GPOS_WSZ_LIT("ORCA not support row-level security if dynamic table scan is disabled."));
535+
}
531536
}
532537
}
533538

src/backend/gpopt/translate/CTranslatorRelcacheToDXL.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3044,7 +3044,7 @@ CTranslatorRelcacheToDXL::RetrieveIndexPartitions(CMemoryPool *mp, OID rel_oid)
30443044
{
30453045
OID oid = lfirst_oid(lc);
30463046
partition_oids->Append(GPOS_NEW(mp)
3047-
CMDIdGPDB(IMDId::EmdidGeneral, oid));
3047+
CMDIdGPDB(IMDId::EmdidInd, oid));
30483048
}
30493049

30503050
return partition_oids;

src/backend/gporca/libgpopt/include/gpopt/operators/CLogicalDynamicGetBase.h

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -70,11 +70,6 @@ class CLogicalDynamicGetBase : public CLogical
7070
static ColRefToUlongMapArray *ConstructRootColMappingPerPart(
7171
CMemoryPool *mp, CColRefArray *root_cols, IMdIdArray *partition_mdids);
7272

73-
using ColNameToIndexMap =
74-
CHashMap<const CWStringConst, ULONG, CWStringConst::HashValue,
75-
CWStringConst::Equals, CleanupNULL<const CWStringConst>,
76-
CleanupDelete<ULONG>>;
77-
7873
public:
7974
// ctors
8075
explicit CLogicalDynamicGetBase(CMemoryPool *mp);

src/backend/gporca/libgpopt/include/gpopt/operators/CLogicalDynamicIndexOnlyGet.h

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -87,9 +87,11 @@ class CLogicalDynamicIndexOnlyGet : public CLogicalDynamicIndexGet
8787
{
8888
CXformSet *xform_set = GPOS_NEW(mp) CXformSet(mp);
8989

90-
(void) xform_set->ExchangeSet(
91-
CXform::ExfDynamicIndexOnlyGet2DynamicIndexOnlyScan);
92-
90+
// Append node have not implements the index only scan
91+
if (!GPOS_FTRACE(EopttraceDisableDynamicTableScan)) {
92+
(void) xform_set->ExchangeSet(
93+
CXform::ExfDynamicIndexOnlyGet2DynamicIndexOnlyScan);
94+
}
9395
return xform_set;
9496
}
9597

src/backend/gporca/libgpopt/include/gpopt/translate/CTranslatorExprToDXL.h

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -313,6 +313,26 @@ class CTranslatorExprToDXL
313313
CDistributionSpecArray *pdrgpdsBaseTables,
314314
ULONG *pulNonGatherMotions, BOOL *pfDML);
315315

316+
// translate a dynamic seq/foreign scan to append
317+
template <class PhysicalScanType>
318+
CDXLNode *PdxlnDynamicScanToAppend(
319+
CExpression *pexprDTS, CColRefArray *colref_array,
320+
CDistributionSpecArray *pdrgpdsBaseTables, CExpression *pexprScalarCond,
321+
CDXLPhysicalProperties *dxl_properties);
322+
323+
// translate a dynamic index/index only scan to append
324+
template <class PhysicalScanType>
325+
CDXLNode *PdxlnDynamicIndexScanToAppend(CExpression *pexprDIS,
326+
CColRefArray *colref_array,
327+
CDXLPhysicalProperties *dxl_properties,
328+
CReqdPropPlan *prpp);
329+
330+
// translate a dynamic bitmap scan to append
331+
CDXLNode *PdxlnDynamicBitmapScanToAppend(
332+
CExpression *pexprDTS, CColRefArray *colref_array,
333+
CDistributionSpecArray *pdrgpdsBaseTables, CExpression *pexprScalarCond,
334+
CDXLPhysicalProperties *dxl_properties);
335+
316336
// translate a dynamic table scan
317337
CDXLNode *PdxlnDynamicTableScan(CExpression *pexprDTS,
318338
CColRefArray *colref_array,
@@ -562,6 +582,16 @@ class CTranslatorExprToDXL
562582
const CColRefArray *root_colrefs,
563583
CExpression *pred);
564584

585+
CDXLNode *PdxlnBitmapIndexProbeForChildPart(
586+
const ColRefToUlongMap *root_col_mapping,
587+
const CColRefArray *part_colrefs, const CColRefArray *root_colrefs,
588+
const IMDRelation *part, CExpression *pexprBitmapIndexProbe);
589+
590+
CDXLNode *PdxlnBitmapIndexPathForChildPart(
591+
const ColRefToUlongMap *root_col_mapping,
592+
const CColRefArray *part_colrefs, const CColRefArray *root_colrefs,
593+
const IMDRelation *part, CExpression *pexprBitmapIndexPath);
594+
565595
// translate a project list expression into a DXL proj list node
566596
// according to the order specified in the dynamic array
567597
CDXLNode *PdxlnProjList(const CExpression *pexprProjList,

src/backend/gporca/libgpopt/src/operators/CLogicalDynamicGetBase.cpp

Lines changed: 23 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -236,15 +236,6 @@ CLogicalDynamicGetBase::ConstructRootColMappingPerPart(
236236
CMDAccessor *mda = COptCtxt::PoctxtFromTLS()->Pmda();
237237

238238
ColRefToUlongMapArray *part_maps = GPOS_NEW(mp) ColRefToUlongMapArray(mp);
239-
240-
// Build hashmap of colname to the index
241-
ColNameToIndexMap *root_mapping = GPOS_NEW(mp) ColNameToIndexMap(mp);
242-
for (ULONG i = 0; i < root_cols->Size(); ++i)
243-
{
244-
CColRef *root_colref = (*root_cols)[i];
245-
root_mapping->Insert(root_colref->Name().Pstr(), GPOS_NEW(mp) ULONG(i));
246-
}
247-
248239
for (ULONG ul = 0; ul < partition_mdids->Size(); ++ul)
249240
{
250241
IMDId *part_mdid = (*partition_mdids)[ul];
@@ -253,28 +244,35 @@ CLogicalDynamicGetBase::ConstructRootColMappingPerPart(
253244
GPOS_ASSERT(nullptr != partrel);
254245

255246
ColRefToUlongMap *mapping = GPOS_NEW(mp) ColRefToUlongMap(mp);
256-
// The root mapping cannot contain dropped columns, but may be
257-
// in a different order than the child cols.Iterate through each of the child
258-
// cols, and retrieve the corresponding index in the parent table
259-
for (ULONG j = 0; j < partrel->ColumnCount(); ++j)
247+
248+
for (ULONG i = 0; i < root_cols->Size(); ++i)
260249
{
261-
const IMDColumn *coldesc = partrel->GetMdCol(j);
262-
const CWStringConst *colname = coldesc->Mdname().GetMDName();
250+
CColRef *root_colref = (*root_cols)[i];
263251

264-
if (coldesc->IsDropped())
252+
BOOL found_mapping = false;
253+
for (ULONG j = 0, idx = 0; j < partrel->ColumnCount(); ++j, ++idx)
265254
{
266-
continue;
255+
const IMDColumn *coldesc = partrel->GetMdCol(j);
256+
const CWStringConst *colname = coldesc->Mdname().GetMDName();
257+
258+
if (coldesc->IsDropped())
259+
{
260+
--idx;
261+
continue;
262+
}
263+
264+
if (colname->Equals(root_colref->Name().Pstr()))
265+
{
266+
// Found the corresponding column in the child partition
267+
// Save the index in the mapping
268+
mapping->Insert(root_colref, GPOS_NEW(mp) ULONG(idx));
269+
found_mapping = true;
270+
break;
271+
}
267272
}
268273

269-
ULONG *root_idx = root_mapping->Find(colname);
270-
if (nullptr != root_idx)
271-
{
272-
mapping->Insert((*root_cols)[*root_idx],
273-
GPOS_NEW(mp) ULONG(*root_idx));
274-
}
275-
else
274+
if (!found_mapping)
276275
{
277-
root_mapping->Release();
278276
GPOS_RAISE(
279277
CException::ExmaInvalid, CException::ExmiInvalid,
280278
GPOS_WSZ_LIT(
@@ -283,6 +281,5 @@ CLogicalDynamicGetBase::ConstructRootColMappingPerPart(
283281
}
284282
part_maps->Append(mapping);
285283
}
286-
root_mapping->Release();
287284
return part_maps;
288285
}

0 commit comments

Comments
 (0)