greenplumn CTranslatorDXLToPlStmt 源码
greenplumn CTranslatorDXLToPlStmt 代码
文件路径:/src/backend/gpopt/translate/CTranslatorDXLToPlStmt.cpp
//---------------------------------------------------------------------------
// Greenplum Database
// Copyright (C) 2010 Greenplum, Inc.
//
// @filename:
// CTranslatorDXLToPlStmt.cpp
//
// @doc:
// Implementation of the methods for translating from DXL tree to GPDB
// PlannedStmt.
//
// @test:
//
//
//---------------------------------------------------------------------------
extern "C" {
#include "postgres.h"
#include "catalog/gp_distribution_policy.h"
#include "catalog/pg_collation.h"
#include "cdb/cdbutil.h"
#include "cdb/cdbvars.h"
#include "executor/execPartition.h"
#include "executor/executor.h"
#include "nodes/nodes.h"
#include "nodes/plannodes.h"
#include "nodes/primnodes.h"
#include "partitioning/partdesc.h"
#include "storage/lmgr.h"
#include "utils/partcache.h"
#if 0
#include "cdb/partitionselection.h"
#endif
#include "utils/guc.h"
#include "utils/lsyscache.h"
#include "utils/rel.h"
#include "utils/typcache.h"
#include "utils/uri.h"
}
#include <algorithm>
#include <numeric>
#include <tuple>
#include "gpos/base.h"
#include "gpos/common/CBitSet.h"
#include "gpos/common/CBitSetIter.h"
#include "gpopt/base/CUtils.h"
#include "gpopt/gpdbwrappers.h"
#include "gpopt/mdcache/CMDAccessor.h"
#include "gpopt/translate/CIndexQualInfo.h"
#include "gpopt/translate/CPartPruneStepsBuilder.h"
#include "gpopt/translate/CTranslatorDXLToPlStmt.h"
#include "gpopt/translate/CTranslatorUtils.h"
#include "naucrates/dxl/operators/CDXLDatumGeneric.h"
#include "naucrates/dxl/operators/CDXLDirectDispatchInfo.h"
#include "naucrates/dxl/operators/CDXLNode.h"
#include "naucrates/dxl/operators/CDXLPhysicalAgg.h"
#include "naucrates/dxl/operators/CDXLPhysicalAppend.h"
#include "naucrates/dxl/operators/CDXLPhysicalAssert.h"
#include "naucrates/dxl/operators/CDXLPhysicalBitmapTableScan.h"
#include "naucrates/dxl/operators/CDXLPhysicalCTAS.h"
#include "naucrates/dxl/operators/CDXLPhysicalCTEConsumer.h"
#include "naucrates/dxl/operators/CDXLPhysicalCTEProducer.h"
#include "naucrates/dxl/operators/CDXLPhysicalDynamicBitmapTableScan.h"
#include "naucrates/dxl/operators/CDXLPhysicalDynamicIndexScan.h"
#include "naucrates/dxl/operators/CDXLPhysicalDynamicTableScan.h"
#include "naucrates/dxl/operators/CDXLPhysicalGatherMotion.h"
#include "naucrates/dxl/operators/CDXLPhysicalHashJoin.h"
#include "naucrates/dxl/operators/CDXLPhysicalIndexOnlyScan.h"
#include "naucrates/dxl/operators/CDXLPhysicalLimit.h"
#include "naucrates/dxl/operators/CDXLPhysicalMaterialize.h"
#include "naucrates/dxl/operators/CDXLPhysicalMergeJoin.h"
#include "naucrates/dxl/operators/CDXLPhysicalNLJoin.h"
#include "naucrates/dxl/operators/CDXLPhysicalPartitionSelector.h"
#include "naucrates/dxl/operators/CDXLPhysicalRedistributeMotion.h"
#include "naucrates/dxl/operators/CDXLPhysicalResult.h"
#include "naucrates/dxl/operators/CDXLPhysicalRoutedDistributeMotion.h"
#include "naucrates/dxl/operators/CDXLPhysicalSort.h"
#include "naucrates/dxl/operators/CDXLPhysicalSplit.h"
#include "naucrates/dxl/operators/CDXLPhysicalSubqueryScan.h"
#include "naucrates/dxl/operators/CDXLPhysicalTVF.h"
#include "naucrates/dxl/operators/CDXLPhysicalTableScan.h"
#include "naucrates/dxl/operators/CDXLPhysicalValuesScan.h"
#include "naucrates/dxl/operators/CDXLPhysicalWindow.h"
#include "naucrates/dxl/operators/CDXLScalarBitmapBoolOp.h"
#include "naucrates/dxl/operators/CDXLScalarBitmapIndexProbe.h"
#include "naucrates/dxl/operators/CDXLScalarBoolExpr.h"
#include "naucrates/dxl/operators/CDXLScalarFuncExpr.h"
#include "naucrates/dxl/operators/CDXLScalarHashExpr.h"
#include "naucrates/dxl/operators/CDXLScalarOpExpr.h"
#include "naucrates/dxl/operators/CDXLScalarProjElem.h"
#include "naucrates/dxl/operators/CDXLScalarSortCol.h"
#include "naucrates/dxl/operators/CDXLScalarWindowFrameEdge.h"
#include "naucrates/exception.h"
#include "naucrates/md/IMDAggregate.h"
#include "naucrates/md/IMDFunction.h"
#include "naucrates/md/IMDIndex.h"
#include "naucrates/md/IMDRelationExternal.h"
#include "naucrates/md/IMDScalarOp.h"
#include "naucrates/md/IMDType.h"
#include "naucrates/md/IMDTypeBool.h"
#include "naucrates/md/IMDTypeInt4.h"
#include "naucrates/traceflags/traceflags.h"
using namespace gpdxl;
using namespace gpos;
using namespace gpopt;
using namespace gpmd;
#define GPDXL_ROOT_PLAN_ID -1
#define GPDXL_PLAN_ID_START 1
#define GPDXL_MOTION_ID_START 1
#define GPDXL_PARAM_ID_START 0
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToPlStmt::CTranslatorDXLToPlStmt
//
// @doc:
// Ctor
//
//---------------------------------------------------------------------------
CTranslatorDXLToPlStmt::CTranslatorDXLToPlStmt(
CMemoryPool *mp, CMDAccessor *md_accessor,
CContextDXLToPlStmt *dxl_to_plstmt_context, ULONG num_of_segments)
: m_mp(mp),
m_md_accessor(md_accessor),
m_dxl_to_plstmt_context(dxl_to_plstmt_context),
m_cmd_type(CMD_SELECT),
m_is_tgt_tbl_distributed(false),
m_result_rel_list(nullptr),
m_num_of_segments(num_of_segments),
m_partition_selector_counter(0)
{
m_translator_dxl_to_scalar = GPOS_NEW(m_mp)
CTranslatorDXLToScalar(m_mp, m_md_accessor, m_num_of_segments);
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToPlStmt::~CTranslatorDXLToPlStmt
//
// @doc:
// Dtor
//
//---------------------------------------------------------------------------
CTranslatorDXLToPlStmt::~CTranslatorDXLToPlStmt()
{
GPOS_DELETE(m_translator_dxl_to_scalar);
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToPlStmt::GetPlannedStmtFromDXL
//
// @doc:
// Translate DXL node into a PlannedStmt
//
//---------------------------------------------------------------------------
PlannedStmt *
CTranslatorDXLToPlStmt::GetPlannedStmtFromDXL(const CDXLNode *dxlnode,
const Query *orig_query,
bool can_set_tag)
{
GPOS_ASSERT(nullptr != dxlnode);
CDXLTranslateContext dxl_translate_ctxt(m_mp, false);
PlanSlice *topslice;
topslice = (PlanSlice *) gpdb::GPDBAlloc(sizeof(PlanSlice));
memset(topslice, 0, sizeof(PlanSlice));
topslice->sliceIndex = 0;
topslice->parentIndex = -1;
topslice->gangType = GANGTYPE_UNALLOCATED;
topslice->numsegments = 1;
topslice->segindex = -1;
topslice->directDispatch.isDirectDispatch = false;
topslice->directDispatch.contentIds = NIL;
topslice->directDispatch.haveProcessedAnyCalculations = false;
m_dxl_to_plstmt_context->AddSlice(topslice);
m_dxl_to_plstmt_context->SetCurrentSlice(topslice);
CDXLTranslationContextArray *ctxt_translation_prev_siblings =
GPOS_NEW(m_mp) CDXLTranslationContextArray(m_mp);
Plan *plan = TranslateDXLOperatorToPlan(dxlnode, &dxl_translate_ctxt,
ctxt_translation_prev_siblings);
ctxt_translation_prev_siblings->Release();
GPOS_ASSERT(nullptr != plan);
// collect oids from rtable
List *oids_list = NIL;
ListCell *lc_rte = nullptr;
ForEach(lc_rte, m_dxl_to_plstmt_context->GetRTableEntriesList())
{
RangeTblEntry *pRTE = (RangeTblEntry *) lfirst(lc_rte);
if (pRTE->rtekind == RTE_RELATION)
{
oids_list = gpdb::LAppendOid(oids_list, pRTE->relid);
}
}
// assemble planned stmt
PlannedStmt *planned_stmt = MakeNode(PlannedStmt);
planned_stmt->planGen = PLANGEN_OPTIMIZER;
planned_stmt->rtable = m_dxl_to_plstmt_context->GetRTableEntriesList();
planned_stmt->subplans = m_dxl_to_plstmt_context->GetSubplanEntriesList();
planned_stmt->planTree = plan;
#if 0
// store partitioned table indexes in planned stmt
planned_stmt->queryPartOids = m_dxl_to_plstmt_context->GetPartitionedTablesList();
planned_stmt->numSelectorsPerScanId = m_dxl_to_plstmt_context->GetNumPartitionSelectorsList();
#endif
planned_stmt->canSetTag = can_set_tag;
planned_stmt->relationOids = oids_list;
planned_stmt->commandType = m_cmd_type;
planned_stmt->resultRelations = m_result_rel_list;
// GPDB_92_MERGE_FIXME: we really *should* be handling intoClause
// but currently planner cheats (c.f. createas.c)
// shift the intoClause handling into planner and re-enable this
// pplstmt->intoClause = m_pctxdxltoplstmt->Pintocl();
planned_stmt->intoPolicy = m_dxl_to_plstmt_context->GetDistributionPolicy();
planned_stmt->paramExecTypes = m_dxl_to_plstmt_context->GetParamTypes();
planned_stmt->slices =
m_dxl_to_plstmt_context->GetSlices(&planned_stmt->numSlices);
planned_stmt->subplan_sliceIds =
m_dxl_to_plstmt_context->GetSubplanSliceIdArray();
topslice = &planned_stmt->slices[0];
// Can we do direct dispatch?
if (CMD_SELECT == m_cmd_type &&
nullptr != dxlnode->GetDXLDirectDispatchInfo())
{
List *direct_dispatch_segids =
TranslateDXLDirectDispatchInfo(dxlnode->GetDXLDirectDispatchInfo());
if (direct_dispatch_segids != NIL)
{
for (int i = 0; i < planned_stmt->numSlices; i++)
{
PlanSlice *slice = &planned_stmt->slices[i];
slice->directDispatch.isDirectDispatch = true;
slice->directDispatch.contentIds = direct_dispatch_segids;
}
}
}
if (CMD_INSERT == m_cmd_type && planned_stmt->numSlices == 1 &&
dxlnode->GetOperator()->GetDXLOperator() == EdxlopPhysicalDML)
{
CDXLPhysicalDML *phy_dml_dxlop =
CDXLPhysicalDML::Cast(dxlnode->GetOperator());
List *direct_dispatch_segids = TranslateDXLDirectDispatchInfo(
phy_dml_dxlop->GetDXLDirectDispatchInfo());
if (direct_dispatch_segids != NIL)
{
topslice->directDispatch.isDirectDispatch = true;
topslice->directDispatch.contentIds = direct_dispatch_segids;
}
}
/*
* If it's a CREATE TABLE AS, we have to dispatch the top slice to
* all segments, because the catalog changes need to be made
* everywhere even if the data originates from only some segments.
*/
if (orig_query->commandType == CMD_SELECT &&
orig_query->parentStmtType == PARENTSTMTTYPE_CTAS)
{
topslice->numsegments = m_num_of_segments;
topslice->gangType = GANGTYPE_PRIMARY_WRITER;
}
return planned_stmt;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToPlStmt::TranslateDXLOperatorToPlan
//
// @doc:
// Translates a DXL tree into a Plan node
//
//---------------------------------------------------------------------------
Plan *
CTranslatorDXLToPlStmt::TranslateDXLOperatorToPlan(
const CDXLNode *dxlnode, CDXLTranslateContext *output_context,
CDXLTranslationContextArray *ctxt_translation_prev_siblings)
{
GPOS_ASSERT(nullptr != dxlnode);
GPOS_ASSERT(nullptr != ctxt_translation_prev_siblings);
Plan *plan;
const CDXLOperator *dxlop = dxlnode->GetOperator();
gpdxl::Edxlopid ulOpId = dxlop->GetDXLOperator();
switch (ulOpId)
{
default:
{
GPOS_RAISE(gpdxl::ExmaDXL, gpdxl::ExmiDXL2PlStmtConversion,
dxlnode->GetOperator()->GetOpNameStr()->GetBuffer());
}
case EdxlopPhysicalTableScan:
case EdxlopPhysicalExternalScan:
{
plan = TranslateDXLTblScan(dxlnode, output_context,
ctxt_translation_prev_siblings);
break;
}
case EdxlopPhysicalIndexScan:
{
plan = TranslateDXLIndexScan(dxlnode, output_context,
ctxt_translation_prev_siblings);
break;
}
case EdxlopPhysicalIndexOnlyScan:
{
plan = TranslateDXLIndexOnlyScan(dxlnode, output_context,
ctxt_translation_prev_siblings);
break;
}
case EdxlopPhysicalHashJoin:
{
plan = TranslateDXLHashJoin(dxlnode, output_context,
ctxt_translation_prev_siblings);
break;
}
case EdxlopPhysicalNLJoin:
{
plan = TranslateDXLNLJoin(dxlnode, output_context,
ctxt_translation_prev_siblings);
break;
}
case EdxlopPhysicalMergeJoin:
{
plan = TranslateDXLMergeJoin(dxlnode, output_context,
ctxt_translation_prev_siblings);
break;
}
case EdxlopPhysicalMotionGather:
case EdxlopPhysicalMotionBroadcast:
case EdxlopPhysicalMotionRoutedDistribute:
{
plan = TranslateDXLMotion(dxlnode, output_context,
ctxt_translation_prev_siblings);
break;
}
case EdxlopPhysicalMotionRedistribute:
case EdxlopPhysicalMotionRandom:
{
plan = TranslateDXLDuplicateSensitiveMotion(
dxlnode, output_context, ctxt_translation_prev_siblings);
break;
}
case EdxlopPhysicalLimit:
{
plan = TranslateDXLLimit(dxlnode, output_context,
ctxt_translation_prev_siblings);
break;
}
case EdxlopPhysicalAgg:
{
plan = TranslateDXLAgg(dxlnode, output_context,
ctxt_translation_prev_siblings);
break;
}
case EdxlopPhysicalWindow:
{
plan = TranslateDXLWindow(dxlnode, output_context,
ctxt_translation_prev_siblings);
break;
}
case EdxlopPhysicalSort:
{
plan = TranslateDXLSort(dxlnode, output_context,
ctxt_translation_prev_siblings);
break;
}
case EdxlopPhysicalSubqueryScan:
{
plan = TranslateDXLSubQueryScan(dxlnode, output_context,
ctxt_translation_prev_siblings);
break;
}
case EdxlopPhysicalResult:
{
plan = TranslateDXLResult(dxlnode, output_context,
ctxt_translation_prev_siblings);
break;
}
case EdxlopPhysicalAppend:
{
plan = TranslateDXLAppend(dxlnode, output_context,
ctxt_translation_prev_siblings);
break;
}
case EdxlopPhysicalMaterialize:
{
plan = TranslateDXLMaterialize(dxlnode, output_context,
ctxt_translation_prev_siblings);
break;
}
case EdxlopPhysicalSequence:
{
plan = TranslateDXLSequence(dxlnode, output_context,
ctxt_translation_prev_siblings);
break;
}
case EdxlopPhysicalDynamicTableScan:
{
plan = TranslateDXLDynTblScan(dxlnode, output_context,
ctxt_translation_prev_siblings);
break;
}
case EdxlopPhysicalDynamicIndexScan:
{
plan = TranslateDXLDynIdxScan(dxlnode, output_context,
ctxt_translation_prev_siblings);
break;
}
case EdxlopPhysicalTVF:
{
plan = TranslateDXLTvf(dxlnode, output_context,
ctxt_translation_prev_siblings);
break;
}
case EdxlopPhysicalDML:
{
plan = TranslateDXLDml(dxlnode, output_context,
ctxt_translation_prev_siblings);
break;
}
case EdxlopPhysicalSplit:
{
plan = TranslateDXLSplit(dxlnode, output_context,
ctxt_translation_prev_siblings);
break;
}
case EdxlopPhysicalAssert:
{
plan = TranslateDXLAssert(dxlnode, output_context,
ctxt_translation_prev_siblings);
break;
}
case EdxlopPhysicalCTEProducer:
{
plan = TranslateDXLCTEProducerToSharedScan(
dxlnode, output_context, ctxt_translation_prev_siblings);
break;
}
case EdxlopPhysicalCTEConsumer:
{
plan = TranslateDXLCTEConsumerToSharedScan(
dxlnode, output_context, ctxt_translation_prev_siblings);
break;
}
case EdxlopPhysicalBitmapTableScan:
case EdxlopPhysicalDynamicBitmapTableScan:
{
plan = TranslateDXLBitmapTblScan(dxlnode, output_context,
ctxt_translation_prev_siblings);
break;
}
case EdxlopPhysicalCTAS:
{
plan = TranslateDXLCtas(dxlnode, output_context,
ctxt_translation_prev_siblings);
break;
}
case EdxlopPhysicalPartitionSelector:
{
plan = TranslateDXLPartSelector(dxlnode, output_context,
ctxt_translation_prev_siblings);
break;
}
case EdxlopPhysicalValuesScan:
{
plan = TranslateDXLValueScan(dxlnode, output_context,
ctxt_translation_prev_siblings);
break;
}
}
if (nullptr == plan)
{
GPOS_RAISE(gpdxl::ExmaDXL, gpdxl::ExmiDXL2PlStmtConversion,
dxlnode->GetOperator()->GetOpNameStr()->GetBuffer());
}
return plan;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToPlStmt::SetParamIds
//
// @doc:
// Set the bitmapset with the param_ids defined in the plan
//
//---------------------------------------------------------------------------
void
CTranslatorDXLToPlStmt::SetParamIds(Plan *plan)
{
List *params_node_list = gpdb::ExtractNodesPlan(
plan, T_Param, true /* descend_into_subqueries */);
ListCell *lc = nullptr;
Bitmapset *bitmapset = nullptr;
ForEach(lc, params_node_list)
{
Param *param = (Param *) lfirst(lc);
bitmapset = gpdb::BmsAddMember(bitmapset, param->paramid);
}
plan->extParam = bitmapset;
plan->allParam = bitmapset;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToPlStmt::TranslateDXLTblScan
//
// @doc:
// Translates a DXL table scan node into a TableScan node
//
//---------------------------------------------------------------------------
Plan *
CTranslatorDXLToPlStmt::TranslateDXLTblScan(
const CDXLNode *tbl_scan_dxlnode, CDXLTranslateContext *output_context,
CDXLTranslationContextArray *ctxt_translation_prev_siblings)
{
// translate table descriptor into a range table entry
CDXLPhysicalTableScan *phy_tbl_scan_dxlop =
CDXLPhysicalTableScan::Cast(tbl_scan_dxlnode->GetOperator());
// translation context for column mappings in the base relation
CDXLTranslateContextBaseTable base_table_context(m_mp);
// we will add the new range table entry as the last element of the range table
Index index =
gpdb::ListLength(m_dxl_to_plstmt_context->GetRTableEntriesList()) + 1;
const CDXLTableDescr *dxl_table_descr =
phy_tbl_scan_dxlop->GetDXLTableDescr();
const IMDRelation *md_rel =
m_md_accessor->RetrieveRel(dxl_table_descr->MDId());
// Lock any table we are to scan, since it may not have been properly locked
// by the parser (e.g in case of generated scans for partitioned tables)
CMDIdGPDB *mdid = CMDIdGPDB::CastMdid(md_rel->MDId());
GPOS_RTL_ASSERT(dxl_table_descr->LockMode() != -1);
gpdb::GPDBLockRelationOid(mdid->Oid(), dxl_table_descr->LockMode());
RangeTblEntry *rte = TranslateDXLTblDescrToRangeTblEntry(
dxl_table_descr, index, &base_table_context);
GPOS_ASSERT(nullptr != rte);
rte->requiredPerms |= ACL_SELECT;
m_dxl_to_plstmt_context->AddRTE(rte);
// a table scan node must have 2 children: projection list and filter
GPOS_ASSERT(2 == tbl_scan_dxlnode->Arity());
// translate proj list and filter
CDXLNode *project_list_dxlnode = (*tbl_scan_dxlnode)[EdxltsIndexProjList];
CDXLNode *filter_dxlnode = (*tbl_scan_dxlnode)[EdxltsIndexFilter];
List *targetlist = NIL;
List *qual = NIL;
TranslateProjListAndFilter(
project_list_dxlnode, filter_dxlnode,
&base_table_context, // translate context for the base table
nullptr, // translate_ctxt_left and pdxltrctxRight,
&targetlist, &qual, output_context);
Plan *plan = nullptr;
Plan *plan_return = nullptr;
if (IMDRelation::ErelstorageExternal == md_rel->RetrieveRelStorageType())
{
OID oidRel = CMDIdGPDB::CastMdid(md_rel->MDId())->Oid();
// create foreign scan node
ForeignScan *foreign_scan = gpdb::CreateForeignScanForExternalTable(
oidRel, index, qual, targetlist);
plan = &(foreign_scan->scan.plan);
plan_return = (Plan *) foreign_scan;
}
else
{
// create seq scan node
SeqScan *seq_scan = MakeNode(SeqScan);
seq_scan->scanrelid = index;
plan = &(seq_scan->plan);
plan_return = (Plan *) seq_scan;
plan->targetlist = targetlist;
plan->qual = qual;
}
plan->plan_node_id = m_dxl_to_plstmt_context->GetNextPlanId();
// translate operator costs
TranslatePlanCosts(tbl_scan_dxlnode, plan);
SetParamIds(plan);
return plan_return;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToPlStmt::SetIndexVarAttnoWalker
//
// @doc:
// Walker to set index var attno's,
// attnos of index vars are set to their relative positions in index keys,
// skip any outer references while walking the expression tree
//
//---------------------------------------------------------------------------
BOOL
CTranslatorDXLToPlStmt::SetIndexVarAttnoWalker(
Node *node, SContextIndexVarAttno *ctxt_index_var_attno_walker)
{
if (nullptr == node)
{
return false;
}
if (IsA(node, Var) && ((Var *) node)->varno != OUTER_VAR)
{
INT attno = ((Var *) node)->varattno;
const IMDRelation *md_rel = ctxt_index_var_attno_walker->m_md_rel;
const IMDIndex *index = ctxt_index_var_attno_walker->m_md_index;
ULONG index_col_pos_idx_max = gpos::ulong_max;
const ULONG arity = md_rel->ColumnCount();
for (ULONG col_pos_idx = 0; col_pos_idx < arity; col_pos_idx++)
{
const IMDColumn *md_col = md_rel->GetMdCol(col_pos_idx);
if (attno == md_col->AttrNum())
{
index_col_pos_idx_max = col_pos_idx;
break;
}
}
if (gpos::ulong_max > index_col_pos_idx_max)
{
((Var *) node)->varattno =
1 + index->GetKeyPos(index_col_pos_idx_max);
}
return false;
}
return gpdb::WalkExpressionTree(
node, (BOOL(*)()) CTranslatorDXLToPlStmt::SetIndexVarAttnoWalker,
ctxt_index_var_attno_walker);
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToPlStmt::TranslateDXLIndexScan
//
// @doc:
// Translates a DXL index scan node into a IndexScan node
//
//---------------------------------------------------------------------------
Plan *
CTranslatorDXLToPlStmt::TranslateDXLIndexScan(
const CDXLNode *index_scan_dxlnode, CDXLTranslateContext *output_context,
CDXLTranslationContextArray *ctxt_translation_prev_siblings)
{
// translate table descriptor into a range table entry
CDXLPhysicalIndexScan *physical_idx_scan_dxlop =
CDXLPhysicalIndexScan::Cast(index_scan_dxlnode->GetOperator());
return TranslateDXLIndexScan(index_scan_dxlnode, physical_idx_scan_dxlop,
output_context,
ctxt_translation_prev_siblings);
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToPlStmt::TranslateDXLIndexScan
//
// @doc:
// Translates a DXL index scan node into a IndexScan node
//
//---------------------------------------------------------------------------
Plan *
CTranslatorDXLToPlStmt::TranslateDXLIndexScan(
const CDXLNode *index_scan_dxlnode,
CDXLPhysicalIndexScan *physical_idx_scan_dxlop,
CDXLTranslateContext *output_context,
CDXLTranslationContextArray *ctxt_translation_prev_siblings)
{
// translation context for column mappings in the base relation
CDXLTranslateContextBaseTable base_table_context(m_mp);
Index index =
gpdb::ListLength(m_dxl_to_plstmt_context->GetRTableEntriesList()) + 1;
const CDXLTableDescr *dxl_table_descr =
physical_idx_scan_dxlop->GetDXLTableDescr();
const IMDRelation *md_rel =
m_md_accessor->RetrieveRel(dxl_table_descr->MDId());
// Lock any table we are to scan, since it may not have been properly locked
// by the parser (e.g in case of generated scans for partitioned tables)
CMDIdGPDB *mdid = CMDIdGPDB::CastMdid(md_rel->MDId());
GPOS_RTL_ASSERT(dxl_table_descr->LockMode() != -1);
gpdb::GPDBLockRelationOid(mdid->Oid(), dxl_table_descr->LockMode());
RangeTblEntry *rte = TranslateDXLTblDescrToRangeTblEntry(
physical_idx_scan_dxlop->GetDXLTableDescr(), index,
&base_table_context);
GPOS_ASSERT(nullptr != rte);
rte->requiredPerms |= ACL_SELECT;
m_dxl_to_plstmt_context->AddRTE(rte);
IndexScan *index_scan = nullptr;
index_scan = MakeNode(IndexScan);
index_scan->scan.scanrelid = index;
CMDIdGPDB *mdid_index = CMDIdGPDB::CastMdid(
physical_idx_scan_dxlop->GetDXLIndexDescr()->MDId());
const IMDIndex *md_index = m_md_accessor->RetrieveIndex(mdid_index);
Oid index_oid = mdid_index->Oid();
GPOS_ASSERT(InvalidOid != index_oid);
// Lock any index we are to scan, since it may not have been properly locked
// by the parser (e.g in case of generated scans for partitioned indexes)
gpdb::GPDBLockRelationOid(index_oid, dxl_table_descr->LockMode());
index_scan->indexid = index_oid;
Plan *plan = &(index_scan->scan.plan);
plan->plan_node_id = m_dxl_to_plstmt_context->GetNextPlanId();
// translate operator costs
TranslatePlanCosts(index_scan_dxlnode, plan);
// an index scan node must have 3 children: projection list, filter and index condition list
GPOS_ASSERT(3 == index_scan_dxlnode->Arity());
// translate proj list and filter
CDXLNode *project_list_dxlnode = (*index_scan_dxlnode)[EdxlisIndexProjList];
CDXLNode *filter_dxlnode = (*index_scan_dxlnode)[EdxlisIndexFilter];
CDXLNode *index_cond_list_dxlnode =
(*index_scan_dxlnode)[EdxlisIndexCondition];
// translate proj list
plan->targetlist =
TranslateDXLProjList(project_list_dxlnode, &base_table_context,
nullptr /*child_contexts*/, output_context);
// translate index filter
plan->qual = TranslateDXLIndexFilter(filter_dxlnode, output_context,
&base_table_context,
ctxt_translation_prev_siblings);
index_scan->indexorderdir = CTranslatorUtils::GetScanDirection(
physical_idx_scan_dxlop->GetIndexScanDir());
// translate index condition list
List *index_cond = NIL;
List *index_orig_cond = NIL;
List *index_strategy_list = NIL;
List *index_subtype_list = NIL;
TranslateIndexConditions(
index_cond_list_dxlnode, physical_idx_scan_dxlop->GetDXLTableDescr(),
false, // is_bitmap_index_probe
md_index, md_rel, output_context, &base_table_context,
ctxt_translation_prev_siblings, &index_cond, &index_orig_cond,
&index_strategy_list, &index_subtype_list);
index_scan->indexqual = index_cond;
index_scan->indexqualorig = index_orig_cond;
/*
* As of 8.4, the indexstrategy and indexsubtype fields are no longer
* available or needed in IndexScan. Ignore them.
*/
SetParamIds(plan);
return (Plan *) index_scan;
}
static List *
TranslateDXLIndexTList(const IMDRelation *md_rel, const IMDIndex *md_index,
Index new_varno, const CDXLTableDescr *table_descr,
CDXLTranslateContextBaseTable *index_context)
{
List *target_list = NIL;
index_context->SetRelIndex(INDEX_VAR);
for (ULONG ul = 0; ul < md_index->Keys(); ul++)
{
ULONG key = md_index->KeyAt(ul);
const IMDColumn *col = md_rel->GetMdCol(key);
TargetEntry *target_entry = MakeNode(TargetEntry);
target_entry->resno = (AttrNumber) ul + 1;
Expr *indexvar = (Expr *) gpdb::MakeVar(
new_varno, col->AttrNum(),
CMDIdGPDB::CastMdid(col->MdidType())->Oid(),
col->TypeModifier() /*vartypmod*/, 0 /*varlevelsup*/);
target_entry->expr = indexvar;
// Fix up proj list. Since index only scan does not read full tuples,
// the var->varattno must be updated as it should no longer point to
// column in the table, but rather a column in the index. We achieve
// this by mapping col id to a new varattno based on index columns.
for (ULONG j = 0; j < table_descr->Arity(); j++)
{
const CDXLColDescr *dxl_col_descr =
table_descr->GetColumnDescrAt(j);
if (dxl_col_descr->AttrNum() == ((Var *) indexvar)->varattno)
{
(void) index_context->InsertMapping(dxl_col_descr->Id(),
ul + 1);
break;
}
}
target_list = gpdb::LAppend(target_list, target_entry);
}
return target_list;
}
Plan *
CTranslatorDXLToPlStmt::TranslateDXLIndexOnlyScan(
const CDXLNode *index_scan_dxlnode, CDXLTranslateContext *output_context,
CDXLTranslationContextArray *ctxt_translation_prev_siblings)
{
// translate table descriptor into a range table entry
CDXLPhysicalIndexOnlyScan *physical_idx_scan_dxlop =
CDXLPhysicalIndexOnlyScan::Cast(index_scan_dxlnode->GetOperator());
const CDXLTableDescr *table_desc =
physical_idx_scan_dxlop->GetDXLTableDescr();
// translation context for column mappings in the base relation
CDXLTranslateContextBaseTable base_table_context(m_mp);
Index index =
gpdb::ListLength(m_dxl_to_plstmt_context->GetRTableEntriesList()) + 1;
const IMDRelation *md_rel = m_md_accessor->RetrieveRel(
physical_idx_scan_dxlop->GetDXLTableDescr()->MDId());
RangeTblEntry *rte = TranslateDXLTblDescrToRangeTblEntry(
physical_idx_scan_dxlop->GetDXLTableDescr(), index,
&base_table_context);
GPOS_ASSERT(nullptr != rte);
rte->requiredPerms |= ACL_SELECT;
m_dxl_to_plstmt_context->AddRTE(rte);
IndexOnlyScan *index_scan = MakeNode(IndexOnlyScan);
index_scan->scan.scanrelid = index;
CMDIdGPDB *mdid_index = CMDIdGPDB::CastMdid(
physical_idx_scan_dxlop->GetDXLIndexDescr()->MDId());
const IMDIndex *md_index = m_md_accessor->RetrieveIndex(mdid_index);
Oid index_oid = mdid_index->Oid();
GPOS_ASSERT(InvalidOid != index_oid);
index_scan->indexid = index_oid;
Plan *plan = &(index_scan->scan.plan);
plan->plan_node_id = m_dxl_to_plstmt_context->GetNextPlanId();
// translate operator costs
TranslatePlanCosts(index_scan_dxlnode, plan);
// an index scan node must have 3 children: projection list, filter and index condition list
GPOS_ASSERT(3 == index_scan_dxlnode->Arity());
// translate proj list and filter
CDXLNode *project_list_dxlnode = (*index_scan_dxlnode)[EdxlisIndexProjList];
CDXLNode *filter_dxlnode = (*index_scan_dxlnode)[EdxlisIndexFilter];
CDXLNode *index_cond_list_dxlnode =
(*index_scan_dxlnode)[EdxlisIndexCondition];
CDXLTranslateContextBaseTable index_context(m_mp);
// translate index targetlist
index_scan->indextlist = TranslateDXLIndexTList(md_rel, md_index, index,
table_desc, &index_context);
// translate target list
plan->targetlist =
TranslateDXLProjList(project_list_dxlnode, &index_context,
nullptr /*child_contexts*/, output_context);
// translate index filter
plan->qual =
TranslateDXLIndexFilter(filter_dxlnode, output_context, &index_context,
ctxt_translation_prev_siblings);
index_scan->indexorderdir = CTranslatorUtils::GetScanDirection(
physical_idx_scan_dxlop->GetIndexScanDir());
// translate index condition list
List *index_cond = NIL;
List *index_orig_cond = NIL;
List *index_strategy_list = NIL;
List *index_subtype_list = NIL;
TranslateIndexConditions(
index_cond_list_dxlnode, physical_idx_scan_dxlop->GetDXLTableDescr(),
false, // is_bitmap_index_probe
md_index, md_rel, output_context, &base_table_context,
ctxt_translation_prev_siblings, &index_cond, &index_orig_cond,
&index_strategy_list, &index_subtype_list);
index_scan->indexqual = index_cond;
index_scan->indexqualorig = index_orig_cond;
SetParamIds(plan);
return (Plan *) index_scan;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToPlStmt::TranslateIndexFilter
//
// @doc:
// Translate the index filter list in an Index scan
//
//---------------------------------------------------------------------------
List *
CTranslatorDXLToPlStmt::TranslateDXLIndexFilter(
CDXLNode *filter_dxlnode, CDXLTranslateContext *output_context,
CDXLTranslateContextBaseTable *base_table_context,
CDXLTranslationContextArray *ctxt_translation_prev_siblings)
{
List *quals_list = NIL;
// build colid->var mapping
CMappingColIdVarPlStmt colid_var_mapping(
m_mp, base_table_context, ctxt_translation_prev_siblings,
output_context, m_dxl_to_plstmt_context);
const ULONG arity = filter_dxlnode->Arity();
for (ULONG ul = 0; ul < arity; ul++)
{
CDXLNode *index_filter_dxlnode = (*filter_dxlnode)[ul];
Expr *index_filter_expr =
m_translator_dxl_to_scalar->TranslateDXLToScalar(
index_filter_dxlnode, &colid_var_mapping);
quals_list = gpdb::LAppend(quals_list, index_filter_expr);
}
return quals_list;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToPlStmt::TranslateIndexConditions
//
// @doc:
// Translate the index condition list in an Index scan
//
//---------------------------------------------------------------------------
void
CTranslatorDXLToPlStmt::TranslateIndexConditions(
CDXLNode *index_cond_list_dxlnode, const CDXLTableDescr *dxl_tbl_descr,
BOOL is_bitmap_index_probe, const IMDIndex *index,
const IMDRelation *md_rel, CDXLTranslateContext *output_context,
CDXLTranslateContextBaseTable *base_table_context,
CDXLTranslationContextArray *ctxt_translation_prev_siblings,
List **index_cond, List **index_orig_cond, List **index_strategy_list,
List **index_subtype_list)
{
// array of index qual info
CIndexQualInfoArray *index_qual_info_array =
GPOS_NEW(m_mp) CIndexQualInfoArray(m_mp);
// build colid->var mapping
CMappingColIdVarPlStmt colid_var_mapping(
m_mp, base_table_context, ctxt_translation_prev_siblings,
output_context, m_dxl_to_plstmt_context);
const ULONG arity = index_cond_list_dxlnode->Arity();
for (ULONG ul = 0; ul < arity; ul++)
{
CDXLNode *index_cond_dxlnode = (*index_cond_list_dxlnode)[ul];
Expr *original_index_cond_expr =
m_translator_dxl_to_scalar->TranslateDXLToScalar(
index_cond_dxlnode, &colid_var_mapping);
Expr *index_cond_expr =
m_translator_dxl_to_scalar->TranslateDXLToScalar(
index_cond_dxlnode, &colid_var_mapping);
GPOS_ASSERT((IsA(index_cond_expr, OpExpr) ||
IsA(index_cond_expr, ScalarArrayOpExpr)) &&
"expected OpExpr or ScalarArrayOpExpr in index qual");
if (!is_bitmap_index_probe && IsA(index_cond_expr, ScalarArrayOpExpr) &&
IMDIndex::EmdindBitmap != index->IndexType())
{
GPOS_RAISE(
gpdxl::ExmaDXL, gpdxl::ExmiDXL2PlStmtConversion,
GPOS_WSZ_LIT("ScalarArrayOpExpr condition on index scan"));
}
// We need to perform mapping of Varattnos relative to column positions in index keys
SContextIndexVarAttno index_varattno_ctxt(md_rel, index);
SetIndexVarAttnoWalker((Node *) index_cond_expr, &index_varattno_ctxt);
// find index key's attno
List *args_list = nullptr;
if (IsA(index_cond_expr, OpExpr))
{
args_list = ((OpExpr *) index_cond_expr)->args;
}
else
{
args_list = ((ScalarArrayOpExpr *) index_cond_expr)->args;
}
Node *left_arg = (Node *) lfirst(gpdb::ListHead(args_list));
Node *right_arg = (Node *) lfirst(gpdb::ListTail(args_list));
BOOL is_relabel_type = false;
if (IsA(left_arg, RelabelType) &&
IsA(((RelabelType *) left_arg)->arg, Var))
{
left_arg = (Node *) ((RelabelType *) left_arg)->arg;
is_relabel_type = true;
}
else if (IsA(right_arg, RelabelType) &&
IsA(((RelabelType *) right_arg)->arg, Var))
{
right_arg = (Node *) ((RelabelType *) right_arg)->arg;
is_relabel_type = true;
}
if (is_relabel_type)
{
List *new_args_list = ListMake2(left_arg, right_arg);
gpdb::GPDBFree(args_list);
if (IsA(index_cond_expr, OpExpr))
{
((OpExpr *) index_cond_expr)->args = new_args_list;
}
else
{
((ScalarArrayOpExpr *) index_cond_expr)->args = new_args_list;
}
}
GPOS_ASSERT((IsA(left_arg, Var) || IsA(right_arg, Var)) &&
"expected index key in index qual");
INT attno = 0;
if (IsA(left_arg, Var) && ((Var *) left_arg)->varno != OUTER_VAR)
{
// index key is on the left side
attno = ((Var *) left_arg)->varattno;
// GPDB_92_MERGE_FIXME: helluva hack
// Upstream commit a0185461 cleaned up how the varno of indices
// We are patching up varno here, but it seems this really should
// happen in CTranslatorDXLToScalar::PexprFromDXLNodeScalar .
// Furthermore, should we guard against nonsensical varno?
((Var *) left_arg)->varno = INDEX_VAR;
}
else
{
// index key is on the right side
GPOS_ASSERT(((Var *) right_arg)->varno != OUTER_VAR &&
"unexpected outer reference in index qual");
attno = ((Var *) right_arg)->varattno;
}
// retrieve index strategy and subtype
INT strategy_num = 0;
OID index_subtype_oid = InvalidOid;
OID cmp_operator_oid =
CTranslatorUtils::OidCmpOperator(index_cond_expr);
GPOS_ASSERT(InvalidOid != cmp_operator_oid);
OID op_family_oid = CTranslatorUtils::GetOpFamilyForIndexQual(
attno, CMDIdGPDB::CastMdid(index->MDId())->Oid());
GPOS_ASSERT(InvalidOid != op_family_oid);
gpdb::IndexOpProperties(cmp_operator_oid, op_family_oid, &strategy_num,
&index_subtype_oid);
// create index qual
index_qual_info_array->Append(GPOS_NEW(m_mp) CIndexQualInfo(
attno, index_cond_expr, original_index_cond_expr,
(StrategyNumber) strategy_num, index_subtype_oid));
}
// the index quals much be ordered by attribute number
index_qual_info_array->Sort(CIndexQualInfo::IndexQualInfoCmp);
ULONG length = index_qual_info_array->Size();
for (ULONG ul = 0; ul < length; ul++)
{
CIndexQualInfo *index_qual_info = (*index_qual_info_array)[ul];
*index_cond = gpdb::LAppend(*index_cond, index_qual_info->m_expr);
*index_orig_cond =
gpdb::LAppend(*index_orig_cond, index_qual_info->m_original_expr);
*index_strategy_list = gpdb::LAppendInt(
*index_strategy_list, index_qual_info->m_index_subtype_oid);
*index_subtype_list = gpdb::LAppendOid(
*index_subtype_list, index_qual_info->m_index_subtype_oid);
}
// clean up
index_qual_info_array->Release();
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToPlStmt::TranslateDXLAssertConstraints
//
// @doc:
// Translate the constraints from an Assert node into a list of quals
//
//---------------------------------------------------------------------------
List *
CTranslatorDXLToPlStmt::TranslateDXLAssertConstraints(
CDXLNode *assert_contraint_list_dxlnode,
CDXLTranslateContext *output_context,
CDXLTranslationContextArray *child_contexts)
{
List *quals_list = NIL;
// build colid->var mapping
CMappingColIdVarPlStmt colid_var_mapping(
m_mp, nullptr /*base_table_context*/, child_contexts, output_context,
m_dxl_to_plstmt_context);
const ULONG arity = assert_contraint_list_dxlnode->Arity();
for (ULONG ul = 0; ul < arity; ul++)
{
CDXLNode *assert_contraint_dxlnode =
(*assert_contraint_list_dxlnode)[ul];
Expr *assert_contraint_expr =
m_translator_dxl_to_scalar->TranslateDXLToScalar(
(*assert_contraint_dxlnode)[0], &colid_var_mapping);
quals_list = gpdb::LAppend(quals_list, assert_contraint_expr);
}
return quals_list;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToPlStmt::TranslateDXLLimit
//
// @doc:
// Translates a DXL Limit node into a Limit node
//
//---------------------------------------------------------------------------
Plan *
CTranslatorDXLToPlStmt::TranslateDXLLimit(
const CDXLNode *limit_dxlnode, CDXLTranslateContext *output_context,
CDXLTranslationContextArray *ctxt_translation_prev_siblings)
{
// create limit node
Limit *limit = MakeNode(Limit);
Plan *plan = &(limit->plan);
plan->plan_node_id = m_dxl_to_plstmt_context->GetNextPlanId();
// translate operator costs
TranslatePlanCosts(limit_dxlnode, plan);
GPOS_ASSERT(4 == limit_dxlnode->Arity());
CDXLTranslateContext left_dxl_translate_ctxt(
m_mp, false, output_context->GetColIdToParamIdMap());
// translate proj list
CDXLNode *project_list_dxlnode = (*limit_dxlnode)[EdxllimitIndexProjList];
CDXLNode *child_plan_dxlnode = (*limit_dxlnode)[EdxllimitIndexChildPlan];
CDXLNode *limit_count_dxlnode = (*limit_dxlnode)[EdxllimitIndexLimitCount];
CDXLNode *limit_offset_dxlnode =
(*limit_dxlnode)[EdxllimitIndexLimitOffset];
// NOTE: Limit node has only the left plan while the right plan is left empty
Plan *left_plan =
TranslateDXLOperatorToPlan(child_plan_dxlnode, &left_dxl_translate_ctxt,
ctxt_translation_prev_siblings);
CDXLTranslationContextArray *child_contexts =
GPOS_NEW(m_mp) CDXLTranslationContextArray(m_mp);
child_contexts->Append(&left_dxl_translate_ctxt);
plan->targetlist =
TranslateDXLProjList(project_list_dxlnode,
nullptr, // base table translation context
child_contexts, output_context);
plan->lefttree = left_plan;
if (nullptr != limit_count_dxlnode && limit_count_dxlnode->Arity() > 0)
{
CMappingColIdVarPlStmt colid_var_mapping(m_mp, nullptr, child_contexts,
output_context,
m_dxl_to_plstmt_context);
Node *limit_count =
(Node *) m_translator_dxl_to_scalar->TranslateDXLToScalar(
(*limit_count_dxlnode)[0], &colid_var_mapping);
limit->limitCount = limit_count;
}
if (nullptr != limit_offset_dxlnode && limit_offset_dxlnode->Arity() > 0)
{
CMappingColIdVarPlStmt colid_var_mapping =
CMappingColIdVarPlStmt(m_mp, nullptr, child_contexts,
output_context, m_dxl_to_plstmt_context);
Node *limit_offset =
(Node *) m_translator_dxl_to_scalar->TranslateDXLToScalar(
(*limit_offset_dxlnode)[0], &colid_var_mapping);
limit->limitOffset = limit_offset;
}
SetParamIds(plan);
// cleanup
child_contexts->Release();
return (Plan *) limit;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToPlStmt::TranslateDXLHashJoin
//
// @doc:
// Translates a DXL hash join node into a HashJoin node
//
//---------------------------------------------------------------------------
Plan *
CTranslatorDXLToPlStmt::TranslateDXLHashJoin(
const CDXLNode *hj_dxlnode, CDXLTranslateContext *output_context,
CDXLTranslationContextArray *ctxt_translation_prev_siblings)
{
GPOS_ASSERT(hj_dxlnode->GetOperator()->GetDXLOperator() ==
EdxlopPhysicalHashJoin);
GPOS_ASSERT(hj_dxlnode->Arity() == EdxlhjIndexSentinel);
// create hash join node
HashJoin *hashjoin = MakeNode(HashJoin);
Join *join = &(hashjoin->join);
Plan *plan = &(join->plan);
plan->plan_node_id = m_dxl_to_plstmt_context->GetNextPlanId();
CDXLPhysicalHashJoin *hashjoin_dxlop =
CDXLPhysicalHashJoin::Cast(hj_dxlnode->GetOperator());
// set join type
join->jointype =
GetGPDBJoinTypeFromDXLJoinType(hashjoin_dxlop->GetJoinType());
join->prefetch_inner = true;
// translate operator costs
TranslatePlanCosts(hj_dxlnode, plan);
// translate join children
CDXLNode *left_tree_dxlnode = (*hj_dxlnode)[EdxlhjIndexHashLeft];
CDXLNode *right_tree_dxlnode = (*hj_dxlnode)[EdxlhjIndexHashRight];
CDXLNode *project_list_dxlnode = (*hj_dxlnode)[EdxlhjIndexProjList];
CDXLNode *filter_dxlnode = (*hj_dxlnode)[EdxlhjIndexFilter];
CDXLNode *join_filter_dxlnode = (*hj_dxlnode)[EdxlhjIndexJoinFilter];
CDXLNode *hash_cond_list_dxlnode = (*hj_dxlnode)[EdxlhjIndexHashCondList];
CDXLTranslateContext left_dxl_translate_ctxt(
m_mp, false, output_context->GetColIdToParamIdMap());
CDXLTranslateContext right_dxl_translate_ctxt(
m_mp, false, output_context->GetColIdToParamIdMap());
Plan *left_plan =
TranslateDXLOperatorToPlan(left_tree_dxlnode, &left_dxl_translate_ctxt,
ctxt_translation_prev_siblings);
// the right side of the join is the one where the hash phase is done
CDXLTranslationContextArray *translation_context_arr_with_siblings =
GPOS_NEW(m_mp) CDXLTranslationContextArray(m_mp);
translation_context_arr_with_siblings->Append(&left_dxl_translate_ctxt);
translation_context_arr_with_siblings->AppendArray(
ctxt_translation_prev_siblings);
Plan *right_plan =
(Plan *) TranslateDXLHash(right_tree_dxlnode, &right_dxl_translate_ctxt,
translation_context_arr_with_siblings);
CDXLTranslationContextArray *child_contexts =
GPOS_NEW(m_mp) CDXLTranslationContextArray(m_mp);
child_contexts->Append(&left_dxl_translate_ctxt);
child_contexts->Append(&right_dxl_translate_ctxt);
// translate proj list and filter
TranslateProjListAndFilter(project_list_dxlnode, filter_dxlnode,
nullptr, // translate context for the base table
child_contexts, &plan->targetlist, &plan->qual,
output_context);
// translate join filter
join->joinqual = TranslateDXLFilterToQual(
join_filter_dxlnode,
nullptr, // translate context for the base table
child_contexts, output_context);
// translate hash cond
List *hash_conditions_list = NIL;
BOOL has_is_not_distinct_from_cond = false;
const ULONG arity = hash_cond_list_dxlnode->Arity();
for (ULONG ul = 0; ul < arity; ul++)
{
CDXLNode *hash_cond_dxlnode = (*hash_cond_list_dxlnode)[ul];
List *hash_cond_list =
TranslateDXLScCondToQual(hash_cond_dxlnode,
nullptr, // base table translation context
child_contexts, output_context);
GPOS_ASSERT(1 == gpdb::ListLength(hash_cond_list));
Expr *expr = (Expr *) LInitial(hash_cond_list);
if (IsA(expr, BoolExpr) && ((BoolExpr *) expr)->boolop == NOT_EXPR)
{
// INDF test
GPOS_ASSERT(gpdb::ListLength(((BoolExpr *) expr)->args) == 1 &&
(IsA((Expr *) LInitial(((BoolExpr *) expr)->args),
DistinctExpr)));
has_is_not_distinct_from_cond = true;
}
hash_conditions_list =
gpdb::ListConcat(hash_conditions_list, hash_cond_list);
}
if (!has_is_not_distinct_from_cond)
{
// no INDF conditions in the hash condition list
hashjoin->hashclauses = hash_conditions_list;
}
else
{
// hash conditions contain INDF clauses -> extract equality conditions to
// construct the hash clauses list
List *hash_clauses_list = NIL;
for (ULONG ul = 0; ul < arity; ul++)
{
CDXLNode *hash_cond_dxlnode = (*hash_cond_list_dxlnode)[ul];
// condition can be either a scalar comparison or a NOT DISTINCT FROM expression
GPOS_ASSERT(
EdxlopScalarCmp ==
hash_cond_dxlnode->GetOperator()->GetDXLOperator() ||
EdxlopScalarBoolExpr ==
hash_cond_dxlnode->GetOperator()->GetDXLOperator());
if (EdxlopScalarBoolExpr ==
hash_cond_dxlnode->GetOperator()->GetDXLOperator())
{
// clause is a NOT DISTINCT FROM check -> extract the distinct comparison node
GPOS_ASSERT(Edxlnot == CDXLScalarBoolExpr::Cast(
hash_cond_dxlnode->GetOperator())
->GetDxlBoolTypeStr());
hash_cond_dxlnode = (*hash_cond_dxlnode)[0];
GPOS_ASSERT(EdxlopScalarDistinct ==
hash_cond_dxlnode->GetOperator()->GetDXLOperator());
}
CMappingColIdVarPlStmt colid_var_mapping =
CMappingColIdVarPlStmt(m_mp, nullptr, child_contexts,
output_context, m_dxl_to_plstmt_context);
// translate the DXL scalar or scalar distinct comparison into an equality comparison
// to store in the hash clauses
Expr *hash_clause_expr =
(Expr *)
m_translator_dxl_to_scalar->TranslateDXLScalarCmpToScalar(
hash_cond_dxlnode, &colid_var_mapping);
hash_clauses_list =
gpdb::LAppend(hash_clauses_list, hash_clause_expr);
}
hashjoin->hashclauses = hash_clauses_list;
hashjoin->hashqualclauses = hash_conditions_list;
}
GPOS_ASSERT(NIL != hashjoin->hashclauses);
plan->lefttree = left_plan;
plan->righttree = right_plan;
SetParamIds(plan);
// cleanup
translation_context_arr_with_siblings->Release();
child_contexts->Release();
return (Plan *) hashjoin;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToPlStmt::TranslateDXLTvf
//
// @doc:
// Translates a DXL TVF node into a GPDB Function scan node
//
//---------------------------------------------------------------------------
Plan *
CTranslatorDXLToPlStmt::TranslateDXLTvf(
const CDXLNode *tvf_dxlnode, CDXLTranslateContext *output_context,
CDXLTranslationContextArray *ctxt_translation_prev_siblings)
{
// translation context for column mappings
CDXLTranslateContextBaseTable base_table_context(m_mp);
// create function scan node
FunctionScan *func_scan = MakeNode(FunctionScan);
Plan *plan = &(func_scan->scan.plan);
RangeTblEntry *rte = TranslateDXLTvfToRangeTblEntry(
tvf_dxlnode, output_context, &base_table_context);
GPOS_ASSERT(rte != nullptr);
GPOS_ASSERT(list_length(rte->functions) == 1);
RangeTblFunction *rtfunc =
(RangeTblFunction *) gpdb::CopyObject(linitial(rte->functions));
// we will add the new range table entry as the last element of the range table
Index index =
gpdb::ListLength(m_dxl_to_plstmt_context->GetRTableEntriesList()) + 1;
base_table_context.SetRelIndex(index);
func_scan->scan.scanrelid = index;
m_dxl_to_plstmt_context->AddRTE(rte);
plan->plan_node_id = m_dxl_to_plstmt_context->GetNextPlanId();
// translate operator costs
TranslatePlanCosts(tvf_dxlnode, plan);
// a table scan node must have at least 1 child: projection list
GPOS_ASSERT(1 <= tvf_dxlnode->Arity());
CDXLNode *project_list_dxlnode = (*tvf_dxlnode)[EdxltsIndexProjList];
// translate proj list
List *target_list = TranslateDXLProjList(
project_list_dxlnode, &base_table_context, nullptr, output_context);
plan->targetlist = target_list;
ListCell *lc_target_entry = nullptr;
rtfunc->funccolnames = NIL;
rtfunc->funccoltypes = NIL;
rtfunc->funccoltypmods = NIL;
rtfunc->funccolcollations = NIL;
ForEach(lc_target_entry, target_list)
{
TargetEntry *target_entry = (TargetEntry *) lfirst(lc_target_entry);
OID oid_type = gpdb::ExprType((Node *) target_entry->expr);
GPOS_ASSERT(InvalidOid != oid_type);
INT typ_mod = gpdb::ExprTypeMod((Node *) target_entry->expr);
Oid collation_type_oid = gpdb::TypeCollation(oid_type);
rtfunc->funccolnames = gpdb::LAppend(
rtfunc->funccolnames, gpdb::MakeStringValue(target_entry->resname));
rtfunc->funccoltypes = gpdb::LAppendOid(rtfunc->funccoltypes, oid_type);
rtfunc->funccoltypmods =
gpdb::LAppendInt(rtfunc->funccoltypmods, typ_mod);
// GPDB_91_MERGE_FIXME: collation
rtfunc->funccolcollations =
gpdb::LAppendOid(rtfunc->funccolcollations, collation_type_oid);
}
func_scan->functions = ListMake1(rtfunc);
SetParamIds(plan);
return (Plan *) func_scan;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToPlStmt::TranslateDXLTvfToRangeTblEntry
//
// @doc:
// Create a range table entry from a CDXLPhysicalTVF node
//
//---------------------------------------------------------------------------
RangeTblEntry *
CTranslatorDXLToPlStmt::TranslateDXLTvfToRangeTblEntry(
const CDXLNode *tvf_dxlnode, CDXLTranslateContext *output_context,
CDXLTranslateContextBaseTable *base_table_context)
{
CDXLPhysicalTVF *dxlop = CDXLPhysicalTVF::Cast(tvf_dxlnode->GetOperator());
RangeTblEntry *rte = MakeNode(RangeTblEntry);
rte->rtekind = RTE_FUNCTION;
// get function alias
Alias *alias = MakeNode(Alias);
alias->colnames = NIL;
alias->aliasname = CTranslatorUtils::CreateMultiByteCharStringFromWCString(
dxlop->Pstr()->GetBuffer());
// project list
CDXLNode *project_list_dxlnode = (*tvf_dxlnode)[EdxltsIndexProjList];
// get column names
const ULONG num_of_cols = project_list_dxlnode->Arity();
for (ULONG ul = 0; ul < num_of_cols; ul++)
{
CDXLNode *proj_elem_dxlnode = (*project_list_dxlnode)[ul];
CDXLScalarProjElem *dxl_proj_elem =
CDXLScalarProjElem::Cast(proj_elem_dxlnode->GetOperator());
CHAR *col_name_char_array =
CTranslatorUtils::CreateMultiByteCharStringFromWCString(
dxl_proj_elem->GetMdNameAlias()->GetMDName()->GetBuffer());
Value *val_colname = gpdb::MakeStringValue(col_name_char_array);
alias->colnames = gpdb::LAppend(alias->colnames, val_colname);
// save mapping col id -> index in translate context
(void) base_table_context->InsertMapping(dxl_proj_elem->Id(),
ul + 1 /*attno*/);
}
RangeTblFunction *rtfunc = MakeNode(RangeTblFunction);
Bitmapset *funcparams = nullptr;
// invalid funcid indicates TVF evaluates to const
if (!dxlop->FuncMdId()->IsValid())
{
Const *const_expr = MakeNode(Const);
const_expr->consttype =
CMDIdGPDB::CastMdid(dxlop->ReturnTypeMdId())->Oid();
const_expr->consttypmod = -1;
CDXLNode *constVa = (*tvf_dxlnode)[1];
CDXLScalarConstValue *constValue =
CDXLScalarConstValue::Cast(constVa->GetOperator());
const CDXLDatum *datum_dxl = constValue->GetDatumVal();
CDXLDatumGeneric *datum_generic_dxl =
CDXLDatumGeneric::Cast(const_cast<gpdxl::CDXLDatum *>(datum_dxl));
const IMDType *type =
m_md_accessor->RetrieveType(datum_generic_dxl->MDId());
const_expr->constlen = type->Length();
Datum val = gpdb::DatumFromPointer(datum_generic_dxl->GetByteArray());
ULONG length =
(ULONG) gpdb::DatumSize(val, false, const_expr->constlen);
CHAR *str = (CHAR *) gpdb::GPDBAlloc(length + 1);
memcpy(str, datum_generic_dxl->GetByteArray(), length);
str[length] = '\0';
const_expr->constvalue = gpdb::DatumFromPointer(str);
rtfunc->funcexpr = (Node *) const_expr;
rtfunc->funccolcount = (int) num_of_cols;
}
else
{
FuncExpr *func_expr = MakeNode(FuncExpr);
func_expr->funcid = CMDIdGPDB::CastMdid(dxlop->FuncMdId())->Oid();
func_expr->funcretset = gpdb::GetFuncRetset(func_expr->funcid);
// this is a function call, as opposed to a cast
func_expr->funcformat = COERCE_EXPLICIT_CALL;
func_expr->funcresulttype =
CMDIdGPDB::CastMdid(dxlop->ReturnTypeMdId())->Oid();
// function arguments
const ULONG num_of_child = tvf_dxlnode->Arity();
for (ULONG ul = 1; ul < num_of_child; ++ul)
{
CDXLNode *func_arg_dxlnode = (*tvf_dxlnode)[ul];
CMappingColIdVarPlStmt colid_var_mapping(m_mp, base_table_context,
nullptr, output_context,
m_dxl_to_plstmt_context);
Expr *pexprFuncArg =
m_translator_dxl_to_scalar->TranslateDXLToScalar(
func_arg_dxlnode, &colid_var_mapping);
func_expr->args = gpdb::LAppend(func_expr->args, pexprFuncArg);
}
// GPDB_91_MERGE_FIXME: collation
func_expr->inputcollid = gpdb::ExprCollation((Node *) func_expr->args);
func_expr->funccollid = gpdb::TypeCollation(func_expr->funcresulttype);
// Populate RangeTblFunction::funcparams, by walking down the entire
// func_expr to capture ids of all the PARAMs
ListCell *lc = nullptr;
List *param_exprs = gpdb::ExtractNodesExpression(
(Node *) func_expr, T_Param, false /*descend_into_subqueries */);
ForEach(lc, param_exprs)
{
Param *param = (Param *) lfirst(lc);
funcparams = gpdb::BmsAddMember(funcparams, param->paramid);
}
rtfunc->funcexpr = (Node *) func_expr;
}
rtfunc->funcparams = funcparams;
// GPDB_91_MERGE_FIXME: collation
// set rtfunc->funccoltypemods & rtfunc->funccolcollations?
rte->functions = ListMake1(rtfunc);
rte->inFromCl = true;
rte->eref = alias;
return rte;
}
// create a range table entry from a CDXLPhysicalValuesScan node
RangeTblEntry *
CTranslatorDXLToPlStmt::TranslateDXLValueScanToRangeTblEntry(
const CDXLNode *value_scan_dxlnode, CDXLTranslateContext *output_context,
CDXLTranslateContextBaseTable *base_table_context)
{
CDXLPhysicalValuesScan *phy_values_scan_dxlop =
CDXLPhysicalValuesScan::Cast(value_scan_dxlnode->GetOperator());
RangeTblEntry *rte = MakeNode(RangeTblEntry);
rte->relid = InvalidOid;
rte->subquery = nullptr;
rte->rtekind = RTE_VALUES;
rte->inh = false; /* never true for values RTEs */
rte->inFromCl = true;
rte->requiredPerms = 0;
rte->checkAsUser = InvalidOid;
Alias *alias = MakeNode(Alias);
alias->colnames = NIL;
// get value alias
alias->aliasname = CTranslatorUtils::CreateMultiByteCharStringFromWCString(
phy_values_scan_dxlop->GetOpNameStr()->GetBuffer());
// project list
CDXLNode *project_list_dxlnode = (*value_scan_dxlnode)[EdxltsIndexProjList];
// get column names
const ULONG num_of_cols = project_list_dxlnode->Arity();
for (ULONG ul = 0; ul < num_of_cols; ul++)
{
CDXLNode *proj_elem_dxlnode = (*project_list_dxlnode)[ul];
CDXLScalarProjElem *dxl_proj_elem =
CDXLScalarProjElem::Cast(proj_elem_dxlnode->GetOperator());
CHAR *col_name_char_array =
CTranslatorUtils::CreateMultiByteCharStringFromWCString(
dxl_proj_elem->GetMdNameAlias()->GetMDName()->GetBuffer());
Value *val_colname = gpdb::MakeStringValue(col_name_char_array);
alias->colnames = gpdb::LAppend(alias->colnames, val_colname);
// save mapping col id -> index in translate context
(void) base_table_context->InsertMapping(dxl_proj_elem->Id(),
ul + 1 /*attno*/);
}
CMappingColIdVarPlStmt colid_var_mapping =
CMappingColIdVarPlStmt(m_mp, base_table_context, nullptr,
output_context, m_dxl_to_plstmt_context);
const ULONG num_of_child = value_scan_dxlnode->Arity();
List *values_lists = NIL;
List *values_collations = NIL;
for (ULONG ulValue = EdxlValIndexConstStart; ulValue < num_of_child;
ulValue++)
{
CDXLNode *value_list_dxlnode = (*value_scan_dxlnode)[ulValue];
const ULONG num_of_cols = value_list_dxlnode->Arity();
List *value = NIL;
for (ULONG ulCol = 0; ulCol < num_of_cols; ulCol++)
{
Expr *const_expr = m_translator_dxl_to_scalar->TranslateDXLToScalar(
(*value_list_dxlnode)[ulCol], &colid_var_mapping);
value = gpdb::LAppend(value, const_expr);
}
values_lists = gpdb::LAppend(values_lists, value);
// GPDB_91_MERGE_FIXME: collation
if (NIL == values_collations)
{
// Set collation based on the first list of values
for (ULONG ulCol = 0; ulCol < num_of_cols; ulCol++)
{
values_collations = gpdb::LAppendOid(
values_collations, gpdb::ExprCollation((Node *) value));
}
}
}
rte->values_lists = values_lists;
rte->colcollations = values_collations;
rte->eref = alias;
return rte;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToPlStmt::TranslateDXLNLJoin
//
// @doc:
// Translates a DXL nested loop join node into a NestLoop plan node
//
//---------------------------------------------------------------------------
Plan *
CTranslatorDXLToPlStmt::TranslateDXLNLJoin(
const CDXLNode *nl_join_dxlnode, CDXLTranslateContext *output_context,
CDXLTranslationContextArray *ctxt_translation_prev_siblings)
{
GPOS_ASSERT(nl_join_dxlnode->GetOperator()->GetDXLOperator() ==
EdxlopPhysicalNLJoin);
GPOS_ASSERT(nl_join_dxlnode->Arity() == EdxlnljIndexSentinel);
// create hash join node
NestLoop *nested_loop = MakeNode(NestLoop);
Join *join = &(nested_loop->join);
Plan *plan = &(join->plan);
plan->plan_node_id = m_dxl_to_plstmt_context->GetNextPlanId();
CDXLPhysicalNLJoin *dxl_nlj =
CDXLPhysicalNLJoin::PdxlConvert(nl_join_dxlnode->GetOperator());
// set join type
join->jointype = GetGPDBJoinTypeFromDXLJoinType(dxl_nlj->GetJoinType());
// translate operator costs
TranslatePlanCosts(nl_join_dxlnode, plan);
// translate join children
CDXLNode *left_tree_dxlnode = (*nl_join_dxlnode)[EdxlnljIndexLeftChild];
CDXLNode *right_tree_dxlnode = (*nl_join_dxlnode)[EdxlnljIndexRightChild];
CDXLNode *project_list_dxlnode = (*nl_join_dxlnode)[EdxlnljIndexProjList];
CDXLNode *filter_dxlnode = (*nl_join_dxlnode)[EdxlnljIndexFilter];
CDXLNode *join_filter_dxlnode = (*nl_join_dxlnode)[EdxlnljIndexJoinFilter];
CDXLTranslateContext left_dxl_translate_ctxt(
m_mp, false, output_context->GetColIdToParamIdMap());
CDXLTranslateContext right_dxl_translate_ctxt(
m_mp, false, output_context->GetColIdToParamIdMap());
// setting of prefetch_inner to true except for the case of index NLJ where we cannot prefetch inner
// because inner child depends on variables coming from outer child
join->prefetch_inner = !dxl_nlj->IsIndexNLJ();
CDXLTranslationContextArray *translation_context_arr_with_siblings =
GPOS_NEW(m_mp) CDXLTranslationContextArray(m_mp);
Plan *left_plan = nullptr;
Plan *right_plan = nullptr;
if (dxl_nlj->IsIndexNLJ())
{
const CDXLColRefArray *pdrgdxlcrOuterRefs =
dxl_nlj->GetNestLoopParamsColRefs();
const ULONG ulLen = pdrgdxlcrOuterRefs->Size();
for (ULONG ul = 0; ul < ulLen; ul++)
{
CDXLColRef *pdxlcr = (*pdrgdxlcrOuterRefs)[ul];
IMDId *pmdid = pdxlcr->MdidType();
ULONG ulColid = pdxlcr->Id();
INT iTypeModifier = pdxlcr->TypeModifier();
OID iTypeOid = CMDIdGPDB::CastMdid(pmdid)->Oid();
if (nullptr ==
right_dxl_translate_ctxt.GetParamIdMappingElement(ulColid))
{
ULONG param_id =
m_dxl_to_plstmt_context->GetNextParamId(iTypeOid);
CMappingElementColIdParamId *pmecolidparamid =
GPOS_NEW(m_mp) CMappingElementColIdParamId(
ulColid, param_id, pmdid, iTypeModifier);
#ifdef GPOS_DEBUG
BOOL fInserted GPOS_ASSERTS_ONLY =
#endif
right_dxl_translate_ctxt.FInsertParamMapping(
ulColid, pmecolidparamid);
GPOS_ASSERT(fInserted);
}
}
// right child (the index scan side) has references to left child's columns,
// we need to translate left child first to load its columns into translation context
left_plan = TranslateDXLOperatorToPlan(left_tree_dxlnode,
&left_dxl_translate_ctxt,
ctxt_translation_prev_siblings);
translation_context_arr_with_siblings->Append(&left_dxl_translate_ctxt);
translation_context_arr_with_siblings->AppendArray(
ctxt_translation_prev_siblings);
// translate right child after left child translation is complete
right_plan = TranslateDXLOperatorToPlan(
right_tree_dxlnode, &right_dxl_translate_ctxt,
translation_context_arr_with_siblings);
}
else
{
// left child may include a PartitionSelector with references to right child's columns,
// we need to translate right child first to load its columns into translation context
right_plan = TranslateDXLOperatorToPlan(right_tree_dxlnode,
&right_dxl_translate_ctxt,
ctxt_translation_prev_siblings);
translation_context_arr_with_siblings->Append(
&right_dxl_translate_ctxt);
translation_context_arr_with_siblings->AppendArray(
ctxt_translation_prev_siblings);
// translate left child after right child translation is complete
left_plan = TranslateDXLOperatorToPlan(
left_tree_dxlnode, &left_dxl_translate_ctxt,
translation_context_arr_with_siblings);
}
CDXLTranslationContextArray *child_contexts =
GPOS_NEW(m_mp) CDXLTranslationContextArray(m_mp);
child_contexts->Append(&left_dxl_translate_ctxt);
child_contexts->Append(&right_dxl_translate_ctxt);
// translate proj list and filter
TranslateProjListAndFilter(project_list_dxlnode, filter_dxlnode,
nullptr, // translate context for the base table
child_contexts, &plan->targetlist, &plan->qual,
output_context);
// translate join condition
join->joinqual = TranslateDXLFilterToQual(
join_filter_dxlnode,
nullptr, // translate context for the base table
child_contexts, output_context);
// create nest loop params for index nested loop joins
if (dxl_nlj->IsIndexNLJ())
{
((NestLoop *) plan)->nestParams = TranslateNestLoopParamList(
dxl_nlj->GetNestLoopParamsColRefs(), &left_dxl_translate_ctxt,
&right_dxl_translate_ctxt);
}
plan->lefttree = left_plan;
plan->righttree = right_plan;
SetParamIds(plan);
// cleanup
translation_context_arr_with_siblings->Release();
child_contexts->Release();
return (Plan *) nested_loop;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToPlStmt::TranslateDXLMergeJoin
//
// @doc:
// Translates a DXL merge join node into a MergeJoin node
//
//---------------------------------------------------------------------------
Plan *
CTranslatorDXLToPlStmt::TranslateDXLMergeJoin(
const CDXLNode *merge_join_dxlnode, CDXLTranslateContext *output_context,
CDXLTranslationContextArray *ctxt_translation_prev_siblings)
{
GPOS_ASSERT(merge_join_dxlnode->GetOperator()->GetDXLOperator() ==
EdxlopPhysicalMergeJoin);
GPOS_ASSERT(merge_join_dxlnode->Arity() == EdxlmjIndexSentinel);
// create merge join node
MergeJoin *merge_join = MakeNode(MergeJoin);
Join *join = &(merge_join->join);
Plan *plan = &(join->plan);
plan->plan_node_id = m_dxl_to_plstmt_context->GetNextPlanId();
CDXLPhysicalMergeJoin *merge_join_dxlop =
CDXLPhysicalMergeJoin::Cast(merge_join_dxlnode->GetOperator());
// set join type
join->jointype =
GetGPDBJoinTypeFromDXLJoinType(merge_join_dxlop->GetJoinType());
// translate operator costs
TranslatePlanCosts(merge_join_dxlnode, plan);
// translate join children
CDXLNode *left_tree_dxlnode = (*merge_join_dxlnode)[EdxlmjIndexLeftChild];
CDXLNode *right_tree_dxlnode = (*merge_join_dxlnode)[EdxlmjIndexRightChild];
CDXLNode *project_list_dxlnode = (*merge_join_dxlnode)[EdxlmjIndexProjList];
CDXLNode *filter_dxlnode = (*merge_join_dxlnode)[EdxlmjIndexFilter];
CDXLNode *join_filter_dxlnode =
(*merge_join_dxlnode)[EdxlmjIndexJoinFilter];
CDXLNode *merge_cond_list_dxlnode =
(*merge_join_dxlnode)[EdxlmjIndexMergeCondList];
CDXLTranslateContext left_dxl_translate_ctxt(
m_mp, false, output_context->GetColIdToParamIdMap());
CDXLTranslateContext right_dxl_translate_ctxt(
m_mp, false, output_context->GetColIdToParamIdMap());
Plan *left_plan =
TranslateDXLOperatorToPlan(left_tree_dxlnode, &left_dxl_translate_ctxt,
ctxt_translation_prev_siblings);
CDXLTranslationContextArray *translation_context_arr_with_siblings =
GPOS_NEW(m_mp) CDXLTranslationContextArray(m_mp);
translation_context_arr_with_siblings->Append(&left_dxl_translate_ctxt);
translation_context_arr_with_siblings->AppendArray(
ctxt_translation_prev_siblings);
Plan *right_plan = TranslateDXLOperatorToPlan(
right_tree_dxlnode, &right_dxl_translate_ctxt,
translation_context_arr_with_siblings);
CDXLTranslationContextArray *child_contexts =
GPOS_NEW(m_mp) CDXLTranslationContextArray(m_mp);
child_contexts->Append(&left_dxl_translate_ctxt);
child_contexts->Append(&right_dxl_translate_ctxt);
// translate proj list and filter
TranslateProjListAndFilter(project_list_dxlnode, filter_dxlnode,
nullptr, // translate context for the base table
child_contexts, &plan->targetlist, &plan->qual,
output_context);
// translate join filter
join->joinqual = TranslateDXLFilterToQual(
join_filter_dxlnode,
nullptr, // translate context for the base table
child_contexts, output_context);
// translate merge cond
List *merge_conditions_list = NIL;
const ULONG num_join_conds = merge_cond_list_dxlnode->Arity();
for (ULONG ul = 0; ul < num_join_conds; ul++)
{
CDXLNode *merge_condition_dxlnode = (*merge_cond_list_dxlnode)[ul];
List *merge_condition_list =
TranslateDXLScCondToQual(merge_condition_dxlnode,
nullptr, // base table translation context
child_contexts, output_context);
GPOS_ASSERT(1 == gpdb::ListLength(merge_condition_list));
merge_conditions_list =
gpdb::ListConcat(merge_conditions_list, merge_condition_list);
}
GPOS_ASSERT(NIL != merge_conditions_list);
merge_join->mergeclauses = merge_conditions_list;
plan->lefttree = left_plan;
plan->righttree = right_plan;
SetParamIds(plan);
merge_join->mergeFamilies =
(Oid *) gpdb::GPDBAlloc(sizeof(Oid) * num_join_conds);
merge_join->mergeStrategies =
(int *) gpdb::GPDBAlloc(sizeof(int) * num_join_conds);
merge_join->mergeCollations =
(Oid *) gpdb::GPDBAlloc(sizeof(Oid) * num_join_conds);
merge_join->mergeNullsFirst =
(bool *) gpdb::GPDBAlloc(sizeof(bool) * num_join_conds);
ListCell *lc;
ULONG ul = 0;
foreach (lc, merge_join->mergeclauses)
{
Expr *expr = (Expr *) lfirst(lc);
if (IsA(expr, OpExpr))
{
// we are ok - phew
OpExpr *opexpr = (OpExpr *) expr;
List *mergefamilies = gpdb::GetMergeJoinOpFamilies(opexpr->opno);
GPOS_ASSERT(nullptr != mergefamilies &&
gpdb::ListLength(mergefamilies) > 0);
// Pick the first - it's probably what we want
merge_join->mergeFamilies[ul] = gpdb::ListNthOid(mergefamilies, 0);
GPOS_ASSERT(gpdb::ListLength(opexpr->args) == 2);
Expr *leftarg = (Expr *) gpdb::ListNth(opexpr->args, 0);
Expr *rightarg PG_USED_FOR_ASSERTS_ONLY =
(Expr *) gpdb::ListNth(opexpr->args, 1);
GPOS_ASSERT(gpdb::ExprCollation((Node *) leftarg) ==
gpdb::ExprCollation((Node *) rightarg));
merge_join->mergeCollations[ul] =
gpdb::ExprCollation((Node *) leftarg);
// Make sure that the following properties match
// those in CPhysicalFullMergeJoin::PosRequired().
merge_join->mergeStrategies[ul] = BTLessStrategyNumber;
merge_join->mergeNullsFirst[ul] = false;
++ul;
}
else
{
GPOS_RAISE(gpdxl::ExmaDXL, gpdxl::ExmiQuery2DXLUnsupportedFeature,
GPOS_WSZ_LIT("Not an op expression in merge clause"));
break;
}
}
// cleanup
translation_context_arr_with_siblings->Release();
child_contexts->Release();
return (Plan *) merge_join;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToPlStmt::TranslateDXLHash
//
// @doc:
// Translates a DXL physical operator node into a Hash node
//
//---------------------------------------------------------------------------
Plan *
CTranslatorDXLToPlStmt::TranslateDXLHash(
const CDXLNode *dxlnode, CDXLTranslateContext *output_context,
CDXLTranslationContextArray *ctxt_translation_prev_siblings)
{
Hash *hash = MakeNode(Hash);
Plan *plan = &(hash->plan);
plan->plan_node_id = m_dxl_to_plstmt_context->GetNextPlanId();
// translate dxl node
CDXLTranslateContext dxl_translate_ctxt(
m_mp, false, output_context->GetColIdToParamIdMap());
Plan *left_plan = TranslateDXLOperatorToPlan(
dxlnode, &dxl_translate_ctxt, ctxt_translation_prev_siblings);
GPOS_ASSERT(0 < dxlnode->Arity());
// create a reference to each entry in the child project list to create the target list of
// the hash node
CDXLNode *project_list_dxlnode = (*dxlnode)[0];
List *target_list = TranslateDXLProjectListToHashTargetList(
project_list_dxlnode, &dxl_translate_ctxt, output_context);
// copy costs from child node; the startup cost for the hash node is the total cost
// of the child plan, see make_hash in createplan.c
plan->startup_cost = left_plan->total_cost;
plan->total_cost = left_plan->total_cost;
plan->plan_rows = left_plan->plan_rows;
plan->plan_width = left_plan->plan_width;
plan->targetlist = target_list;
plan->lefttree = left_plan;
plan->righttree = nullptr;
plan->qual = NIL;
hash->rescannable = false;
SetParamIds(plan);
return (Plan *) hash;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToPlStmt::TranslateDXLDuplicateSensitiveMotion
//
// @doc:
// Translate DXL motion node
//
//---------------------------------------------------------------------------
Plan *
CTranslatorDXLToPlStmt::TranslateDXLDuplicateSensitiveMotion(
const CDXLNode *motion_dxlnode, CDXLTranslateContext *output_context,
CDXLTranslationContextArray *ctxt_translation_prev_siblings)
{
CDXLPhysicalMotion *motion_dxlop =
CDXLPhysicalMotion::Cast(motion_dxlnode->GetOperator());
if (CTranslatorUtils::IsDuplicateSensitiveMotion(motion_dxlop))
{
return TranslateDXLRedistributeMotionToResultHashFilters(
motion_dxlnode, output_context, ctxt_translation_prev_siblings);
}
return TranslateDXLMotion(motion_dxlnode, output_context,
ctxt_translation_prev_siblings);
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToPlStmt::TranslateDXLMotion
//
// @doc:
// Translate DXL motion node into GPDB Motion plan node
//
//---------------------------------------------------------------------------
Plan *
CTranslatorDXLToPlStmt::TranslateDXLMotion(
const CDXLNode *motion_dxlnode, CDXLTranslateContext *output_context,
CDXLTranslationContextArray *ctxt_translation_prev_siblings)
{
CDXLPhysicalMotion *motion_dxlop =
CDXLPhysicalMotion::Cast(motion_dxlnode->GetOperator());
const IntPtrArray *input_segids_array = motion_dxlop->GetInputSegIdsArray();
PlanSlice *recvslice = m_dxl_to_plstmt_context->GetCurrentSlice();
// create motion node
Motion *motion = MakeNode(Motion);
Plan *plan = &(motion->plan);
plan->plan_node_id = m_dxl_to_plstmt_context->GetNextPlanId();
// Translate operator costs before changing the current slice.
TranslatePlanCosts(motion_dxlnode, plan);
CDXLNode *project_list_dxlnode = (*motion_dxlnode)[EdxlgmIndexProjList];
CDXLNode *filter_dxlnode = (*motion_dxlnode)[EdxlgmIndexFilter];
CDXLNode *sort_col_list_dxl = (*motion_dxlnode)[EdxlgmIndexSortColList];
PlanSlice *sendslice = (PlanSlice *) gpdb::GPDBAlloc(sizeof(PlanSlice));
memset(sendslice, 0, sizeof(PlanSlice));
sendslice->sliceIndex = m_dxl_to_plstmt_context->AddSlice(sendslice);
sendslice->parentIndex = recvslice->sliceIndex;
m_dxl_to_plstmt_context->SetCurrentSlice(sendslice);
// only one sender
if (1 == input_segids_array->Size())
{
int segindex = *((*input_segids_array)[0]);
// only one segment in total
if (segindex == MASTER_CONTENT_ID)
{
// sender is on master, must be singleton gang
sendslice->gangType = GANGTYPE_ENTRYDB_READER;
}
else if (1 == gpdb::GetGPSegmentCount())
{
// sender is on segment, can not tell it's singleton or
// all-segment gang, so treat it as all-segment reader gang.
// It can be promoted to writer gang later if needed.
sendslice->gangType = GANGTYPE_PRIMARY_READER;
}
else
{
// multiple segments, must be singleton gang
sendslice->gangType = GANGTYPE_SINGLETON_READER;
}
sendslice->numsegments = 1;
sendslice->segindex = segindex;
}
else
{
// Mark it as reader for now. Will be overwritten into WRITER, if we
// encounter a DML node.
sendslice->gangType = GANGTYPE_PRIMARY_READER;
sendslice->numsegments = m_num_of_segments;
sendslice->segindex = 0;
}
sendslice->directDispatch.isDirectDispatch = false;
sendslice->directDispatch.contentIds = NIL;
sendslice->directDispatch.haveProcessedAnyCalculations = false;
motion->motionID = sendslice->sliceIndex;
// translate motion child
// child node is in the same position in broadcast and gather motion nodes
// but different in redistribute motion nodes
ULONG child_index = motion_dxlop->GetRelationChildIdx();
CDXLNode *child_dxlnode = (*motion_dxlnode)[child_index];
CDXLTranslateContext child_context(m_mp, false,
output_context->GetColIdToParamIdMap());
// Recurse into the child, which runs in the sending slice.
m_dxl_to_plstmt_context->SetCurrentSlice(sendslice);
Plan *child_plan = TranslateDXLOperatorToPlan(
child_dxlnode, &child_context, ctxt_translation_prev_siblings);
CDXLTranslationContextArray *child_contexts =
GPOS_NEW(m_mp) CDXLTranslationContextArray(m_mp);
child_contexts->Append(&child_context);
// translate proj list and filter
TranslateProjListAndFilter(project_list_dxlnode, filter_dxlnode,
nullptr, // translate context for the base table
child_contexts, &plan->targetlist, &plan->qual,
output_context);
// translate sorting info
ULONG num_sort_cols = sort_col_list_dxl->Arity();
if (0 < num_sort_cols)
{
motion->sendSorted = true;
motion->numSortCols = num_sort_cols;
motion->sortColIdx =
(AttrNumber *) gpdb::GPDBAlloc(num_sort_cols * sizeof(AttrNumber));
motion->sortOperators =
(Oid *) gpdb::GPDBAlloc(num_sort_cols * sizeof(Oid));
motion->collations =
(Oid *) gpdb::GPDBAlloc(num_sort_cols * sizeof(Oid));
motion->nullsFirst =
(bool *) gpdb::GPDBAlloc(num_sort_cols * sizeof(bool));
TranslateSortCols(sort_col_list_dxl, output_context, motion->sortColIdx,
motion->sortOperators, motion->collations,
motion->nullsFirst);
}
else
{
// not a sorting motion
motion->sendSorted = false;
motion->numSortCols = 0;
motion->sortColIdx = nullptr;
motion->sortOperators = nullptr;
motion->nullsFirst = nullptr;
}
if (motion_dxlop->GetDXLOperator() == EdxlopPhysicalMotionRedistribute ||
motion_dxlop->GetDXLOperator() ==
EdxlopPhysicalMotionRoutedDistribute ||
motion_dxlop->GetDXLOperator() == EdxlopPhysicalMotionRandom)
{
// translate hash expr list
List *hash_expr_list = NIL;
List *hash_expr_opfamilies = NIL;
int numHashExprs;
if (EdxlopPhysicalMotionRedistribute == motion_dxlop->GetDXLOperator())
{
CDXLNode *hash_expr_list_dxlnode =
(*motion_dxlnode)[EdxlrmIndexHashExprList];
TranslateHashExprList(hash_expr_list_dxlnode, &child_context,
&hash_expr_list, &hash_expr_opfamilies,
output_context);
}
numHashExprs = gpdb::ListLength(hash_expr_list);
int i = 0;
ListCell *lc, *lcoid;
Oid *hashFuncs = (Oid *) gpdb::GPDBAlloc(numHashExprs * sizeof(Oid));
if (GPOS_FTRACE(EopttraceConsiderOpfamiliesForDistribution))
{
GPOS_ASSERT(gpdb::ListLength(hash_expr_list) ==
gpdb::ListLength(hash_expr_opfamilies));
forboth(lc, hash_expr_list, lcoid, hash_expr_opfamilies)
{
Node *expr = (Node *) lfirst(lc);
Oid typeoid = gpdb::ExprType(expr);
Oid opfamily = lfirst_oid(lcoid);
hashFuncs[i] = gpdb::GetHashProcInOpfamily(opfamily, typeoid);
i++;
}
}
else
{
foreach (lc, hash_expr_list)
{
Node *expr = (Node *) lfirst(lc);
Oid typeoid = gpdb::ExprType(expr);
hashFuncs[i] =
m_dxl_to_plstmt_context->GetDistributionHashFuncForType(
typeoid);
i++;
}
}
motion->hashExprs = hash_expr_list;
motion->hashFuncs = hashFuncs;
}
// cleanup
child_contexts->Release();
m_dxl_to_plstmt_context->SetCurrentSlice(recvslice);
plan->lefttree = child_plan;
// translate properties of the specific type of motion operator
switch (motion_dxlop->GetDXLOperator())
{
case EdxlopPhysicalMotionGather:
{
motion->motionType = MOTIONTYPE_GATHER;
break;
}
case EdxlopPhysicalMotionRedistribute:
case EdxlopPhysicalMotionRandom:
{
motion->motionType = MOTIONTYPE_HASH;
motion->numHashSegments =
(int) motion_dxlop->GetOutputSegIdsArray()->Size();
GPOS_ASSERT(motion->numHashSegments > 0);
break;
}
case EdxlopPhysicalMotionBroadcast:
{
motion->motionType = MOTIONTYPE_BROADCAST;
break;
}
case EdxlopPhysicalMotionRoutedDistribute:
{
ULONG segid_col =
CDXLPhysicalRoutedDistributeMotion::Cast(motion_dxlop)
->SegmentIdCol();
const TargetEntry *te_sort_col =
child_context.GetTargetEntry(segid_col);
motion->motionType = MOTIONTYPE_EXPLICIT;
motion->segidColIdx = te_sort_col->resno;
break;
}
default:
GPOS_ASSERT(!"Unrecognized Motion operator");
return nullptr;
}
SetParamIds(plan);
return (Plan *) motion;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToPlStmt::TranslateDXLRedistributeMotionToResultHashFilters
//
// @doc:
// Translate DXL duplicate sensitive redistribute motion node into
// GPDB result node with hash filters
//
//---------------------------------------------------------------------------
Plan *
CTranslatorDXLToPlStmt::TranslateDXLRedistributeMotionToResultHashFilters(
const CDXLNode *motion_dxlnode, CDXLTranslateContext *output_context,
CDXLTranslationContextArray *ctxt_translation_prev_siblings)
{
// create motion node
Result *result = MakeNode(Result);
Plan *plan = &(result->plan);
plan->plan_node_id = m_dxl_to_plstmt_context->GetNextPlanId();
CDXLPhysicalMotion *motion_dxlop =
CDXLPhysicalMotion::Cast(motion_dxlnode->GetOperator());
// translate operator costs
TranslatePlanCosts(motion_dxlnode, plan);
CDXLNode *project_list_dxlnode = (*motion_dxlnode)[EdxlrmIndexProjList];
CDXLNode *filter_dxlnode = (*motion_dxlnode)[EdxlrmIndexFilter];
CDXLNode *child_dxlnode =
(*motion_dxlnode)[motion_dxlop->GetRelationChildIdx()];
CDXLTranslateContext child_context(m_mp, false,
output_context->GetColIdToParamIdMap());
Plan *child_plan = TranslateDXLOperatorToPlan(
child_dxlnode, &child_context, ctxt_translation_prev_siblings);
CDXLTranslationContextArray *child_contexts =
GPOS_NEW(m_mp) CDXLTranslationContextArray(m_mp);
child_contexts->Append(&child_context);
// translate proj list and filter
TranslateProjListAndFilter(project_list_dxlnode, filter_dxlnode,
nullptr, // translate context for the base table
child_contexts, &plan->targetlist, &plan->qual,
output_context);
bool targetlist_modified = false;
// translate hash expr list
if (EdxlopPhysicalMotionRedistribute == motion_dxlop->GetDXLOperator())
{
CDXLNode *hash_expr_list_dxlnode =
(*motion_dxlnode)[EdxlrmIndexHashExprList];
const ULONG length = hash_expr_list_dxlnode->Arity();
GPOS_ASSERT(0 < length);
result->numHashFilterCols = length;
result->hashFilterColIdx =
(AttrNumber *) gpdb::GPDBAlloc(length * sizeof(AttrNumber));
result->hashFilterFuncs = (Oid *) gpdb::GPDBAlloc(length * sizeof(Oid));
for (ULONG ul = 0; ul < length; ul++)
{
CDXLNode *hash_expr_dxlnode = (*hash_expr_list_dxlnode)[ul];
CDXLNode *expr_dxlnode = (*hash_expr_dxlnode)[0];
const TargetEntry *target_entry;
if (EdxlopScalarIdent ==
expr_dxlnode->GetOperator()->GetDXLOperator())
{
ULONG colid = CDXLScalarIdent::Cast(expr_dxlnode->GetOperator())
->GetDXLColRef()
->Id();
target_entry = output_context->GetTargetEntry(colid);
}
else
{
// The expression is not a scalar ident that points to an output column in the child node.
// Rather, it is an expresssion that is evaluated by the hash filter such as CAST(a) or a+b.
// We therefore, create a corresponding GPDB scalar expression and add it to the project list
// of the hash filter
CMappingColIdVarPlStmt colid_var_mapping =
CMappingColIdVarPlStmt(
m_mp,
nullptr, // translate context for the base table
child_contexts, output_context,
m_dxl_to_plstmt_context);
Expr *expr = m_translator_dxl_to_scalar->TranslateDXLToScalar(
expr_dxlnode, &colid_var_mapping);
GPOS_ASSERT(nullptr != expr);
// create a target entry for the hash filter
CWStringConst str_unnamed_col(GPOS_WSZ_LIT("?column?"));
target_entry = gpdb::MakeTargetEntry(
expr, gpdb::ListLength(plan->targetlist) + 1,
CTranslatorUtils::CreateMultiByteCharStringFromWCString(
str_unnamed_col.GetBuffer()),
false /* resjunk */);
plan->targetlist =
gpdb::LAppend(plan->targetlist, (void *) target_entry);
targetlist_modified = true;
}
result->hashFilterColIdx[ul] = target_entry->resno;
result->hashFilterFuncs[ul] =
m_dxl_to_plstmt_context->GetDistributionHashFuncForType(
gpdb::ExprType((Node *) target_entry->expr));
}
}
else
{
// A Redistribute Motion without any expressions to hash, means that
// the subtree should run on one segment only, and we don't care which
// segment it is. That is represented by a One-Off Filter, where we
// check that the segment number matches an arbitrarily chosen one.
int segment = gpdb::CdbHashRandomSeg(gpdb::GetGPSegmentCount());
result->resconstantqual =
(Node *) ListMake1(gpdb::MakeSegmentFilterExpr(segment));
}
// cleanup
child_contexts->Release();
plan->lefttree = child_plan;
SetParamIds(plan);
Plan *child_result = (Plan *) result;
if (targetlist_modified)
{
// If the targetlist is modified by adding any expressions, such as for
// hashFilterColIdx & hashFilterFuncs, add an additional Result node on top
// to project only the elements from the original targetlist.
// This is needed in case the Result node is created under the Hash
// operator (or any non-projecting node), which expects the targetlist of its
// child node to contain only elements that are to be hashed.
// We should not generate a plan where the target list of a non-projecting
// node such as Hash does not match its child. Additional expressions
// here can cause issues with memtuple bindings that can lead to errors.
Result *result = MakeNode(Result);
Plan *plan = &(result->plan);
plan->plan_node_id = m_dxl_to_plstmt_context->GetNextPlanId();
// keep the same costs & rows estimates
plan->startup_cost = child_result->startup_cost;
plan->total_cost = child_result->total_cost;
plan->plan_rows = child_result->plan_rows;
plan->plan_width = child_result->plan_width;
// populate the targetlist based on child_result's original targetlist
plan->targetlist = NIL;
ListCell *lc = nullptr;
ULONG ul = 0;
ForEach(lc, child_result->targetlist)
{
if (ul++ >= project_list_dxlnode->Arity())
{
// done with the original targetlist, stop
// all expressions added after project_list_dxlnode->Arity() are
// not output cols, but rather hash expressions and should not be projected
break;
}
TargetEntry *te = (TargetEntry *) lfirst(lc);
Var *var = gpdb::MakeVar(
OUTER_VAR, te->resno, gpdb::ExprType((Node *) te->expr),
gpdb::ExprTypeMod((Node *) te->expr), 0 /* varlevelsup */);
TargetEntry *new_te =
gpdb::MakeTargetEntry((Expr *) var, ul, /* resno */
te->resname, te->resjunk);
plan->targetlist = gpdb::LAppend(plan->targetlist, new_te);
}
plan->qual = NIL;
plan->lefttree = child_result;
SetParamIds(plan);
return (Plan *) result;
}
return (Plan *) result;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToPlStmt::TranslateDXLAgg
//
// @doc:
// Translate DXL aggregate node into GPDB Agg plan node
//
//---------------------------------------------------------------------------
Plan *
CTranslatorDXLToPlStmt::TranslateDXLAgg(
const CDXLNode *agg_dxlnode, CDXLTranslateContext *output_context,
CDXLTranslationContextArray *ctxt_translation_prev_siblings)
{
// create aggregate plan node
Agg *agg = MakeNode(Agg);
Plan *plan = &(agg->plan);
plan->plan_node_id = m_dxl_to_plstmt_context->GetNextPlanId();
CDXLPhysicalAgg *dxl_phy_agg_dxlop =
CDXLPhysicalAgg::Cast(agg_dxlnode->GetOperator());
// translate operator costs
TranslatePlanCosts(agg_dxlnode, plan);
// translate agg child
CDXLNode *child_dxlnode = (*agg_dxlnode)[EdxlaggIndexChild];
CDXLNode *project_list_dxlnode = (*agg_dxlnode)[EdxlaggIndexProjList];
CDXLNode *filter_dxlnode = (*agg_dxlnode)[EdxlaggIndexFilter];
CDXLTranslateContext child_context(m_mp, true,
output_context->GetColIdToParamIdMap());
Plan *child_plan = TranslateDXLOperatorToPlan(
child_dxlnode, &child_context, ctxt_translation_prev_siblings);
CDXLTranslationContextArray *child_contexts =
GPOS_NEW(m_mp) CDXLTranslationContextArray(m_mp);
child_contexts->Append(&child_context);
// translate proj list and filter
TranslateProjListAndFilter(project_list_dxlnode, filter_dxlnode,
nullptr, // translate context for the base table
child_contexts, // pdxltrctxRight,
&plan->targetlist, &plan->qual, output_context);
// Set the aggsplit for the agg node
ListCell *lc;
foreach (lc, plan->targetlist)
{
TargetEntry *te = (TargetEntry *) lfirst(lc);
if (IsA(te->expr, Aggref))
{
Aggref *aggref = (Aggref *) te->expr;
agg->aggsplit = aggref->aggsplit;
break;
}
}
plan->lefttree = child_plan;
// translate aggregation strategy
switch (dxl_phy_agg_dxlop->GetAggStrategy())
{
case EdxlaggstrategyPlain:
agg->aggstrategy = AGG_PLAIN;
break;
case EdxlaggstrategySorted:
agg->aggstrategy = AGG_SORTED;
break;
case EdxlaggstrategyHashed:
agg->aggstrategy = AGG_HASHED;
break;
default:
GPOS_ASSERT(!"Invalid aggregation strategy");
}
if (agg->aggstrategy == AGG_HASHED &&
CTranslatorUtils::HasOrderedAggRefInProjList(project_list_dxlnode))
{
GPOS_RAISE(gpopt::ExmaDXL, gpopt::ExmiExpr2DXLUnsupportedFeature,
GPOS_WSZ_LIT("Hash aggregation with ORDER BY"));
}
agg->streaming = dxl_phy_agg_dxlop->IsStreamSafe();
// translate grouping cols
const ULongPtrArray *grouping_colid_array =
dxl_phy_agg_dxlop->GetGroupingColidArray();
agg->numCols = grouping_colid_array->Size();
if (agg->numCols > 0)
{
agg->grpColIdx =
(AttrNumber *) gpdb::GPDBAlloc(agg->numCols * sizeof(AttrNumber));
agg->grpOperators = (Oid *) gpdb::GPDBAlloc(agg->numCols * sizeof(Oid));
agg->grpCollations =
(Oid *) gpdb::GPDBAlloc(agg->numCols * sizeof(Oid));
}
else
{
agg->grpColIdx = nullptr;
agg->grpOperators = nullptr;
agg->grpCollations = nullptr;
}
const ULONG length = grouping_colid_array->Size();
for (ULONG ul = 0; ul < length; ul++)
{
ULONG grouping_colid = *((*grouping_colid_array)[ul]);
const TargetEntry *target_entry_grouping_col =
child_context.GetTargetEntry(grouping_colid);
if (nullptr == target_entry_grouping_col)
{
GPOS_RAISE(gpdxl::ExmaDXL, gpdxl::ExmiDXL2PlStmtAttributeNotFound,
grouping_colid);
}
agg->grpColIdx[ul] = target_entry_grouping_col->resno;
// Also find the equality operators to use for each grouping col.
Oid typeId = gpdb::ExprType((Node *) target_entry_grouping_col->expr);
agg->grpOperators[ul] = gpdb::GetEqualityOp(typeId);
agg->grpCollations[ul] =
gpdb::ExprCollation((Node *) target_entry_grouping_col->expr);
Assert(agg->grpOperators[ul] != 0);
}
agg->numGroups =
std::max(1L, (long) std::min(agg->plan.plan_rows, (double) LONG_MAX));
SetParamIds(plan);
// cleanup
child_contexts->Release();
return (Plan *) agg;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToPlStmt::TranslateDXLWindow
//
// @doc:
// Translate DXL window node into GPDB window plan node
//
//---------------------------------------------------------------------------
Plan *
CTranslatorDXLToPlStmt::TranslateDXLWindow(
const CDXLNode *window_dxlnode, CDXLTranslateContext *output_context,
CDXLTranslationContextArray *ctxt_translation_prev_siblings)
{
// create a WindowAgg plan node
WindowAgg *window = MakeNode(WindowAgg);
Plan *plan = &(window->plan);
plan->plan_node_id = m_dxl_to_plstmt_context->GetNextPlanId();
CDXLPhysicalWindow *window_dxlop =
CDXLPhysicalWindow::Cast(window_dxlnode->GetOperator());
// translate the operator costs
TranslatePlanCosts(window_dxlnode, plan);
// translate children
CDXLNode *child_dxlnode = (*window_dxlnode)[EdxlwindowIndexChild];
CDXLNode *project_list_dxlnode = (*window_dxlnode)[EdxlwindowIndexProjList];
CDXLNode *filter_dxlnode = (*window_dxlnode)[EdxlwindowIndexFilter];
CDXLTranslateContext child_context(m_mp, true,
output_context->GetColIdToParamIdMap());
Plan *child_plan = TranslateDXLOperatorToPlan(
child_dxlnode, &child_context, ctxt_translation_prev_siblings);
CDXLTranslationContextArray *child_contexts =
GPOS_NEW(m_mp) CDXLTranslationContextArray(m_mp);
child_contexts->Append(&child_context);
// translate proj list and filter
TranslateProjListAndFilter(project_list_dxlnode, filter_dxlnode,
nullptr, // translate context for the base table
child_contexts, // pdxltrctxRight,
&plan->targetlist, &plan->qual, output_context);
ListCell *lc;
foreach (lc, plan->targetlist)
{
TargetEntry *target_entry = (TargetEntry *) lfirst(lc);
if (IsA(target_entry->expr, WindowFunc))
{
WindowFunc *window_func = (WindowFunc *) target_entry->expr;
window->winref = window_func->winref;
break;
}
}
plan->lefttree = child_plan;
// translate partition columns
const ULongPtrArray *part_by_cols_array =
window_dxlop->GetPartByColsArray();
window->partNumCols = part_by_cols_array->Size();
window->partColIdx = nullptr;
window->partOperators = nullptr;
window->partCollations = nullptr;
if (window->partNumCols > 0)
{
window->partColIdx = (AttrNumber *) gpdb::GPDBAlloc(
window->partNumCols * sizeof(AttrNumber));
window->partOperators =
(Oid *) gpdb::GPDBAlloc(window->partNumCols * sizeof(Oid));
window->partCollations =
(Oid *) gpdb::GPDBAlloc(window->partNumCols * sizeof(Oid));
}
const ULONG num_of_part_cols = part_by_cols_array->Size();
for (ULONG ul = 0; ul < num_of_part_cols; ul++)
{
ULONG part_colid = *((*part_by_cols_array)[ul]);
const TargetEntry *te_part_colid =
child_context.GetTargetEntry(part_colid);
if (nullptr == te_part_colid)
{
GPOS_RAISE(gpdxl::ExmaDXL, gpdxl::ExmiDXL2PlStmtAttributeNotFound,
part_colid);
}
window->partColIdx[ul] = te_part_colid->resno;
// Also find the equality operators to use for each partitioning key col.
Oid type_id = gpdb::ExprType((Node *) te_part_colid->expr);
window->partOperators[ul] = gpdb::GetEqualityOp(type_id);
Assert(window->partOperators[ul] != 0);
window->partCollations[ul] =
gpdb::ExprCollation((Node *) te_part_colid->expr);
}
// translate window keys
const ULONG size = window_dxlop->WindowKeysCount();
if (size > 1)
{
GpdbEreport(ERRCODE_INTERNAL_ERROR, ERROR,
"ORCA produced a plan with more than one window key",
nullptr);
}
GPOS_ASSERT(size <= 1 && "cannot have more than one window key");
if (size == 1)
{
// translate the sorting columns used in the window key
const CDXLWindowKey *window_key = window_dxlop->GetDXLWindowKeyAt(0);
const CDXLWindowFrame *window_frame = window_key->GetWindowFrame();
const CDXLNode *sort_col_list_dxlnode = window_key->GetSortColListDXL();
const ULONG num_of_cols = sort_col_list_dxlnode->Arity();
window->ordNumCols = num_of_cols;
window->ordColIdx =
(AttrNumber *) gpdb::GPDBAlloc(num_of_cols * sizeof(AttrNumber));
window->ordOperators =
(Oid *) gpdb::GPDBAlloc(num_of_cols * sizeof(Oid));
window->ordCollations =
(Oid *) gpdb::GPDBAlloc(num_of_cols * sizeof(Oid));
bool *is_nulls_first =
(bool *) gpdb::GPDBAlloc(num_of_cols * sizeof(bool));
TranslateSortCols(sort_col_list_dxlnode, &child_context,
window->ordColIdx, window->ordOperators,
window->ordCollations, is_nulls_first);
// The firstOrder* fields are separate from just picking the first of ordCol*,
// because the Postgres planner might omit columns that are redundant with the
// PARTITION BY from ordCol*. But ORCA doesn't do that, so we can just copy
// the first entry of ordColIdx/ordOperators into firstOrder* fields.
if (num_of_cols > 0)
{
window->firstOrderCol = window->ordColIdx[0];
window->firstOrderCmpOperator = window->ordOperators[0];
window->firstOrderNullsFirst = is_nulls_first[0];
}
gpdb::GPDBFree(is_nulls_first);
// The ordOperators array is actually supposed to contain equality operators,
// not ordering operators (< or >). So look up the corresponding equality
// operator for each ordering operator.
for (ULONG i = 0; i < num_of_cols; i++)
{
window->ordOperators[i] = gpdb::GetEqualityOpForOrderingOp(
window->ordOperators[i], nullptr);
}
// translate the window frame specified in the window key
if (nullptr != window_key->GetWindowFrame())
{
window->frameOptions = FRAMEOPTION_NONDEFAULT;
if (EdxlfsRow == window_frame->ParseDXLFrameSpec())
{
window->frameOptions |= FRAMEOPTION_ROWS;
}
else
{
window->frameOptions |= FRAMEOPTION_RANGE;
}
if (window_frame->ParseFrameExclusionStrategy() != EdxlfesNulls)
{
GPOS_RAISE(gpdxl::ExmaDXL,
gpdxl::ExmiQuery2DXLUnsupportedFeature,
GPOS_WSZ_LIT("EXCLUDE clause in window frame"));
}
// translate the CDXLNodes representing the leading and trailing edge
CDXLTranslationContextArray *child_contexts =
GPOS_NEW(m_mp) CDXLTranslationContextArray(m_mp);
child_contexts->Append(&child_context);
CMappingColIdVarPlStmt colid_var_mapping =
CMappingColIdVarPlStmt(m_mp, nullptr, child_contexts,
output_context, m_dxl_to_plstmt_context);
// Translate lead boundary
//
// Note that we don't distinguish between the delayed and undelayed
// versions beoynd this point. Executor will make that decision
// without our help.
//
CDXLNode *win_frame_leading_dxlnode = window_frame->PdxlnLeading();
EdxlFrameBoundary lead_boundary_type =
CDXLScalarWindowFrameEdge::Cast(
win_frame_leading_dxlnode->GetOperator())
->ParseDXLFrameBoundary();
if (lead_boundary_type == EdxlfbUnboundedPreceding)
{
window->frameOptions |= FRAMEOPTION_END_UNBOUNDED_PRECEDING;
}
if (lead_boundary_type == EdxlfbBoundedPreceding)
{
window->frameOptions |= FRAMEOPTION_END_OFFSET_PRECEDING;
}
if (lead_boundary_type == EdxlfbCurrentRow)
{
window->frameOptions |= FRAMEOPTION_END_CURRENT_ROW;
}
if (lead_boundary_type == EdxlfbBoundedFollowing)
{
window->frameOptions |= FRAMEOPTION_END_OFFSET_FOLLOWING;
}
if (lead_boundary_type == EdxlfbUnboundedFollowing)
{
window->frameOptions |= FRAMEOPTION_END_UNBOUNDED_FOLLOWING;
}
if (lead_boundary_type == EdxlfbDelayedBoundedPreceding)
{
window->frameOptions |= FRAMEOPTION_END_OFFSET_PRECEDING;
}
if (lead_boundary_type == EdxlfbDelayedBoundedFollowing)
{
window->frameOptions |= FRAMEOPTION_END_OFFSET_FOLLOWING;
}
if (0 != win_frame_leading_dxlnode->Arity())
{
window->endOffset =
(Node *) m_translator_dxl_to_scalar->TranslateDXLToScalar(
(*win_frame_leading_dxlnode)[0], &colid_var_mapping);
}
// And the same for the trail boundary
CDXLNode *win_frame_trailing_dxlnode =
window_frame->PdxlnTrailing();
EdxlFrameBoundary trail_boundary_type =
CDXLScalarWindowFrameEdge::Cast(
win_frame_trailing_dxlnode->GetOperator())
->ParseDXLFrameBoundary();
if (trail_boundary_type == EdxlfbUnboundedPreceding)
{
window->frameOptions |= FRAMEOPTION_START_UNBOUNDED_PRECEDING;
}
if (trail_boundary_type == EdxlfbBoundedPreceding)
{
window->frameOptions |= FRAMEOPTION_START_OFFSET_PRECEDING;
}
if (trail_boundary_type == EdxlfbCurrentRow)
{
window->frameOptions |= FRAMEOPTION_START_CURRENT_ROW;
}
if (trail_boundary_type == EdxlfbBoundedFollowing)
{
window->frameOptions |= FRAMEOPTION_START_OFFSET_FOLLOWING;
}
if (trail_boundary_type == EdxlfbUnboundedFollowing)
{
window->frameOptions |= FRAMEOPTION_START_UNBOUNDED_FOLLOWING;
}
if (trail_boundary_type == EdxlfbDelayedBoundedPreceding)
{
window->frameOptions |= FRAMEOPTION_START_OFFSET_PRECEDING;
}
if (trail_boundary_type == EdxlfbDelayedBoundedFollowing)
{
window->frameOptions |= FRAMEOPTION_START_OFFSET_FOLLOWING;
}
if (0 != win_frame_trailing_dxlnode->Arity())
{
window->startOffset =
(Node *) m_translator_dxl_to_scalar->TranslateDXLToScalar(
(*win_frame_trailing_dxlnode)[0], &colid_var_mapping);
}
// cleanup
child_contexts->Release();
}
else
{
window->frameOptions = FRAMEOPTION_DEFAULTS;
}
}
SetParamIds(plan);
// cleanup
child_contexts->Release();
return (Plan *) window;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToPlStmt::TranslateDXLSort
//
// @doc:
// Translate DXL sort node into GPDB Sort plan node
//
//---------------------------------------------------------------------------
Plan *
CTranslatorDXLToPlStmt::TranslateDXLSort(
const CDXLNode *sort_dxlnode, CDXLTranslateContext *output_context,
CDXLTranslationContextArray *ctxt_translation_prev_siblings)
{
// create sort plan node
Sort *sort = MakeNode(Sort);
Plan *plan = &(sort->plan);
plan->plan_node_id = m_dxl_to_plstmt_context->GetNextPlanId();
CDXLPhysicalSort *sort_dxlop =
CDXLPhysicalSort::Cast(sort_dxlnode->GetOperator());
// translate operator costs
TranslatePlanCosts(sort_dxlnode, plan);
// translate sort child
CDXLNode *child_dxlnode = (*sort_dxlnode)[EdxlsortIndexChild];
CDXLNode *project_list_dxlnode = (*sort_dxlnode)[EdxlsortIndexProjList];
CDXLNode *filter_dxlnode = (*sort_dxlnode)[EdxlsortIndexFilter];
CDXLTranslateContext child_context(m_mp, false,
output_context->GetColIdToParamIdMap());
Plan *child_plan = TranslateDXLOperatorToPlan(
child_dxlnode, &child_context, ctxt_translation_prev_siblings);
CDXLTranslationContextArray *child_contexts =
GPOS_NEW(m_mp) CDXLTranslationContextArray(m_mp);
child_contexts->Append(&child_context);
// translate proj list and filter
TranslateProjListAndFilter(project_list_dxlnode, filter_dxlnode,
nullptr, // translate context for the base table
child_contexts, &plan->targetlist, &plan->qual,
output_context);
plan->lefttree = child_plan;
// set sorting info
sort->noduplicates = sort_dxlop->FDiscardDuplicates();
// translate sorting columns
const CDXLNode *sort_col_list_dxl =
(*sort_dxlnode)[EdxlsortIndexSortColList];
const ULONG num_of_cols = sort_col_list_dxl->Arity();
sort->numCols = num_of_cols;
sort->sortColIdx =
(AttrNumber *) gpdb::GPDBAlloc(num_of_cols * sizeof(AttrNumber));
sort->sortOperators = (Oid *) gpdb::GPDBAlloc(num_of_cols * sizeof(Oid));
sort->collations = (Oid *) gpdb::GPDBAlloc(num_of_cols * sizeof(Oid));
sort->nullsFirst = (bool *) gpdb::GPDBAlloc(num_of_cols * sizeof(bool));
TranslateSortCols(sort_col_list_dxl, &child_context, sort->sortColIdx,
sort->sortOperators, sort->collations, sort->nullsFirst);
SetParamIds(plan);
// cleanup
child_contexts->Release();
return (Plan *) sort;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToPlStmt::TranslateDXLSubQueryScan
//
// @doc:
// Translate DXL subquery scan node into GPDB SubqueryScan plan node
//
//---------------------------------------------------------------------------
Plan *
CTranslatorDXLToPlStmt::TranslateDXLSubQueryScan(
const CDXLNode *subquery_scan_dxlnode, CDXLTranslateContext *output_context,
CDXLTranslationContextArray *ctxt_translation_prev_siblings)
{
// create sort plan node
SubqueryScan *subquery_scan = MakeNode(SubqueryScan);
Plan *plan = &(subquery_scan->scan.plan);
plan->plan_node_id = m_dxl_to_plstmt_context->GetNextPlanId();
CDXLPhysicalSubqueryScan *subquery_scan_dxlop =
CDXLPhysicalSubqueryScan::Cast(subquery_scan_dxlnode->GetOperator());
// translate operator costs
TranslatePlanCosts(subquery_scan_dxlnode, plan);
// translate subplan
CDXLNode *child_dxlnode = (*subquery_scan_dxlnode)[EdxlsubqscanIndexChild];
CDXLNode *project_list_dxlnode =
(*subquery_scan_dxlnode)[EdxlsubqscanIndexProjList];
CDXLNode *filter_dxlnode =
(*subquery_scan_dxlnode)[EdxlsubqscanIndexFilter];
CDXLTranslateContext child_context(m_mp, false,
output_context->GetColIdToParamIdMap());
Plan *child_plan = TranslateDXLOperatorToPlan(
child_dxlnode, &child_context, ctxt_translation_prev_siblings);
// create an rtable entry for the subquery scan
RangeTblEntry *rte = MakeNode(RangeTblEntry);
rte->rtekind = RTE_SUBQUERY;
Alias *alias = MakeNode(Alias);
alias->colnames = NIL;
// get table alias
alias->aliasname = CTranslatorUtils::CreateMultiByteCharStringFromWCString(
subquery_scan_dxlop->MdName()->GetMDName()->GetBuffer());
// get column names from child project list
CDXLTranslateContextBaseTable base_table_context(m_mp);
Index index =
gpdb::ListLength(m_dxl_to_plstmt_context->GetRTableEntriesList()) + 1;
(subquery_scan->scan).scanrelid = index;
base_table_context.SetRelIndex(index);
ListCell *lc_tgtentry = nullptr;
CDXLNode *child_proj_list_dxlnode = (*child_dxlnode)[0];
ULONG ul = 0;
ForEach(lc_tgtentry, child_plan->targetlist)
{
TargetEntry *target_entry = (TargetEntry *) lfirst(lc_tgtentry);
// non-system attribute
CHAR *col_name_char_array = PStrDup(target_entry->resname);
Value *val_colname = gpdb::MakeStringValue(col_name_char_array);
alias->colnames = gpdb::LAppend(alias->colnames, val_colname);
// get corresponding child project element
CDXLScalarProjElem *sc_proj_elem_dxlop = CDXLScalarProjElem::Cast(
(*child_proj_list_dxlnode)[ul]->GetOperator());
// save mapping col id -> index in translate context
(void) base_table_context.InsertMapping(sc_proj_elem_dxlop->Id(),
target_entry->resno);
ul++;
}
rte->eref = alias;
// add range table entry for the subquery to the list
m_dxl_to_plstmt_context->AddRTE(rte);
// translate proj list and filter
TranslateProjListAndFilter(
project_list_dxlnode, filter_dxlnode,
&base_table_context, // translate context for the base table
nullptr, &plan->targetlist, &plan->qual, output_context);
subquery_scan->subplan = child_plan;
SetParamIds(plan);
return (Plan *) subquery_scan;
}
static bool
ContainsSetReturningFuncOrOp(const CDXLNode *project_list_dxlnode,
CMDAccessor *md_accessor)
{
const ULONG arity = project_list_dxlnode->Arity();
for (ULONG ul = 0; ul < arity; ++ul)
{
CDXLNode *proj_elem_dxlnode = (*project_list_dxlnode)[ul];
GPOS_ASSERT(EdxlopScalarProjectElem ==
proj_elem_dxlnode->GetOperator()->GetDXLOperator());
GPOS_ASSERT(1 == proj_elem_dxlnode->Arity());
// translate proj element expression
CDXLNode *expr_dxlnode = (*proj_elem_dxlnode)[0];
CDXLOperator *op = expr_dxlnode->GetOperator();
switch (op->GetDXLOperator())
{
case EdxlopScalarFuncExpr:
if (CDXLScalarFuncExpr::Cast(op)->ReturnsSet())
{
return true;
}
break;
case EdxlopScalarOpExpr:
{
const IMDScalarOp *md_sclar_op = md_accessor->RetrieveScOp(
CDXLScalarOpExpr::Cast(op)->MDId());
const IMDFunction *md_func =
md_accessor->RetrieveFunc(md_sclar_op->FuncMdId());
if (md_func->ReturnsSet())
{
return true;
}
break;
}
default:
break;
}
}
return false;
}
// GPDB_12_MERGE_FIXME: this duplicates a check in ExecInitProjectSet
static bool
SanityCheckProjectSetTargetList(List *targetlist)
{
ListCell *lc;
ForEach(lc, targetlist)
{
TargetEntry *te = (TargetEntry *) lfirst(lc);
Expr *expr = te->expr;
List *args;
if ((IsA(expr, FuncExpr) && ((FuncExpr *) expr)->funcretset) ||
(IsA(expr, OpExpr) && ((OpExpr *) expr)->opretset))
{
if (IsA(expr, FuncExpr))
{
args = ((FuncExpr *) expr)->args;
}
else
{
args = ((OpExpr *) expr)->args;
}
if (gpdb::ExpressionReturnsSet((Node *) args))
{
return false;
}
continue;
}
if (gpdb::ExpressionReturnsSet((Node *) expr))
{
return false;
}
}
return true;
}
// XXX: this is a copy-pasta of TranslateDXLResult
// Is there a way to reduce the duplication?
Plan *
CTranslatorDXLToPlStmt::TranslateDXLProjectSet(
const CDXLNode *result_dxlnode, CDXLTranslateContext *output_context,
CDXLTranslationContextArray *ctxt_translation_prev_siblings)
{
// GPDB_12_MERGE_FIXME: had we generated a DXLProjectSet in ORCA we wouldn't
// have needed to be defensive here...
if ((*result_dxlnode)[EdxlresultIndexFilter]->Arity() > 0)
{
GPOS_RAISE(
gpdxl::ExmaDXL, gpdxl::ExmiQuery2DXLUnsupportedFeature,
GPOS_WSZ_LIT("Unsupported one-time filter in ProjectSet node"));
}
// create project set (nee result) plan node
ProjectSet *project_set = MakeNode(ProjectSet);
Plan *plan = &(project_set->plan);
plan->plan_node_id = m_dxl_to_plstmt_context->GetNextPlanId();
// translate operator costs
TranslatePlanCosts(result_dxlnode, plan);
CDXLNode *child_dxlnode = nullptr;
CDXLTranslateContext child_context(m_mp, false,
output_context->GetColIdToParamIdMap());
if (result_dxlnode->Arity() - 1 == EdxlresultIndexChild)
{
// translate child plan
child_dxlnode = (*result_dxlnode)[EdxlresultIndexChild];
Plan *child_plan = TranslateDXLOperatorToPlan(
child_dxlnode, &child_context, ctxt_translation_prev_siblings);
GPOS_ASSERT(nullptr != child_plan && "child plan cannot be NULL");
project_set->plan.lefttree = child_plan;
}
CDXLNode *project_list_dxlnode = (*result_dxlnode)[EdxlresultIndexProjList];
CDXLNode *filter_dxlnode = (*result_dxlnode)[EdxlresultIndexFilter];
List *quals_list = nullptr;
CDXLTranslationContextArray *child_contexts =
GPOS_NEW(m_mp) CDXLTranslationContextArray(m_mp);
child_contexts->Append(&child_context);
// translate proj list and filter
TranslateProjListAndFilter(project_list_dxlnode, filter_dxlnode,
nullptr, // translate context for the base table
child_contexts, &plan->targetlist, &quals_list,
output_context);
plan->qual = quals_list;
SetParamIds(plan);
// cleanup
child_contexts->Release();
// double check the targetlist is kosher
// we are only doing this because ORCA didn't do it...
if (!SanityCheckProjectSetTargetList(plan->targetlist))
{
GPOS_RAISE(
gpdxl::ExmaDXL, gpdxl::ExmiQuery2DXLUnsupportedFeature,
GPOS_WSZ_LIT("Unexpected target list entries in ProjectSet node"));
}
return (Plan *) project_set;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToPlStmt::TranslateDXLResult
//
// @doc:
// Translate DXL result node into GPDB result plan node
//
//---------------------------------------------------------------------------
Plan *
CTranslatorDXLToPlStmt::TranslateDXLResult(
const CDXLNode *result_dxlnode, CDXLTranslateContext *output_context,
CDXLTranslationContextArray *ctxt_translation_prev_siblings)
{
// GPDB_12_MERGE_FIXME: this *really* should be done inside ORCA
// at the latest during CTranslatorExprToDXL, to create a DXLProjectSet
// that way we don't have to "frisk" the DXLResult to distinguish it from an
// actual result node
if (ContainsSetReturningFuncOrOp((*result_dxlnode)[EdxlresultIndexProjList],
m_md_accessor))
{
return TranslateDXLProjectSet(result_dxlnode, output_context,
ctxt_translation_prev_siblings);
}
// create result plan node
Result *result = MakeNode(Result);
Plan *plan = &(result->plan);
plan->plan_node_id = m_dxl_to_plstmt_context->GetNextPlanId();
// translate operator costs
TranslatePlanCosts(result_dxlnode, plan);
CDXLNode *child_dxlnode = nullptr;
CDXLTranslateContext child_context(m_mp, false,
output_context->GetColIdToParamIdMap());
if (result_dxlnode->Arity() - 1 == EdxlresultIndexChild)
{
// translate child plan
child_dxlnode = (*result_dxlnode)[EdxlresultIndexChild];
Plan *child_plan = TranslateDXLOperatorToPlan(
child_dxlnode, &child_context, ctxt_translation_prev_siblings);
GPOS_ASSERT(nullptr != child_plan && "child plan cannot be NULL");
result->plan.lefttree = child_plan;
}
CDXLNode *project_list_dxlnode = (*result_dxlnode)[EdxlresultIndexProjList];
CDXLNode *filter_dxlnode = (*result_dxlnode)[EdxlresultIndexFilter];
CDXLNode *one_time_filter_dxlnode =
(*result_dxlnode)[EdxlresultIndexOneTimeFilter];
List *quals_list = nullptr;
CDXLTranslationContextArray *child_contexts =
GPOS_NEW(m_mp) CDXLTranslationContextArray(m_mp);
child_contexts->Append(&child_context);
// translate proj list and filter
TranslateProjListAndFilter(project_list_dxlnode, filter_dxlnode,
nullptr, // translate context for the base table
child_contexts, &plan->targetlist, &quals_list,
output_context);
// translate one time filter
List *one_time_quals_list =
TranslateDXLFilterToQual(one_time_filter_dxlnode,
nullptr, // base table translation context
child_contexts, output_context);
plan->qual = quals_list;
result->resconstantqual = (Node *) one_time_quals_list;
SetParamIds(plan);
// cleanup
child_contexts->Release();
// double check the targetlist is kosher
// we are only doing this because ORCA didn't do it...
if (!SanityCheckProjectSetTargetList(plan->targetlist))
{
GPOS_RAISE(
gpdxl::ExmaDXL, gpdxl::ExmiQuery2DXLUnsupportedFeature,
GPOS_WSZ_LIT("Unexpected target list entries in ProjectSet node"));
}
return (Plan *) result;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToPlStmt::TranslateDXLPartSelector
//
// @doc:
// Translate DXL PartitionSelector into a GPDB PartitionSelector node
//
//---------------------------------------------------------------------------
Plan *
CTranslatorDXLToPlStmt::TranslateDXLPartSelector(
const CDXLNode *partition_selector_dxlnode,
CDXLTranslateContext *output_context,
CDXLTranslationContextArray *ctxt_translation_prev_siblings)
{
PartitionSelector *partition_selector = MakeNode(PartitionSelector);
Plan *plan = &(partition_selector->plan);
plan->plan_node_id = m_dxl_to_plstmt_context->GetNextPlanId();
CDXLPhysicalPartitionSelector *partition_selector_dxlop =
CDXLPhysicalPartitionSelector::Cast(
partition_selector_dxlnode->GetOperator());
TranslatePlanCosts(partition_selector_dxlnode, plan);
CDXLNode *child_dxlnode = nullptr;
CDXLTranslationContextArray *child_contexts =
GPOS_NEW(m_mp) CDXLTranslationContextArray(m_mp);
CDXLTranslateContext child_context(m_mp, false,
output_context->GetColIdToParamIdMap());
// translate child plan
child_dxlnode = (*partition_selector_dxlnode)[2];
Plan *child_plan = TranslateDXLOperatorToPlan(
child_dxlnode, &child_context, ctxt_translation_prev_siblings);
GPOS_ASSERT(nullptr != child_plan && "child plan cannot be NULL");
partition_selector->plan.lefttree = child_plan;
child_contexts->Append(&child_context);
CDXLNode *project_list_dxlnode = (*partition_selector_dxlnode)[0];
plan->targetlist = TranslateDXLProjList(project_list_dxlnode,
nullptr /*base_table_context*/,
child_contexts, output_context);
CMDIdGPDB *mdid =
CMDIdGPDB::CastMdid(partition_selector_dxlop->GetRelMdId());
gpdb::RelationWrapper relation = gpdb::GetRelation(mdid->Oid());
CMappingColIdVarPlStmt colid_var_mapping = CMappingColIdVarPlStmt(
m_mp, nullptr /*base_table_context*/, child_contexts, output_context,
m_dxl_to_plstmt_context);
// paramid
OID oid_type =
CMDIdGPDB::CastMdid(m_md_accessor->PtMDType<IMDTypeInt4>()->MDId())
->Oid();
partition_selector->paramid =
m_dxl_to_plstmt_context->GetParamIdForSelector(
oid_type, partition_selector_dxlop->SelectorId());
// search the rtable for rtindex
// an Append node on the outer side of a parent HashJoin would already have
// beeen translated and would have populated the rtable with the root RTE
Index rtindex = m_dxl_to_plstmt_context->FindRTE(mdid->Oid());
GPOS_ASSERT(rtindex > 0);
// part_prune_info
CDXLNode *filterNode = (*partition_selector_dxlnode)[1];
ULongPtrArray *part_indexes = partition_selector_dxlop->Partitions();
List *prune_infos = CPartPruneStepsBuilder::CreatePartPruneInfos(
filterNode, relation.get(), rtindex, part_indexes, &colid_var_mapping,
m_translator_dxl_to_scalar);
partition_selector->part_prune_info = MakeNode(PartitionPruneInfo);
partition_selector->part_prune_info->prune_infos = prune_infos;
SetParamIds(plan);
// cleanup
child_contexts->Release();
return (Plan *) partition_selector;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToPlStmt::TranslateDXLFilterList
//
// @doc:
// Translate DXL filter list into GPDB filter list
//
//---------------------------------------------------------------------------
List *
CTranslatorDXLToPlStmt::TranslateDXLFilterList(
const CDXLNode *filter_list_dxlnode,
const CDXLTranslateContextBaseTable *base_table_context,
CDXLTranslationContextArray *child_contexts,
CDXLTranslateContext *output_context)
{
GPOS_ASSERT(EdxlopScalarOpList ==
filter_list_dxlnode->GetOperator()->GetDXLOperator());
List *filters_list = NIL;
CMappingColIdVarPlStmt colid_var_mapping =
CMappingColIdVarPlStmt(m_mp, base_table_context, child_contexts,
output_context, m_dxl_to_plstmt_context);
const ULONG arity = filter_list_dxlnode->Arity();
for (ULONG ul = 0; ul < arity; ul++)
{
CDXLNode *child_filter_dxlnode = (*filter_list_dxlnode)[ul];
if (gpdxl::CTranslatorDXLToScalar::HasConstTrue(child_filter_dxlnode,
m_md_accessor))
{
filters_list = gpdb::LAppend(filters_list, nullptr /*datum*/);
continue;
}
Expr *filter_expr = m_translator_dxl_to_scalar->TranslateDXLToScalar(
child_filter_dxlnode, &colid_var_mapping);
filters_list = gpdb::LAppend(filters_list, filter_expr);
}
return filters_list;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToPlStmt::TranslateDXLAppend
//
// @doc:
// Translate DXL append node into GPDB Append plan node
//
//---------------------------------------------------------------------------
Plan *
CTranslatorDXLToPlStmt::TranslateDXLAppend(
const CDXLNode *append_dxlnode, CDXLTranslateContext *output_context,
CDXLTranslationContextArray *ctxt_translation_prev_siblings)
{
// create append plan node
Append *append = MakeNode(Append);
Plan *plan = &(append->plan);
plan->plan_node_id = m_dxl_to_plstmt_context->GetNextPlanId();
// translate operator costs
TranslatePlanCosts(append_dxlnode, plan);
const ULONG arity = append_dxlnode->Arity();
GPOS_ASSERT(EdxlappendIndexFirstChild < arity);
append->appendplans = NIL;
// translate table descriptor into a range table entry
CDXLPhysicalAppend *phy_append_dxlop =
CDXLPhysicalAppend::Cast(append_dxlnode->GetOperator());
// If this append was create from a DynamicTableScan node in ORCA, it will
// contain the table descriptor of the root partitioned table. Add that to
// the range table in the PlStmt.
if (phy_append_dxlop->GetScanId() != gpos::ulong_max)
{
GPOS_ASSERT(nullptr != phy_append_dxlop->GetDXLTableDesc());
// translation context for column mappings in the base relation
CDXLTranslateContextBaseTable base_table_context(m_mp);
// we will add the new range table entry as the last element of the range table
Index index =
gpdb::ListLength(m_dxl_to_plstmt_context->GetRTableEntriesList()) +
1;
RangeTblEntry *rte = TranslateDXLTblDescrToRangeTblEntry(
phy_append_dxlop->GetDXLTableDesc(), index, &base_table_context);
GPOS_ASSERT(nullptr != rte);
rte->requiredPerms |= ACL_SELECT;
m_dxl_to_plstmt_context->AddRTE(rte);
append->join_prune_paramids = NIL;
const ULongPtrArray *selector_ids = phy_append_dxlop->GetSelectorIds();
OID oid_type =
CMDIdGPDB::CastMdid(m_md_accessor->PtMDType<IMDTypeInt4>()->MDId())
->Oid();
for (ULONG ul = 0; ul < selector_ids->Size(); ++ul)
{
ULONG selector_id = *(*selector_ids)[ul];
ULONG param_id = m_dxl_to_plstmt_context->GetParamIdForSelector(
oid_type, selector_id);
append->join_prune_paramids =
gpdb::LAppendInt(append->join_prune_paramids, param_id);
}
}
// translate children
CDXLTranslateContext child_context(m_mp, false,
output_context->GetColIdToParamIdMap());
for (ULONG ul = EdxlappendIndexFirstChild; ul < arity; ul++)
{
CDXLNode *child_dxlnode = (*append_dxlnode)[ul];
Plan *child_plan = TranslateDXLOperatorToPlan(
child_dxlnode, &child_context, ctxt_translation_prev_siblings);
GPOS_ASSERT(nullptr != child_plan && "child plan cannot be NULL");
append->appendplans = gpdb::LAppend(append->appendplans, child_plan);
}
CDXLNode *project_list_dxlnode = (*append_dxlnode)[EdxlappendIndexProjList];
CDXLNode *filter_dxlnode = (*append_dxlnode)[EdxlappendIndexFilter];
plan->targetlist = NIL;
const ULONG length = project_list_dxlnode->Arity();
for (ULONG ul = 0; ul < length; ++ul)
{
CDXLNode *proj_elem_dxlnode = (*project_list_dxlnode)[ul];
GPOS_ASSERT(EdxlopScalarProjectElem ==
proj_elem_dxlnode->GetOperator()->GetDXLOperator());
CDXLScalarProjElem *sc_proj_elem_dxlop =
CDXLScalarProjElem::Cast(proj_elem_dxlnode->GetOperator());
GPOS_ASSERT(1 == proj_elem_dxlnode->Arity());
// translate proj element expression
CDXLNode *expr_dxlnode = (*proj_elem_dxlnode)[0];
CDXLScalarIdent *sc_ident_dxlop =
CDXLScalarIdent::Cast(expr_dxlnode->GetOperator());
Index idxVarno = OUTER_VAR;
AttrNumber attno = (AttrNumber)(ul + 1);
Var *var = gpdb::MakeVar(
idxVarno, attno,
CMDIdGPDB::CastMdid(sc_ident_dxlop->MdidType())->Oid(),
sc_ident_dxlop->TypeModifier(),
0 // varlevelsup
);
TargetEntry *target_entry = MakeNode(TargetEntry);
target_entry->expr = (Expr *) var;
target_entry->resname =
CTranslatorUtils::CreateMultiByteCharStringFromWCString(
sc_proj_elem_dxlop->GetMdNameAlias()->GetMDName()->GetBuffer());
target_entry->resno = attno;
// add column mapping to output translation context
output_context->InsertMapping(sc_proj_elem_dxlop->Id(), target_entry);
plan->targetlist = gpdb::LAppend(plan->targetlist, target_entry);
}
CDXLTranslationContextArray *child_contexts =
GPOS_NEW(m_mp) CDXLTranslationContextArray(m_mp);
child_contexts->Append(output_context);
// translate filter
plan->qual = TranslateDXLFilterToQual(
filter_dxlnode,
nullptr, // translate context for the base table
child_contexts, output_context);
SetParamIds(plan);
// cleanup
child_contexts->Release();
return (Plan *) append;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToPlStmt::TranslateDXLMaterialize
//
// @doc:
// Translate DXL materialize node into GPDB Material plan node
//
//---------------------------------------------------------------------------
Plan *
CTranslatorDXLToPlStmt::TranslateDXLMaterialize(
const CDXLNode *materialize_dxlnode, CDXLTranslateContext *output_context,
CDXLTranslationContextArray *ctxt_translation_prev_siblings)
{
// create materialize plan node
Material *materialize = MakeNode(Material);
Plan *plan = &(materialize->plan);
plan->plan_node_id = m_dxl_to_plstmt_context->GetNextPlanId();
CDXLPhysicalMaterialize *materialize_dxlop =
CDXLPhysicalMaterialize::Cast(materialize_dxlnode->GetOperator());
materialize->cdb_strict = materialize_dxlop->IsEager();
// ensure that executor actually materializes results
materialize->cdb_shield_child_from_rescans = true;
// translate operator costs
TranslatePlanCosts(materialize_dxlnode, plan);
// translate materialize child
CDXLNode *child_dxlnode = (*materialize_dxlnode)[EdxlmatIndexChild];
CDXLNode *project_list_dxlnode =
(*materialize_dxlnode)[EdxlmatIndexProjList];
CDXLNode *filter_dxlnode = (*materialize_dxlnode)[EdxlmatIndexFilter];
CDXLTranslateContext child_context(m_mp, false,
output_context->GetColIdToParamIdMap());
Plan *child_plan = TranslateDXLOperatorToPlan(
child_dxlnode, &child_context, ctxt_translation_prev_siblings);
CDXLTranslationContextArray *child_contexts =
GPOS_NEW(m_mp) CDXLTranslationContextArray(m_mp);
child_contexts->Append(&child_context);
// translate proj list and filter
TranslateProjListAndFilter(project_list_dxlnode, filter_dxlnode,
nullptr, // translate context for the base table
child_contexts, &plan->targetlist, &plan->qual,
output_context);
plan->lefttree = child_plan;
SetParamIds(plan);
// cleanup
child_contexts->Release();
return (Plan *) materialize;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToPlStmt::TranslateDXLCTEProducerToSharedScan
//
// @doc:
// Translate DXL CTE Producer node into GPDB share input scan plan node
//
//---------------------------------------------------------------------------
Plan *
CTranslatorDXLToPlStmt::TranslateDXLCTEProducerToSharedScan(
const CDXLNode *cte_producer_dxlnode, CDXLTranslateContext *output_context,
CDXLTranslationContextArray *ctxt_translation_prev_siblings)
{
CDXLPhysicalCTEProducer *cte_prod_dxlop =
CDXLPhysicalCTEProducer::Cast(cte_producer_dxlnode->GetOperator());
ULONG cte_id = cte_prod_dxlop->Id();
// create the shared input scan representing the CTE Producer
ShareInputScan *shared_input_scan = MakeNode(ShareInputScan);
shared_input_scan->share_id = cte_id;
shared_input_scan->discard_output = true;
Plan *plan = &(shared_input_scan->scan.plan);
plan->plan_node_id = m_dxl_to_plstmt_context->GetNextPlanId();
// store share scan node for the translation of CTE Consumers
m_dxl_to_plstmt_context->AddCTEConsumerInfo(cte_id, shared_input_scan);
// translate cost of the producer
TranslatePlanCosts(cte_producer_dxlnode, plan);
// translate child plan
CDXLNode *project_list_dxlnode = (*cte_producer_dxlnode)[0];
CDXLNode *child_dxlnode = (*cte_producer_dxlnode)[1];
CDXLTranslateContext child_context(m_mp, false,
output_context->GetColIdToParamIdMap());
Plan *child_plan = TranslateDXLOperatorToPlan(
child_dxlnode, &child_context, ctxt_translation_prev_siblings);
GPOS_ASSERT(nullptr != child_plan && "child plan cannot be NULL");
CDXLTranslationContextArray *child_contexts =
GPOS_NEW(m_mp) CDXLTranslationContextArray(m_mp);
child_contexts->Append(&child_context);
// translate proj list
plan->targetlist =
TranslateDXLProjList(project_list_dxlnode,
nullptr, // base table translation context
child_contexts, output_context);
plan->lefttree = child_plan;
plan->qual = NIL;
SetParamIds(plan);
// cleanup
child_contexts->Release();
return (Plan *) shared_input_scan;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToPlStmt::TranslateDXLCTEConsumerToSharedScan
//
// @doc:
// Translate DXL CTE Consumer node into GPDB share input scan plan node
//
//---------------------------------------------------------------------------
Plan *
CTranslatorDXLToPlStmt::TranslateDXLCTEConsumerToSharedScan(
const CDXLNode *cte_consumer_dxlnode, CDXLTranslateContext *output_context,
CDXLTranslationContextArray *ctxt_translation_prev_siblings)
{
CDXLPhysicalCTEConsumer *cte_consumer_dxlop =
CDXLPhysicalCTEConsumer::Cast(cte_consumer_dxlnode->GetOperator());
ULONG cte_id = cte_consumer_dxlop->Id();
ShareInputScan *share_input_scan_cte_consumer = MakeNode(ShareInputScan);
share_input_scan_cte_consumer->share_id = cte_id;
share_input_scan_cte_consumer->discard_output = false;
Plan *plan = &(share_input_scan_cte_consumer->scan.plan);
plan->plan_node_id = m_dxl_to_plstmt_context->GetNextPlanId();
// translate operator costs
TranslatePlanCosts(cte_consumer_dxlnode, plan);
#ifdef GPOS_DEBUG
ULongPtrArray *output_colids_array =
cte_consumer_dxlop->GetOutputColIdsArray();
#endif
// generate the target list of the CTE Consumer
plan->targetlist = NIL;
CDXLNode *project_list_dxlnode = (*cte_consumer_dxlnode)[0];
const ULONG num_of_proj_list_elem = project_list_dxlnode->Arity();
GPOS_ASSERT(num_of_proj_list_elem == output_colids_array->Size());
for (ULONG ul = 0; ul < num_of_proj_list_elem; ul++)
{
CDXLNode *proj_elem_dxlnode = (*project_list_dxlnode)[ul];
CDXLScalarProjElem *sc_proj_elem_dxlop =
CDXLScalarProjElem::Cast(proj_elem_dxlnode->GetOperator());
ULONG colid = sc_proj_elem_dxlop->Id();
GPOS_ASSERT(colid == *(*output_colids_array)[ul]);
CDXLNode *sc_ident_dxlnode = (*proj_elem_dxlnode)[0];
CDXLScalarIdent *sc_ident_dxlop =
CDXLScalarIdent::Cast(sc_ident_dxlnode->GetOperator());
OID oid_type = CMDIdGPDB::CastMdid(sc_ident_dxlop->MdidType())->Oid();
Var *var =
gpdb::MakeVar(OUTER_VAR, (AttrNumber)(ul + 1), oid_type,
sc_ident_dxlop->TypeModifier(), 0 /* varlevelsup */);
CHAR *resname = CTranslatorUtils::CreateMultiByteCharStringFromWCString(
sc_proj_elem_dxlop->GetMdNameAlias()->GetMDName()->GetBuffer());
TargetEntry *target_entry = gpdb::MakeTargetEntry(
(Expr *) var, (AttrNumber)(ul + 1), resname, false /* resjunk */);
plan->targetlist = gpdb::LAppend(plan->targetlist, target_entry);
output_context->InsertMapping(colid, target_entry);
}
plan->qual = nullptr;
SetParamIds(plan);
// store share scan node for the translation of CTE Consumers
m_dxl_to_plstmt_context->AddCTEConsumerInfo(cte_id,
share_input_scan_cte_consumer);
return (Plan *) share_input_scan_cte_consumer;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToPlStmt::TranslateDXLSequence
//
// @doc:
// Translate DXL sequence node into GPDB Sequence plan node
//
//---------------------------------------------------------------------------
Plan *
CTranslatorDXLToPlStmt::TranslateDXLSequence(
const CDXLNode *sequence_dxlnode, CDXLTranslateContext *output_context,
CDXLTranslationContextArray *ctxt_translation_prev_siblings)
{
// create append plan node
Sequence *psequence = MakeNode(Sequence);
Plan *plan = &(psequence->plan);
plan->plan_node_id = m_dxl_to_plstmt_context->GetNextPlanId();
// translate operator costs
TranslatePlanCosts(sequence_dxlnode, plan);
ULONG arity = sequence_dxlnode->Arity();
CDXLTranslateContext child_context(m_mp, false,
output_context->GetColIdToParamIdMap());
for (ULONG ul = 1; ul < arity; ul++)
{
CDXLNode *child_dxlnode = (*sequence_dxlnode)[ul];
Plan *child_plan = TranslateDXLOperatorToPlan(
child_dxlnode, &child_context, ctxt_translation_prev_siblings);
psequence->subplans = gpdb::LAppend(psequence->subplans, child_plan);
}
CDXLNode *project_list_dxlnode = (*sequence_dxlnode)[0];
CDXLTranslationContextArray *child_contexts =
GPOS_NEW(m_mp) CDXLTranslationContextArray(m_mp);
child_contexts->Append(&child_context);
// translate proj list
plan->targetlist =
TranslateDXLProjList(project_list_dxlnode,
nullptr, // base table translation context
child_contexts, output_context);
SetParamIds(plan);
// cleanup
child_contexts->Release();
return (Plan *) psequence;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToPlStmt::TranslateDXLDynTblScan
//
// @doc:
// Translates a DXL dynamic table scan node into a DynamicSeqScan node
//
//---------------------------------------------------------------------------
Plan *
CTranslatorDXLToPlStmt::TranslateDXLDynTblScan(
const CDXLNode *dyn_tbl_scan_dxlnode, CDXLTranslateContext *output_context,
CDXLTranslationContextArray *ctxt_translation_prev_siblings)
{
// translate table descriptor into a range table entry
CDXLPhysicalDynamicTableScan *dyn_tbl_scan_dxlop =
CDXLPhysicalDynamicTableScan::Cast(dyn_tbl_scan_dxlnode->GetOperator());
// translation context for column mappings in the base relation
CDXLTranslateContextBaseTable base_table_context(m_mp);
// add the new range table entry as the last element of the range table
Index index =
gpdb::ListLength(m_dxl_to_plstmt_context->GetRTableEntriesList()) + 1;
RangeTblEntry *rte = TranslateDXLTblDescrToRangeTblEntry(
dyn_tbl_scan_dxlop->GetDXLTableDescr(), index, &base_table_context);
GPOS_ASSERT(nullptr != rte);
rte->requiredPerms |= ACL_SELECT;
m_dxl_to_plstmt_context->AddRTE(rte);
// create dynamic scan node
DynamicSeqScan *dyn_seq_scan = MakeNode(DynamicSeqScan);
dyn_seq_scan->seqscan.scanrelid = index;
IMdIdArray *parts = dyn_tbl_scan_dxlop->GetParts();
List *oids_list = NIL;
for (ULONG ul = 0; ul < parts->Size(); ul++)
{
Oid part = CMDIdGPDB::CastMdid((*parts)[ul])->Oid();
oids_list = gpdb::LAppendOid(oids_list, part);
}
dyn_seq_scan->partOids = oids_list;
dyn_seq_scan->join_prune_paramids = NIL;
OID oid_type =
CMDIdGPDB::CastMdid(m_md_accessor->PtMDType<IMDTypeInt4>()->MDId())
->Oid();
const ULongPtrArray *selector_ids = dyn_tbl_scan_dxlop->GetSelectorIds();
for (ULONG ul = 0; ul < selector_ids->Size(); ++ul)
{
ULONG selector_id = *(*selector_ids)[ul];
ULONG param_id = m_dxl_to_plstmt_context->GetParamIdForSelector(
oid_type, selector_id);
dyn_seq_scan->join_prune_paramids =
gpdb::LAppendInt(dyn_seq_scan->join_prune_paramids, param_id);
}
Plan *plan = &(dyn_seq_scan->seqscan.plan);
plan->plan_node_id = m_dxl_to_plstmt_context->GetNextPlanId();
//plan->nMotionNodes = 0;
// translate operator costs
TranslatePlanCosts(dyn_tbl_scan_dxlnode, plan);
GPOS_ASSERT(2 == dyn_tbl_scan_dxlnode->Arity());
// translate proj list and filter
CDXLNode *project_list_dxlnode =
(*dyn_tbl_scan_dxlnode)[EdxltsIndexProjList];
CDXLNode *filter_dxlnode = (*dyn_tbl_scan_dxlnode)[EdxltsIndexFilter];
TranslateProjListAndFilter(
project_list_dxlnode, filter_dxlnode,
&base_table_context, // translate context for the base table
nullptr, // translate_ctxt_left and pdxltrctxRight,
&plan->targetlist, &plan->qual, output_context);
SetParamIds(plan);
return plan;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToPlStmt::TranslateDXLDynIdxScan
//
// @doc:
// Translates a DXL dynamic index scan node into a DynamicIndexScan node
//
//---------------------------------------------------------------------------
Plan *
CTranslatorDXLToPlStmt::TranslateDXLDynIdxScan(
const CDXLNode *dyn_idx_scan_dxlnode, CDXLTranslateContext *output_context,
CDXLTranslationContextArray *ctxt_translation_prev_siblings)
{
CDXLPhysicalDynamicIndexScan *dyn_index_scan_dxlop =
CDXLPhysicalDynamicIndexScan::Cast(dyn_idx_scan_dxlnode->GetOperator());
// translation context for column mappings in the base relation
CDXLTranslateContextBaseTable base_table_context(m_mp);
Index index =
gpdb::ListLength(m_dxl_to_plstmt_context->GetRTableEntriesList()) + 1;
const IMDRelation *md_rel = m_md_accessor->RetrieveRel(
dyn_index_scan_dxlop->GetDXLTableDescr()->MDId());
RangeTblEntry *rte = TranslateDXLTblDescrToRangeTblEntry(
dyn_index_scan_dxlop->GetDXLTableDescr(), index, &base_table_context);
GPOS_ASSERT(nullptr != rte);
rte->requiredPerms |= ACL_SELECT;
m_dxl_to_plstmt_context->AddRTE(rte);
DynamicIndexScan *dyn_idx_scan = MakeNode(DynamicIndexScan);
dyn_idx_scan->indexscan.scan.scanrelid = index;
IMdIdArray *parts = dyn_index_scan_dxlop->GetParts();
List *oids_list = NIL;
for (ULONG ul = 0; ul < parts->Size(); ul++)
{
Oid part = CMDIdGPDB::CastMdid((*parts)[ul])->Oid();
oids_list = gpdb::LAppendOid(oids_list, part);
}
dyn_idx_scan->partOids = oids_list;
dyn_idx_scan->join_prune_paramids = NIL;
OID oid_type =
CMDIdGPDB::CastMdid(m_md_accessor->PtMDType<IMDTypeInt4>()->MDId())
->Oid();
const ULongPtrArray *selector_ids = dyn_index_scan_dxlop->GetSelectorIds();
for (ULONG ul = 0; ul < selector_ids->Size(); ++ul)
{
ULONG selector_id = *(*selector_ids)[ul];
ULONG param_id = m_dxl_to_plstmt_context->GetParamIdForSelector(
oid_type, selector_id);
dyn_idx_scan->join_prune_paramids =
gpdb::LAppendInt(dyn_idx_scan->join_prune_paramids, param_id);
}
CMDIdGPDB *mdid_index =
CMDIdGPDB::CastMdid(dyn_index_scan_dxlop->GetDXLIndexDescr()->MDId());
const IMDIndex *md_index = m_md_accessor->RetrieveIndex(mdid_index);
Oid index_oid = mdid_index->Oid();
GPOS_ASSERT(InvalidOid != index_oid);
dyn_idx_scan->indexscan.indexid = index_oid;
Plan *plan = &(dyn_idx_scan->indexscan.scan.plan);
plan->plan_node_id = m_dxl_to_plstmt_context->GetNextPlanId();
// translate operator costs
TranslatePlanCosts(dyn_idx_scan_dxlnode, plan);
// an index scan node must have 3 children: projection list, filter and index condition list
GPOS_ASSERT(3 == dyn_idx_scan_dxlnode->Arity());
// translate proj list and filter
CDXLNode *project_list_dxlnode = (*dyn_idx_scan_dxlnode)
[CDXLPhysicalDynamicIndexScan::EdxldisIndexProjList];
CDXLNode *filter_dxlnode = (*dyn_idx_scan_dxlnode)
[CDXLPhysicalDynamicIndexScan::EdxldisIndexFilter];
CDXLNode *index_cond_list_dxlnode = (*dyn_idx_scan_dxlnode)
[CDXLPhysicalDynamicIndexScan::EdxldisIndexCondition];
// translate proj list
plan->targetlist =
TranslateDXLProjList(project_list_dxlnode, &base_table_context,
nullptr /*child_contexts*/, output_context);
// translate index filter
plan->qual = TranslateDXLIndexFilter(filter_dxlnode, output_context,
&base_table_context,
ctxt_translation_prev_siblings);
dyn_idx_scan->indexscan.indexorderdir = CTranslatorUtils::GetScanDirection(
dyn_index_scan_dxlop->GetIndexScanDir());
// translate index condition list
List *index_cond = NIL;
List *index_orig_cond = NIL;
List *index_strategy_list = NIL;
List *index_subtype_list = NIL;
TranslateIndexConditions(
index_cond_list_dxlnode, dyn_index_scan_dxlop->GetDXLTableDescr(),
false, // is_bitmap_index_probe
md_index, md_rel, output_context, &base_table_context,
ctxt_translation_prev_siblings, &index_cond, &index_orig_cond,
&index_strategy_list, &index_subtype_list);
dyn_idx_scan->indexscan.indexqual = index_cond;
dyn_idx_scan->indexscan.indexqualorig = index_orig_cond;
SetParamIds(plan);
return (Plan *) dyn_idx_scan;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToPlStmt::TranslateDXLDml
//
// @doc:
// Translates a DXL DML node
//
//---------------------------------------------------------------------------
Plan *
CTranslatorDXLToPlStmt::TranslateDXLDml(
const CDXLNode *dml_dxlnode, CDXLTranslateContext *output_context,
CDXLTranslationContextArray *ctxt_translation_prev_siblings)
{
// translate table descriptor into a range table entry
CDXLPhysicalDML *phy_dml_dxlop =
CDXLPhysicalDML::Cast(dml_dxlnode->GetOperator());
// create ModifyTable node
ModifyTable *dml = MakeNode(ModifyTable);
Plan *plan = &(dml->plan);
AclMode acl_mode = ACL_NO_RIGHTS;
BOOL isSplit = phy_dml_dxlop->FSplit();
switch (phy_dml_dxlop->GetDmlOpType())
{
case gpdxl::Edxldmldelete:
{
m_cmd_type = CMD_DELETE;
acl_mode = ACL_DELETE;
break;
}
case gpdxl::Edxldmlupdate:
{
m_cmd_type = CMD_UPDATE;
acl_mode = ACL_UPDATE;
break;
}
case gpdxl::Edxldmlinsert:
{
m_cmd_type = CMD_INSERT;
acl_mode = ACL_INSERT;
break;
}
case gpdxl::EdxldmlSentinel:
default:
{
GPOS_RAISE(
gpdxl::ExmaDXL, gpdxl::ExmiDXL2PlStmtConversion,
GPOS_WSZ_LIT("Unexpected error during plan generation."));
break;
}
}
IMDId *mdid_target_table = phy_dml_dxlop->GetDXLTableDescr()->MDId();
const IMDRelation *md_rel = m_md_accessor->RetrieveRel(mdid_target_table);
if (IMDRelation::EreldistrMasterOnly != md_rel->GetRelDistribution())
{
m_is_tgt_tbl_distributed = true;
}
if (CMD_UPDATE == m_cmd_type &&
gpdb::HasUpdateTriggers(CMDIdGPDB::CastMdid(mdid_target_table)->Oid()))
{
GPOS_RAISE(gpdxl::ExmaDXL, gpdxl::ExmiQuery2DXLUnsupportedFeature,
GPOS_WSZ_LIT("UPDATE on a table with UPDATE triggers"));
}
// translation context for column mappings in the base relation
CDXLTranslateContextBaseTable base_table_context(m_mp);
// add the new range table entry as the last element of the range table
Index index =
gpdb::ListLength(m_dxl_to_plstmt_context->GetRTableEntriesList()) + 1;
m_result_rel_list = gpdb::LAppendInt(m_result_rel_list, index);
CDXLTableDescr *table_descr = phy_dml_dxlop->GetDXLTableDescr();
RangeTblEntry *rte = TranslateDXLTblDescrToRangeTblEntry(
table_descr, index, &base_table_context);
GPOS_ASSERT(nullptr != rte);
rte->requiredPerms |= acl_mode;
m_dxl_to_plstmt_context->AddRTE(rte, true);
CDXLNode *project_list_dxlnode = (*dml_dxlnode)[0];
CDXLNode *child_dxlnode = (*dml_dxlnode)[1];
CDXLTranslateContext child_context(m_mp, false,
output_context->GetColIdToParamIdMap());
Plan *child_plan = TranslateDXLOperatorToPlan(
child_dxlnode, &child_context, ctxt_translation_prev_siblings);
CDXLTranslationContextArray *child_contexts =
GPOS_NEW(m_mp) CDXLTranslationContextArray(m_mp);
child_contexts->Append(&child_context);
// translate proj list
List *dml_target_list =
TranslateDXLProjList(project_list_dxlnode,
nullptr, // translate context for the base table
child_contexts, output_context);
// pad child plan's target list with NULLs for dropped columns for all DML operator types
List *target_list_with_dropped_cols =
CreateTargetListWithNullsForDroppedCols(dml_target_list, md_rel);
dml_target_list = target_list_with_dropped_cols;
// Add junk columns to the target list for the 'action', 'ctid',
// 'gp_segment_id', and tuple's 'oid'. The ModifyTable node will find
// these based on the resnames. ORCA also includes a similar column for
// partition Oid in the child's target list, but we don't use it for
// anything in GPDB.
if (m_cmd_type == CMD_UPDATE && isSplit)
{
(void) AddJunkTargetEntryForColId(&dml_target_list, &child_context,
phy_dml_dxlop->ActionColId(),
"DMLAction");
}
if (m_cmd_type == CMD_UPDATE || m_cmd_type == CMD_DELETE)
{
AddJunkTargetEntryForColId(&dml_target_list, &child_context,
phy_dml_dxlop->GetCtIdColId(), "ctid");
AddJunkTargetEntryForColId(&dml_target_list, &child_context,
phy_dml_dxlop->GetSegmentIdColId(),
"gp_segment_id");
}
// Add a Result node on top of the child plan, to coerce the target
// list to match the exact physical layout of the target table,
// including dropped columns. Often, the Result node isn't really
// needed, as the child node could do the projection, but we don't have
// the information to determine that here. There's a step in the
// backend optimize_query() function to eliminate unnecessary Results
// throught the plan, hopefully this Result gets eliminated there.
Result *result = MakeNode(Result);
Plan *result_plan = &(result->plan);
result_plan->plan_node_id = m_dxl_to_plstmt_context->GetNextPlanId();
result_plan->lefttree = child_plan;
result_plan->targetlist = target_list_with_dropped_cols;
SetParamIds(result_plan);
child_plan = (Plan *) result;
dml->operation = m_cmd_type;
dml->canSetTag = true; // FIXME
dml->nominalRelation = index;
dml->resultRelations = ListMake1Int(index);
dml->resultRelIndex = list_length(m_result_rel_list) - 1;
dml->rootRelation = md_rel->IsPartitioned() ? index : 0;
dml->plans = ListMake1(child_plan);
dml->fdwPrivLists = ListMake1(NIL);
// ORCA plans all updates as split updates
if (m_cmd_type == CMD_UPDATE)
{
dml->isSplitUpdates = ListMake1Int((int) isSplit);
}
plan->targetlist = NIL;
plan->plan_node_id = m_dxl_to_plstmt_context->GetNextPlanId();
SetParamIds(plan);
if (m_is_tgt_tbl_distributed)
{
PlanSlice *current_slice = m_dxl_to_plstmt_context->GetCurrentSlice();
current_slice->numsegments = m_num_of_segments;
current_slice->gangType = GANGTYPE_PRIMARY_WRITER;
}
// cleanup
child_contexts->Release();
// translate operator costs
TranslatePlanCosts(dml_dxlnode, plan);
return (Plan *) dml;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToPlStmt::TranslateDXLDirectDispatchInfo
//
// @doc:
// Translate the direct dispatch info
//
//---------------------------------------------------------------------------
List *
CTranslatorDXLToPlStmt::TranslateDXLDirectDispatchInfo(
CDXLDirectDispatchInfo *dxl_direct_dispatch_info)
{
if (!optimizer_enable_direct_dispatch ||
nullptr == dxl_direct_dispatch_info)
{
return NIL;
}
CDXLDatum2dArray *dispatch_identifier_datum_arrays =
dxl_direct_dispatch_info->GetDispatchIdentifierDatumArray();
if (dispatch_identifier_datum_arrays == nullptr ||
0 == dispatch_identifier_datum_arrays->Size())
{
return NIL;
}
CDXLDatumArray *dxl_datum_array = (*dispatch_identifier_datum_arrays)[0];
GPOS_ASSERT(0 < dxl_datum_array->Size());
const ULONG length = dispatch_identifier_datum_arrays->Size();
if (dxl_direct_dispatch_info->FContainsRawValues())
{
List *segids_list = NIL;
INT segid;
Const *const_expr = nullptr;
for (ULONG ul = 0; ul < length; ul++)
{
CDXLDatumArray *dispatch_identifier_datum_array =
(*dispatch_identifier_datum_arrays)[ul];
GPOS_ASSERT(1 == dispatch_identifier_datum_array->Size());
const_expr =
(Const *) m_translator_dxl_to_scalar->TranslateDXLDatumToScalar(
(*dispatch_identifier_datum_array)[0]);
segid = DatumGetInt32(const_expr->constvalue);
if (segid >= -1 && segid < (INT) m_num_of_segments)
{
segids_list = gpdb::LAppendInt(segids_list, segid);
}
}
if (segids_list == NIL && const_expr)
{
// If no valid segids were found, and there were items in the
// dispatch identifier array, then append the last item to behave
// in same manner as Planner for consistency. Currently this will
// lead to a FATAL in the backend when we dispatch.
segids_list = gpdb::LAppendInt(segids_list, segid);
}
return segids_list;
}
ULONG hash_code = GetDXLDatumGPDBHash(dxl_datum_array);
for (ULONG ul = 0; ul < length; ul++)
{
CDXLDatumArray *dispatch_identifier_datum_array =
(*dispatch_identifier_datum_arrays)[ul];
GPOS_ASSERT(0 < dispatch_identifier_datum_array->Size());
ULONG hash_code_new =
GetDXLDatumGPDBHash(dispatch_identifier_datum_array);
if (hash_code != hash_code_new)
{
// values don't hash to the same segment
return NIL;
}
}
List *segids_list = gpdb::LAppendInt(NIL, hash_code);
return segids_list;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToPlStmt::GetDXLDatumGPDBHash
//
// @doc:
// Hash a DXL datum
//
//---------------------------------------------------------------------------
ULONG
CTranslatorDXLToPlStmt::GetDXLDatumGPDBHash(CDXLDatumArray *dxl_datum_array)
{
List *consts_list = NIL;
Oid *hashfuncs;
const ULONG length = dxl_datum_array->Size();
hashfuncs = (Oid *) gpdb::GPDBAlloc(length * sizeof(Oid));
for (ULONG ul = 0; ul < length; ul++)
{
CDXLDatum *datum_dxl = (*dxl_datum_array)[ul];
Const *const_expr =
(Const *) m_translator_dxl_to_scalar->TranslateDXLDatumToScalar(
datum_dxl);
consts_list = gpdb::LAppend(consts_list, const_expr);
hashfuncs[ul] = m_dxl_to_plstmt_context->GetDistributionHashFuncForType(
const_expr->consttype);
}
ULONG hash =
gpdb::CdbHashConstList(consts_list, m_num_of_segments, hashfuncs);
gpdb::ListFreeDeep(consts_list);
gpdb::GPDBFree(hashfuncs);
return hash;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToPlStmt::TranslateDXLSplit
//
// @doc:
// Translates a DXL Split node
//
//---------------------------------------------------------------------------
Plan *
CTranslatorDXLToPlStmt::TranslateDXLSplit(
const CDXLNode *split_dxlnode, CDXLTranslateContext *output_context,
CDXLTranslationContextArray *ctxt_translation_prev_siblings)
{
CDXLPhysicalSplit *phy_split_dxlop =
CDXLPhysicalSplit::Cast(split_dxlnode->GetOperator());
// create SplitUpdate node
SplitUpdate *split = MakeNode(SplitUpdate);
Plan *plan = &(split->plan);
CDXLNode *project_list_dxlnode = (*split_dxlnode)[0];
CDXLNode *child_dxlnode = (*split_dxlnode)[1];
CDXLTranslateContext child_context(m_mp, false,
output_context->GetColIdToParamIdMap());
Plan *child_plan = TranslateDXLOperatorToPlan(
child_dxlnode, &child_context, ctxt_translation_prev_siblings);
CDXLTranslationContextArray *child_contexts =
GPOS_NEW(m_mp) CDXLTranslationContextArray(m_mp);
child_contexts->Append(&child_context);
// translate proj list and filter
plan->targetlist =
TranslateDXLProjList(project_list_dxlnode,
nullptr, // translate context for the base table
child_contexts, output_context);
// translate delete and insert columns
ULongPtrArray *deletion_colid_array =
phy_split_dxlop->GetDeletionColIdArray();
ULongPtrArray *insertion_colid_array =
phy_split_dxlop->GetInsertionColIdArray();
GPOS_ASSERT(insertion_colid_array->Size() == deletion_colid_array->Size());
split->deleteColIdx = CTranslatorUtils::ConvertColidToAttnos(
deletion_colid_array, &child_context);
split->insertColIdx = CTranslatorUtils::ConvertColidToAttnos(
insertion_colid_array, &child_context);
const TargetEntry *te_action_col =
output_context->GetTargetEntry(phy_split_dxlop->ActionColId());
if (nullptr == te_action_col)
{
GPOS_RAISE(gpdxl::ExmaDXL, gpdxl::ExmiDXL2PlStmtAttributeNotFound,
phy_split_dxlop->ActionColId());
}
split->actionColIdx = te_action_col->resno;
plan->lefttree = child_plan;
plan->plan_node_id = m_dxl_to_plstmt_context->GetNextPlanId();
SetParamIds(plan);
// cleanup
child_contexts->Release();
// translate operator costs
TranslatePlanCosts(split_dxlnode, plan);
return (Plan *) split;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToPlStmt::TranslateDXLAssert
//
// @doc:
// Translate DXL assert node into GPDB assert plan node
//
//---------------------------------------------------------------------------
Plan *
CTranslatorDXLToPlStmt::TranslateDXLAssert(
const CDXLNode *assert_dxlnode, CDXLTranslateContext *output_context,
CDXLTranslationContextArray *ctxt_translation_prev_siblings)
{
// create assert plan node
AssertOp *assert_node = MakeNode(AssertOp);
Plan *plan = &(assert_node->plan);
plan->plan_node_id = m_dxl_to_plstmt_context->GetNextPlanId();
CDXLPhysicalAssert *assert_dxlop =
CDXLPhysicalAssert::Cast(assert_dxlnode->GetOperator());
// translate error code into the its internal GPDB representation
const CHAR *error_code = assert_dxlop->GetSQLState();
GPOS_ASSERT(GPOS_SQLSTATE_LENGTH == clib::Strlen(error_code));
assert_node->errcode =
MAKE_SQLSTATE(error_code[0], error_code[1], error_code[2],
error_code[3], error_code[4]);
CDXLNode *filter_dxlnode =
(*assert_dxlnode)[CDXLPhysicalAssert::EdxlassertIndexFilter];
assert_node->errmessage =
CTranslatorUtils::GetAssertErrorMsgs(filter_dxlnode);
// translate operator costs
TranslatePlanCosts(assert_dxlnode, plan);
CDXLTranslateContext child_context(m_mp, false,
output_context->GetColIdToParamIdMap());
// translate child plan
CDXLNode *child_dxlnode =
(*assert_dxlnode)[CDXLPhysicalAssert::EdxlassertIndexChild];
Plan *child_plan = TranslateDXLOperatorToPlan(
child_dxlnode, &child_context, ctxt_translation_prev_siblings);
GPOS_ASSERT(nullptr != child_plan && "child plan cannot be NULL");
assert_node->plan.lefttree = child_plan;
CDXLNode *project_list_dxlnode =
(*assert_dxlnode)[CDXLPhysicalAssert::EdxlassertIndexProjList];
CDXLTranslationContextArray *child_contexts =
GPOS_NEW(m_mp) CDXLTranslationContextArray(m_mp);
child_contexts->Append(&child_context);
// translate proj list
plan->targetlist =
TranslateDXLProjList(project_list_dxlnode,
nullptr, // translate context for the base table
child_contexts, output_context);
// translate assert constraints
plan->qual = TranslateDXLAssertConstraints(filter_dxlnode, output_context,
child_contexts);
GPOS_ASSERT(gpdb::ListLength(plan->qual) ==
gpdb::ListLength(assert_node->errmessage));
SetParamIds(plan);
// cleanup
child_contexts->Release();
return (Plan *) assert_node;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToPlStmt::TranslateDXLTblDescrToRangeTblEntry
//
// @doc:
// Translates a DXL table descriptor into a range table entry. If an index
// descriptor is provided, we use the mapping from colids to index attnos
// instead of table attnos
//
//---------------------------------------------------------------------------
RangeTblEntry *
CTranslatorDXLToPlStmt::TranslateDXLTblDescrToRangeTblEntry(
const CDXLTableDescr *table_descr, Index index,
CDXLTranslateContextBaseTable *base_table_context)
{
GPOS_ASSERT(nullptr != table_descr);
const IMDRelation *md_rel = m_md_accessor->RetrieveRel(table_descr->MDId());
const ULONG num_of_non_sys_cols =
CTranslatorUtils::GetNumNonSystemColumns(md_rel);
RangeTblEntry *rte = MakeNode(RangeTblEntry);
rte->rtekind = RTE_RELATION;
// get oid for table
Oid oid = CMDIdGPDB::CastMdid(table_descr->MDId())->Oid();
GPOS_ASSERT(InvalidOid != oid);
rte->relid = oid;
rte->checkAsUser = table_descr->GetExecuteAsUserId();
rte->requiredPerms |= ACL_NO_RIGHTS;
rte->rellockmode = table_descr->LockMode();
// save oid and range index in translation context
base_table_context->SetOID(oid);
base_table_context->SetRelIndex(index);
Alias *alias = MakeNode(Alias);
alias->colnames = NIL;
// get table alias
alias->aliasname = CTranslatorUtils::CreateMultiByteCharStringFromWCString(
table_descr->MdName()->GetMDName()->GetBuffer());
// get column names
const ULONG arity = table_descr->Arity();
INT last_attno = 0;
for (ULONG ul = 0; ul < arity; ++ul)
{
const CDXLColDescr *dxl_col_descr = table_descr->GetColumnDescrAt(ul);
GPOS_ASSERT(nullptr != dxl_col_descr);
INT attno = dxl_col_descr->AttrNum();
GPOS_ASSERT(0 != attno);
if (0 < attno)
{
// if attno > last_attno + 1, there were dropped attributes
// add those to the RTE as they are required by GPDB
for (INT dropped_col_attno = last_attno + 1;
dropped_col_attno < attno; dropped_col_attno++)
{
Value *val_dropped_colname = gpdb::MakeStringValue(PStrDup(""));
alias->colnames =
gpdb::LAppend(alias->colnames, val_dropped_colname);
}
// non-system attribute
CHAR *col_name_char_array =
CTranslatorUtils::CreateMultiByteCharStringFromWCString(
dxl_col_descr->MdName()->GetMDName()->GetBuffer());
Value *val_colname = gpdb::MakeStringValue(col_name_char_array);
alias->colnames = gpdb::LAppend(alias->colnames, val_colname);
last_attno = attno;
}
// save mapping col id -> index in translate context
(void) base_table_context->InsertMapping(dxl_col_descr->Id(), attno);
}
// if there are any dropped columns at the end, add those too to the RangeTblEntry
for (ULONG ul = last_attno + 1; ul <= num_of_non_sys_cols; ul++)
{
Value *val_dropped_colname = gpdb::MakeStringValue(PStrDup(""));
alias->colnames = gpdb::LAppend(alias->colnames, val_dropped_colname);
}
rte->eref = alias;
return rte;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToPlStmt::TranslateDXLProjList
//
// @doc:
// Translates a DXL projection list node into a target list.
// For base table projection lists, the caller should provide a base table
// translation context with table oid, rtable index and mappings for the columns.
// For other nodes translate_ctxt_left and pdxltrctxRight give
// the mappings of column ids to target entries in the corresponding child nodes
// for resolving the origin of the target entries
//
//---------------------------------------------------------------------------
List *
CTranslatorDXLToPlStmt::TranslateDXLProjList(
const CDXLNode *project_list_dxlnode,
const CDXLTranslateContextBaseTable *base_table_context,
CDXLTranslationContextArray *child_contexts,
CDXLTranslateContext *output_context)
{
if (nullptr == project_list_dxlnode)
{
return nullptr;
}
List *target_list = NIL;
// translate each DXL project element into a target entry
const ULONG arity = project_list_dxlnode->Arity();
for (ULONG ul = 0; ul < arity; ++ul)
{
CDXLNode *proj_elem_dxlnode = (*project_list_dxlnode)[ul];
GPOS_ASSERT(EdxlopScalarProjectElem ==
proj_elem_dxlnode->GetOperator()->GetDXLOperator());
CDXLScalarProjElem *sc_proj_elem_dxlop =
CDXLScalarProjElem::Cast(proj_elem_dxlnode->GetOperator());
GPOS_ASSERT(1 == proj_elem_dxlnode->Arity());
// translate proj element expression
CDXLNode *expr_dxlnode = (*proj_elem_dxlnode)[0];
CMappingColIdVarPlStmt colid_var_mapping =
CMappingColIdVarPlStmt(m_mp, base_table_context, child_contexts,
output_context, m_dxl_to_plstmt_context);
Expr *expr = m_translator_dxl_to_scalar->TranslateDXLToScalar(
expr_dxlnode, &colid_var_mapping);
GPOS_ASSERT(nullptr != expr);
TargetEntry *target_entry = MakeNode(TargetEntry);
target_entry->expr = expr;
target_entry->resname =
CTranslatorUtils::CreateMultiByteCharStringFromWCString(
sc_proj_elem_dxlop->GetMdNameAlias()->GetMDName()->GetBuffer());
target_entry->resno = (AttrNumber)(ul + 1);
if (IsA(expr, Var))
{
// check the origin of the left or the right side
// of the current operator and if it is derived from a base relation,
// set resorigtbl and resorigcol appropriately
if (nullptr != base_table_context)
{
// translating project list of a base table
target_entry->resorigtbl = base_table_context->GetOid();
target_entry->resorigcol = ((Var *) expr)->varattno;
}
else
{
// not translating a base table proj list: variable must come from
// the left or right child of the operator
GPOS_ASSERT(nullptr != child_contexts);
GPOS_ASSERT(0 != child_contexts->Size());
ULONG colid = CDXLScalarIdent::Cast(expr_dxlnode->GetOperator())
->GetDXLColRef()
->Id();
const CDXLTranslateContext *translate_ctxt_left =
(*child_contexts)[0];
GPOS_ASSERT(nullptr != translate_ctxt_left);
const TargetEntry *pteOriginal =
translate_ctxt_left->GetTargetEntry(colid);
if (nullptr == pteOriginal)
{
// variable not found on the left side
GPOS_ASSERT(2 == child_contexts->Size());
const CDXLTranslateContext *pdxltrctxRight =
(*child_contexts)[1];
GPOS_ASSERT(nullptr != pdxltrctxRight);
pteOriginal = pdxltrctxRight->GetTargetEntry(colid);
}
if (nullptr == pteOriginal)
{
GPOS_RAISE(gpdxl::ExmaDXL,
gpdxl::ExmiDXL2PlStmtAttributeNotFound, colid);
}
target_entry->resorigtbl = pteOriginal->resorigtbl;
target_entry->resorigcol = pteOriginal->resorigcol;
}
}
// add column mapping to output translation context
output_context->InsertMapping(sc_proj_elem_dxlop->Id(), target_entry);
target_list = gpdb::LAppend(target_list, target_entry);
}
return target_list;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToPlStmt::CreateTargetListWithNullsForDroppedCols
//
// @doc:
// Construct the target list for a DML statement by adding NULL elements
// for dropped columns
//
//---------------------------------------------------------------------------
List *
CTranslatorDXLToPlStmt::CreateTargetListWithNullsForDroppedCols(
List *target_list, const IMDRelation *md_rel)
{
GPOS_ASSERT(nullptr != target_list);
GPOS_ASSERT(gpdb::ListLength(target_list) <= md_rel->ColumnCount());
List *result_list = NIL;
ULONG last_tgt_elem = 0;
ULONG resno = 1;
const ULONG num_of_rel_cols = md_rel->ColumnCount();
for (ULONG ul = 0; ul < num_of_rel_cols; ul++)
{
const IMDColumn *md_col = md_rel->GetMdCol(ul);
if (md_col->IsSystemColumn())
{
continue;
}
Expr *expr = nullptr;
if (md_col->IsDropped())
{
// add a NULL element
OID oid_type = CMDIdGPDB::CastMdid(
m_md_accessor->PtMDType<IMDTypeInt4>()->MDId())
->Oid();
expr = (Expr *) gpdb::MakeNULLConst(oid_type);
}
else
{
TargetEntry *target_entry =
(TargetEntry *) gpdb::ListNth(target_list, last_tgt_elem);
expr = (Expr *) gpdb::CopyObject(target_entry->expr);
last_tgt_elem++;
}
CHAR *name_str =
CTranslatorUtils::CreateMultiByteCharStringFromWCString(
md_col->Mdname().GetMDName()->GetBuffer());
TargetEntry *te_new =
gpdb::MakeTargetEntry(expr, resno, name_str, false /*resjunk*/);
result_list = gpdb::LAppend(result_list, te_new);
resno++;
}
return result_list;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToPlStmt::TranslateDXLProjectListToHashTargetList
//
// @doc:
// Create a target list for the hash node of a hash join plan node by creating a list
// of references to the elements in the child project list
//
//---------------------------------------------------------------------------
List *
CTranslatorDXLToPlStmt::TranslateDXLProjectListToHashTargetList(
const CDXLNode *project_list_dxlnode, CDXLTranslateContext *child_context,
CDXLTranslateContext *output_context)
{
List *target_list = NIL;
const ULONG arity = project_list_dxlnode->Arity();
for (ULONG ul = 0; ul < arity; ul++)
{
CDXLNode *proj_elem_dxlnode = (*project_list_dxlnode)[ul];
CDXLScalarProjElem *sc_proj_elem_dxlop =
CDXLScalarProjElem::Cast(proj_elem_dxlnode->GetOperator());
const TargetEntry *te_child =
child_context->GetTargetEntry(sc_proj_elem_dxlop->Id());
if (nullptr == te_child)
{
GPOS_RAISE(gpdxl::ExmaDXL, gpdxl::ExmiDXL2PlStmtAttributeNotFound,
sc_proj_elem_dxlop->Id());
}
// get type oid for project element's expression
GPOS_ASSERT(1 == proj_elem_dxlnode->Arity());
// find column type
OID oid_type = gpdb::ExprType((Node *) te_child->expr);
INT type_modifier = gpdb::ExprTypeMod((Node *) te_child->expr);
// find the original varno and attno for this column
Index idx_varnoold = 0;
AttrNumber attno_old = 0;
if (IsA(te_child->expr, Var))
{
Var *pv = (Var *) te_child->expr;
idx_varnoold = pv->varnoold;
attno_old = pv->varoattno;
}
else
{
idx_varnoold = OUTER_VAR;
attno_old = te_child->resno;
}
// create a Var expression for this target list entry expression
Var *var =
gpdb::MakeVar(OUTER_VAR, te_child->resno, oid_type, type_modifier,
0 // varlevelsup
);
// set old varno and varattno since makeVar does not set them
var->varnoold = idx_varnoold;
var->varoattno = attno_old;
CHAR *resname = CTranslatorUtils::CreateMultiByteCharStringFromWCString(
sc_proj_elem_dxlop->GetMdNameAlias()->GetMDName()->GetBuffer());
TargetEntry *target_entry =
gpdb::MakeTargetEntry((Expr *) var, (AttrNumber)(ul + 1), resname,
false // resjunk
);
target_list = gpdb::LAppend(target_list, target_entry);
output_context->InsertMapping(sc_proj_elem_dxlop->Id(), target_entry);
}
return target_list;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToPlStmt::TranslateDXLFilterToQual
//
// @doc:
// Translates a DXL filter node into a Qual list.
//
//---------------------------------------------------------------------------
List *
CTranslatorDXLToPlStmt::TranslateDXLFilterToQual(
const CDXLNode *filter_dxlnode,
const CDXLTranslateContextBaseTable *base_table_context,
CDXLTranslationContextArray *child_contexts,
CDXLTranslateContext *output_context)
{
const ULONG arity = filter_dxlnode->Arity();
if (0 == arity)
{
return NIL;
}
GPOS_ASSERT(1 == arity);
CDXLNode *filter_cond_dxlnode = (*filter_dxlnode)[0];
GPOS_ASSERT(CTranslatorDXLToScalar::HasBoolResult(filter_cond_dxlnode,
m_md_accessor));
return TranslateDXLScCondToQual(filter_cond_dxlnode, base_table_context,
child_contexts, output_context);
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToPlStmt::TranslateDXLScCondToQual
//
// @doc:
// Translates a DXL scalar condition node node into a Qual list.
//
//---------------------------------------------------------------------------
List *
CTranslatorDXLToPlStmt::TranslateDXLScCondToQual(
const CDXLNode *condition_dxlnode,
const CDXLTranslateContextBaseTable *base_table_context,
CDXLTranslationContextArray *child_contexts,
CDXLTranslateContext *output_context)
{
List *quals_list = NIL;
GPOS_ASSERT(CTranslatorDXLToScalar::HasBoolResult(
const_cast<CDXLNode *>(condition_dxlnode), m_md_accessor));
CMappingColIdVarPlStmt colid_var_mapping =
CMappingColIdVarPlStmt(m_mp, base_table_context, child_contexts,
output_context, m_dxl_to_plstmt_context);
Expr *expr = m_translator_dxl_to_scalar->TranslateDXLToScalar(
condition_dxlnode, &colid_var_mapping);
quals_list = gpdb::LAppend(quals_list, expr);
return quals_list;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToPlStmt::TranslatePlanCosts
//
// @doc:
// Translates DXL plan costs into the GPDB cost variables
//
//---------------------------------------------------------------------------
void
CTranslatorDXLToPlStmt::TranslatePlanCosts(const CDXLNode *dxlnode, Plan *plan)
{
CDXLOperatorCost *costs =
CDXLPhysicalProperties::PdxlpropConvert(dxlnode->GetProperties())
->GetDXLOperatorCost();
plan->startup_cost = CostFromStr(costs->GetStartUpCostStr());
plan->total_cost = CostFromStr(costs->GetTotalCostStr());
plan->plan_width = CTranslatorUtils::GetIntFromStr(costs->GetWidthStr());
// In the Postgres planner, the estimates on each node are per QE
// process, whereas the row estimates in GPORCA are global, across all
// processes. Divide the row count estimate by the number of segments
// executing it.
plan->plan_rows =
ceil(CostFromStr(costs->GetRowsOutStr()) /
m_dxl_to_plstmt_context->GetCurrentSlice()->numsegments);
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToPlStmt::TranslateProjListAndFilter
//
// @doc:
// Translates DXL proj list and filter into GPDB's target and qual lists,
// respectively
//
//---------------------------------------------------------------------------
void
CTranslatorDXLToPlStmt::TranslateProjListAndFilter(
const CDXLNode *project_list_dxlnode, const CDXLNode *filter_dxlnode,
const CDXLTranslateContextBaseTable *base_table_context,
CDXLTranslationContextArray *child_contexts, List **targetlist_out,
List **qual_out, CDXLTranslateContext *output_context)
{
// translate proj list
*targetlist_out = TranslateDXLProjList(
project_list_dxlnode,
base_table_context, // base table translation context
child_contexts, output_context);
// translate filter
*qual_out = TranslateDXLFilterToQual(
filter_dxlnode,
base_table_context, // base table translation context
child_contexts, output_context);
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToPlStmt::TranslateHashExprList
//
// @doc:
// Translates DXL hash expression list in a redistribute motion node into
// GPDB's hash expression and expression types lists, respectively
//
//---------------------------------------------------------------------------
void
CTranslatorDXLToPlStmt::TranslateHashExprList(
const CDXLNode *hash_expr_list_dxlnode,
const CDXLTranslateContext *child_context, List **hash_expr_out_list,
List **hash_expr_opfamilies_out_list, CDXLTranslateContext *output_context)
{
GPOS_ASSERT(NIL == *hash_expr_out_list);
GPOS_ASSERT(NIL == *hash_expr_opfamilies_out_list);
List *hash_expr_list = NIL;
CDXLTranslationContextArray *child_contexts =
GPOS_NEW(m_mp) CDXLTranslationContextArray(m_mp);
child_contexts->Append(child_context);
const ULONG arity = hash_expr_list_dxlnode->Arity();
for (ULONG ul = 0; ul < arity; ul++)
{
CDXLNode *hash_expr_dxlnode = (*hash_expr_list_dxlnode)[ul];
GPOS_ASSERT(1 == hash_expr_dxlnode->Arity());
CDXLNode *expr_dxlnode = (*hash_expr_dxlnode)[0];
CMappingColIdVarPlStmt colid_var_mapping =
CMappingColIdVarPlStmt(m_mp, nullptr, child_contexts,
output_context, m_dxl_to_plstmt_context);
Expr *expr = m_translator_dxl_to_scalar->TranslateDXLToScalar(
expr_dxlnode, &colid_var_mapping);
hash_expr_list = gpdb::LAppend(hash_expr_list, expr);
GPOS_ASSERT((ULONG) gpdb::ListLength(hash_expr_list) == ul + 1);
}
List *hash_expr_opfamilies = NIL;
if (GPOS_FTRACE(EopttraceConsiderOpfamiliesForDistribution))
{
for (ULONG ul = 0; ul < arity; ul++)
{
CDXLNode *hash_expr_dxlnode = (*hash_expr_list_dxlnode)[ul];
CDXLScalarHashExpr *hash_expr_dxlop =
CDXLScalarHashExpr::Cast(hash_expr_dxlnode->GetOperator());
const IMDId *opfamily = hash_expr_dxlop->MdidOpfamily();
hash_expr_opfamilies = gpdb::LAppendOid(
hash_expr_opfamilies, CMDIdGPDB::CastMdid(opfamily)->Oid());
}
}
*hash_expr_out_list = hash_expr_list;
*hash_expr_opfamilies_out_list = hash_expr_opfamilies;
// cleanup
child_contexts->Release();
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToPlStmt::TranslateSortCols
//
// @doc:
// Translates DXL sorting columns list into GPDB's arrays of sorting attribute numbers,
// and sorting operator ids, respectively.
// The two arrays must be allocated by the caller.
//
//---------------------------------------------------------------------------
void
CTranslatorDXLToPlStmt::TranslateSortCols(
const CDXLNode *sort_col_list_dxl,
const CDXLTranslateContext *child_context, AttrNumber *att_no_sort_colids,
Oid *sort_op_oids, Oid *sort_collations_oids, bool *is_nulls_first)
{
const ULONG arity = sort_col_list_dxl->Arity();
for (ULONG ul = 0; ul < arity; ul++)
{
CDXLNode *sort_col_dxlnode = (*sort_col_list_dxl)[ul];
CDXLScalarSortCol *sc_sort_col_dxlop =
CDXLScalarSortCol::Cast(sort_col_dxlnode->GetOperator());
ULONG sort_colid = sc_sort_col_dxlop->GetColId();
const TargetEntry *te_sort_col =
child_context->GetTargetEntry(sort_colid);
if (nullptr == te_sort_col)
{
GPOS_RAISE(gpdxl::ExmaDXL, gpdxl::ExmiDXL2PlStmtAttributeNotFound,
sort_colid);
}
att_no_sort_colids[ul] = te_sort_col->resno;
sort_op_oids[ul] =
CMDIdGPDB::CastMdid(sc_sort_col_dxlop->GetMdIdSortOp())->Oid();
if (sort_collations_oids)
{
sort_collations_oids[ul] =
gpdb::ExprCollation((Node *) te_sort_col->expr);
}
is_nulls_first[ul] = sc_sort_col_dxlop->IsSortedNullsFirst();
}
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToPlStmt::CostFromStr
//
// @doc:
// Parses a cost value from a string
//
//---------------------------------------------------------------------------
Cost
CTranslatorDXLToPlStmt::CostFromStr(const CWStringBase *str)
{
CHAR *sz = CTranslatorUtils::CreateMultiByteCharStringFromWCString(
str->GetBuffer());
return gpos::clib::Strtod(sz);
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToPlStmt::IsTgtTblDistributed
//
// @doc:
// Check if given operator is a DML on a distributed table
//
//---------------------------------------------------------------------------
BOOL
CTranslatorDXLToPlStmt::IsTgtTblDistributed(CDXLOperator *dxlop)
{
if (EdxlopPhysicalDML != dxlop->GetDXLOperator())
{
return false;
}
CDXLPhysicalDML *phy_dml_dxlop = CDXLPhysicalDML::Cast(dxlop);
IMDId *mdid = phy_dml_dxlop->GetDXLTableDescr()->MDId();
return IMDRelation::EreldistrMasterOnly !=
m_md_accessor->RetrieveRel(mdid)->GetRelDistribution();
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToPlStmt::AddJunkTargetEntryForColId
//
// @doc:
// Add a new target entry for the given colid to the given target list
//
//---------------------------------------------------------------------------
void
CTranslatorDXLToPlStmt::AddJunkTargetEntryForColId(
List **target_list, CDXLTranslateContext *dxl_translate_ctxt, ULONG colid,
const char *resname)
{
GPOS_ASSERT(nullptr != target_list);
const TargetEntry *target_entry = dxl_translate_ctxt->GetTargetEntry(colid);
if (nullptr == target_entry)
{
// colid not found in translate context
GPOS_RAISE(gpdxl::ExmaDXL, gpdxl::ExmiDXL2PlStmtAttributeNotFound,
colid);
}
// TODO: Oct 29, 2012; see if entry already exists in the target list
OID expr_oid = gpdb::ExprType((Node *) target_entry->expr);
INT type_modifier = gpdb::ExprTypeMod((Node *) target_entry->expr);
Var *var =
gpdb::MakeVar(OUTER_VAR, target_entry->resno, expr_oid, type_modifier,
0 // varlevelsup
);
ULONG resno = gpdb::ListLength(*target_list) + 1;
CHAR *resname_str = PStrDup(resname);
TargetEntry *te_new = gpdb::MakeTargetEntry(
(Expr *) var, resno, resname_str, true /* resjunk */);
*target_list = gpdb::LAppend(*target_list, te_new);
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToPlStmt::GetGPDBJoinTypeFromDXLJoinType
//
// @doc:
// Translates the join type from its DXL representation into the GPDB one
//
//---------------------------------------------------------------------------
JoinType
CTranslatorDXLToPlStmt::GetGPDBJoinTypeFromDXLJoinType(EdxlJoinType join_type)
{
GPOS_ASSERT(EdxljtSentinel > join_type);
JoinType jt = JOIN_INNER;
switch (join_type)
{
case EdxljtInner:
jt = JOIN_INNER;
break;
case EdxljtLeft:
jt = JOIN_LEFT;
break;
case EdxljtFull:
jt = JOIN_FULL;
break;
case EdxljtRight:
jt = JOIN_RIGHT;
break;
case EdxljtIn:
jt = JOIN_SEMI;
break;
case EdxljtLeftAntiSemijoin:
jt = JOIN_ANTI;
break;
case EdxljtLeftAntiSemijoinNotIn:
jt = JOIN_LASJ_NOTIN;
break;
default:
GPOS_ASSERT(!"Unrecognized join type");
}
return jt;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToPlStmt::TranslateDXLCtas
//
// @doc:
// Sets the vartypmod fields in the target entries of the given target list
//
//---------------------------------------------------------------------------
void
CTranslatorDXLToPlStmt::SetVarTypMod(const CDXLPhysicalCTAS *phy_ctas_dxlop,
List *target_list)
{
GPOS_ASSERT(nullptr != target_list);
IntPtrArray *var_type_mod_array = phy_ctas_dxlop->GetVarTypeModArray();
GPOS_ASSERT(var_type_mod_array->Size() == gpdb::ListLength(target_list));
ULONG ul = 0;
ListCell *lc = nullptr;
ForEach(lc, target_list)
{
TargetEntry *target_entry = (TargetEntry *) lfirst(lc);
GPOS_ASSERT(IsA(target_entry, TargetEntry));
if (IsA(target_entry->expr, Var))
{
Var *var = (Var *) target_entry->expr;
var->vartypmod = *(*var_type_mod_array)[ul];
}
++ul;
}
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToPlStmt::TranslateDXLCtas
//
// @doc:
// Translates a DXL CTAS node
//
//---------------------------------------------------------------------------
Plan *
CTranslatorDXLToPlStmt::TranslateDXLCtas(
const CDXLNode *ctas_dxlnode, CDXLTranslateContext *output_context,
CDXLTranslationContextArray *ctxt_translation_prev_siblings)
{
CDXLPhysicalCTAS *phy_ctas_dxlop =
CDXLPhysicalCTAS::Cast(ctas_dxlnode->GetOperator());
CDXLNode *project_list_dxlnode = (*ctas_dxlnode)[0];
CDXLNode *child_dxlnode = (*ctas_dxlnode)[1];
GPOS_ASSERT(
nullptr ==
phy_ctas_dxlop->GetDxlCtasStorageOption()->GetDXLCtasOptionArray());
CDXLTranslateContext child_context(m_mp, false,
output_context->GetColIdToParamIdMap());
Plan *plan = TranslateDXLOperatorToPlan(child_dxlnode, &child_context,
ctxt_translation_prev_siblings);
// fix target list to match the required column names
CDXLTranslationContextArray *child_contexts =
GPOS_NEW(m_mp) CDXLTranslationContextArray(m_mp);
child_contexts->Append(&child_context);
List *target_list = TranslateDXLProjList(project_list_dxlnode,
nullptr, // base_table_context
child_contexts, output_context);
SetVarTypMod(phy_ctas_dxlop, target_list);
SetParamIds(plan);
// cleanup
child_contexts->Release();
// translate operator costs
TranslatePlanCosts(ctas_dxlnode, plan);
//IntoClause *into_clause = TranslateDXLPhyCtasToIntoClause(phy_ctas_dxlop);
IntoClause *into_clause = nullptr;
GpPolicy *distr_policy =
TranslateDXLPhyCtasToDistrPolicy(phy_ctas_dxlop, target_list);
m_dxl_to_plstmt_context->AddCtasInfo(into_clause, distr_policy);
GPOS_ASSERT(IMDRelation::EreldistrMasterOnly !=
phy_ctas_dxlop->Ereldistrpolicy());
m_is_tgt_tbl_distributed = true;
// Add a result node on top with the correct projection list
Result *result = MakeNode(Result);
Plan *result_plan = &(result->plan);
result_plan->plan_node_id = m_dxl_to_plstmt_context->GetNextPlanId();
result_plan->lefttree = plan;
result_plan->targetlist = target_list;
SetParamIds(result_plan);
plan = (Plan *) result;
return (Plan *) plan;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToPlStmt::TranslateDXLPhyCtasToIntoClause
//
// @doc:
// Translates a DXL CTAS into clause
//
//---------------------------------------------------------------------------
IntoClause *
CTranslatorDXLToPlStmt::TranslateDXLPhyCtasToIntoClause(
const CDXLPhysicalCTAS *phy_ctas_dxlop)
{
IntoClause *into_clause = MakeNode(IntoClause);
into_clause->rel = MakeNode(RangeVar);
/* GPDB_91_MERGE_FIXME: what about unlogged? */
into_clause->rel->relpersistence = phy_ctas_dxlop->IsTemporary()
? RELPERSISTENCE_TEMP
: RELPERSISTENCE_PERMANENT;
into_clause->rel->relname =
CTranslatorUtils::CreateMultiByteCharStringFromWCString(
phy_ctas_dxlop->MdName()->GetMDName()->GetBuffer());
into_clause->rel->schemaname = nullptr;
if (nullptr != phy_ctas_dxlop->GetMdNameSchema())
{
into_clause->rel->schemaname =
CTranslatorUtils::CreateMultiByteCharStringFromWCString(
phy_ctas_dxlop->GetMdNameSchema()->GetMDName()->GetBuffer());
}
CDXLCtasStorageOptions *dxl_ctas_storage_option =
phy_ctas_dxlop->GetDxlCtasStorageOption();
if (nullptr != dxl_ctas_storage_option->GetMdNameTableSpace())
{
into_clause->tableSpaceName =
CTranslatorUtils::CreateMultiByteCharStringFromWCString(
phy_ctas_dxlop->GetDxlCtasStorageOption()
->GetMdNameTableSpace()
->GetMDName()
->GetBuffer());
}
into_clause->onCommit =
(OnCommitAction) dxl_ctas_storage_option->GetOnCommitAction();
into_clause->options = TranslateDXLCtasStorageOptions(
dxl_ctas_storage_option->GetDXLCtasOptionArray());
// get column names
CDXLColDescrArray *dxl_col_descr_array =
phy_ctas_dxlop->GetDXLColumnDescrArray();
const ULONG num_of_cols = dxl_col_descr_array->Size();
into_clause->colNames = NIL;
for (ULONG ul = 0; ul < num_of_cols; ++ul)
{
const CDXLColDescr *dxl_col_descr = (*dxl_col_descr_array)[ul];
CHAR *col_name_char_array =
CTranslatorUtils::CreateMultiByteCharStringFromWCString(
dxl_col_descr->MdName()->GetMDName()->GetBuffer());
ColumnDef *col_def = MakeNode(ColumnDef);
col_def->colname = col_name_char_array;
col_def->is_local = true;
// GPDB_91_MERGE_FIXME: collation
col_def->collClause = nullptr;
col_def->collOid = gpdb::TypeCollation(
CMDIdGPDB::CastMdid(dxl_col_descr->MdidType())->Oid());
into_clause->colNames = gpdb::LAppend(into_clause->colNames, col_def);
}
return into_clause;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToPlStmt::TranslateDXLPhyCtasToDistrPolicy
//
// @doc:
// Translates distribution policy given by a physical CTAS operator
//
//---------------------------------------------------------------------------
GpPolicy *
CTranslatorDXLToPlStmt::TranslateDXLPhyCtasToDistrPolicy(
const CDXLPhysicalCTAS *dxlop, List *target_list)
{
ULongPtrArray *distr_col_pos_array = dxlop->GetDistrColPosArray();
const ULONG num_of_distr_cols =
(distr_col_pos_array == nullptr) ? 0 : distr_col_pos_array->Size();
ULONG num_of_distr_cols_alloc = 1;
if (0 < num_of_distr_cols)
{
num_of_distr_cols_alloc = num_of_distr_cols;
}
// always set numsegments to ALL for CTAS
GpPolicy *distr_policy =
gpdb::MakeGpPolicy(POLICYTYPE_PARTITIONED, num_of_distr_cols_alloc,
gpdb::GetGPSegmentCount());
GPOS_ASSERT(IMDRelation::EreldistrHash == dxlop->Ereldistrpolicy() ||
IMDRelation::EreldistrRandom == dxlop->Ereldistrpolicy() ||
IMDRelation::EreldistrReplicated == dxlop->Ereldistrpolicy());
if (IMDRelation::EreldistrReplicated == dxlop->Ereldistrpolicy())
{
distr_policy->ptype = POLICYTYPE_REPLICATED;
}
else
{
distr_policy->ptype = POLICYTYPE_PARTITIONED;
}
distr_policy->nattrs = 0;
if (IMDRelation::EreldistrHash == dxlop->Ereldistrpolicy())
{
GPOS_ASSERT(0 < num_of_distr_cols);
distr_policy->nattrs = num_of_distr_cols;
IMdIdArray *opclasses = dxlop->GetDistrOpclasses();
GPOS_ASSERT(opclasses->Size() == num_of_distr_cols);
for (ULONG ul = 0; ul < num_of_distr_cols; ul++)
{
ULONG col_pos_idx = *((*distr_col_pos_array)[ul]);
distr_policy->attrs[ul] = col_pos_idx + 1;
Oid opclass = CMDIdGPDB::CastMdid((*opclasses)[ul])->Oid();
distr_policy->opclasses[ul] = opclass;
}
}
return distr_policy;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToPlStmt::TranslateDXLCtasStorageOptions
//
// @doc:
// Translates CTAS options
//
//---------------------------------------------------------------------------
List *
CTranslatorDXLToPlStmt::TranslateDXLCtasStorageOptions(
CDXLCtasStorageOptions::CDXLCtasOptionArray *ctas_storage_options)
{
if (nullptr == ctas_storage_options)
{
return NIL;
}
const ULONG num_of_options = ctas_storage_options->Size();
List *options = NIL;
for (ULONG ul = 0; ul < num_of_options; ul++)
{
CDXLCtasStorageOptions::CDXLCtasOption *pdxlopt =
(*ctas_storage_options)[ul];
CWStringBase *str_name = pdxlopt->m_str_name;
CWStringBase *str_value = pdxlopt->m_str_value;
DefElem *def_elem = MakeNode(DefElem);
def_elem->defname =
CTranslatorUtils::CreateMultiByteCharStringFromWCString(
str_name->GetBuffer());
if (!pdxlopt->m_is_null)
{
NodeTag arg_type = (NodeTag) pdxlopt->m_type;
GPOS_ASSERT(T_Integer == arg_type || T_String == arg_type);
if (T_Integer == arg_type)
{
def_elem->arg = (Node *) gpdb::MakeIntegerValue(
CTranslatorUtils::GetLongFromStr(str_value));
}
else
{
def_elem->arg = (Node *) gpdb::MakeStringValue(
CTranslatorUtils::CreateMultiByteCharStringFromWCString(
str_value->GetBuffer()));
}
}
options = gpdb::LAppend(options, def_elem);
}
return options;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToPlStmt::TranslateDXLBitmapTblScan
//
// @doc:
// Translates a DXL bitmap table scan node into a BitmapHeapScan node
//
//---------------------------------------------------------------------------
Plan *
CTranslatorDXLToPlStmt::TranslateDXLBitmapTblScan(
const CDXLNode *bitmapscan_dxlnode, CDXLTranslateContext *output_context,
CDXLTranslationContextArray *ctxt_translation_prev_siblings)
{
BOOL is_dynamic = false;
const CDXLTableDescr *table_descr = nullptr;
CDXLOperator *dxl_operator = bitmapscan_dxlnode->GetOperator();
if (EdxlopPhysicalBitmapTableScan == dxl_operator->GetDXLOperator())
{
table_descr =
CDXLPhysicalBitmapTableScan::Cast(dxl_operator)->GetDXLTableDescr();
}
else
{
GPOS_ASSERT(EdxlopPhysicalDynamicBitmapTableScan ==
dxl_operator->GetDXLOperator());
CDXLPhysicalDynamicBitmapTableScan *phy_dyn_bitmap_tblscan_dxlop =
CDXLPhysicalDynamicBitmapTableScan::Cast(dxl_operator);
table_descr = phy_dyn_bitmap_tblscan_dxlop->GetDXLTableDescr();
is_dynamic = true;
}
// translation context for column mappings in the base relation
CDXLTranslateContextBaseTable base_table_context(m_mp);
// add the new range table entry as the last element of the range table
Index index =
gpdb::ListLength(m_dxl_to_plstmt_context->GetRTableEntriesList()) + 1;
const IMDRelation *md_rel = m_md_accessor->RetrieveRel(table_descr->MDId());
// Lock any table we are to scan, since it may not have been properly locked
// by the parser (e.g in case of generated scans for partitioned tables)
CMDIdGPDB *mdid = CMDIdGPDB::CastMdid(md_rel->MDId());
GPOS_RTL_ASSERT(table_descr->LockMode() != -1);
gpdb::GPDBLockRelationOid(mdid->Oid(), table_descr->LockMode());
RangeTblEntry *rte = TranslateDXLTblDescrToRangeTblEntry(
table_descr, index, &base_table_context);
GPOS_ASSERT(nullptr != rte);
rte->requiredPerms |= ACL_SELECT;
m_dxl_to_plstmt_context->AddRTE(rte);
DynamicBitmapHeapScan *dscan;
BitmapHeapScan *bitmap_tbl_scan;
dscan = MakeNode(DynamicBitmapHeapScan);
if (is_dynamic)
{
bitmap_tbl_scan = &dscan->bitmapheapscan;
CDXLPhysicalDynamicBitmapTableScan *phy_dyn_bitmap_tblscan_dxlop =
CDXLPhysicalDynamicBitmapTableScan::Cast(dxl_operator);
IMdIdArray *parts = phy_dyn_bitmap_tblscan_dxlop->GetParts();
List *oids_list = NIL;
for (ULONG ul = 0; ul < parts->Size(); ul++)
{
Oid part = CMDIdGPDB::CastMdid((*parts)[ul])->Oid();
oids_list = gpdb::LAppendOid(oids_list, part);
}
dscan->partOids = oids_list;
dscan->join_prune_paramids = NIL;
OID oid_type =
CMDIdGPDB::CastMdid(m_md_accessor->PtMDType<IMDTypeInt4>()->MDId())
->Oid();
const ULongPtrArray *selector_ids =
phy_dyn_bitmap_tblscan_dxlop->GetSelectorIds();
for (ULONG ul = 0; ul < selector_ids->Size(); ++ul)
{
ULONG selector_id = *(*selector_ids)[ul];
ULONG param_id = m_dxl_to_plstmt_context->GetParamIdForSelector(
oid_type, selector_id);
dscan->join_prune_paramids =
gpdb::LAppendInt(dscan->join_prune_paramids, param_id);
}
}
else
{
bitmap_tbl_scan = MakeNode(BitmapHeapScan);
}
bitmap_tbl_scan->scan.scanrelid = index;
Plan *plan = &(bitmap_tbl_scan->scan.plan);
plan->plan_node_id = m_dxl_to_plstmt_context->GetNextPlanId();
// translate operator costs
TranslatePlanCosts(bitmapscan_dxlnode, plan);
GPOS_ASSERT(4 == bitmapscan_dxlnode->Arity());
// translate proj list and filter
CDXLNode *project_list_dxlnode = (*bitmapscan_dxlnode)[0];
CDXLNode *filter_dxlnode = (*bitmapscan_dxlnode)[1];
CDXLNode *recheck_cond_dxlnode = (*bitmapscan_dxlnode)[2];
CDXLNode *bitmap_access_path_dxlnode = (*bitmapscan_dxlnode)[3];
List *quals_list = nullptr;
TranslateProjListAndFilter(
project_list_dxlnode, filter_dxlnode,
&base_table_context, // translate context for the base table
ctxt_translation_prev_siblings, &plan->targetlist, &quals_list,
output_context);
plan->qual = quals_list;
bitmap_tbl_scan->bitmapqualorig = TranslateDXLFilterToQual(
recheck_cond_dxlnode, &base_table_context,
ctxt_translation_prev_siblings, output_context);
bitmap_tbl_scan->scan.plan.lefttree = TranslateDXLBitmapAccessPath(
bitmap_access_path_dxlnode, output_context, md_rel, table_descr,
&base_table_context, ctxt_translation_prev_siblings, bitmap_tbl_scan);
SetParamIds(plan);
if (is_dynamic)
{
return (Plan *) dscan;
}
return (Plan *) bitmap_tbl_scan;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToPlStmt::TranslateDXLBitmapAccessPath
//
// @doc:
// Translate the tree of bitmap index operators that are under the given
// (dynamic) bitmap table scan.
//
//---------------------------------------------------------------------------
Plan *
CTranslatorDXLToPlStmt::TranslateDXLBitmapAccessPath(
const CDXLNode *bitmap_access_path_dxlnode,
CDXLTranslateContext *output_context, const IMDRelation *md_rel,
const CDXLTableDescr *table_descr,
CDXLTranslateContextBaseTable *base_table_context,
CDXLTranslationContextArray *ctxt_translation_prev_siblings,
BitmapHeapScan *bitmap_tbl_scan)
{
Edxlopid dxl_op_id =
bitmap_access_path_dxlnode->GetOperator()->GetDXLOperator();
if (EdxlopScalarBitmapIndexProbe == dxl_op_id)
{
return TranslateDXLBitmapIndexProbe(
bitmap_access_path_dxlnode, output_context, md_rel, table_descr,
base_table_context, ctxt_translation_prev_siblings,
bitmap_tbl_scan);
}
GPOS_ASSERT(EdxlopScalarBitmapBoolOp == dxl_op_id);
return TranslateDXLBitmapBoolOp(
bitmap_access_path_dxlnode, output_context, md_rel, table_descr,
base_table_context, ctxt_translation_prev_siblings, bitmap_tbl_scan);
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToScalar::TranslateDXLBitmapBoolOp
//
// @doc:
// Translates a DML bitmap bool op expression
//
//---------------------------------------------------------------------------
Plan *
CTranslatorDXLToPlStmt::TranslateDXLBitmapBoolOp(
const CDXLNode *bitmap_boolop_dxlnode, CDXLTranslateContext *output_context,
const IMDRelation *md_rel, const CDXLTableDescr *table_descr,
CDXLTranslateContextBaseTable *base_table_context,
CDXLTranslationContextArray *ctxt_translation_prev_siblings,
BitmapHeapScan *bitmap_tbl_scan)
{
GPOS_ASSERT(nullptr != bitmap_boolop_dxlnode);
GPOS_ASSERT(EdxlopScalarBitmapBoolOp ==
bitmap_boolop_dxlnode->GetOperator()->GetDXLOperator());
CDXLScalarBitmapBoolOp *sc_bitmap_boolop_dxlop =
CDXLScalarBitmapBoolOp::Cast(bitmap_boolop_dxlnode->GetOperator());
CDXLNode *left_tree_dxlnode = (*bitmap_boolop_dxlnode)[0];
CDXLNode *right_tree_dxlnode = (*bitmap_boolop_dxlnode)[1];
Plan *left_plan = TranslateDXLBitmapAccessPath(
left_tree_dxlnode, output_context, md_rel, table_descr,
base_table_context, ctxt_translation_prev_siblings, bitmap_tbl_scan);
Plan *right_plan = TranslateDXLBitmapAccessPath(
right_tree_dxlnode, output_context, md_rel, table_descr,
base_table_context, ctxt_translation_prev_siblings, bitmap_tbl_scan);
List *child_plan_list = ListMake2(left_plan, right_plan);
Plan *plan = nullptr;
if (CDXLScalarBitmapBoolOp::EdxlbitmapAnd ==
sc_bitmap_boolop_dxlop->GetDXLBitmapOpType())
{
BitmapAnd *bitmapand = MakeNode(BitmapAnd);
bitmapand->plan.plan_node_id = m_dxl_to_plstmt_context->GetNextPlanId();
bitmapand->bitmapplans = child_plan_list;
bitmapand->plan.targetlist = nullptr;
bitmapand->plan.qual = nullptr;
plan = (Plan *) bitmapand;
}
else
{
BitmapOr *bitmapor = MakeNode(BitmapOr);
bitmapor->plan.plan_node_id = m_dxl_to_plstmt_context->GetNextPlanId();
bitmapor->bitmapplans = child_plan_list;
bitmapor->plan.targetlist = nullptr;
bitmapor->plan.qual = nullptr;
plan = (Plan *) bitmapor;
}
return plan;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToPlStmt::TranslateDXLBitmapIndexProbe
//
// @doc:
// Translate CDXLScalarBitmapIndexProbe into a BitmapIndexScan
// or a DynamicBitmapIndexScan
//
//---------------------------------------------------------------------------
Plan *
CTranslatorDXLToPlStmt::TranslateDXLBitmapIndexProbe(
const CDXLNode *bitmap_index_probe_dxlnode,
CDXLTranslateContext *output_context, const IMDRelation *md_rel,
const CDXLTableDescr *table_descr,
CDXLTranslateContextBaseTable *base_table_context,
CDXLTranslationContextArray *ctxt_translation_prev_siblings,
BitmapHeapScan *bitmap_tbl_scan)
{
CDXLScalarBitmapIndexProbe *sc_bitmap_idx_probe_dxlop =
CDXLScalarBitmapIndexProbe::Cast(
bitmap_index_probe_dxlnode->GetOperator());
BitmapIndexScan *bitmap_idx_scan;
DynamicBitmapIndexScan *dyn_bitmap_idx_scan;
if (IsA(bitmap_tbl_scan, DynamicBitmapHeapScan))
{
/* It's a Dynamic Bitmap Index Scan */
dyn_bitmap_idx_scan = MakeNode(DynamicBitmapIndexScan);
bitmap_idx_scan = &(dyn_bitmap_idx_scan->biscan);
}
else
{
dyn_bitmap_idx_scan = nullptr;
bitmap_idx_scan = MakeNode(BitmapIndexScan);
}
bitmap_idx_scan->scan.scanrelid = bitmap_tbl_scan->scan.scanrelid;
CMDIdGPDB *mdid_index = CMDIdGPDB::CastMdid(
sc_bitmap_idx_probe_dxlop->GetDXLIndexDescr()->MDId());
const IMDIndex *index = m_md_accessor->RetrieveIndex(mdid_index);
Oid index_oid = mdid_index->Oid();
// Lock any index we are to scan, since it may not have been properly locked
// by the parser (e.g in case of generated scans for partitioned indexes)
gpdb::GPDBLockRelationOid(index_oid, table_descr->LockMode());
GPOS_ASSERT(InvalidOid != index_oid);
bitmap_idx_scan->indexid = index_oid;
Plan *plan = &(bitmap_idx_scan->scan.plan);
plan->plan_node_id = m_dxl_to_plstmt_context->GetNextPlanId();
GPOS_ASSERT(1 == bitmap_index_probe_dxlnode->Arity());
CDXLNode *index_cond_list_dxlnode = (*bitmap_index_probe_dxlnode)[0];
List *index_cond = NIL;
List *index_orig_cond = NIL;
List *index_strategy_list = NIL;
List *index_subtype_list = NIL;
TranslateIndexConditions(
index_cond_list_dxlnode, table_descr, true /*is_bitmap_index_probe*/,
index, md_rel, output_context, base_table_context,
ctxt_translation_prev_siblings, &index_cond, &index_orig_cond,
&index_strategy_list, &index_subtype_list);
bitmap_idx_scan->indexqual = index_cond;
bitmap_idx_scan->indexqualorig = index_orig_cond;
/*
* As of 8.4, the indexstrategy and indexsubtype fields are no longer
* available or needed in IndexScan. Ignore them.
*/
SetParamIds(plan);
return plan;
}
// translates a DXL Value Scan node into a GPDB Value scan node
Plan *
CTranslatorDXLToPlStmt::TranslateDXLValueScan(
const CDXLNode *value_scan_dxlnode, CDXLTranslateContext *output_context,
CDXLTranslationContextArray *ctxt_translation_prev_siblings)
{
// translation context for column mappings
CDXLTranslateContextBaseTable base_table_context(m_mp);
// we will add the new range table entry as the last element of the range table
Index index =
gpdb::ListLength(m_dxl_to_plstmt_context->GetRTableEntriesList()) + 1;
base_table_context.SetRelIndex(index);
// create value scan node
ValuesScan *value_scan = MakeNode(ValuesScan);
value_scan->scan.scanrelid = index;
Plan *plan = &(value_scan->scan.plan);
RangeTblEntry *rte = TranslateDXLValueScanToRangeTblEntry(
value_scan_dxlnode, output_context, &base_table_context);
GPOS_ASSERT(nullptr != rte);
value_scan->values_lists = (List *) gpdb::CopyObject(rte->values_lists);
m_dxl_to_plstmt_context->AddRTE(rte);
plan->plan_node_id = m_dxl_to_plstmt_context->GetNextPlanId();
// translate operator costs
TranslatePlanCosts(value_scan_dxlnode, plan);
// a table scan node must have at least 2 children: projection list and at least 1 value list
GPOS_ASSERT(2 <= value_scan_dxlnode->Arity());
CDXLNode *project_list_dxlnode = (*value_scan_dxlnode)[EdxltsIndexProjList];
// translate proj list
List *target_list = TranslateDXLProjList(
project_list_dxlnode, &base_table_context, nullptr, output_context);
plan->targetlist = target_list;
return (Plan *) value_scan;
}
List *
CTranslatorDXLToPlStmt::TranslateNestLoopParamList(
CDXLColRefArray *pdrgdxlcrOuterRefs, CDXLTranslateContext *dxltrctxLeft,
CDXLTranslateContext *dxltrctxRight)
{
List *nest_params_list = NIL;
for (ULONG ul = 0; ul < pdrgdxlcrOuterRefs->Size(); ul++)
{
CDXLColRef *pdxlcr = (*pdrgdxlcrOuterRefs)[ul];
ULONG ulColid = pdxlcr->Id();
// left child context contains the target entry for the nest params col refs
const TargetEntry *target_entry = dxltrctxLeft->GetTargetEntry(ulColid);
GPOS_ASSERT(nullptr != target_entry);
Var *old_var = (Var *) target_entry->expr;
Var *new_var =
gpdb::MakeVar(OUTER_VAR, target_entry->resno, old_var->vartype,
old_var->vartypmod, 0 /*varlevelsup*/);
new_var->varnoold = old_var->varnoold;
new_var->varoattno = old_var->varoattno;
NestLoopParam *nest_params = MakeNode(NestLoopParam);
// right child context contains the param entry for the nest params col refs
const CMappingElementColIdParamId *colid_param_mapping =
dxltrctxRight->GetParamIdMappingElement(ulColid);
GPOS_ASSERT(nullptr != colid_param_mapping);
nest_params->paramno = colid_param_mapping->ParamId();
nest_params->paramval = new_var;
nest_params_list =
gpdb::LAppend(nest_params_list, (void *) nest_params);
}
return nest_params_list;
}
// EOF
相关信息
相关文章
greenplumn CContextDXLToPlStmt 源码
greenplumn CContextQueryToDXL 源码
greenplumn CDXLTranslateContext 源码
greenplumn CDXLTranslateContextBaseTable 源码
greenplumn CMappingColIdVar 源码
greenplumn CMappingColIdVarPlStmt 源码
greenplumn CMappingElementColIdParamId 源码
0
赞
热门推荐
-
2、 - 优质文章
-
3、 gate.io
-
8、 golang
-
9、 openharmony
-
10、 Vue中input框自动聚焦