blob: 833a5621bc30413569f8eb44d2d047cf1c2c1097 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
//---------------------------------------------------------------------------
// @filename:
// CTranslatorDXLToPlStmt.cpp
//
// @doc:
// Implementation of the methods for translating from DXL tree to GPDB
// PlannedStmt.
//
// @test:
//
//
//---------------------------------------------------------------------------
#include "postgres.h"
#include "nodes/nodes.h"
#include "nodes/pg_list.h"
#include "nodes/plannodes.h"
#include "nodes/primnodes.h"
#include "catalog/gp_policy.h"
#include "catalog/pg_exttable.h"
#include "cdb/cdbutil.h"
#include "cdb/cdbvars.h"
#include "cdb/partitionselection.h"
#include "utils/uri.h"
#include "gpos/base.h"
#include "gpopt/mdcache/CMDAccessor.h"
#include "gpopt/translate/CTranslatorDXLToPlStmt.h"
#include "gpopt/translate/CTranslatorUtils.h"
#include "gpopt/translate/CIndexQualInfo.h"
#include "naucrates/dxl/operators/CDXLNode.h"
#include "naucrates/dxl/operators/CDXLDirectDispatchInfo.h"
#include "naucrates/md/IMDFunction.h"
#include "naucrates/md/IMDScalarOp.h"
#include "naucrates/md/IMDAggregate.h"
#include "naucrates/md/IMDType.h"
#include "naucrates/md/IMDTypeBool.h"
#include "naucrates/md/IMDTypeInt4.h"
#include "naucrates/md/IMDIndex.h"
#include "naucrates/md/IMDRelationExternal.h"
#include "gpopt/gpdbwrappers.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:
// ShtypeFromSpoolInfo
//
// @doc:
// Helper function for extracting the GPDB share type from a DXL spool info object
//
//---------------------------------------------------------------------------
ShareType
ShtypeFromSpoolInfo(const CDXLSpoolInfo *pspoolinfo)
{
ShareType shtype = SHARE_NOTSHARED;
GPOS_ASSERT(NULL != pspoolinfo);
if (EdxlspoolMaterialize == pspoolinfo->Edxlsptype())
{
shtype = SHARE_MATERIAL;
if (pspoolinfo->FMultiSlice())
{
shtype = SHARE_MATERIAL_XSLICE;
}
}
else if (EdxlspoolSort == pspoolinfo->Edxlsptype())
{
shtype = SHARE_SORT;
if (pspoolinfo->FMultiSlice())
{
shtype = SHARE_SORT_XSLICE;
}
}
return shtype;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToPlStmt::CTranslatorDXLToPlStmt
//
// @doc:
// Ctor
//
//---------------------------------------------------------------------------
CTranslatorDXLToPlStmt::CTranslatorDXLToPlStmt
(
IMemoryPool *pmp,
CMDAccessor *pmda,
CContextDXLToPlStmt* pctxdxltoplstmt,
ULONG ulSegments
)
:
m_pmp(pmp),
m_pmda(pmda),
m_pctxdxltoplstmt(pctxdxltoplstmt),
m_cmdtype(CMD_SELECT),
m_fTargetTableDistributed(false),
m_plResultRelations(NULL),
m_ulExternalScanCounter(0),
m_ulSegments(ulSegments),
m_ulPartitionSelectorCounter(0)
{
m_pdxlsctranslator = GPOS_NEW(m_pmp) CTranslatorDXLToScalar(m_pmp, m_pmda, m_ulSegments);
InitTranslators();
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToPlStmt::~CTranslatorDXLToPlStmt
//
// @doc:
// Dtor
//
//---------------------------------------------------------------------------
CTranslatorDXLToPlStmt::~CTranslatorDXLToPlStmt()
{
GPOS_DELETE(m_pdxlsctranslator);
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToPlStmt::InitTranslators
//
// @doc:
// Initialize index of translators
//
//---------------------------------------------------------------------------
void
CTranslatorDXLToPlStmt::InitTranslators()
{
for (ULONG ul = 0; ul < GPOS_ARRAY_SIZE(m_rgpfTranslators); ul++)
{
m_rgpfTranslators[ul] = NULL;
}
// array mapping operator type to translator function
STranslatorMapping rgTranslators[] =
{
{EdxlopPhysicalTableScan, &gpopt::CTranslatorDXLToPlStmt::PtsFromDXLTblScan},
{EdxlopPhysicalExternalScan, &gpopt::CTranslatorDXLToPlStmt::PtsFromDXLTblScan},
//{EdxlopPhysicalIndexOnlyScan, &gpopt::CTranslatorDXLToPlStmt::PiosFromDXLIndexOnlyScan},
{EdxlopPhysicalIndexScan, &gpopt::CTranslatorDXLToPlStmt::PisFromDXLIndexScan},
{EdxlopPhysicalHashJoin, &gpopt::CTranslatorDXLToPlStmt::PhjFromDXLHJ},
{EdxlopPhysicalNLJoin, &gpopt::CTranslatorDXLToPlStmt::PnljFromDXLNLJ},
{EdxlopPhysicalMergeJoin, &gpopt::CTranslatorDXLToPlStmt::PmjFromDXLMJ},
{EdxlopPhysicalMotionGather, &gpopt::CTranslatorDXLToPlStmt::PplanMotionFromDXLMotion},
{EdxlopPhysicalMotionBroadcast, &gpopt::CTranslatorDXLToPlStmt::PplanMotionFromDXLMotion},
{EdxlopPhysicalMotionRedistribute, &gpopt::CTranslatorDXLToPlStmt::PplanTranslateDXLMotion},
{EdxlopPhysicalMotionRandom, &gpopt::CTranslatorDXLToPlStmt::PplanTranslateDXLMotion},
{EdxlopPhysicalMotionRoutedDistribute, &gpopt::CTranslatorDXLToPlStmt::PplanMotionFromDXLMotion},
{EdxlopPhysicalLimit, &gpopt::CTranslatorDXLToPlStmt::PlimitFromDXLLimit},
{EdxlopPhysicalAgg, &gpopt::CTranslatorDXLToPlStmt::PaggFromDXLAgg},
{EdxlopPhysicalWindow, &gpopt::CTranslatorDXLToPlStmt::PwindowFromDXLWindow},
{EdxlopPhysicalSort, &gpopt::CTranslatorDXLToPlStmt::PsortFromDXLSort},
{EdxlopPhysicalSubqueryScan, &gpopt::CTranslatorDXLToPlStmt::PsubqscanFromDXLSubqScan},
{EdxlopPhysicalResult, &gpopt::CTranslatorDXLToPlStmt::PresultFromDXLResult},
{EdxlopPhysicalAppend, &gpopt::CTranslatorDXLToPlStmt::PappendFromDXLAppend},
{EdxlopPhysicalMaterialize, &gpopt::CTranslatorDXLToPlStmt::PmatFromDXLMaterialize},
{EdxlopPhysicalSharedScan, &gpopt::CTranslatorDXLToPlStmt::PshscanFromDXLSharedScan},
{EdxlopPhysicalSequence, &gpopt::CTranslatorDXLToPlStmt::PplanSequence},
{EdxlopPhysicalDynamicTableScan, &gpopt::CTranslatorDXLToPlStmt::PplanDTS},
{EdxlopPhysicalDynamicIndexScan, &gpopt::CTranslatorDXLToPlStmt::PplanDIS},
{EdxlopPhysicalTVF, &gpopt::CTranslatorDXLToPlStmt::PplanFunctionScanFromDXLTVF},
{EdxlopPhysicalDML, &gpopt::CTranslatorDXLToPlStmt::PplanDML},
{EdxlopPhysicalSplit, &gpopt::CTranslatorDXLToPlStmt::PplanSplit},
{EdxlopPhysicalRowTrigger, &gpopt::CTranslatorDXLToPlStmt::PplanRowTrigger},
{EdxlopPhysicalAssert, &gpopt::CTranslatorDXLToPlStmt::PplanAssert},
{EdxlopPhysicalCTEProducer, &gpopt::CTranslatorDXLToPlStmt::PshscanFromDXLCTEProducer},
{EdxlopPhysicalCTEConsumer, &gpopt::CTranslatorDXLToPlStmt::PshscanFromDXLCTEConsumer},
{EdxlopPhysicalBitmapTableScan, &gpopt::CTranslatorDXLToPlStmt::PplanBitmapTableScan},
{EdxlopPhysicalDynamicBitmapTableScan, &gpopt::CTranslatorDXLToPlStmt::PplanBitmapTableScan},
{EdxlopPhysicalCTAS, &gpopt::CTranslatorDXLToPlStmt::PplanCTAS},
{EdxlopPhysicalPartitionSelector, &gpopt::CTranslatorDXLToPlStmt::PplanPartitionSelector},
};
const ULONG ulTranslators = GPOS_ARRAY_SIZE(rgTranslators);
for (ULONG ul = 0; ul < ulTranslators; ul++)
{
STranslatorMapping elem = rgTranslators[ul];
m_rgpfTranslators[elem.edxlopid] = elem.pf;
}
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToPlStmt::PplstmtFromDXL
//
// @doc:
// Translate DXL node into a PlannedStmt
//
//---------------------------------------------------------------------------
PlannedStmt *
CTranslatorDXLToPlStmt::PplstmtFromDXL
(
const CDXLNode *pdxln,
bool canSetTag
)
{
GPOS_ASSERT(NULL != pdxln);
CDXLTranslateContext dxltrctx(m_pmp, false);
DrgPdxltrctx *pdrgpdxltrctxPrevSiblings = GPOS_NEW(m_pmp) DrgPdxltrctx(m_pmp);
Plan *pplan = PplFromDXL(pdxln, &dxltrctx, NULL, pdrgpdxltrctxPrevSiblings);
pdrgpdxltrctxPrevSiblings->Release();
GPOS_ASSERT(NULL != pplan);
// collect oids from rtable
List *plOids = NIL;
ListCell *plcRTE = NULL;
ForEach (plcRTE, m_pctxdxltoplstmt->PlPrte())
{
RangeTblEntry *pRTE = (RangeTblEntry *) lfirst(plcRTE);
if (pRTE->rtekind == RTE_RELATION)
{
plOids = gpdb::PlAppendOid(plOids, pRTE->relid);
}
}
// assemble planned stmt
PlannedStmt *pplstmt = MakeNode(PlannedStmt);
pplstmt->planGen = PLANGEN_OPTIMIZER;
pplstmt->rtable = m_pctxdxltoplstmt->PlPrte();
pplstmt->subplans = m_pctxdxltoplstmt->PlPplanSubplan();
pplstmt->planTree = pplan;
// store partitioned table indexes in planned stmt
pplstmt->queryPartOids = m_pctxdxltoplstmt->PlPartitionedTables();
pplstmt->canSetTag = canSetTag;
pplstmt->relationOids = plOids;
pplstmt->numSelectorsPerScanId = m_pctxdxltoplstmt->PlNumPartitionSelectors();
pplan->nMotionNodes = m_pctxdxltoplstmt->UlCurrentMotionId()-1;
pplstmt->nMotionNodes = m_pctxdxltoplstmt->UlCurrentMotionId()-1;
pplstmt->commandType = m_cmdtype;
GPOS_ASSERT(pplan->nMotionNodes >= 0);
if (0 == pplan->nMotionNodes && !m_fTargetTableDistributed)
{
// no motion nodes and not a DML on a distributed table
pplan->dispatch = DISPATCH_SEQUENTIAL;
}
else
{
pplan->dispatch = DISPATCH_PARALLEL;
}
pplstmt->resultRelations = m_plResultRelations;
pplstmt->intoClause = m_pctxdxltoplstmt->Pintocl();
pplstmt->intoPolicy = m_pctxdxltoplstmt->Pdistrpolicy();
SetInitPlanVariables(pplstmt);
if (CMD_SELECT == m_cmdtype && NULL != pdxln->Pdxlddinfo())
{
List *plDirectDispatchSegIds = PlDirectDispatchSegIds(pdxln->Pdxlddinfo());
pplan->directDispatch.contentIds = plDirectDispatchSegIds;
pplan->directDispatch.isDirectDispatch = (NIL != plDirectDispatchSegIds);
if (pplan->directDispatch.isDirectDispatch)
{
List *plMotions = gpdb::PlExtractNodesPlan(pplstmt->planTree, T_Motion, true /*descendIntoSubqueries*/);
ListCell *plc = NULL;
ForEach(plc, plMotions)
{
Motion *pmotion = (Motion *) lfirst(plc);
GPOS_ASSERT(IsA(pmotion, Motion));
GPOS_ASSERT(gpdb::FMotionGather(pmotion));
pmotion->plan.directDispatch.isDirectDispatch = true;
pmotion->plan.directDispatch.contentIds = pplan->directDispatch.contentIds;
}
}
}
return pplstmt;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToPlStmt::PplFromDXL
//
// @doc:
// Translates a DXL tree into a Plan node
//
//---------------------------------------------------------------------------
Plan *
CTranslatorDXLToPlStmt::PplFromDXL
(
const CDXLNode *pdxln,
CDXLTranslateContext *pdxltrctxOut,
Plan *pplanParent,
DrgPdxltrctx *pdrgpdxltrctxPrevSiblings
)
{
GPOS_ASSERT(NULL != pdxln);
GPOS_ASSERT(NULL != pdrgpdxltrctxPrevSiblings);
CDXLOperator *pdxlop = pdxln->Pdxlop();
ULONG ulOpId = (ULONG) pdxlop->Edxlop();
PfPplan pf = m_rgpfTranslators[ulOpId];
if (NULL == pf)
{
GPOS_RAISE(gpdxl::ExmaDXL, gpdxl::ExmiDXL2PlStmtConversion, pdxln->Pdxlop()->PstrOpName()->Wsz());
}
return (this->* pf)(pdxln, pdxltrctxOut, pplanParent, pdrgpdxltrctxPrevSiblings);
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToPlStmt::IPlanId
//
// @doc:
// If pplParent == NULL returns -1 else eeturns the plan id.
//
//---------------------------------------------------------------------------
INT
CTranslatorDXLToPlStmt::IPlanId(Plan* pplParent)
{
if (NULL == pplParent)
{
return GPDXL_ROOT_PLAN_ID;
}
else
{
return pplParent->plan_node_id;
}
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToPlStmt::SetInitPlanVariables
//
// @doc:
// Iterates over the plan to set the qDispSliceId that is found in the plan
// as well as its subplans. Set the number of parameters used in the plan.
//---------------------------------------------------------------------------
void
CTranslatorDXLToPlStmt::SetInitPlanVariables(PlannedStmt* pplstmt)
{
if(1 != m_pctxdxltoplstmt->UlCurrentMotionId()) // For Distributed Tables m_ulMotionId > 1
{
pplstmt->nInitPlans = m_pctxdxltoplstmt->UlCurrentParamId();
pplstmt->planTree->nInitPlans = m_pctxdxltoplstmt->UlCurrentParamId();
}
pplstmt->planTree->nParamExec = m_pctxdxltoplstmt->UlCurrentParamId();
pplstmt->nCrossLevelParams = m_pctxdxltoplstmt->UlCurrentParamId();
// Extract all subplans defined in the planTree
List *plSubPlans = gpdb::PlExtractNodesPlan(pplstmt->planTree, T_SubPlan, true);
ListCell *plc = NULL;
ForEach (plc, plSubPlans)
{
SubPlan *psubplan = (SubPlan*) lfirst(plc);
if (psubplan->is_initplan)
{
SetInitPlanSliceInformation(psubplan);
}
}
// InitPlans can also be defined in subplans. We therefore have to iterate
// over all the subplans referred to in the planned statement.
List *plInitPlans = pplstmt->subplans;
ForEach (plc,plInitPlans)
{
plSubPlans = gpdb::PlExtractNodesPlan((Plan*) lfirst(plc), T_SubPlan, true);
ListCell *plc2;
ForEach (plc2, plSubPlans)
{
SubPlan *psubplan = (SubPlan*) lfirst(plc2);
if (psubplan->is_initplan)
{
SetInitPlanSliceInformation(psubplan);
}
}
}
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToPlStmt::SetInitPlanSliceInformation
//
// @doc:
// Set the qDispSliceId for a given subplans. In GPDB once all motion node
// have been assigned a slice, each initplan is assigned a slice number.
// The initplan are traversed in an postorder fashion. Since in CTranslatorDXLToPlStmt
// we assign the plan_id to each initplan in a postorder fashion, we take
// advantage of this.
//
//---------------------------------------------------------------------------
void
CTranslatorDXLToPlStmt::SetInitPlanSliceInformation(SubPlan * psubplan)
{
GPOS_ASSERT(psubplan->is_initplan && "This is processed for initplans only");
if (psubplan->is_initplan)
{
GPOS_ASSERT(0 < m_pctxdxltoplstmt->UlCurrentMotionId());
if(1 < m_pctxdxltoplstmt->UlCurrentMotionId())
{
psubplan->qDispSliceId = m_pctxdxltoplstmt->UlCurrentMotionId() + psubplan->plan_id-1;
}
else
{
psubplan->qDispSliceId = 0;
}
}
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToPlStmt::SetParamIds
//
// @doc:
// Set the bitmapset with the param_ids defined in the plan
//
//---------------------------------------------------------------------------
void
CTranslatorDXLToPlStmt::SetParamIds(Plan* pplan)
{
List *plParams = gpdb::PlExtractNodesPlan(pplan, T_Param, true);
ListCell *plc = NULL;
Bitmapset *pbitmapset = NULL;
ForEach (plc, plParams)
{
Param *pparam = (Param*) lfirst(plc);
pbitmapset = gpdb::PbmsAddMember(pbitmapset, pparam->paramid);
}
pplan->extParam = pbitmapset;
pplan->allParam = pbitmapset;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToPlStmt::MapLocationsFile
//
// @doc:
// Segment mapping for tables with LOCATION http:// or file://
// These two protocols are very similar in that they enforce a 1-URI:1-segdb
// relationship. The only difference between them is that file:// URI must
// be assigned to a segdb on a host that is local to that URI.
//
//---------------------------------------------------------------------------
void
CTranslatorDXLToPlStmt::MapLocationsFile
(
OID oidRel,
char **rgszSegFileMap,
List *segments
)
{
// extract file path and name from URI strings and assign them a primary segdb
ExtTableEntry *extentry = gpdb::Pexttable(oidRel);
ListCell *plcLocation = NULL;
ForEach (plcLocation, extentry->locations)
{
Value* pvLocation = (Value *)lfirst(plcLocation);
CHAR *szUri = pvLocation->val.str;
Uri *pUri = gpdb::PuriParseExternalTable(szUri);
BOOL fCandidateFound = false;
BOOL fMatchFound = false;
ListCell *lcSegment;
// try to find a segment database that can handle this uri
ForEach(lcSegment, segments)
{
Segment *segment = (Segment *)lfirst(lcSegment);
INT iSegInd = segment->segindex;
if (segment->alive)
{
if (URI_FILE == pUri->protocol &&
0 != gpdb::IStrCmpIgnoreCase(pUri->hostname, segment->hostname) &&
0 != gpdb::IStrCmpIgnoreCase(pUri->hostname, segment->hostip) &&
0 != gpdb::IStrCmpIgnoreCase(pUri->hostname, "localhost"))
{
continue;
}
fCandidateFound = true;
if (NULL == rgszSegFileMap[iSegInd])
{
rgszSegFileMap[iSegInd] = PStrDup(szUri);
fMatchFound = true;
}
}
if (fMatchFound)
{
break;
}
}
}
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToPlStmt::MapLocationsFdist
//
// @doc:
// Segment mapping for tables with LOCATION gpfdist(s):// or custom protocol
// The user supplied gpfdist(s):// URIs are duplicated so that there is one
// available to every segdb. However, in some cases (as determined by
// gp_external_max_segs GUC) we don't want to use *all* segdbs but instead
// figure out how many and pick them randomly (for better performance)
//
//---------------------------------------------------------------------------
void
CTranslatorDXLToPlStmt::MapLocationsFdist
(
OID oidRel,
char **rgszSegFileMap,
List *segments,
Uri *pUri,
const ULONG ulTotalPrimaries,
IMDId *pmdidRel,
List *plQuals
)
{
ULONG ulParticipatingSegments = ulTotalPrimaries;
ULONG ulMaxParticipants = ulParticipatingSegments;
ExtTableEntry *extentry = gpdb::Pexttable(oidRel);
const ULONG ulLocations = gpdb::UlListLength(extentry->locations);
BOOL fPxfProtocol = gpdb::FPxfProtocol(pUri);
if (URI_GPFDIST == pUri->protocol || URI_GPFDISTS == pUri->protocol)
{
ulMaxParticipants = ulLocations * gp_external_max_segs;
}
else if (fPxfProtocol)
{
ulMaxParticipants = gpdb::IMaxParticipantsPxf(ulTotalPrimaries);
if(ulParticipatingSegments > ulMaxParticipants)
elog(NOTICE, "External scan using PXF protocol will utilize %d out "
"of %d segment databases", ulMaxParticipants, ulParticipatingSegments);
ulParticipatingSegments = ulMaxParticipants;
}
ULONG ulSkip = 0;
BOOL fSkipRandomly = false;
if (ulParticipatingSegments > ulMaxParticipants)
{
elog(NOTICE, "External scan using GPFDIST protocol will utilize %d out "
"of %d segment databases", ulMaxParticipants, ulParticipatingSegments);
ulSkip = ulParticipatingSegments - ulMaxParticipants;
ulParticipatingSegments = ulMaxParticipants;
fSkipRandomly = true;
}
if (ulLocations > ulParticipatingSegments)
{
GPOS_RAISE(gpdxl::ExmaDXL, gpdxl::ExmiDXL2PlStmtExternalScanError,
GPOS_WSZ_LIT("There are more external files (URLs) than primary segments that can read them"));
}
BOOL fDone = false;
List *plModifiedLocations = NIL;
ULONG ulModifiedLocations = 0;
while (!fDone)
{
ListCell *plcLocation = NULL;
ForEach (plcLocation, extentry->locations)
{
Value* pvLocation = (Value *)lfirst(plcLocation);
CHAR *szUri = pvLocation->val.str;
plModifiedLocations = gpdb::PlAppendElement(plModifiedLocations, gpdb::PvalMakeString(szUri));
ulModifiedLocations ++;
if (ulModifiedLocations == ulParticipatingSegments)
{
fDone = true;
break;
}
if (ulModifiedLocations > ulParticipatingSegments)
{
GPOS_RAISE(gpdxl::ExmaDXL, gpdxl::ExmiDXL2PlStmtExternalScanError,
GPOS_WSZ_LIT("External scan location list failed building distribution"));
}
}
}
BOOL *rgfSkipMap = NULL;
if (fSkipRandomly)
{
rgfSkipMap = gpdb::RgfRandomSegMap(ulTotalPrimaries, ulSkip);
}
CHAR **rgszSegWorkMap = NULL;
if (fPxfProtocol)
{
Relation rel = gpdb::RelGetRelation(CMDIdGPDB::PmdidConvert(pmdidRel)->OidObjectId());
if (NULL == rel)
{
GPOS_RAISE(gpdxl::ExmaMD, gpdxl::ExmiMDCacheEntryNotFound, pmdidRel->Wsz());
}
GPOS_TRY
{
Value *pvUri = (Value *) gpdb::PvListNth(extentry->locations, 0);
CHAR * szUri = pvUri->val.str;
rgszSegWorkMap = gpdb::RgszMapHdDataToSegments(szUri, ulTotalPrimaries, ulMaxParticipants, rel, plQuals);
GPOS_ASSERT(NULL != rgszSegWorkMap);
gpdb::CloseRelation(rel);
}
GPOS_CATCH_EX(ex)
{
gpdb::CloseRelation(rel);
GPOS_RETHROW(ex);
}
GPOS_CATCH_END;
}
// assign each URI from the new location list a primary segdb
ListCell *plc = NULL;
ForEach (plc, plModifiedLocations)
{
const CHAR *szUri = (CHAR *) strVal(lfirst(plc));
BOOL fCandidateFound = false;
BOOL fMatchFound = false;
ListCell *lcSegment;
ForEach(lcSegment, segments)
{
Segment *segment = (Segment *)lfirst(lcSegment);
INT iSegInd = segment->segindex;
if (!segment->alive)
{
continue;
}
if (fSkipRandomly)
{
GPOS_ASSERT(iSegInd < ulTotalPrimaries);
if (rgfSkipMap[iSegInd])
{
continue;
}
}
fCandidateFound = true;
if (NULL == rgszSegFileMap[iSegInd])
{
if (!fPxfProtocol)
{
rgszSegFileMap[iSegInd] = PStrDup(szUri);
fMatchFound = true;
break;
}
else if (NULL != rgszSegWorkMap[iSegInd])
{
CHAR cDelim = '?';
StringInfoData seg_uri;
gpdb::InitStringInfoOfSize(&seg_uri, 512 /*size*/);
gpdb::AppendStringInfoString(&seg_uri, szUri);
// if the segwork string is the first option we delimit it with '?' otherwise with '&'
if (NULL != gpos::clib::SzStrChr(szUri, '?'))
{
cDelim = '&';
}
gpdb::AppendStringInfoChar(&seg_uri, cDelim);
gpdb::AppendStringInfoString(&seg_uri, rgszSegWorkMap[iSegInd]);
rgszSegFileMap[iSegInd] = seg_uri.data;
fMatchFound = true;
}
}
}
if (!fMatchFound && !fPxfProtocol)
{
GPOS_RAISE(gpdxl::ExmaDXL, gpdxl::ExmiDXL2PlStmtExternalScanError,
GPOS_WSZ_LIT("Unable to assign segments for gpfdist(s)"));
}
}
if (fPxfProtocol)
{
gpdb::FreeHdDataToSegmentsMapping(rgszSegWorkMap, ulTotalPrimaries);
}
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToPlStmt::MapLocationsExecute
//
// @doc:
// Segment mapping for tables with EXECUTE 'cmd' ON.
// In here we don't have URI's. We have a single command string and a
// specification of the segdb granularity it should get executed on (the
// ON clause). Depending on the ON clause specification we could go many
// different ways, for example: assign the command to all segdb, or one
// command per host, or assign to 5 random segments, etc...
//
//---------------------------------------------------------------------------
void
CTranslatorDXLToPlStmt::MapLocationsExecute
(
OID oidRel,
char **rgszSegFileMap,
List *segments,
const ULONG ulTotalPrimaries
)
{
ExtTableEntry *extentry = gpdb::Pexttable(oidRel);
CHAR *szCommand = extentry->command;
const CHAR *szPrefix = "execute:";
StringInfo si = gpdb::SiMakeStringInfo();
gpdb::AppendStringInfo(si, szPrefix, szCommand);
CHAR *szPrefixedCommand = PStrDup(si->data);
gpdb::GPDBFree(si->data);
gpdb::GPDBFree(si);
si = NULL;
// get the ON clause (execute location) information
Value *pvOnClause = (Value *) gpdb::PvListNth(extentry->locations, 0);
CHAR *szOnClause = pvOnClause->val.str;
if (0 == gpos::clib::IStrCmp(szOnClause, "ALL_SEGMENTS"))
{
MapLocationsExecuteAllSegments(szPrefixedCommand, rgszSegFileMap, segments);
}
else if (0 == gpos::clib::IStrCmp(szOnClause, "PER_HOST"))
{
MapLocationsExecutePerHost(szPrefixedCommand, rgszSegFileMap, segments);
}
else if (0 == gpos::clib::IStrNCmp(szOnClause, "HOST:", gpos::clib::UlStrLen("HOST:")))
{
CHAR *szHostName = szOnClause + gpos::clib::UlStrLen("HOST:");
MapLocationsExecuteOneHost(szHostName, szPrefixedCommand, rgszSegFileMap, segments);
}
else if (0 == gpos::clib::IStrNCmp(szOnClause, "SEGMENT_ID:", gpos::clib::UlStrLen("SEGMENT_ID:")))
{
CHAR *pcEnd = NULL;
INT iTargetSegInd = (INT) gpos::clib::LStrToL(szOnClause + gpos::clib::UlStrLen("SEGMENT_ID:"), &pcEnd, 10);
MapLocationsExecuteOneSegment(iTargetSegInd, szPrefixedCommand, rgszSegFileMap, segments);
}
else if (0 == gpos::clib::IStrNCmp(szOnClause, "TOTAL_SEGS:", gpos::clib::UlStrLen("TOTAL_SEGS:")))
{
// total n segments selected randomly
CHAR *pcEnd = NULL;
ULONG ulSegsToUse = gpos::clib::LStrToL(szOnClause + gpos::clib::UlStrLen("TOTAL_SEGS:"), &pcEnd, 10);
MapLocationsExecuteRandomSegments(ulSegsToUse, ulTotalPrimaries, szPrefixedCommand, rgszSegFileMap, segments);
}
else if (0 == gpos::clib::IStrCmp(szOnClause, "MASTER_ONLY"))
{
rgszSegFileMap[0] = PStrDup(szPrefixedCommand);
}
else
{
GPOS_RAISE(gpdxl::ExmaDXL, gpdxl::ExmiDXL2PlStmtExternalScanError,
GPOS_WSZ_LIT("Invalid ON clause"));
}
gpdb::GPDBFree(szPrefixedCommand);
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToPlStmt::MapLocationsExecuteAllSegments
//
// @doc:
// Segment mapping for tables with EXECUTE 'cmd' on all segments
//
//---------------------------------------------------------------------------
void
CTranslatorDXLToPlStmt::MapLocationsExecuteAllSegments
(
CHAR *szPrefixedCommand,
char **rgszSegFileMap,
List *segments
)
{
ListCell *lcSegment;
ForEach(lcSegment, segments)
{
Segment *segment = (Segment *)lfirst(lcSegment);
INT iSegInd = segment->segindex;
if (segment->alive)
{
rgszSegFileMap[iSegInd] = PStrDup(szPrefixedCommand);
}
}
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToPlStmt::MapLocationsExecutePerHost
//
// @doc:
// Segment mapping for tables with EXECUTE 'cmd' per host
//
//---------------------------------------------------------------------------
void
CTranslatorDXLToPlStmt::MapLocationsExecutePerHost
(
CHAR *szPrefixedCommand,
char **rgszSegFileMap,
List *segments
)
{
List *plVisitedHosts = NIL;
ListCell *lcSegment;
ForEach(lcSegment, segments)
{
Segment *segment = (Segment *)lfirst(lcSegment);
INT iSegInd = segment->segindex;
if (segment->alive)
{
BOOL fHostTaken = false;
ListCell *plc = NULL;
ForEach (plc, plVisitedHosts)
{
const CHAR *szHostName = (CHAR *) strVal(lfirst(plc));
if (0 == gpdb::IStrCmpIgnoreCase(szHostName, segment->hostname))
{
fHostTaken = true;
break;
}
}
if (!fHostTaken)
{
rgszSegFileMap[iSegInd] = PStrDup(szPrefixedCommand);
plVisitedHosts = gpdb::PlAppendElement
(
plVisitedHosts,
gpdb::PvalMakeString(PStrDup(segment->hostname))
);
}
}
}
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToPlStmt::MapLocationsExecuteOneHost
//
// @doc:
// Segment mapping for tables with EXECUTE 'cmd' on a given host
//
//---------------------------------------------------------------------------
void
CTranslatorDXLToPlStmt::MapLocationsExecuteOneHost
(
CHAR *szHostName,
CHAR *szPrefixedCommand,
char **rgszSegFileMap,
List *segments
)
{
BOOL fMatchFound = false;
ListCell *lcSegment;
ForEach(lcSegment, segments)
{
Segment *segment = (Segment *)lfirst(lcSegment);
INT iSegInd = segment->segindex;
if (segment->alive &&
(0 == gpdb::IStrCmpIgnoreCase(szHostName, segment->hostname)))
{
rgszSegFileMap[iSegInd] = PStrDup(szPrefixedCommand);
fMatchFound = true;
}
}
if (!fMatchFound)
{
GPOS_RAISE(gpdxl::ExmaDXL, gpdxl::ExmiDXL2PlStmtExternalScanError,
GPOS_WSZ_LIT("Could not assign a segment database for given command. No valid primary segment was found in the requested host name."));
}
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToPlStmt::MapLocationsExecuteOneSegment
//
// @doc:
// Segment mapping for tables with EXECUTE 'cmd' on a given segment
//
//---------------------------------------------------------------------------
void
CTranslatorDXLToPlStmt::MapLocationsExecuteOneSegment
(
INT iTargetSegInd,
CHAR *szPrefixedCommand,
char **rgszSegFileMap,
List *segments
)
{
BOOL fMatchFound = false;
ListCell *lcSegment;
ForEach(lcSegment, segments)
{
Segment *segment = (Segment *)lfirst(lcSegment);
INT iSegInd = segment->segindex;
if (segment->alive &&
(iSegInd == iTargetSegInd))
{
rgszSegFileMap[iSegInd] = PStrDup(szPrefixedCommand);
fMatchFound = true;
}
}
if(!fMatchFound)
{
GPOS_RAISE(gpdxl::ExmaDXL, gpdxl::ExmiDXL2PlStmtExternalScanError,
GPOS_WSZ_LIT("Could not assign a segment database for given command. The requested segment id is not a valid primary segment."));
}
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToPlStmt::MapLocationsExecuteRandomSegments
//
// @doc:
// Segment mapping for tables with EXECUTE 'cmd' on N random segments
//
//---------------------------------------------------------------------------
void
CTranslatorDXLToPlStmt::MapLocationsExecuteRandomSegments
(
ULONG ulSegments,
const ULONG ulTotalPrimaries,
CHAR *szPrefixedCommand,
char **rgszSegFileMap,
List *segments
)
{
if (ulSegments > ulTotalPrimaries)
{
GPOS_RAISE(gpdxl::ExmaDXL, gpdxl::ExmiDXL2PlStmtExternalScanError,
GPOS_WSZ_LIT("More segments in table definition than valid primary segments in the database."));
}
ULONG ulSkip = ulTotalPrimaries - ulSegments;
BOOL *rgfSkipMap = gpdb::RgfRandomSegMap(ulTotalPrimaries, ulSkip);
ListCell *lcSegment;
ForEach(lcSegment, segments)
{
Segment *segment = (Segment *)lfirst(lcSegment);
INT iSegInd = segment->segindex;
if (segment->alive)
{
GPOS_ASSERT(iSegInd < ulTotalPrimaries);
if (rgfSkipMap[iSegInd])
{
continue;
}
rgszSegFileMap[iSegInd] = PStrDup(szPrefixedCommand);
}
}
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToPlStmt::PlExternalScanUriList
//
// @doc:
// List of URIs for external scan
//
//---------------------------------------------------------------------------
List*
CTranslatorDXLToPlStmt::PlExternalScanUriList
(
OID oidRel,
IMDId *pmdidRel,
List *plQuals
)
{
ExtTableEntry *extentry = gpdb::Pexttable(oidRel);
if (extentry->iswritable)
{
GPOS_RAISE(gpdxl::ExmaDXL, gpdxl::ExmiDXL2PlStmtExternalScanError,
GPOS_WSZ_LIT("It is not possible to read from a WRITABLE external table. Create the table as READABLE instead."));
}
//get the total valid primary segdb count
List *segments = gpdb::PcdbComponentDatabases();
ListCell *lc;
ULONG ulTotalPrimaries = 0;
ForEach(lc, segments)
{
Segment *segment = (Segment *)lfirst(lc);
if (segment->alive)
{
ulTotalPrimaries++;
}
}
char **rgszSegFileMap = NULL;
if (ulTotalPrimaries > 0)
{
rgszSegFileMap = (char **) gpdb::GPDBAlloc(ulTotalPrimaries * sizeof(char *));
gpos::clib::PvMemSet(rgszSegFileMap, 0, ulTotalPrimaries * sizeof(char *));
}
// is this an EXECUTE table or a LOCATION (URI) table
BOOL fUsingExecute = false;
BOOL fUsingLocation = false;
const CHAR *szCommand = extentry->command;
if (NULL != szCommand)
{
if (!gp_external_enable_exec)
{
GPOS_RAISE(gpdxl::ExmaDXL, gpdxl::ExmiDXL2PlStmtExternalScanError,
GPOS_WSZ_LIT("Using external tables with OS level commands is disabled. Use (set gp_external_enable_exec = on) to enable"));
}
fUsingExecute = true;
}
else
{
fUsingLocation = true;
}
GPOS_ASSERT(0 < gpdb::UlListLength(extentry->locations));
CHAR *szFirstUri = NULL;
Uri *pUri = NULL;
if (!fUsingExecute)
{
szFirstUri = ((Value *) gpdb::PvListNth(extentry->locations, 0))->val.str;
pUri = gpdb::PuriParseExternalTable(szFirstUri);
}
if (fUsingLocation && (URI_FILE == pUri->protocol || URI_HTTP == pUri->protocol))
{
if (ulTotalPrimaries > 0)
{
MapLocationsFile(oidRel, rgszSegFileMap, segments);
}
}
else if (fUsingLocation && (URI_GPFDIST == pUri->protocol || URI_GPFDISTS == pUri->protocol || URI_CUSTOM == pUri->protocol))
{
if (ulTotalPrimaries > 0)
{
MapLocationsFdist(oidRel, rgszSegFileMap, segments, pUri, ulTotalPrimaries, pmdidRel, plQuals);
}
}
else if (fUsingExecute)
{
if (ulTotalPrimaries > 0)
{
MapLocationsExecute(oidRel, rgszSegFileMap, segments, ulTotalPrimaries);
}
}
else
{
GPOS_RAISE(gpdxl::ExmaDXL, gpdxl::ExmiDXL2PlStmtExternalScanError, GPOS_WSZ_LIT("Unsupported protocol and/or file location"));
}
// convert array map to a list so it can be serialized as part of the plan
List *plFileNames = NIL;
for (ULONG ul = 0; ul < ulTotalPrimaries; ul++)
{
Value *pval = NULL;
if (NULL != rgszSegFileMap[ul])
{
pval = gpdb::PvalMakeString(rgszSegFileMap[ul]);
}
else
{
// no file for this segdb. add a null entry
pval = MakeNode(Value);
pval->type = T_Null;
}
plFileNames = gpdb::PlAppendElement(plFileNames, pval);
}
return plFileNames;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToPlStmt::PtsFromDXLTblScan
//
// @doc:
// Translates a DXL table scan node into a TableScan node
//
//---------------------------------------------------------------------------
Plan *
CTranslatorDXLToPlStmt::PtsFromDXLTblScan
(
const CDXLNode *pdxlnTblScan,
CDXLTranslateContext *pdxltrctxOut,
Plan *pplanParent,
DrgPdxltrctx *pdrgpdxltrctxPrevSiblings
)
{
// translate table descriptor into a range table entry
CDXLPhysicalTableScan *pdxlopTS = CDXLPhysicalTableScan::PdxlopConvert(pdxlnTblScan->Pdxlop());
// translation context for column mappings in the base relation
CDXLTranslateContextBaseTable dxltrctxbt(m_pmp);
// we will add the new range table entry as the last element of the range table
Index iRel = gpdb::UlListLength(m_pctxdxltoplstmt->PlPrte()) + 1;
const CDXLTableDescr *pdxltabdesc = pdxlopTS->Pdxltabdesc();
IMDId *pmdidRel = pdxltabdesc->Pmdid();
const IMDRelation *pmdrel = m_pmda->Pmdrel(pmdidRel);
const ULONG ulRelCols = pmdrel->UlColumns() - pmdrel->UlSystemColumns();
RangeTblEntry *prte = PrteFromTblDescr(pdxltabdesc, NULL /*pdxlid*/, ulRelCols, iRel, &dxltrctxbt);
GPOS_ASSERT(NULL != prte);
prte->requiredPerms |= ACL_SELECT;
m_pctxdxltoplstmt->AddRTE(prte);
Plan *pplan = NULL;
Plan *pplanReturn = NULL;
if (IMDRelation::ErelstorageExternal == pmdrel->Erelstorage())
{
const IMDRelationExternal *pmdrelext = dynamic_cast<const IMDRelationExternal*>(pmdrel);
OID oidRel = CMDIdGPDB::PmdidConvert(pmdrel->Pmdid())->OidObjectId();
ExtTableEntry *pextentry = gpdb::Pexttable(oidRel);
// create external scan node
ExternalScan *pes = MakeNode(ExternalScan);
pplan = &(pes->scan.plan);
// translate filter
CDXLNode *pdxlnFilter = (*pdxlnTblScan)[EdxltsIndexFilter];
pplan->qual = PlQualFromFilter(pdxlnFilter, &dxltrctxbt, NULL /*pdrgpdxltrctx*/, pdxltrctxOut, pplan);
pes->scan.scanrelid = iRel;
pes->uriList = PlExternalScanUriList(oidRel, pmdidRel, pplan->qual);
Value *pval = gpdb::PvalMakeString(pextentry->fmtopts);
pes->fmtOpts = ListMake1(pval);
pes->fmtType = pextentry->fmtcode;
pes->isMasterOnly = (IMDRelation::EreldistrMasterOnly == pmdrelext->Ereldistribution());
pes->rejLimit = pmdrelext->IRejectLimit();
pes->rejLimitInRows = pmdrelext->FRejLimitInRows();
IMDId *pmdidFmtErrTbl = pmdrelext->PmdidFmtErrRel();
if (NULL == pmdidFmtErrTbl)
{
pes->fmterrtbl = InvalidOid;
}
else
{
pes->fmterrtbl = CMDIdGPDB::PmdidConvert(pmdidFmtErrTbl)->OidObjectId();
}
pes->encoding = pextentry->encoding;
pes->scancounter = m_ulExternalScanCounter++;
pplanReturn = (Plan *) pes;
}
else
{
// create table scan node
TableScan *pts = MakeNode(TableScan);
pts->scanrelid = iRel;
pplan = &(pts->plan);
pplanReturn = (Plan *) pts;
// translate filter
CDXLNode *pdxlnFilter = (*pdxlnTblScan)[EdxltsIndexFilter];
pplan->qual = PlQualFromFilter(pdxlnFilter, &dxltrctxbt, NULL /*pdrgpdxltrctx*/, pdxltrctxOut, pplan);
}
pplan->plan_node_id = m_pctxdxltoplstmt->UlNextPlanId();
pplan->plan_parent_node_id = IPlanId(pplanParent);
pplan->nMotionNodes = 0;
// translate operator costs
TranslatePlanCosts
(
CDXLPhysicalProperties::PdxlpropConvert(pdxlnTblScan->Pdxlprop())->Pdxlopcost(),
&(pplan->startup_cost),
&(pplan->total_cost),
&(pplan->plan_rows),
&(pplan->plan_width)
);
// a table scan node must have 2 children: projection list and filter
GPOS_ASSERT(2 == pdxlnTblScan->UlArity());
// translate proj list
CDXLNode *pdxlnPrL = (*pdxlnTblScan)[EdxltsIndexProjList];
pplan->targetlist = PlTargetListFromProjList(pdxlnPrL, &dxltrctxbt, NULL /*pdrgpdxltrctx*/, pdxltrctxOut, pplan);
SetParamIds(pplan);
return pplanReturn;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToPlStmt::FSetIndexVarAttno
//
// @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::FSetIndexVarAttno
(
Node *pnode,
SContextIndexVarAttno *pctxtidxvarattno
)
{
if (NULL == pnode)
{
return false;
}
if (IsA(pnode, Var) && ((Var *)pnode)->varno != OUTER)
{
INT iAttno = ((Var *)pnode)->varattno;
const IMDRelation *pmdrel = pctxtidxvarattno->m_pmdrel;
const IMDIndex *pmdindex = pctxtidxvarattno->m_pmdindex;
ULONG ulIndexColPos = ULONG_MAX;
const ULONG ulArity = pmdrel->UlColumns();
for (ULONG ulColPos = 0; ulColPos < ulArity; ulColPos++)
{
const IMDColumn *pmdcol = pmdrel->Pmdcol(ulColPos);
if (iAttno == pmdcol->IAttno())
{
ulIndexColPos = ulColPos;
break;
}
}
if (ULONG_MAX > ulIndexColPos)
{
((Var *)pnode)->varattno = 1 + pmdindex->UlPosInKey(ulIndexColPos);
}
return false;
}
return gpdb::FWalkExpressionTree
(
pnode,
(BOOL (*)()) CTranslatorDXLToPlStmt::FSetIndexVarAttno,
pctxtidxvarattno
);
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToPlStmt::PisFromDXLIndexScan
//
// @doc:
// Translates a DXL index scan node into a IndexScan node
//
//---------------------------------------------------------------------------
Plan *
CTranslatorDXLToPlStmt::PisFromDXLIndexScan
(
const CDXLNode *pdxlnIndexScan,
CDXLTranslateContext *pdxltrctxOut,
Plan *pplanParent,
DrgPdxltrctx *pdrgpdxltrctxPrevSiblings
)
{
// translate table descriptor into a range table entry
CDXLPhysicalIndexScan *pdxlopIndexScan = CDXLPhysicalIndexScan::PdxlopConvert(pdxlnIndexScan->Pdxlop());
return PisFromDXLIndexScan(pdxlnIndexScan, pdxlopIndexScan, pdxltrctxOut, pplanParent, false /*fIndexOnlyScan*/, pdrgpdxltrctxPrevSiblings);
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToPlStmt::PisFromDXLIndexScan
//
// @doc:
// Translates a DXL index scan node into a IndexScan node
//
//---------------------------------------------------------------------------
Plan *
CTranslatorDXLToPlStmt::PisFromDXLIndexScan
(
const CDXLNode *pdxlnIndexScan,
CDXLPhysicalIndexScan *pdxlopIndexScan,
CDXLTranslateContext *pdxltrctxOut,
Plan *pplanParent,
BOOL fIndexOnlyScan,
DrgPdxltrctx *pdrgpdxltrctxPrevSiblings
)
{
// translation context for column mappings in the base relation
CDXLTranslateContextBaseTable dxltrctxbt(m_pmp);
Index iRel = gpdb::UlListLength(m_pctxdxltoplstmt->PlPrte()) + 1;
const CDXLIndexDescr *pdxlid = NULL;
if (fIndexOnlyScan)
{
pdxlid = pdxlopIndexScan->Pdxlid();
}
const IMDRelation *pmdrel = m_pmda->Pmdrel(pdxlopIndexScan->Pdxltabdesc()->Pmdid());
const ULONG ulRelCols = pmdrel->UlColumns() - pmdrel->UlSystemColumns();
RangeTblEntry *prte = PrteFromTblDescr(pdxlopIndexScan->Pdxltabdesc(), pdxlid, ulRelCols, iRel, &dxltrctxbt);
GPOS_ASSERT(NULL != prte);
prte->requiredPerms |= ACL_SELECT;
m_pctxdxltoplstmt->AddRTE(prte);
IndexScan *pis = NULL;
GPOS_ASSERT(!fIndexOnlyScan);
pis = MakeNode(IndexScan);
pis->scan.scanrelid = iRel;
CMDIdGPDB *pmdidIndex = CMDIdGPDB::PmdidConvert(pdxlopIndexScan->Pdxlid()->Pmdid());
const IMDIndex *pmdindex = m_pmda->Pmdindex(pmdidIndex);
Oid oidIndex = pmdidIndex->OidObjectId();
GPOS_ASSERT(InvalidOid != oidIndex);
pis->indexid = oidIndex;
Plan *pplan = &(pis->scan.plan);
pplan->plan_node_id = m_pctxdxltoplstmt->UlNextPlanId();
pplan->plan_parent_node_id = IPlanId(pplanParent);
pplan->nMotionNodes = 0;
// translate operator costs
TranslatePlanCosts
(
CDXLPhysicalProperties::PdxlpropConvert(pdxlnIndexScan->Pdxlprop())->Pdxlopcost(),
&(pplan->startup_cost),
&(pplan->total_cost),
&(pplan->plan_rows),
&(pplan->plan_width)
);
// an index scan node must have 3 children: projection list, filter and index condition list
GPOS_ASSERT(3 == pdxlnIndexScan->UlArity());
// translate proj list and filter
CDXLNode *pdxlnPrL = (*pdxlnIndexScan)[EdxlisIndexProjList];
CDXLNode *pdxlnFilter = (*pdxlnIndexScan)[EdxlisIndexFilter];
CDXLNode *pdxlnIndexCondList = (*pdxlnIndexScan)[EdxlisIndexCondition];
// translate proj list
pplan->targetlist = PlTargetListFromProjList(pdxlnPrL, &dxltrctxbt, NULL /*pdrgpdxltrctx*/, pdxltrctxOut, pplan);
// translate index filter
pplan->qual = PlTranslateIndexFilter
(
pdxlnFilter,
pdxltrctxOut,
&dxltrctxbt,
pdrgpdxltrctxPrevSiblings,
pplan
);
pis->indexorderdir = CTranslatorUtils::Scandirection(pdxlopIndexScan->EdxlScanDirection());
// translate index condition list
List *plIndexConditions = NIL;
List *plIndexOrigConditions = NIL;
List *plIndexStratgey = NIL;
List *plIndexSubtype = NIL;
TranslateIndexConditions
(
pdxlnIndexCondList,
pdxlopIndexScan->Pdxltabdesc(),
fIndexOnlyScan,
pmdindex,
pmdrel,
pdxltrctxOut,
&dxltrctxbt,
pdrgpdxltrctxPrevSiblings,
pplan,
&plIndexConditions,
&plIndexOrigConditions,
&plIndexStratgey,
&plIndexSubtype
);
pis->indexqual = plIndexConditions;
pis->indexqualorig = plIndexOrigConditions;
pis->indexstrategy = plIndexStratgey;
pis->indexsubtype = plIndexSubtype;
SetParamIds(pplan);
return (Plan *) pis;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToPlStmt::TranslateIndexFilter
//
// @doc:
// Translate the index filter list in an Index scan
//
//---------------------------------------------------------------------------
List *
CTranslatorDXLToPlStmt::PlTranslateIndexFilter
(
CDXLNode *pdxlnFilter,
CDXLTranslateContext *pdxltrctxOut,
CDXLTranslateContextBaseTable *pdxltrctxbt,
DrgPdxltrctx *pdrgpdxltrctxPrevSiblings,
Plan *pplanParent
)
{
List *plQuals = NIL;
// build colid->var mapping
CMappingColIdVarPlStmt mapcidvarplstmt(m_pmp, pdxltrctxbt, pdrgpdxltrctxPrevSiblings, pdxltrctxOut, m_pctxdxltoplstmt, pplanParent);
const ULONG ulArity = pdxlnFilter->UlArity();
for (ULONG ul = 0; ul < ulArity; ul++)
{
CDXLNode *pdxlnIndexFilter = (*pdxlnFilter)[ul];
Expr *pexprIndexFilter = m_pdxlsctranslator->PexprFromDXLNodeScalar(pdxlnIndexFilter, &mapcidvarplstmt);
plQuals = gpdb::PlAppendElement(plQuals, pexprIndexFilter);
}
return plQuals;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToPlStmt::TranslateIndexConditions
//
// @doc:
// Translate the index condition list in an Index scan
//
//---------------------------------------------------------------------------
void
CTranslatorDXLToPlStmt::TranslateIndexConditions
(
CDXLNode *pdxlnIndexCondList,
const CDXLTableDescr *pdxltd,
BOOL fIndexOnlyScan,
const IMDIndex *pmdindex,
const IMDRelation *pmdrel,
CDXLTranslateContext *pdxltrctxOut,
CDXLTranslateContextBaseTable *pdxltrctxbt,
DrgPdxltrctx *pdrgpdxltrctxPrevSiblings,
Plan *pplanParent,
List **pplIndexConditions,
List **pplIndexOrigConditions,
List **pplIndexStratgey,
List **pplIndexSubtype
)
{
// array of index qual info
DrgPindexqualinfo *pdrgpindexqualinfo = GPOS_NEW(m_pmp) DrgPindexqualinfo(m_pmp);
// build colid->var mapping
CMappingColIdVarPlStmt mapcidvarplstmt(m_pmp, pdxltrctxbt, pdrgpdxltrctxPrevSiblings, pdxltrctxOut, m_pctxdxltoplstmt, pplanParent);
const ULONG ulArity = pdxlnIndexCondList->UlArity();
for (ULONG ul = 0; ul < ulArity; ul++)
{
CDXLNode *pdxlnIndexCond = (*pdxlnIndexCondList)[ul];
Expr *pexprOrigIndexCond = m_pdxlsctranslator->PexprFromDXLNodeScalar(pdxlnIndexCond, &mapcidvarplstmt);
Expr *pexprIndexCond = m_pdxlsctranslator->PexprFromDXLNodeScalar(pdxlnIndexCond, &mapcidvarplstmt);
GPOS_ASSERT((IsA(pexprIndexCond, OpExpr) || IsA(pexprIndexCond, ScalarArrayOpExpr))
&& "expected OpExpr or ScalarArrayOpExpr in index qual");
if (IsA(pexprIndexCond, ScalarArrayOpExpr) && IMDIndex::EmdindBitmap != pmdindex->Emdindt())
{
GPOS_RAISE(gpdxl::ExmaDXL, gpdxl::ExmiDXL2PlStmtConversion, GPOS_WSZ_LIT("ScalarArrayOpExpr condition on index scan"));
}
// for indexonlyscan, we already have the attno referring to the index
if (!fIndexOnlyScan)
{
// Otherwise, we need to perform mapping of Varattnos relative to column positions in index keys
SContextIndexVarAttno ctxtidxvarattno(pmdrel, pmdindex);
FSetIndexVarAttno((Node *) pexprIndexCond, &ctxtidxvarattno);
}
// find index key's attno
List *plistArgs = NULL;
if (IsA(pexprIndexCond, OpExpr))
{
plistArgs = ((OpExpr *) pexprIndexCond)->args;
}
else
{
plistArgs = ((ScalarArrayOpExpr *) pexprIndexCond)->args;
}
Node *pnodeFst = (Node *) lfirst(gpdb::PlcListHead(plistArgs));
Node *pnodeSnd = (Node *) lfirst(gpdb::PlcListTail(plistArgs));
BOOL fRelabel = false;
if (IsA(pnodeFst, RelabelType) && IsA(((RelabelType *) pnodeFst)->arg, Var))
{
pnodeFst = (Node *) ((RelabelType *) pnodeFst)->arg;
fRelabel = true;
}
else if (IsA(pnodeSnd, RelabelType) && IsA(((RelabelType *) pnodeSnd)->arg, Var))
{
pnodeSnd = (Node *) ((RelabelType *) pnodeSnd)->arg;
fRelabel = true;
}
if (fRelabel)
{
List *plNewArgs = ListMake2(pnodeFst, pnodeSnd);
gpdb::GPDBFree(plistArgs);
if (IsA(pexprIndexCond, OpExpr))
{
((OpExpr *) pexprIndexCond)->args = plNewArgs;
}
else
{
((ScalarArrayOpExpr *) pexprIndexCond)->args = plNewArgs;
}
}
GPOS_ASSERT(IsA(pnodeFst, Var) || IsA(pnodeSnd, Var) && "expected index key in index qual");
INT iAttno = 0;
if (IsA(pnodeFst, Var) && ((Var *) pnodeFst)->varno != OUTER)
{
// index key is on the left side
iAttno = ((Var *) pnodeFst)->varattno;
}
else
{
// index key is on the right side
GPOS_ASSERT(((Var *) pnodeSnd)->varno != OUTER && "unexpected outer reference in index qual");
iAttno = ((Var *) pnodeSnd)->varattno;
}
// retrieve index strategy and subtype
INT iSN = 0;
OID oidIndexSubtype = InvalidOid;
BOOL fRecheck = false;
OID oidCmpOperator = CTranslatorUtils::OidCmpOperator(pexprIndexCond);
GPOS_ASSERT(InvalidOid != oidCmpOperator);
OID oidOpclass = CTranslatorUtils::OidIndexQualOpclass(iAttno, CMDIdGPDB::PmdidConvert(pmdindex->Pmdid())->OidObjectId());
GPOS_ASSERT(InvalidOid != oidOpclass);
gpdb::IndexOpProperties(oidCmpOperator, oidOpclass, &iSN, &oidIndexSubtype, &fRecheck);
GPOS_ASSERT(!fRecheck);
// create index qual
pdrgpindexqualinfo->Append(GPOS_NEW(m_pmp) CIndexQualInfo(iAttno, pexprIndexCond, pexprOrigIndexCond, (StrategyNumber) iSN, oidIndexSubtype));
}
// the index quals much be ordered by attribute number
pdrgpindexqualinfo->Sort(CIndexQualInfo::IIndexQualInfoCmp);
ULONG ulLen = pdrgpindexqualinfo->UlLength();
for (ULONG ul = 0; ul < ulLen; ul++)
{
CIndexQualInfo *pindexqualinfo = (*pdrgpindexqualinfo)[ul];
*pplIndexConditions = gpdb::PlAppendElement(*pplIndexConditions, pindexqualinfo->m_pexpr);
*pplIndexOrigConditions = gpdb::PlAppendElement(*pplIndexOrigConditions, pindexqualinfo->m_pexprOriginal);
*pplIndexStratgey = gpdb::PlAppendInt(*pplIndexStratgey, pindexqualinfo->m_sn);
*pplIndexSubtype = gpdb::PlAppendOid(*pplIndexSubtype, pindexqualinfo->m_oidIndexSubtype);
}
// clean up
pdrgpindexqualinfo->Release();
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToPlStmt::PlTranslateAssertConstraints
//
// @doc:
// Translate the constraints from an Assert node into a list of quals
//
//---------------------------------------------------------------------------
List *
CTranslatorDXLToPlStmt::PlTranslateAssertConstraints
(
CDXLNode *pdxlnAssertConstraintList,
CDXLTranslateContext *pdxltrctxOut,
DrgPdxltrctx *pdrgpdxltrctx,
Plan *pplanParent
)
{
List *plQuals = NIL;
// build colid->var mapping
CMappingColIdVarPlStmt mapcidvarplstmt(m_pmp, NULL /*pdxltrctxbt*/, pdrgpdxltrctx, pdxltrctxOut, m_pctxdxltoplstmt, pplanParent);
const ULONG ulArity = pdxlnAssertConstraintList->UlArity();
for (ULONG ul = 0; ul < ulArity; ul++)
{
CDXLNode *pdxlnpdxlnAssertConstraint = (*pdxlnAssertConstraintList)[ul];
Expr *pexprAssertConstraint = m_pdxlsctranslator->PexprFromDXLNodeScalar((*pdxlnpdxlnAssertConstraint)[0], &mapcidvarplstmt);
plQuals = gpdb::PlAppendElement(plQuals, pexprAssertConstraint);
}
return plQuals;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToPlStmt::PlimitFromDXLLimit
//
// @doc:
// Translates a DXL Limit node into a Limit node
//
//---------------------------------------------------------------------------
Plan *
CTranslatorDXLToPlStmt::PlimitFromDXLLimit
(
const CDXLNode *pdxlnLimit,
CDXLTranslateContext *pdxltrctxOut,
Plan *pplanParent,
DrgPdxltrctx *pdrgpdxltrctxPrevSiblings
)
{
// create limit node
Limit *plimit = MakeNode(Limit);
Plan *pplan = &(plimit->plan);
pplan->plan_node_id = m_pctxdxltoplstmt->UlNextPlanId();
pplan->plan_parent_node_id = IPlanId(pplanParent);
// translate operator costs
TranslatePlanCosts
(
CDXLPhysicalProperties::PdxlpropConvert(pdxlnLimit->Pdxlprop())->Pdxlopcost(),
&(pplan->startup_cost),
&(pplan->total_cost),
&(pplan->plan_rows),
&(pplan->plan_width)
);
GPOS_ASSERT(4 == pdxlnLimit->UlArity());
CDXLTranslateContext dxltrctxLeft(m_pmp, false, pdxltrctxOut->PhmColParam());
// translate proj list
CDXLNode *pdxlnPrL = (*pdxlnLimit)[EdxllimitIndexProjList];
CDXLNode *pdxlnChildPlan = (*pdxlnLimit)[EdxllimitIndexChildPlan];
CDXLNode *pdxlnLimitCount = (*pdxlnLimit)[EdxllimitIndexLimitCount];
CDXLNode *pdxlnLimitOffset = (*pdxlnLimit)[EdxllimitIndexLimitOffset];
// NOTE: Limit node has only the left plan while the right plan is left empty
Plan *pplanLeft = PplFromDXL(pdxlnChildPlan, &dxltrctxLeft, pplan, pdrgpdxltrctxPrevSiblings);
DrgPdxltrctx *pdrgpdxltrctx = GPOS_NEW(m_pmp) DrgPdxltrctx(m_pmp);
pdrgpdxltrctx->Append(&dxltrctxLeft);
pplan->targetlist = PlTargetListFromProjList
(
pdxlnPrL,
NULL, // base table translation context
pdrgpdxltrctx,
pdxltrctxOut,
pplan
);
pplan->lefttree = pplanLeft;
if(NULL != pdxlnLimitCount && pdxlnLimitCount->UlArity() >0)
{
CMappingColIdVarPlStmt mapcidvarplstmt(m_pmp, NULL, pdrgpdxltrctx, pdxltrctxOut, m_pctxdxltoplstmt, pplan);
Node *pnodeLimitCount = (Node *) m_pdxlsctranslator->PexprFromDXLNodeScalar((*pdxlnLimitCount)[0], &mapcidvarplstmt);
plimit->limitCount = pnodeLimitCount;
}
if(NULL != pdxlnLimitOffset && pdxlnLimitOffset->UlArity() >0)
{
CMappingColIdVarPlStmt mapcidvarplstmt = CMappingColIdVarPlStmt(m_pmp, NULL, pdrgpdxltrctx, pdxltrctxOut, m_pctxdxltoplstmt, pplan);
Node *pexprLimitOffset = (Node *) m_pdxlsctranslator->PexprFromDXLNodeScalar((*pdxlnLimitOffset)[0], &mapcidvarplstmt);
plimit->limitOffset = pexprLimitOffset;
}
pplan->nMotionNodes = pplanLeft->nMotionNodes;
SetParamIds(pplan);
// cleanup
pdrgpdxltrctx->Release();
return (Plan *) plimit;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToPlStmt::PhjFromDXLHJ
//
// @doc:
// Translates a DXL hash join node into a HashJoin node
//
//---------------------------------------------------------------------------
Plan *
CTranslatorDXLToPlStmt::PhjFromDXLHJ
(
const CDXLNode *pdxlnHJ,
CDXLTranslateContext *pdxltrctxOut,
Plan *pplanParent,
DrgPdxltrctx *pdrgpdxltrctxPrevSiblings
)
{
GPOS_ASSERT(pdxlnHJ->Pdxlop()->Edxlop() == EdxlopPhysicalHashJoin);
GPOS_ASSERT(pdxlnHJ->UlArity() == EdxlhjIndexSentinel);
// create hash join node
HashJoin *phj = MakeNode(HashJoin);
Join *pj = &(phj->join);
Plan *pplan = &(pj->plan);
pplan->plan_node_id = m_pctxdxltoplstmt->UlNextPlanId();
pplan->plan_parent_node_id = IPlanId(pplanParent);
CDXLPhysicalHashJoin *pdxlopHashJoin = CDXLPhysicalHashJoin::PdxlopConvert(pdxlnHJ->Pdxlop());
// set join type
pj->jointype = JtFromEdxljt(pdxlopHashJoin->Edxltype());
pj->prefetch_inner = true;
// translate operator costs
TranslatePlanCosts
(
CDXLPhysicalProperties::PdxlpropConvert(pdxlnHJ->Pdxlprop())->Pdxlopcost(),
&(pplan->startup_cost),
&(pplan->total_cost),
&(pplan->plan_rows),
&(pplan->plan_width)
);
// translate join children
CDXLNode *pdxlnLeft = (*pdxlnHJ)[EdxlhjIndexHashLeft];
CDXLNode *pdxlnRight = (*pdxlnHJ)[EdxlhjIndexHashRight];
CDXLNode *pdxlnPrL = (*pdxlnHJ)[EdxlhjIndexProjList];
CDXLNode *pdxlnFilter = (*pdxlnHJ)[EdxlhjIndexFilter];
CDXLNode *pdxlnJoinFilter = (*pdxlnHJ)[EdxlhjIndexJoinFilter];
CDXLNode *pdxlnHashCondList = (*pdxlnHJ)[EdxlhjIndexHashCondList];
CDXLTranslateContext dxltrctxLeft(m_pmp, false, pdxltrctxOut->PhmColParam());
CDXLTranslateContext dxltrctxRight(m_pmp, false, pdxltrctxOut->PhmColParam());
Plan *pplanLeft = PplFromDXL(pdxlnLeft, &dxltrctxLeft, pplan, pdrgpdxltrctxPrevSiblings);
// the right side of the join is the one where the hash phase is done
DrgPdxltrctx *pdrgpdxltrctxWithSiblings = GPOS_NEW(m_pmp) DrgPdxltrctx(m_pmp);
pdrgpdxltrctxWithSiblings->Append(&dxltrctxLeft);
pdrgpdxltrctxWithSiblings->AppendArray(pdrgpdxltrctxPrevSiblings);
Plan *pplanRight = (Plan*) PhhashFromDXL(pdxlnRight, &dxltrctxRight, pplan, pdrgpdxltrctxWithSiblings);
DrgPdxltrctx *pdrgpdxltrctx = GPOS_NEW(m_pmp) DrgPdxltrctx(m_pmp);
pdrgpdxltrctx->Append(const_cast<CDXLTranslateContext*>(&dxltrctxLeft));
pdrgpdxltrctx->Append(const_cast<CDXLTranslateContext*>(&dxltrctxRight));
// translate proj list and filter
TranslateProjListAndFilter
(
pdxlnPrL,
pdxlnFilter,
NULL, // translate context for the base table
pdrgpdxltrctx,
&pplan->targetlist,
&pplan->qual,
pdxltrctxOut,
pplan
);
// translate join filter
pj->joinqual = PlQualFromFilter
(
pdxlnJoinFilter,
NULL, // translate context for the base table
pdrgpdxltrctx,
pdxltrctxOut,
pplan
);
// translate hash cond
List *plHashConditions = NIL;
BOOL fHasINDFCond = false;
const ULONG ulArity = pdxlnHashCondList->UlArity();
for (ULONG ul = 0; ul < ulArity; ul++)
{
CDXLNode *pdxlnHashCond = (*pdxlnHashCondList)[ul];
List *plHashCond = PlQualFromScalarCondNode
(
pdxlnHashCond,
NULL, // base table translation context
pdrgpdxltrctx,
pdxltrctxOut,
pplan
);
GPOS_ASSERT(1 == gpdb::UlListLength(plHashCond));
Expr *pexpr = (Expr *) LInitial(plHashCond);
if (IsA(pexpr, BoolExpr) && ((BoolExpr *) pexpr)->boolop == NOT_EXPR)
{
// INDF test
GPOS_ASSERT(gpdb::UlListLength(((BoolExpr *) pexpr)->args) == 1 &&
(IsA((Expr *) LInitial(((BoolExpr *) pexpr)->args), DistinctExpr)));
fHasINDFCond = true;
}
plHashConditions = gpdb::PlConcat(plHashConditions, plHashCond);
}
if (!fHasINDFCond)
{
// no INDF conditions in the hash condition list
phj->hashclauses = plHashConditions;
}
else
{
// hash conditions contain INDF clauses -> extract equality conditions to
// construct the hash clauses list
List *plHashClauses = NIL;
for (ULONG ul = 0; ul < ulArity; ul++)
{
CDXLNode *pdxlnHashCond = (*pdxlnHashCondList)[ul];
// condition can be either a scalar comparison or a NOT DISTINCT FROM expression
GPOS_ASSERT(EdxlopScalarCmp == pdxlnHashCond->Pdxlop()->Edxlop() ||
EdxlopScalarBoolExpr == pdxlnHashCond->Pdxlop()->Edxlop());
if (EdxlopScalarBoolExpr == pdxlnHashCond->Pdxlop()->Edxlop())
{
// clause is a NOT DISTINCT FROM check -> extract the distinct comparison node
GPOS_ASSERT(Edxlnot == CDXLScalarBoolExpr::PdxlopConvert(pdxlnHashCond->Pdxlop())->EdxlBoolType());
pdxlnHashCond = (*pdxlnHashCond)[0];
GPOS_ASSERT(EdxlopScalarDistinct == pdxlnHashCond->Pdxlop()->Edxlop());
}
CMappingColIdVarPlStmt mapcidvarplstmt = CMappingColIdVarPlStmt
(
m_pmp,
NULL,
pdrgpdxltrctx,
pdxltrctxOut,
m_pctxdxltoplstmt,
pplan
);
// translate the DXL scalar or scalar distinct comparison into an equality comparison
// to store in the hash clauses
Expr *pexpr2 = (Expr *) m_pdxlsctranslator->PopexprFromDXLNodeScCmp
(
pdxlnHashCond,
&mapcidvarplstmt
);
plHashClauses = gpdb::PlAppendElement(plHashClauses, pexpr2);
}
phj->hashclauses = plHashClauses;
phj->hashqualclauses = plHashConditions;
}
GPOS_ASSERT(NIL != phj->hashclauses);
pplan->lefttree = pplanLeft;
pplan->righttree = pplanRight;
pplan->nMotionNodes = pplanLeft->nMotionNodes + pplanRight->nMotionNodes;
SetParamIds(pplan);
// cleanup
pdrgpdxltrctxWithSiblings->Release();
pdrgpdxltrctx->Release();
return (Plan *) phj;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToPlStmt::PplanFunctionScanFromDXLTVF
//
// @doc:
// Translates a DXL TVF node into a GPDB Function scan node
//
//---------------------------------------------------------------------------
Plan *
CTranslatorDXLToPlStmt::PplanFunctionScanFromDXLTVF
(
const CDXLNode *pdxlnTVF,
CDXLTranslateContext *pdxltrctxOut,
Plan *pplanParent,
DrgPdxltrctx *pdrgpdxltrctxPrevSiblings
)
{
// translation context for column mappings
CDXLTranslateContextBaseTable dxltrctxbt(m_pmp);
// we will add the new range table entry as the last element of the range table
Index iRel = gpdb::UlListLength(m_pctxdxltoplstmt->PlPrte()) + 1;
dxltrctxbt.SetIdx(iRel);
// create function scan node
FunctionScan *pfuncscan = MakeNode(FunctionScan);
pfuncscan->scan.scanrelid = iRel;
Plan *pplan = &(pfuncscan->scan.plan);
RangeTblEntry *prte = PrteFromDXLTVF(pdxlnTVF, pdxltrctxOut, &dxltrctxbt, pplan);
GPOS_ASSERT(NULL != prte);
m_pctxdxltoplstmt->AddRTE(prte);
pplan->plan_node_id = m_pctxdxltoplstmt->UlNextPlanId();
pplan->plan_parent_node_id = IPlanId(pplanParent);
pplan->nMotionNodes = 0;
// translate operator costs
TranslatePlanCosts
(
CDXLPhysicalProperties::PdxlpropConvert(pdxlnTVF->Pdxlprop())->Pdxlopcost(),
&(pplan->startup_cost),
&(pplan->total_cost),
&(pplan->plan_rows),
&(pplan->plan_width)
);
// a table scan node must have at least 1 child: projection list
GPOS_ASSERT(1 <= pdxlnTVF->UlArity());
CDXLNode *pdxlnPrL = (*pdxlnTVF)[EdxltsIndexProjList];
// translate proj list
List *plTargetList = PlTargetListFromProjList
(
pdxlnPrL,
&dxltrctxbt,
NULL,
pdxltrctxOut,
pplan
);
pplan->targetlist = plTargetList;
ListCell *plcTe = NULL;
ForEach (plcTe, plTargetList)
{
TargetEntry *pte = (TargetEntry *) lfirst(plcTe);
OID oidType = gpdb::OidExprType((Node*) pte->expr);
GPOS_ASSERT(InvalidOid != oidType);
INT typMod = gpdb::IExprTypeMod((Node*) pte->expr);
prte->funccoltypes = gpdb::PlAppendOid(prte->funccoltypes, oidType);
prte->funccoltypmods = gpdb::PlAppendInt(prte->funccoltypmods, typMod);
}
SetParamIds(pplan);
return (Plan *) pfuncscan;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToPlStmt::PrteFromDXLTVF
//
// @doc:
// Create a range table entry from a CDXLPhysicalTVF node
//
//---------------------------------------------------------------------------
RangeTblEntry *
CTranslatorDXLToPlStmt::PrteFromDXLTVF
(
const CDXLNode *pdxlnTVF,
CDXLTranslateContext *pdxltrctxOut,
CDXLTranslateContextBaseTable *pdxltrctxbt,
Plan *pplanParent
)
{
CDXLPhysicalTVF *pdxlop = CDXLPhysicalTVF::PdxlopConvert(pdxlnTVF->Pdxlop());
RangeTblEntry *prte = MakeNode(RangeTblEntry);
prte->rtekind = RTE_FUNCTION;
FuncExpr *pfuncexpr = MakeNode(FuncExpr);
pfuncexpr->funcid = CMDIdGPDB::PmdidConvert(pdxlop->PmdidFunc())->OidObjectId();
pfuncexpr->funcretset = true;
// this is a function call, as opposed to a cast
pfuncexpr->funcformat = COERCE_EXPLICIT_CALL;
pfuncexpr->funcresulttype = CMDIdGPDB::PmdidConvert(pdxlop->PmdidRetType())->OidObjectId();
Alias *palias = MakeNode(Alias);
palias->colnames = NIL;
// get function alias
palias->aliasname = CTranslatorUtils::SzFromWsz(pdxlop->Pstr()->Wsz());
// project list
CDXLNode *pdxlnPrL = (*pdxlnTVF)[EdxltsIndexProjList];
// get column names
const ULONG ulCols = pdxlnPrL->UlArity();
for (ULONG ul = 0; ul < ulCols; ul++)
{
CDXLNode *pdxlnPrElem = (*pdxlnPrL)[ul];
CDXLScalarProjElem *pdxlopPrEl = CDXLScalarProjElem::PdxlopConvert(pdxlnPrElem->Pdxlop());
CHAR *szColName = CTranslatorUtils::SzFromWsz(pdxlopPrEl->PmdnameAlias()->Pstr()->Wsz());
Value *pvalColName = gpdb::PvalMakeString(szColName);
palias->colnames = gpdb::PlAppendElement(palias->colnames, pvalColName);
// save mapping col id -> index in translate context
(void) pdxltrctxbt->FInsertMapping(pdxlopPrEl->UlId(), ul+1 /*iAttno*/);
}
// function arguments
const ULONG ulChildren = pdxlnTVF->UlArity();
for (ULONG ul = 1; ul < ulChildren; ++ul)
{
CDXLNode *pdxlnFuncArg = (*pdxlnTVF)[ul];
CMappingColIdVarPlStmt mapcidvarplstmt
(
m_pmp,
pdxltrctxbt,
NULL,
pdxltrctxOut,
m_pctxdxltoplstmt,
pplanParent
);
Expr *pexprFuncArg = m_pdxlsctranslator->PexprFromDXLNodeScalar(pdxlnFuncArg, &mapcidvarplstmt);
pfuncexpr->args = gpdb::PlAppendElement(pfuncexpr->args, pexprFuncArg);
}
prte->funcexpr = (Node *)pfuncexpr;
prte->inFromCl = true;
prte->eref = palias;
return prte;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToPlStmt::PnljFromDXLNLJ
//
// @doc:
// Translates a DXL nested loop join node into a NestLoop plan node
//
//---------------------------------------------------------------------------
Plan *
CTranslatorDXLToPlStmt::PnljFromDXLNLJ
(
const CDXLNode *pdxlnNLJ,
CDXLTranslateContext *pdxltrctxOut,
Plan *pplanParent,
DrgPdxltrctx *pdrgpdxltrctxPrevSiblings
)
{
GPOS_ASSERT(pdxlnNLJ->Pdxlop()->Edxlop() == EdxlopPhysicalNLJoin);
GPOS_ASSERT(pdxlnNLJ->UlArity() == EdxlnljIndexSentinel);
// create hash join node
NestLoop *pnlj = MakeNode(NestLoop);
Join *pj = &(pnlj->join);
Plan *pplan = &(pj->plan);
pplan->plan_node_id = m_pctxdxltoplstmt->UlNextPlanId();
pplan->plan_parent_node_id = IPlanId(pplanParent);
CDXLPhysicalNLJoin *pdxlnlj = CDXLPhysicalNLJoin::PdxlConvert(pdxlnNLJ->Pdxlop());
// set join type
pj->jointype = JtFromEdxljt(pdxlnlj->Edxltype());
// translate operator costs
TranslatePlanCosts
(
CDXLPhysicalProperties::PdxlpropConvert(pdxlnNLJ->Pdxlprop())->Pdxlopcost(),
&(pplan->startup_cost),
&(pplan->total_cost),
&(pplan->plan_rows),
&(pplan->plan_width)
);
// translate join children
CDXLNode *pdxlnLeft = (*pdxlnNLJ)[EdxlnljIndexLeftChild];
CDXLNode *pdxlnRight = (*pdxlnNLJ)[EdxlnljIndexRightChild];
CDXLNode *pdxlnPrL = (*pdxlnNLJ)[EdxlnljIndexProjList];
CDXLNode *pdxlnFilter = (*pdxlnNLJ)[EdxlnljIndexFilter];
CDXLNode *pdxlnJoinFilter = (*pdxlnNLJ)[EdxlnljIndexJoinFilter];
CDXLTranslateContext dxltrctxLeft(m_pmp, false, pdxltrctxOut->PhmColParam());
CDXLTranslateContext dxltrctxRight(m_pmp, false, pdxltrctxOut->PhmColParam());
// 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
pj->prefetch_inner = !pdxlnlj->FIndexNLJ();
DrgPdxltrctx *pdrgpdxltrctxWithSiblings = GPOS_NEW(m_pmp) DrgPdxltrctx(m_pmp);
Plan *pplanLeft = NULL;
Plan *pplanRight = NULL;
if (pdxlnlj->FIndexNLJ())
{
// 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
pplanLeft = PplFromDXL(pdxlnLeft, &dxltrctxLeft, pplan, pdrgpdxltrctxPrevSiblings);
pdrgpdxltrctxWithSiblings->Append(&dxltrctxLeft);
pdrgpdxltrctxWithSiblings->AppendArray(pdrgpdxltrctxPrevSiblings);
// translate right child after left child translation is complete
pplanRight = PplFromDXL(pdxlnRight, &dxltrctxRight, pplan, pdrgpdxltrctxWithSiblings);
}
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
pplanRight = PplFromDXL(pdxlnRight, &dxltrctxRight, pplan, pdrgpdxltrctxPrevSiblings);
pdrgpdxltrctxWithSiblings->Append(&dxltrctxRight);
pdrgpdxltrctxWithSiblings->AppendArray(pdrgpdxltrctxPrevSiblings);
// translate left child after right child translation is complete
pplanLeft = PplFromDXL(pdxlnLeft, &dxltrctxLeft, pplan, pdrgpdxltrctxWithSiblings);
}
DrgPdxltrctx *pdrgpdxltrctx = GPOS_NEW(m_pmp) DrgPdxltrctx(m_pmp);
pdrgpdxltrctx->Append(&dxltrctxLeft);
pdrgpdxltrctx->Append(&dxltrctxRight);
// translate proj list and filter
TranslateProjListAndFilter
(
pdxlnPrL,
pdxlnFilter,
NULL, // translate context for the base table
pdrgpdxltrctx,
&pplan->targetlist,
&pplan->qual,
pdxltrctxOut,
pplan
);
// translate join condition
pj->joinqual = PlQualFromFilter
(
pdxlnJoinFilter,
NULL, // translate context for the base table
pdrgpdxltrctx,
pdxltrctxOut,
pplan
);
pplan->lefttree = pplanLeft;
pplan->righttree = pplanRight;
pplan->nMotionNodes = pplanLeft->nMotionNodes + pplanRight->nMotionNodes;
SetParamIds(pplan);
// cleanup
pdrgpdxltrctxWithSiblings->Release();
pdrgpdxltrctx->Release();
return (Plan *) pnlj;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToPlStmt::PmjFromDXLMJ
//
// @doc:
// Translates a DXL merge join node into a MergeJoin node
//
//---------------------------------------------------------------------------
Plan *
CTranslatorDXLToPlStmt::PmjFromDXLMJ
(
const CDXLNode *pdxlnMJ,
CDXLTranslateContext *pdxltrctxOut,
Plan *pplanParent,
DrgPdxltrctx *pdrgpdxltrctxPrevSiblings
)
{
GPOS_ASSERT(pdxlnMJ->Pdxlop()->Edxlop() == EdxlopPhysicalMergeJoin);
GPOS_ASSERT(pdxlnMJ->UlArity() == EdxlmjIndexSentinel);
// create merge join node
MergeJoin *pmj = MakeNode(MergeJoin);
Join *pj = &(pmj->join);
Plan *pplan = &(pj->plan);
pplan->plan_node_id = m_pctxdxltoplstmt->UlNextPlanId();
pplan->plan_parent_node_id = IPlanId(pplanParent);
CDXLPhysicalMergeJoin *pdxlopMergeJoin = CDXLPhysicalMergeJoin::PdxlopConvert(pdxlnMJ->Pdxlop());
// set join type
pj->jointype = JtFromEdxljt(pdxlopMergeJoin->Edxltype());
// translate operator costs
TranslatePlanCosts
(
CDXLPhysicalProperties::PdxlpropConvert(pdxlnMJ->Pdxlprop())->Pdxlopcost(),
&(pplan->startup_cost),
&(pplan->total_cost),
&(pplan->plan_rows),
&(pplan->plan_width)
);
// translate join children
CDXLNode *pdxlnLeft = (*pdxlnMJ)[EdxlmjIndexLeftChild];
CDXLNode *pdxlnRight = (*pdxlnMJ)[EdxlmjIndexRightChild];
CDXLNode *pdxlnPrL = (*pdxlnMJ)[EdxlmjIndexProjList];
CDXLNode *pdxlnFilter = (*pdxlnMJ)[EdxlmjIndexFilter];
CDXLNode *pdxlnJoinFilter = (*pdxlnMJ)[EdxlmjIndexJoinFilter];
CDXLNode *pdxlnMergeCondList = (*pdxlnMJ)[EdxlmjIndexMergeCondList];
CDXLTranslateContext dxltrctxLeft(m_pmp, false, pdxltrctxOut->PhmColParam());
CDXLTranslateContext dxltrctxRight(m_pmp, false, pdxltrctxOut->PhmColParam());
Plan *pplanLeft = PplFromDXL(pdxlnLeft, &dxltrctxLeft, pplan, pdrgpdxltrctxPrevSiblings);
DrgPdxltrctx *pdrgpdxltrctxWithSiblings = GPOS_NEW(m_pmp) DrgPdxltrctx(m_pmp);
pdrgpdxltrctxWithSiblings->Append(&dxltrctxLeft);
pdrgpdxltrctxWithSiblings->AppendArray(pdrgpdxltrctxPrevSiblings);
Plan *pplanRight = PplFromDXL(pdxlnRight, &dxltrctxRight, pplan, pdrgpdxltrctxWithSiblings);
DrgPdxltrctx *pdrgpdxltrctx = GPOS_NEW(m_pmp) DrgPdxltrctx(m_pmp);
pdrgpdxltrctx->Append(const_cast<CDXLTranslateContext*>(&dxltrctxLeft));
pdrgpdxltrctx->Append(const_cast<CDXLTranslateContext*>(&dxltrctxRight));
// translate proj list and filter
TranslateProjListAndFilter
(
pdxlnPrL,
pdxlnFilter,
NULL, // translate context for the base table
pdrgpdxltrctx,
&pplan->targetlist,
&pplan->qual,
pdxltrctxOut,
pplan
);
// translate join filter
pj->joinqual = PlQualFromFilter
(
pdxlnJoinFilter,
NULL, // translate context for the base table
pdrgpdxltrctx,
pdxltrctxOut,
pplan
);
// translate merge cond
List *plMergeConditions = NIL;
const ULONG ulArity = pdxlnMergeCondList->UlArity();
for (ULONG ul = 0; ul < ulArity; ul++)
{
CDXLNode *pdxlnMergeCond = (*pdxlnMergeCondList)[ul];
List *plMergeCond = PlQualFromScalarCondNode
(
pdxlnMergeCond,
NULL, // base table translation context
pdrgpdxltrctx,
pdxltrctxOut,
pplan
);
GPOS_ASSERT(1 == gpdb::UlListLength(plMergeCond));
plMergeConditions = gpdb::PlConcat(plMergeConditions, plMergeCond);
}
GPOS_ASSERT(NIL != plMergeConditions);
pmj->mergeclauses = plMergeConditions;
pplan->lefttree = pplanLeft;
pplan->righttree = pplanRight;
pplan->nMotionNodes = pplanLeft->nMotionNodes + pplanRight->nMotionNodes;
SetParamIds(pplan);
// cleanup
pdrgpdxltrctxWithSiblings->Release();
pdrgpdxltrctx->Release();
return (Plan *) pmj;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToPlStmt::PhhashFromDXL
//
// @doc:
// Translates a DXL physical operator node into a Hash node
//
//---------------------------------------------------------------------------
Plan *
CTranslatorDXLToPlStmt::PhhashFromDXL
(
const CDXLNode *pdxln,
CDXLTranslateContext *pdxltrctxOut,
Plan *pplanParent,
DrgPdxltrctx *pdrgpdxltrctxPrevSiblings
)
{
Hash *ph = MakeNode(Hash);
Plan *pplan = &(ph->plan);
pplan->plan_node_id = m_pctxdxltoplstmt->UlNextPlanId();
pplan->plan_parent_node_id = IPlanId(pplanParent);
// translate dxl node
CDXLTranslateContext dxltrctx(m_pmp, false, pdxltrctxOut->PhmColParam());
Plan *pplanLeft = PplFromDXL(pdxln, &dxltrctx, pplan, pdrgpdxltrctxPrevSiblings);
GPOS_ASSERT(0 < pdxln->UlArity());
// create a reference to each entry in the child project list to create the target list of
// the hash node
CDXLNode *pdxlnPrL = (*pdxln)[0];
List *plTargetList = PlTargetListForHashNode(pdxlnPrL, &dxltrctx, pdxltrctxOut);
// 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
pplan->startup_cost = pplanLeft->total_cost;
pplan->total_cost = pplanLeft->total_cost;
pplan->plan_rows = pplanLeft->plan_rows;
pplan->plan_width = pplanLeft->plan_width;
pplan->targetlist = plTargetList;
pplan->lefttree = pplanLeft;
pplan->righttree = NULL;
pplan->nMotionNodes = pplanLeft->nMotionNodes;
pplan->qual = NIL;
ph->rescannable = false;
SetParamIds(pplan);
return (Plan *) ph;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToPlStmt::PplanTranslateDXLMotion
//
// @doc:
// Translate DXL motion node
//
//---------------------------------------------------------------------------
Plan *
CTranslatorDXLToPlStmt::PplanTranslateDXLMotion
(
const CDXLNode *pdxlnMotion,
CDXLTranslateContext *pdxltrctxOut,
Plan *pplanParent,
DrgPdxltrctx *pdrgpdxltrctxPrevSiblings
)
{
CDXLPhysicalMotion *pdxlopMotion = CDXLPhysicalMotion::PdxlopConvert(pdxlnMotion->Pdxlop());
if (CTranslatorUtils::FDuplicateSensitiveMotion(pdxlopMotion))
{
return PplanResultHashFilters(pdxlnMotion, pdxltrctxOut, pplanParent, pdrgpdxltrctxPrevSiblings);
}
return PplanMotionFromDXLMotion(pdxlnMotion, pdxltrctxOut, pplanParent, pdrgpdxltrctxPrevSiblings);
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToPlStmt::PplanMotionFromDXLMotion
//
// @doc:
// Translate DXL motion node into GPDB Motion plan node
//
//---------------------------------------------------------------------------
Plan *
CTranslatorDXLToPlStmt::PplanMotionFromDXLMotion
(
const CDXLNode *pdxlnMotion,
CDXLTranslateContext *pdxltrctxOut,
Plan *pplanParent,
DrgPdxltrctx *pdrgpdxltrctxPrevSiblings
)
{
CDXLPhysicalMotion *pdxlopMotion = CDXLPhysicalMotion::PdxlopConvert(pdxlnMotion->Pdxlop());
// create motion node
Motion *pmotion = MakeNode(Motion);
Plan *pplan = &(pmotion->plan);
pplan->plan_node_id = m_pctxdxltoplstmt->UlNextPlanId();
pplan->plan_parent_node_id = IPlanId(pplanParent);
// translate operator costs
TranslatePlanCosts
(
CDXLPhysicalProperties::PdxlpropConvert(pdxlnMotion->Pdxlprop())->Pdxlopcost(),
&(pplan->startup_cost),
&(pplan->total_cost),
&(pplan->plan_rows),
&(pplan->plan_width)
);
CDXLNode *pdxlnPrL = (*pdxlnMotion)[EdxlgmIndexProjList];
CDXLNode *pdxlnFilter = (*pdxlnMotion)[EdxlgmIndexFilter];
CDXLNode *pdxlnSortColList = (*pdxlnMotion)[EdxlgmIndexSortColList];
// translate motion child
// child node is in the same position in broadcast and gather motion nodes
// but different in redistribute motion nodes
ULONG ulChildIndex = pdxlopMotion->UlChildIndex();
CDXLNode *pdxlnChild = (*pdxlnMotion)[ulChildIndex];
CDXLTranslateContext dxltrctxChild(m_pmp, false, pdxltrctxOut->PhmColParam());
Plan *pplanChild = PplFromDXL(pdxlnChild, &dxltrctxChild, pplan, pdrgpdxltrctxPrevSiblings);
DrgPdxltrctx *pdrgpdxltrctx = GPOS_NEW(m_pmp) DrgPdxltrctx(m_pmp);
pdrgpdxltrctx->Append(const_cast<CDXLTranslateContext*>(&dxltrctxChild));
// translate proj list and filter
TranslateProjListAndFilter
(
pdxlnPrL,
pdxlnFilter,
NULL, // translate context for the base table
pdrgpdxltrctx,
&pplan->targetlist,
&pplan->qual,
pdxltrctxOut,
pplan
);
// translate sorting info
ULONG ulNumSortCols = pdxlnSortColList->UlArity();
if (0 < ulNumSortCols)
{
pmotion->sendSorted = true;
pmotion->numSortCols = ulNumSortCols;
pmotion->sortColIdx = (AttrNumber *) gpdb::GPDBAlloc(ulNumSortCols * sizeof(AttrNumber));
pmotion->sortOperators = (Oid *) gpdb::GPDBAlloc(ulNumSortCols * sizeof(Oid));
TranslateSortCols(pdxlnSortColList, pdxltrctxOut, pmotion->sortColIdx, pmotion->sortOperators);
}
else
{
// not a sorting motion
pmotion->sendSorted = false;
pmotion->numSortCols = 0;
pmotion->sortColIdx = NULL;
pmotion->sortOperators = NULL;
}
if (pdxlopMotion->Edxlop() == EdxlopPhysicalMotionRedistribute ||
pdxlopMotion->Edxlop() == EdxlopPhysicalMotionRoutedDistribute ||
pdxlopMotion->Edxlop() == EdxlopPhysicalMotionRandom)
{
// translate hash expr list
List *plHashExpr = NIL;
List *plHashExprTypes = NIL;
if (EdxlopPhysicalMotionRedistribute == pdxlopMotion->Edxlop())
{
CDXLNode *pdxlnHashExprList = (*pdxlnMotion)[EdxlrmIndexHashExprList];
TranslateHashExprList
(
pdxlnHashExprList,
&dxltrctxChild,
&plHashExpr,
&plHashExprTypes,
pdxltrctxOut,
pplan
);
}
GPOS_ASSERT(gpdb::UlListLength(plHashExpr) == gpdb::UlListLength(plHashExprTypes));
pmotion->hashExpr = plHashExpr;
pmotion->hashDataTypes = plHashExprTypes;
}
// cleanup
pdrgpdxltrctx->Release();
// create flow for child node to distinguish between singleton flows and all-segment flows
Flow *pflow = MakeNode(Flow);
const DrgPi *pdrgpiInputSegmentIds = pdxlopMotion->PdrgpiInputSegIds();
if (1 == pdrgpiInputSegmentIds->UlLength())
{
// only one sender - child has a singleton flow
pflow->flotype = FLOW_SINGLETON;
pflow->segindex = *((*pdrgpiInputSegmentIds)[0]);
}
else
{
pflow->flotype = FLOW_UNDEFINED;
}
pplanChild->flow = pflow;
pmotion->motionID = m_pctxdxltoplstmt->UlNextMotionId();
pplan->lefttree = pplanChild;
pplan->nMotionNodes = pplanChild->nMotionNodes + 1;
// translate properties of the specific type of motion operator
switch (pdxlopMotion->Edxlop())
{
case EdxlopPhysicalMotionGather:
{
pmotion->motionType = MOTIONTYPE_FIXED;
// get segment id
INT iSegId = CDXLPhysicalGatherMotion::PdxlopConvert(pdxlopMotion)->IOutputSegIdx();
pmotion->numOutputSegs = 1;
pmotion->outputSegIdx = (INT *) gpdb::GPDBAlloc(sizeof(INT));
*(pmotion->outputSegIdx) = iSegId;
break;
}
case EdxlopPhysicalMotionRedistribute:
case EdxlopPhysicalMotionRandom:
{
pmotion->motionType = MOTIONTYPE_HASH;
// translate output segment ids
const DrgPi *pdrgpiSegIds = CDXLPhysicalMotion::PdxlopConvert(pdxlopMotion)->PdrgpiOutputSegIds();
GPOS_ASSERT(NULL != pdrgpiSegIds && 0 < pdrgpiSegIds->UlLength());
ULONG ulSegIdCount = pdrgpiSegIds->UlLength();
pmotion->outputSegIdx = (INT *) gpdb::GPDBAlloc (ulSegIdCount * sizeof(INT));
pmotion->numOutputSegs = ulSegIdCount;
for(ULONG ul = 0; ul < ulSegIdCount; ul++)
{
INT iSegId = *((*pdrgpiSegIds)[ul]);
pmotion->outputSegIdx[ul] = iSegId;
}
break;
}
case EdxlopPhysicalMotionBroadcast:
{
pmotion->motionType = MOTIONTYPE_FIXED;
pmotion->numOutputSegs = 0;
pmotion->outputSegIdx = NULL;
break;
}
case EdxlopPhysicalMotionRoutedDistribute:
{
pmotion->motionType = MOTIONTYPE_EXPLICIT;
pmotion->numOutputSegs = 0;
pmotion->outputSegIdx = NULL;
ULONG ulSegIdCol = CDXLPhysicalRoutedDistributeMotion::PdxlopConvert(pdxlopMotion)->UlSegmentIdCol();
const TargetEntry *pteSortCol = dxltrctxChild.Pte(ulSegIdCol);
pmotion->segidColIdx = pteSortCol->resno;
break;
}
default:
GPOS_ASSERT(!"Unrecognized Motion operator");
return NULL;
}
SetParamIds(pplan);
return (Plan *) pmotion;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToPlStmt::PplanResultHashFilters
//
// @doc:
// Translate DXL duplicate sensitive redistribute motion node into
// GPDB result node with hash filters
//
//---------------------------------------------------------------------------
Plan *
CTranslatorDXLToPlStmt::PplanResultHashFilters
(
const CDXLNode *pdxlnMotion,
CDXLTranslateContext *pdxltrctxOut,
Plan *pplanParent,
DrgPdxltrctx *pdrgpdxltrctxPrevSiblings
)
{
// create motion node
Result *presult = MakeNode(Result);
Plan *pplan = &(presult->plan);
pplan->plan_node_id = m_pctxdxltoplstmt->UlNextPlanId();
pplan->plan_parent_node_id = IPlanId(pplanParent);
CDXLPhysicalMotion *pdxlopMotion = CDXLPhysicalMotion::PdxlopConvert(pdxlnMotion->Pdxlop());
// translate operator costs
TranslatePlanCosts
(
CDXLPhysicalProperties::PdxlpropConvert(pdxlnMotion->Pdxlprop())->Pdxlopcost(),
&(pplan->startup_cost),
&(pplan->total_cost),
&(pplan->plan_rows),
&(pplan->plan_width)
);
CDXLNode *pdxlnPrL = (*pdxlnMotion)[EdxlrmIndexProjList];
CDXLNode *pdxlnFilter = (*pdxlnMotion)[EdxlrmIndexFilter];
CDXLNode *pdxlnChild = (*pdxlnMotion)[pdxlopMotion->UlChildIndex()];
CDXLTranslateContext dxltrctxChild(m_pmp, false, pdxltrctxOut->PhmColParam());
Plan *pplanChild = PplFromDXL(pdxlnChild, &dxltrctxChild, pplan, pdrgpdxltrctxPrevSiblings);
DrgPdxltrctx *pdrgpdxltrctx = GPOS_NEW(m_pmp) DrgPdxltrctx(m_pmp);
pdrgpdxltrctx->Append(const_cast<CDXLTranslateContext*>(&dxltrctxChild));
// translate proj list and filter
TranslateProjListAndFilter
(
pdxlnPrL,
pdxlnFilter,
NULL, // translate context for the base table
pdrgpdxltrctx,
&pplan->targetlist,
&pplan->qual,
pdxltrctxOut,
pplan
);
// translate hash expr list
presult->hashFilter = true;
if (EdxlopPhysicalMotionRedistribute == pdxlopMotion->Edxlop())
{
CDXLNode *pdxlnHashExprList = (*pdxlnMotion)[EdxlrmIndexHashExprList];
const ULONG ulLength = pdxlnHashExprList->UlArity();
GPOS_ASSERT(0 < ulLength);
for (ULONG ul = 0; ul < ulLength; ul++)
{
CDXLNode *pdxlnHashExpr = (*pdxlnHashExprList)[ul];
CDXLNode *pdxlnExpr = (*pdxlnHashExpr)[0];
INT iResno = INT_MAX;
if (EdxlopScalarIdent == pdxlnExpr->Pdxlop()->Edxlop())
{
ULONG ulColId = CDXLScalarIdent::PdxlopConvert(pdxlnExpr->Pdxlop())->Pdxlcr()->UlID();
iResno = pdxltrctxOut->Pte(ulColId)->resno;
}
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 mapcidvarplstmt = CMappingColIdVarPlStmt
(
m_pmp,
NULL, // translate context for the base table
pdrgpdxltrctx,
pdxltrctxOut,
m_pctxdxltoplstmt,
pplanParent
);
Expr *pexpr = m_pdxlsctranslator->PexprFromDXLNodeScalar(pdxlnExpr, &mapcidvarplstmt);
GPOS_ASSERT(NULL != pexpr);
// create a target entry for the hash filter
CWStringConst strUnnamedCol(GPOS_WSZ_LIT("?column?"));
TargetEntry *pte = gpdb::PteMakeTargetEntry
(
pexpr,
gpdb::UlListLength(pplan->targetlist) + 1,
CTranslatorUtils::SzFromWsz(strUnnamedCol.Wsz()),
false /* resjunk */
);
pplan->targetlist = gpdb::PlAppendElement(pplan->targetlist, pte);
iResno = pte->resno;
}
GPOS_ASSERT(INT_MAX != iResno);
presult->hashList = gpdb::PlAppendInt(presult->hashList, iResno);
}
}
// cleanup
pdrgpdxltrctx->Release();
pplan->lefttree = pplanChild;
pplan->nMotionNodes = pplanChild->nMotionNodes;
SetParamIds(pplan);
return (Plan *) presult;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToPlStmt::PaggFromDXLAgg
//
// @doc:
// Translate DXL aggregate node into GPDB Agg plan node
//
//---------------------------------------------------------------------------
Plan *
CTranslatorDXLToPlStmt::PaggFromDXLAgg
(
const CDXLNode *pdxlnAgg,
CDXLTranslateContext *pdxltrctxOut,
Plan *pplanParent,
DrgPdxltrctx *pdrgpdxltrctxPrevSiblings
)
{
// create aggregate plan node
Agg *pagg = MakeNode(Agg);
Plan *pplan = &(pagg->plan);
pplan->plan_node_id = m_pctxdxltoplstmt->UlNextPlanId();
pplan->plan_parent_node_id = IPlanId(pplanParent);
CDXLPhysicalAgg *pdxlopAgg = CDXLPhysicalAgg::PdxlopConvert(pdxlnAgg->Pdxlop());
// translate operator costs
TranslatePlanCosts
(
CDXLPhysicalProperties::PdxlpropConvert(pdxlnAgg->Pdxlprop())->Pdxlopcost(),
&(pplan->startup_cost),
&(pplan->total_cost),
&(pplan->plan_rows),
&(pplan->plan_width)
);
// translate agg child
CDXLNode *pdxlnChild = (*pdxlnAgg)[EdxlaggIndexChild];
CDXLNode *pdxlnPrL = (*pdxlnAgg)[EdxlaggIndexProjList];
CDXLNode *pdxlnFilter = (*pdxlnAgg)[EdxlaggIndexFilter];
CDXLTranslateContext dxltrctxChild(m_pmp, true, pdxltrctxOut->PhmColParam());
Plan *pplanChild = PplFromDXL(pdxlnChild, &dxltrctxChild, pplan, pdrgpdxltrctxPrevSiblings);
DrgPdxltrctx *pdrgpdxltrctx = GPOS_NEW(m_pmp) DrgPdxltrctx(m_pmp);
pdrgpdxltrctx->Append(const_cast<CDXLTranslateContext*>(&dxltrctxChild));
// translate proj list and filter
TranslateProjListAndFilter
(
pdxlnPrL,
pdxlnFilter,
NULL, // translate context for the base table
pdrgpdxltrctx, // pdxltrctxRight,
&pplan->targetlist,
&pplan->qual,
pdxltrctxOut,
pplan
);
pplan->lefttree = pplanChild;
pplan->nMotionNodes = pplanChild->nMotionNodes;
// translate aggregation strategy
switch (pdxlopAgg->Edxlaggstr())
{
case EdxlaggstrategyPlain:
pagg->aggstrategy = AGG_PLAIN;
break;
case EdxlaggstrategySorted:
pagg->aggstrategy = AGG_SORTED;
break;
case EdxlaggstrategyHashed:
pagg->aggstrategy = AGG_HASHED;
break;
default:
GPOS_ASSERT(!"Invalid aggregation strategy");
}
pagg->streaming = pdxlopAgg->FStreamSafe();
// translate grouping cols
const DrgPul *pdrpulGroupingCols = pdxlopAgg->PdrgpulGroupingCols();
pagg->numCols = pdrpulGroupingCols->UlLength();
if (pagg->numCols > 0)
{
pagg->grpColIdx = (AttrNumber *) gpdb::GPDBAlloc(pagg->numCols * sizeof(AttrNumber));
}
else
{
pagg->grpColIdx = NULL;
}
const ULONG ulLen = pdrpulGroupingCols->UlLength();
for (ULONG ul = 0; ul < ulLen; ul++)
{
ULONG ulGroupingColId = *((*pdrpulGroupingCols)[ul]);
const TargetEntry *pteGroupingCol = dxltrctxChild.Pte(ulGroupingColId);
if (NULL == pteGroupingCol)
{
GPOS_RAISE(gpdxl::ExmaDXL, gpdxl::ExmiDXL2PlStmtAttributeNotFound, ulGroupingColId);
}
pagg->grpColIdx[ul] = pteGroupingCol->resno;
}
SetParamIds(pplan);
// cleanup
pdrgpdxltrctx->Release();
return (Plan *) pagg;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToPlStmt::PwindowFromDXLWindow
//
// @doc:
// Translate DXL window node into GPDB window plan node
//
//---------------------------------------------------------------------------
Plan *
CTranslatorDXLToPlStmt::PwindowFromDXLWindow
(
const CDXLNode *pdxlnWindow,
CDXLTranslateContext *pdxltrctxOut,
Plan *pplanParent,
DrgPdxltrctx *pdrgpdxltrctxPrevSiblings
)
{
// create a window plan node
Window *pwindow = MakeNode(Window);
Plan *pplan = &(pwindow->plan);
pplan->plan_node_id = m_pctxdxltoplstmt->UlNextPlanId();
pplan->plan_parent_node_id = IPlanId(pplanParent);
CDXLPhysicalWindow *pdxlopWindow = CDXLPhysicalWindow::PdxlopConvert(pdxlnWindow->Pdxlop());
// translate the operator costs
TranslatePlanCosts
(
CDXLPhysicalProperties::PdxlpropConvert(pdxlnWindow->Pdxlprop())->Pdxlopcost(),
&(pplan->startup_cost),
&(pplan->total_cost),
&(pplan->plan_rows),
&(pplan->plan_width)
);
// translate children
CDXLNode *pdxlnChild = (*pdxlnWindow)[EdxlwindowIndexChild];
CDXLNode *pdxlnPrL = (*pdxlnWindow)[EdxlwindowIndexProjList];
CDXLNode *pdxlnFilter = (*pdxlnWindow)[EdxlwindowIndexFilter];
CDXLTranslateContext dxltrctxChild(m_pmp, true, pdxltrctxOut->PhmColParam());
Plan *pplanChild = PplFromDXL(pdxlnChild, &dxltrctxChild, pplan, pdrgpdxltrctxPrevSiblings);
DrgPdxltrctx *pdrgpdxltrctx = GPOS_NEW(m_pmp) DrgPdxltrctx(m_pmp);
pdrgpdxltrctx->Append(const_cast<CDXLTranslateContext*>(&dxltrctxChild));
// translate proj list and filter
TranslateProjListAndFilter
(
pdxlnPrL,
pdxlnFilter,
NULL, // translate context for the base table
pdrgpdxltrctx, // pdxltrctxRight,
&pplan->targetlist,
&pplan->qual,
pdxltrctxOut,
pplan
);
pplan->lefttree = pplanChild;
pplan->nMotionNodes = pplanChild->nMotionNodes;
// translate partition columns
const DrgPul *pdrpulPartCols = pdxlopWindow->PrgpulPartCols();
pwindow->numPartCols = pdrpulPartCols->UlLength();
pwindow->partColIdx = NULL;
if (pwindow->numPartCols > 0)
{
pwindow->partColIdx = (AttrNumber *) gpdb::GPDBAlloc(pwindow->numPartCols * sizeof(AttrNumber));
}
const ULONG ulPartCols = pdrpulPartCols->UlLength();
for (ULONG ul = 0; ul < ulPartCols; ul++)
{
ULONG ulPartColId = *((*pdrpulPartCols)[ul]);
const TargetEntry *ptePartCol = dxltrctxChild.Pte(ulPartColId);
if (NULL == ptePartCol)
{
GPOS_RAISE(gpdxl::ExmaDXL, gpdxl::ExmiDXL2PlStmtAttributeNotFound, ulPartColId);
}
pwindow->partColIdx[ul] = ptePartCol->resno;
}
// translate window keys
pwindow->windowKeys = NIL;
const ULONG ulSize = pdxlopWindow->UlWindowKeys();
for (ULONG ul = 0; ul < ulSize; ul++)
{
WindowKey *pwindowkey = MakeNode(WindowKey);
// translate the sorting columns used in the window key
const CDXLWindowKey *pdxlwindowkey = pdxlopWindow->PdxlWindowKey(ul);
const CDXLNode *pdxlnSortColList = pdxlwindowkey->PdxlnSortColList();
const ULONG ulNumCols = pdxlnSortColList->UlArity();
pwindowkey->numSortCols = ulNumCols;
pwindowkey->sortColIdx = (AttrNumber *) gpdb::GPDBAlloc(ulNumCols * sizeof(AttrNumber));
pwindowkey->sortOperators = (Oid *) gpdb::GPDBAlloc(ulNumCols * sizeof(Oid));
TranslateSortCols(pdxlnSortColList, &dxltrctxChild, pwindowkey->sortColIdx, pwindowkey->sortOperators);
// translate the window frame specified in the window key
pwindowkey->frame = NULL;
if (NULL != pdxlwindowkey->Pdxlwf())
{
pwindowkey->frame = Pwindowframe(pdxlwindowkey->Pdxlwf(), &dxltrctxChild, pdxltrctxOut, pplan);
}
pwindow->windowKeys = gpdb::PlAppendElement(pwindow->windowKeys, pwindowkey);
}
SetParamIds(pplan);
// cleanup
pdrgpdxltrctx->Release();
return (Plan *) pwindow;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToPlStmt::Pwindowframe
//
// @doc:
// Translate the DXL window frame into GPDB Window frame node
//
//---------------------------------------------------------------------------
WindowFrame *
CTranslatorDXLToPlStmt::Pwindowframe
(
const CDXLWindowFrame *pdxlwf,
const CDXLTranslateContext *pdxltrctxChild,
CDXLTranslateContext *pdxltrctxOut,
Plan *pplan
)
{
WindowFrame *pwindowframe = MakeNode(WindowFrame);
if (EdxlfsRow == pdxlwf->Edxlfs())
{
pwindowframe->is_rows = true;
}
else
{
pwindowframe->is_rows = false;
}
pwindowframe->is_between = true;
pwindowframe->exclude = CTranslatorUtils::Windowexclusion(pdxlwf->Edxlfes());
// translate the CDXLNodes representing the leading and trailing edge
DrgPdxltrctx *pdrgpdxltrctx = GPOS_NEW(m_pmp) DrgPdxltrctx(m_pmp);
pdrgpdxltrctx->Append(pdxltrctxChild);
CMappingColIdVarPlStmt mapcidvarplstmt = CMappingColIdVarPlStmt
(
m_pmp,
NULL,
pdrgpdxltrctx,
pdxltrctxOut,
m_pctxdxltoplstmt,
pplan
);
CDXLNode *pdxlnLead = pdxlwf->PdxlnLeading();
pwindowframe->lead = MakeNode(WindowFrameEdge);
pwindowframe->lead->kind = CTranslatorUtils::Windowboundkind(CDXLScalarWindowFrameEdge::PdxlopConvert(pdxlnLead->Pdxlop())->Edxlfb());
pwindowframe->lead->val = NULL;
if (0 != pdxlnLead->UlArity())
{
pwindowframe->lead->val = (Node*) m_pdxlsctranslator->PexprFromDXLNodeScalar((*pdxlnLead)[0], &mapcidvarplstmt);
}
CDXLNode *pdxlnTrail = pdxlwf->PdxlnTrailing();
pwindowframe->trail = MakeNode(WindowFrameEdge);
pwindowframe->trail->kind = CTranslatorUtils::Windowboundkind(CDXLScalarWindowFrameEdge::PdxlopConvert(pdxlnTrail->Pdxlop())->Edxlfb());
pwindowframe->trail->val = NULL;
if (0 != pdxlnTrail->UlArity())
{
pwindowframe->trail->val = (Node*) m_pdxlsctranslator->PexprFromDXLNodeScalar((*pdxlnTrail)[0], &mapcidvarplstmt);
}
// cleanup
pdrgpdxltrctx->Release();
return pwindowframe;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToPlStmt::PsortFromDXLSort
//
// @doc:
// Translate DXL sort node into GPDB Sort plan node
//
//---------------------------------------------------------------------------
Plan *
CTranslatorDXLToPlStmt::PsortFromDXLSort
(
const CDXLNode *pdxlnSort,
CDXLTranslateContext *pdxltrctxOut,
Plan *pplanParent,
DrgPdxltrctx *pdrgpdxltrctxPrevSiblings
)
{
// create sort plan node
Sort *psort = MakeNode(Sort);
Plan *pplan = &(psort->plan);
pplan->plan_node_id = m_pctxdxltoplstmt->UlNextPlanId();
pplan->plan_parent_node_id = IPlanId(pplanParent);
CDXLPhysicalSort *pdxlopSort = CDXLPhysicalSort::PdxlopConvert(pdxlnSort->Pdxlop());
// translate operator costs
TranslatePlanCosts
(
CDXLPhysicalProperties::PdxlpropConvert(pdxlnSort->Pdxlprop())->Pdxlopcost(),
&(pplan->startup_cost),
&(pplan->total_cost),
&(pplan->plan_rows),
&(pplan->plan_width)
);
// translate sort child
CDXLNode *pdxlnChild = (*pdxlnSort)[EdxlsortIndexChild];
CDXLNode *pdxlnPrL = (*pdxlnSort)[EdxlsortIndexProjList];
CDXLNode *pdxlnFilter = (*pdxlnSort)[EdxlsortIndexFilter];
CDXLNode *pdxlnLimitCount = (*pdxlnSort)[EdxlsortIndexLimitCount];
CDXLNode *pdxlnLimitOffset = (*pdxlnSort)[EdxlsortIndexLimitOffset];
CDXLTranslateContext dxltrctxChild(m_pmp, false, pdxltrctxOut->PhmColParam());
Plan *pplanChild = PplFromDXL(pdxlnChild, &dxltrctxChild, pplan, pdrgpdxltrctxPrevSiblings);
DrgPdxltrctx *pdrgpdxltrctx = GPOS_NEW(m_pmp) DrgPdxltrctx(m_pmp);
pdrgpdxltrctx->Append(const_cast<CDXLTranslateContext*>(&dxltrctxChild));
// translate proj list and filter
TranslateProjListAndFilter
(
pdxlnPrL,
pdxlnFilter,
NULL, // translate context for the base table
pdrgpdxltrctx,
&pplan->targetlist,
&pplan->qual,
pdxltrctxOut,
pplan
);
pplan->lefttree = pplanChild;
pplan->nMotionNodes = pplanChild->nMotionNodes;
// set sorting info
psort->noduplicates = pdxlopSort->FDiscardDuplicates();
// translate sorting columns
// TODO: antovl - Jan 19, 2011; GPDB only supports nullsLast right now, so nullsFirst is unused
psort->nullsFirst = NULL;
const CDXLNode *pdxlnSortColList = (*pdxlnSort)[EdxlsortIndexSortColList];
const ULONG ulNumCols = pdxlnSortColList->UlArity();
psort->numCols = ulNumCols;
psort->sortColIdx = (AttrNumber *) gpdb::GPDBAlloc(ulNumCols * sizeof(AttrNumber));
psort->sortOperators = (Oid *) gpdb::GPDBAlloc(ulNumCols * sizeof(Oid));
TranslateSortCols(pdxlnSortColList, &dxltrctxChild, psort->sortColIdx, psort->sortOperators);
// translate limit information
if (0 < pdxlnLimitCount->UlArity())
{
GPOS_ASSERT(1 == pdxlnLimitCount->UlArity());
const CDXLNode *pdxlnLimitCountExpr = (*pdxlnLimitCount)[0];
CMappingColIdVarPlStmt mapcidvarplstmt = CMappingColIdVarPlStmt
(
m_pmp,
NULL,
pdrgpdxltrctx,
pdxltrctxOut,
m_pctxdxltoplstmt,
pplan
);
psort->limitCount = (Node *) m_pdxlsctranslator->PexprFromDXLNodeScalar(pdxlnLimitCountExpr, &mapcidvarplstmt);
}
if (0 < pdxlnLimitOffset->UlArity())
{
GPOS_ASSERT(1 == pdxlnLimitOffset->UlArity());
const CDXLNode *pdxlnLimitOffsetExpr = (*pdxlnLimitOffset)[0];
CMappingColIdVarPlStmt mapcidvarplstmt = CMappingColIdVarPlStmt
(
m_pmp,
NULL,
pdrgpdxltrctx,
pdxltrctxOut,
m_pctxdxltoplstmt,
pplan
);
psort->limitOffset = (Node *) m_pdxlsctranslator->PexprFromDXLNodeScalar(pdxlnLimitOffsetExpr, &mapcidvarplstmt);
}
SetParamIds(pplan);
// cleanup
pdrgpdxltrctx->Release();
return (Plan *) psort;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToPlStmt::PsubqscanFromDXLSubqScan
//
// @doc:
// Translate DXL subquery scan node into GPDB SubqueryScan plan node
//
//---------------------------------------------------------------------------
Plan *
CTranslatorDXLToPlStmt::PsubqscanFromDXLSubqScan
(
const CDXLNode *pdxlnSubqScan,
CDXLTranslateContext *pdxltrctxOut,
Plan *pplanParent,
DrgPdxltrctx *pdrgpdxltrctxPrevSiblings
)
{
// create sort plan node
SubqueryScan *psubqscan = MakeNode(SubqueryScan);
Plan *pplan = &(psubqscan->scan.plan);
pplan->plan_node_id = m_pctxdxltoplstmt->UlNextPlanId();
pplan->plan_parent_node_id = IPlanId(pplanParent);
CDXLPhysicalSubqueryScan *pdxlopSubqscan = CDXLPhysicalSubqueryScan::PdxlopConvert(pdxlnSubqScan->Pdxlop());
// translate operator costs
TranslatePlanCosts
(
CDXLPhysicalProperties::PdxlpropConvert(pdxlnSubqScan->Pdxlprop())->Pdxlopcost(),
&(pplan->startup_cost),
&(pplan->total_cost),
&(pplan->plan_rows),
&(pplan->plan_width)
);
// translate subplan
CDXLNode *pdxlnChild = (*pdxlnSubqScan)[EdxlsubqscanIndexChild];
CDXLNode *pdxlnPrL = (*pdxlnSubqScan)[EdxlsubqscanIndexProjList];
CDXLNode *pdxlnFilter = (*pdxlnSubqScan)[EdxlsubqscanIndexFilter];
CDXLTranslateContext dxltrctxChild(m_pmp, false, pdxltrctxOut->PhmColParam());
Plan *pplanChild = PplFromDXL(pdxlnChild, &dxltrctxChild, pplan, pdrgpdxltrctxPrevSiblings);
// create an rtable entry for the subquery scan
RangeTblEntry *prte = MakeNode(RangeTblEntry);
prte->rtekind = RTE_SUBQUERY;
Alias *palias = MakeNode(Alias);
palias->colnames = NIL;
// get table alias
palias->aliasname = CTranslatorUtils::SzFromWsz(pdxlopSubqscan->Pmdname()->Pstr()->Wsz());
// get column names from child project list
CDXLTranslateContextBaseTable dxltrctxbt(m_pmp);
Index iRel = gpdb::UlListLength(m_pctxdxltoplstmt->PlPrte()) + 1;
(psubqscan->scan).scanrelid = iRel;
dxltrctxbt.SetIdx(iRel);
ListCell *plcTE = NULL;
CDXLNode *pdxlnChildProjList = (*pdxlnChild)[0];
ULONG ul = 0;
ForEach (plcTE, pplanChild->targetlist)
{
TargetEntry *pte = (TargetEntry *) lfirst(plcTE);
// non-system attribute
CHAR *szColName = PStrDup(pte->resname);
Value *pvalColName = gpdb::PvalMakeString(szColName);
palias->colnames = gpdb::PlAppendElement(palias->colnames, pvalColName);
// get corresponding child project element
CDXLScalarProjElem *pdxlopPrel = CDXLScalarProjElem::PdxlopConvert((*pdxlnChildProjList)[ul]->Pdxlop());
// save mapping col id -> index in translate context
(void) dxltrctxbt.FInsertMapping(pdxlopPrel->UlId(), pte->resno);
ul++;
}
prte->eref = palias;
// add range table entry for the subquery to the list
m_pctxdxltoplstmt->AddRTE(prte);
// translate proj list and filter
TranslateProjListAndFilter
(
pdxlnPrL,
pdxlnFilter,
&dxltrctxbt, // translate context for the base table
NULL,
&pplan->targetlist,
&pplan->qual,
pdxltrctxOut,
pplan
);
psubqscan->subplan = pplanChild;
pplan->nMotionNodes = pplanChild->nMotionNodes;
SetParamIds(pplan);
return (Plan *) psubqscan;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToPlStmt::PresultFromDXLResult
//
// @doc:
// Translate DXL result node into GPDB result plan node
//
//---------------------------------------------------------------------------
Plan *
CTranslatorDXLToPlStmt::PresultFromDXLResult
(
const CDXLNode *pdxlnResult,
CDXLTranslateContext *pdxltrctxOut,
Plan *pplanParent,
DrgPdxltrctx *pdrgpdxltrctxPrevSiblings
)
{
// create result plan node
Result *presult = MakeNode(Result);
Plan *pplan = &(presult->plan);
pplan->plan_node_id = m_pctxdxltoplstmt->UlNextPlanId();
pplan->plan_parent_node_id = IPlanId(pplanParent);
// translate operator costs
TranslatePlanCosts
(
CDXLPhysicalProperties::PdxlpropConvert(pdxlnResult->Pdxlprop())->Pdxlopcost(),
&(pplan->startup_cost),
&(pplan->total_cost),
&(pplan->plan_rows),
&(pplan->plan_width)
);
pplan->nMotionNodes = 0;
CDXLNode *pdxlnChild = NULL;
CDXLTranslateContext dxltrctxChild(m_pmp, false, pdxltrctxOut->PhmColParam());
if (pdxlnResult->UlArity() - 1 == EdxlresultIndexChild)
{
// translate child plan
pdxlnChild = (*pdxlnResult)[EdxlresultIndexChild];
Plan *pplanChild = PplFromDXL(pdxlnChild, &dxltrctxChild, pplan, pdrgpdxltrctxPrevSiblings);
GPOS_ASSERT(NULL != pplanChild && "child plan cannot be NULL");
presult->plan.lefttree = pplanChild;
pplan->nMotionNodes = pplanChild->nMotionNodes;
}
CDXLNode *pdxlnPrL = (*pdxlnResult)[EdxlresultIndexProjList];
CDXLNode *pdxlnFilter = (*pdxlnResult)[EdxlresultIndexFilter];
CDXLNode *pdxlnOneTimeFilter = (*pdxlnResult)[EdxlresultIndexOneTimeFilter];
List *plQuals = NULL;
DrgPdxltrctx *pdrgpdxltrctx = GPOS_NEW(m_pmp) DrgPdxltrctx(m_pmp);
pdrgpdxltrctx->Append(const_cast<CDXLTranslateContext*>(&dxltrctxChild));
// translate proj list and filter
TranslateProjListAndFilter
(
pdxlnPrL,
pdxlnFilter,
NULL, // translate context for the base table
pdrgpdxltrctx,
&pplan->targetlist,
&plQuals,
pdxltrctxOut,
pplan
);
// translate one time filter
List *plOneTimeQuals = PlQualFromFilter
(
pdxlnOneTimeFilter,
NULL, // base table translation context
pdrgpdxltrctx,
pdxltrctxOut,
pplan
);
pplan->qual = plQuals;
presult->resconstantqual = (Node *) plOneTimeQuals;
SetParamIds(pplan);
// cleanup
pdrgpdxltrctx->Release();
return (Plan *) presult;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToPlStmt::PplanPartitionSelector
//
// @doc:
// Translate DXL PartitionSelector into a GPDB PartitionSelector node
//
//---------------------------------------------------------------------------
Plan *
CTranslatorDXLToPlStmt::PplanPartitionSelector
(
const CDXLNode *pdxlnPartitionSelector,
CDXLTranslateContext *pdxltrctxOut,
Plan *pplanParent,
DrgPdxltrctx *pdrgpdxltrctxPrevSiblings
)
{
PartitionSelector *ppartsel = MakeNode(PartitionSelector);
Plan *pplan = &(ppartsel->plan);
pplan->plan_node_id = m_pctxdxltoplstmt->UlNextPlanId();
pplan->plan_parent_node_id = IPlanId(pplanParent);
CDXLPhysicalPartitionSelector *pdxlopPartSel = CDXLPhysicalPartitionSelector::PdxlopConvert(pdxlnPartitionSelector->Pdxlop());
const ULONG ulLevels = pdxlopPartSel->UlLevels();
ppartsel->nLevels = ulLevels;
ppartsel->scanId = pdxlopPartSel->UlScanId();
ppartsel->relid = CMDIdGPDB::PmdidConvert(pdxlopPartSel->PmdidRel())->OidObjectId();
ppartsel->selectorId = m_ulPartitionSelectorCounter++;
// translate operator costs
TranslatePlanCosts
(
CDXLPhysicalProperties::PdxlpropConvert(pdxlnPartitionSelector->Pdxlprop())->Pdxlopcost(),
&(pplan->startup_cost),
&(pplan->total_cost),
&(pplan->plan_rows),
&(pplan->plan_width)
);
pplan->nMotionNodes = 0;
CDXLNode *pdxlnChild = NULL;
DrgPdxltrctx *pdrgpdxltrctx = GPOS_NEW(m_pmp) DrgPdxltrctx(m_pmp);
DrgPdxltrctx *pdrgpdxltrctxWithSiblings = GPOS_NEW(m_pmp) DrgPdxltrctx(m_pmp);
CDXLTranslateContext dxltrctxChild(m_pmp, false, pdxltrctxOut->PhmColParam());
BOOL fHasChild = (EdxlpsIndexChild == pdxlnPartitionSelector->UlArity() - 1);
if (fHasChild)
{
// translate child plan
pdxlnChild = (*pdxlnPartitionSelector)[EdxlpsIndexChild];
Plan *pplanChild = PplFromDXL(pdxlnChild, &dxltrctxChild, pplan, pdrgpdxltrctxPrevSiblings);
GPOS_ASSERT(NULL != pplanChild && "child plan cannot be NULL");
ppartsel->plan.lefttree = pplanChild;
pplan->nMotionNodes = pplanChild->nMotionNodes;
}
pdrgpdxltrctx->Append(&dxltrctxChild);
pdrgpdxltrctx->Append(pdxltrctxOut);
pdrgpdxltrctxWithSiblings->AppendArray(pdrgpdxltrctx);
if (NULL != pdrgpdxltrctxPrevSiblings)
{
pdrgpdxltrctxWithSiblings->AppendArray(pdrgpdxltrctxPrevSiblings);
}
CDXLNode *pdxlnPrL = (*pdxlnPartitionSelector)[EdxlpsIndexProjList];
CDXLNode *pdxlnEqFilters = (*pdxlnPartitionSelector)[EdxlpsIndexEqFilters];
CDXLNode *pdxlnFilters = (*pdxlnPartitionSelector)[EdxlpsIndexFilters];
CDXLNode *pdxlnResidualFilter = (*pdxlnPartitionSelector)[EdxlpsIndexResidualFilter];
CDXLNode *pdxlnPropExpr = (*pdxlnPartitionSelector)[EdxlpsIndexPropExpr];
CDXLNode *pdxlnPrintableFilter = (*pdxlnPartitionSelector)[EdxlpsIndexPrintableFilter];
// translate proj list
pplan->targetlist = PlTargetListFromProjList(pdxlnPrL, NULL /*pdxltrctxbt*/, pdrgpdxltrctx, pdxltrctxOut, pplan);
// translate filter lists
GPOS_ASSERT(pdxlnEqFilters->UlArity() == ulLevels);
ppartsel->levelEqExpressions = PlFilterList(pdxlnEqFilters, NULL /*pdxltrctxbt*/, pdrgpdxltrctx, pdxltrctxOut, pplan);
GPOS_ASSERT(pdxlnFilters->UlArity() == ulLevels);
ppartsel->levelExpressions = PlFilterList(pdxlnFilters, NULL /*pdxltrctxbt*/, pdrgpdxltrctx, pdxltrctxOut, pplan);
//translate residual filter
CMappingColIdVarPlStmt mapcidvarplstmt = CMappingColIdVarPlStmt(m_pmp, NULL /*pdxltrctxbt*/, pdrgpdxltrctxWithSiblings, pdxltrctxOut, m_pctxdxltoplstmt, pplan);
if (!m_pdxlsctranslator->FConstTrue(pdxlnResidualFilter, m_pmda))
{
ppartsel->residualPredicate = (Node *) m_pdxlsctranslator->PexprFromDXLNodeScalar(pdxlnResidualFilter, &mapcidvarplstmt);
}
//translate propagation expression
if (!m_pdxlsctranslator->FConstNull(pdxlnPropExpr))
{
ppartsel->propagationExpression = (Node *) m_pdxlsctranslator->PexprFromDXLNodeScalar(pdxlnPropExpr, &mapcidvarplstmt);
}
//translate printable filter
if (!m_pdxlsctranslator->FConstTrue(pdxlnPrintableFilter, m_pmda))
{
ppartsel->printablePredicate = (Node *) m_pdxlsctranslator->PexprFromDXLNodeScalar(pdxlnPrintableFilter, &mapcidvarplstmt);
}
ppartsel->staticPartOids = NIL;
ppartsel->staticScanIds = NIL;
ppartsel->staticSelection = (optimizer_static_partition_selection && !fHasChild);
if (ppartsel->staticSelection)
{
SelectedParts *sp = gpdb::SpStaticPartitionSelection(ppartsel);
ppartsel->staticPartOids = sp->partOids;
ppartsel->staticScanIds = sp->scanIds;
gpdb::GPDBFree(sp);
}
else
{
// if we cannot do static elimination then add this partitioned table oid
// to the planned stmt so we can ship the constraints with the plan
m_pctxdxltoplstmt->AddPartitionedTable(ppartsel->relid);
}
// increment the number of partition selectors for the given scan id
m_pctxdxltoplstmt->IncrementPartitionSelectors(ppartsel->scanId);
SetParamIds(pplan);
// cleanup
pdrgpdxltrctx->Release();
pdrgpdxltrctxWithSiblings->Release();
return (Plan *) ppartsel;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToPlStmt::PlFilterList
//
// @doc:
// Translate DXL filter list into GPDB filter list
//
//---------------------------------------------------------------------------
List *
CTranslatorDXLToPlStmt::PlFilterList
(
const CDXLNode *pdxlnFilterList,
const CDXLTranslateContextBaseTable *pdxltrctxbt,
DrgPdxltrctx *pdrgpdxltrctx,
CDXLTranslateContext *pdxltrctxOut,
Plan *pplanParent
)
{
GPOS_ASSERT(EdxlopScalarOpList == pdxlnFilterList->Pdxlop()->Edxlop());
List *plFilters = NIL;
CMappingColIdVarPlStmt mapcidvarplstmt = CMappingColIdVarPlStmt(m_pmp, pdxltrctxbt, pdrgpdxltrctx, pdxltrctxOut, m_pctxdxltoplstmt, pplanParent);
const ULONG ulArity = pdxlnFilterList->UlArity();
for (ULONG ul = 0; ul < ulArity; ul++)
{
CDXLNode *pdxlnChildFilter = (*pdxlnFilterList)[ul];
if (m_pdxlsctranslator->FConstTrue(pdxlnChildFilter, m_pmda))
{
plFilters = gpdb::PlAppendElement(plFilters, NULL /*datum*/);
continue;
}
Expr *pexprFilter = m_pdxlsctranslator->PexprFromDXLNodeScalar(pdxlnChildFilter, &mapcidvarplstmt);
plFilters = gpdb::PlAppendElement(plFilters, pexprFilter);
}
return plFilters;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToPlStmt::PappendFromDXLAppend
//
// @doc:
// Translate DXL append node into GPDB Append plan node
//
//---------------------------------------------------------------------------
Plan *
CTranslatorDXLToPlStmt::PappendFromDXLAppend
(
const CDXLNode *pdxlnAppend,
CDXLTranslateContext *pdxltrctxOut,
Plan *pplanParent,
DrgPdxltrctx *pdrgpdxltrctxPrevSiblings
)
{
// create append plan node
Append *pappend = MakeNode(Append);
Plan *pplan = &(pappend->plan);
pplan->plan_node_id = m_pctxdxltoplstmt->UlNextPlanId();
pplan->plan_parent_node_id = IPlanId(pplanParent);
CDXLPhysicalAppend *pdxlopAppend = CDXLPhysicalAppend::PdxlopConvert(pdxlnAppend->Pdxlop());
pappend->isTarget = pdxlopAppend->FIsTarget();
pappend->isZapped = pdxlopAppend->FIsZapped();
// translate operator costs
TranslatePlanCosts
(
CDXLPhysicalProperties::PdxlpropConvert(pdxlnAppend->Pdxlprop())->Pdxlopcost(),
&(pplan->startup_cost),
&(pplan->total_cost),
&(pplan->plan_rows),
&(pplan->plan_width)
);
const ULONG ulArity = pdxlnAppend->UlArity();
GPOS_ASSERT(EdxlappendIndexFirstChild < ulArity);
pplan->nMotionNodes = 0;
pappend->appendplans = NIL;
// translate children
CDXLTranslateContext dxltrctxChild(m_pmp, false, pdxltrctxOut->PhmColParam());
for (ULONG ul = EdxlappendIndexFirstChild; ul < ulArity; ul++)
{
CDXLNode *pdxlnChild = (*pdxlnAppend)[ul];
Plan *pplanChild = PplFromDXL(pdxlnChild, &dxltrctxChild, pplan, pdrgpdxltrctxPrevSiblings);
GPOS_ASSERT(NULL != pplanChild && "child plan cannot be NULL");
pappend->appendplans = gpdb::PlAppendElement(pappend->appendplans, pplanChild);
pplan->nMotionNodes += pplanChild->nMotionNodes;
}
CDXLNode *pdxlnPrL = (*pdxlnAppend)[EdxlappendIndexProjList];
CDXLNode *pdxlnFilter = (*pdxlnAppend)[EdxlappendIndexFilter];
pplan->targetlist = NIL;
const ULONG ulLen = pdxlnPrL->UlArity();
for (ULONG ul = 0; ul < ulLen; ++ul)
{
CDXLNode *pdxlnPrEl = (*pdxlnPrL)[ul];
GPOS_ASSERT(EdxlopScalarProjectElem == pdxlnPrEl->Pdxlop()->Edxlop());
CDXLScalarProjElem *pdxlopPrel = CDXLScalarProjElem::PdxlopConvert(pdxlnPrEl->Pdxlop());
GPOS_ASSERT(1 == pdxlnPrEl->UlArity());
// translate proj element expression
CDXLNode *pdxlnExpr = (*pdxlnPrEl)[0];
CDXLScalarIdent *pdxlopScIdent = CDXLScalarIdent::PdxlopConvert(pdxlnExpr->Pdxlop());
Index idxVarno = OUTER;
AttrNumber attno = (AttrNumber) (ul + 1);
Var *pvar = gpdb::PvarMakeVar
(
idxVarno,
attno,
CMDIdGPDB::PmdidConvert(pdxlopScIdent->PmdidType())->OidObjectId(),
-1, // vartypmod
0 // varlevelsup
);
TargetEntry *pte = MakeNode(TargetEntry);
pte->expr = (Expr *) pvar;
pte->resname = CTranslatorUtils::SzFromWsz(pdxlopPrel->PmdnameAlias()->Pstr()->Wsz());
pte->resno = attno;
// add column mapping to output translation context
pdxltrctxOut->InsertMapping(pdxlopPrel->UlId(), pte);
pplan->targetlist = gpdb::PlAppendElement(pplan->targetlist, pte);
}
DrgPdxltrctx *pdrgpdxltrctx = GPOS_NEW(m_pmp) DrgPdxltrctx(m_pmp);
pdrgpdxltrctx->Append(const_cast<CDXLTranslateContext*>(pdxltrctxOut));
// translate filter
pplan->qual = PlQualFromFilter
(
pdxlnFilter,
NULL, // translate context for the base table
pdrgpdxltrctx,
pdxltrctxOut,
pplanParent
);
SetParamIds(pplan);
// cleanup
pdrgpdxltrctx->Release();
return (Plan *) pappend;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToPlStmt::PmatFromDXLMaterialize
//
// @doc:
// Translate DXL materialize node into GPDB Material plan node
//
//---------------------------------------------------------------------------
Plan *
CTranslatorDXLToPlStmt::PmatFromDXLMaterialize
(
const CDXLNode *pdxlnMaterialize,
CDXLTranslateContext *pdxltrctxOut,
Plan *pplanParent,
DrgPdxltrctx *pdrgpdxltrctxPrevSiblings
)
{
// create materialize plan node
Material *pmat = MakeNode(Material);
Plan *pplan = &(pmat->plan);
pplan->plan_node_id = m_pctxdxltoplstmt->UlNextPlanId();
pplan->plan_parent_node_id = IPlanId(pplanParent);
CDXLPhysicalMaterialize *pdxlopMat = CDXLPhysicalMaterialize::PdxlopConvert(pdxlnMaterialize->Pdxlop());
pmat->cdb_strict = pdxlopMat->FEager();
// translate operator costs
TranslatePlanCosts
(
CDXLPhysicalProperties::PdxlpropConvert(pdxlnMaterialize->Pdxlprop())->Pdxlopcost(),
&(pplan->startup_cost),
&(pplan->total_cost),
&(pplan->plan_rows),
&(pplan->plan_width)
);
// translate materialize child
CDXLNode *pdxlnChild = (*pdxlnMaterialize)[EdxlmatIndexChild];
CDXLNode *pdxlnPrL = (*pdxlnMaterialize)[EdxlmatIndexProjList];
CDXLNode *pdxlnFilter = (*pdxlnMaterialize)[EdxlmatIndexFilter];
CDXLTranslateContext dxltrctxChild(m_pmp, false, pdxltrctxOut->PhmColParam());
Plan *pplanChild = PplFromDXL(pdxlnChild, &dxltrctxChild, pplan, pdrgpdxltrctxPrevSiblings);
DrgPdxltrctx *pdrgpdxltrctx = GPOS_NEW(m_pmp) DrgPdxltrctx(m_pmp);
pdrgpdxltrctx->Append(const_cast<CDXLTranslateContext*>(&dxltrctxChild));
// translate proj list and filter
TranslateProjListAndFilter
(
pdxlnPrL,
pdxlnFilter,
NULL, // translate context for the base table
pdrgpdxltrctx,
&pplan->targetlist,
&pplan->qual,
pdxltrctxOut,
pplan
);
pplan->lefttree = pplanChild;
pplan->nMotionNodes = pplanChild->nMotionNodes;
// set spooling info
if (pdxlopMat->FSpooling())
{
pmat->share_id = pdxlopMat->UlSpoolId();
pmat->driver_slice = pdxlopMat->IExecutorSlice();
pmat->nsharer_xslice = pdxlopMat->UlConsumerSlices();
pmat->share_type = (0 < pdxlopMat->UlConsumerSlices()) ?
SHARE_MATERIAL_XSLICE : SHARE_MATERIAL;
}
else
{
pmat->share_type = SHARE_NOTSHARED;
}
SetParamIds(pplan);
// cleanup
pdrgpdxltrctx->Release();
return (Plan *) pmat;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToPlStmt::PshscanFromDXLSharedScan
//
// @doc:
// Translate DXL materialize node into GPDB Material plan node
//
//---------------------------------------------------------------------------
Plan *
CTranslatorDXLToPlStmt::PshscanFromDXLSharedScan
(
const CDXLNode *pdxlnSharedScan,
CDXLTranslateContext *pdxltrctxOut,
Plan *pplanParent,
DrgPdxltrctx *pdrgpdxltrctxPrevSiblings
)
{
// create sort plan node
ShareInputScan *pshscan = MakeNode(ShareInputScan);
CDXLPhysicalSharedScan *pdxlopShscan = CDXLPhysicalSharedScan::PdxlopConvert(pdxlnSharedScan->Pdxlop());
// set spooling info
const CDXLSpoolInfo *pspoolinfo = pdxlopShscan->Pspoolinfo();
pshscan->share_id = pspoolinfo->UlSpoolId();
pshscan->driver_slice = pspoolinfo->IExecutorSlice();
pshscan->share_type = ShtypeFromSpoolInfo(pspoolinfo);
GPOS_ASSERT(SHARE_NOTSHARED != pshscan->share_type);
Plan *pplan = &(pshscan->plan);
pplan->plan_node_id = m_pctxdxltoplstmt->UlNextPlanId();
pplan->plan_parent_node_id = IPlanId(pplanParent);
// translate operator costs
TranslatePlanCosts
(
CDXLPhysicalProperties::PdxlpropConvert(pdxlnSharedScan->Pdxlprop())->Pdxlopcost(),
&(pplan->startup_cost),
&(pplan->total_cost),
&(pplan->plan_rows),
&(pplan->plan_width)
);
CDXLTranslateContext *pdxltrctxChild = NULL;
if (EdxlshscanIndexSentinel == pdxlnSharedScan->UlArity())
{
// translate shared scan child
CDXLNode *pdxlnChild = (*pdxlnSharedScan)[EdxlshscanIndexChild];
pdxltrctxChild = GPOS_NEW(m_pmp) CDXLTranslateContext(m_pmp, false, pdxltrctxOut->PhmColParam());
Plan *pplanChild = PplFromDXL(pdxlnChild, pdxltrctxChild, pplan, pdrgpdxltrctxPrevSiblings);
pplan->lefttree = pplanChild;
pplan->nMotionNodes = pplanChild->nMotionNodes;
// store translation context
m_pctxdxltoplstmt->AddSharedScanTranslationContext(pspoolinfo->UlSpoolId(), pdxltrctxChild);
}
else
{
// no direct child: we must have translated the actual spool for this shared scan already
// find the corresponding translation context
pdxltrctxChild = const_cast<CDXLTranslateContext*>(m_pctxdxltoplstmt->PdxltrctxForSharedScan(pspoolinfo->UlSpoolId()));
}
GPOS_ASSERT(NULL != pdxltrctxChild);
CDXLNode *pdxlnPrL = (*pdxlnSharedScan)[EdxlshscanIndexProjList];
CDXLNode *pdxlnFilter = (*pdxlnSharedScan)[EdxlshscanIndexFilter];
DrgPdxltrctx *pdrgpdxltrctx = GPOS_NEW(m_pmp) DrgPdxltrctx(m_pmp);
pdrgpdxltrctx->Append(pdxltrctxChild);
// translate proj list and filter
TranslateProjListAndFilter
(
pdxlnPrL,
pdxlnFilter,
NULL, // translate context for the base table
pdrgpdxltrctx,
&pplan->targetlist,
&pplan->qual,
pdxltrctxOut,
pplan
);
SetParamIds(pplan);
// cleanup
pdrgpdxltrctx->Release();
return (Plan *) pshscan;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToPlStmt::PshscanFromDXLCTEProducer
//
// @doc:
// Translate DXL CTE Producer node into GPDB share input scan plan node
//
//---------------------------------------------------------------------------
Plan *
CTranslatorDXLToPlStmt::PshscanFromDXLCTEProducer
(
const CDXLNode *pdxlnCTEProducer,
CDXLTranslateContext *pdxltrctxOut,
Plan *pplanParent,
DrgPdxltrctx *pdrgpdxltrctxPrevSiblings
)
{
CDXLPhysicalCTEProducer *pdxlopCTEProducer = CDXLPhysicalCTEProducer::PdxlopConvert(pdxlnCTEProducer->Pdxlop());
ULONG ulCTEId = pdxlopCTEProducer->UlId();
// create the shared input scan representing the CTE Producer
ShareInputScan *pshscanCTEProducer = MakeNode(ShareInputScan);
pshscanCTEProducer->share_id = ulCTEId;
Plan *pplan = &(pshscanCTEProducer->plan);
pplan->plan_node_id = m_pctxdxltoplstmt->UlNextPlanId();
pplan->plan_parent_node_id = IPlanId(pplanParent);
// store share scan node for the translation of CTE Consumers
m_pctxdxltoplstmt->AddCTEConsumerInfo(ulCTEId, pshscanCTEProducer);
// translate cost of the producer
TranslatePlanCosts
(
CDXLPhysicalProperties::PdxlpropConvert(pdxlnCTEProducer->Pdxlprop())->Pdxlopcost(),
&(pplan->startup_cost),
&(pplan->total_cost),
&(pplan->plan_rows),
&(pplan->plan_width)
);
// translate child plan
CDXLNode *pdxlnPrL = (*pdxlnCTEProducer)[0];
CDXLNode *pdxlnChild = (*pdxlnCTEProducer)[1];
CDXLTranslateContext dxltrctxChild(m_pmp, false, pdxltrctxOut->PhmColParam());
Plan *pplanChild = PplFromDXL(pdxlnChild, &dxltrctxChild, pplan, pdrgpdxltrctxPrevSiblings);
GPOS_ASSERT(NULL != pplanChild && "child plan cannot be NULL");
DrgPdxltrctx *pdrgpdxltrctx = GPOS_NEW(m_pmp) DrgPdxltrctx(m_pmp);
pdrgpdxltrctx->Append(&dxltrctxChild);
// translate proj list
pplan->targetlist = PlTargetListFromProjList
(
pdxlnPrL,
NULL, // base table translation context
pdrgpdxltrctx,
pdxltrctxOut,
pplan
);
// if the child node is neither a sort or materialize node then add a materialize node
if (!IsA(pplanChild, Material) && !IsA(pplanChild, Sort))
{
Material *pmat = MakeNode(Material);
pmat->cdb_strict = false; // eager-free
Plan *pplanMat = &(pmat->plan);
pplanMat->plan_node_id = m_pctxdxltoplstmt->UlNextPlanId();
pplanMat->plan_parent_node_id = pplan->plan_node_id ;
TranslatePlanCosts
(
CDXLPhysicalProperties::PdxlpropConvert(pdxlnCTEProducer->Pdxlprop())->Pdxlopcost(),
&(pplanMat->startup_cost),
&(pplanMat->total_cost),
&(pplanMat->plan_rows),
&(pplanMat->plan_width)
);
// create a target list for the newly added materialize
ListCell *plcTe = NULL;
pplanMat->targetlist = NIL;
ForEach (plcTe, pplan->targetlist)
{
TargetEntry *pte = (TargetEntry *) lfirst(plcTe);
Expr *pexpr = pte->expr;
GPOS_ASSERT(IsA(pexpr, Var));
Var *pvar = (Var *) pexpr;
Var *pvarNew = gpdb::PvarMakeVar(OUTER, pvar->varattno, pvar->vartype, -1 /* vartypmod */, 0 /* varlevelsup */);
pvarNew->varnoold = pvar->varnoold;
pvarNew->varoattno = pvar->varoattno;
TargetEntry *pteNew = gpdb::PteMakeTargetEntry((Expr *) pvarNew, pvar->varattno, PStrDup(pte->resname), pte->resjunk);
pplanMat->targetlist = gpdb::PlAppendElement(pplanMat->targetlist, pteNew);
}
pplanMat->lefttree = pplanChild;
pplanMat->nMotionNodes = pplanChild->nMotionNodes;
pplanChild = pplanMat;
}
InitializeSpoolingInfo(pplanChild, ulCTEId);
pplan->lefttree = pplanChild;
pplan->nMotionNodes = pplanChild->nMotionNodes;
pplan->qual = NIL;
SetParamIds(pplan);
// cleanup
pdrgpdxltrctx->Release();
return (Plan *) pshscanCTEProducer;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToPlStmt::InitializeSpoolingInfo
//
// @doc:
// Initialize spooling information for (1) the materialize/sort node under the
// shared input scan nodes representing the CTE producer node and
// (2) SIS nodes representing the producer/consumer nodes
//---------------------------------------------------------------------------
void
CTranslatorDXLToPlStmt::InitializeSpoolingInfo
(
Plan *pplan,
ULONG ulShareId
)
{
List *plshscanCTEConsumer = m_pctxdxltoplstmt->PshscanCTEConsumer(ulShareId);
GPOS_ASSERT(NULL != plshscanCTEConsumer);
Flow *pflow = PflowCTEConsumer(plshscanCTEConsumer);
const ULONG ulLenSis = gpdb::UlListLength(plshscanCTEConsumer);
ShareType share_type = SHARE_NOTSHARED;
if (IsA(pplan, Material))
{
Material *pmat = (Material *) pplan;
pmat->share_id = ulShareId;
pmat->nsharer = ulLenSis;
share_type = SHARE_MATERIAL;
// the share_type is later reset to SHARE_MATERIAL_XSLICE (if needed) by the apply_shareinput_xslice
pmat->share_type = share_type;
GPOS_ASSERT(NULL == (pmat->plan).flow);
(pmat->plan).flow = pflow;
}
else
{
GPOS_ASSERT(IsA(pplan, Sort));
Sort *psort = (Sort *) pplan;
psort->share_id = ulShareId;
psort->nsharer = ulLenSis;
share_type = SHARE_SORT;
// the share_type is later reset to SHARE_SORT_XSLICE (if needed) the apply_shareinput_xslice
psort->share_type = share_type;
GPOS_ASSERT(NULL == (psort->plan).flow);
(psort->plan).flow = pflow;
}
GPOS_ASSERT(SHARE_NOTSHARED != share_type);
// set the share type of the consumer nodes based on the producer
ListCell *plcShscanCTEConsumer = NULL;
ForEach (plcShscanCTEConsumer, plshscanCTEConsumer)
{
ShareInputScan *pshscanConsumer = (ShareInputScan *) lfirst(plcShscanCTEConsumer);
pshscanConsumer->share_type = share_type;
pshscanConsumer->driver_slice = -1; // default
if (NULL == (pshscanConsumer->plan).flow)
{
(pshscanConsumer->plan).flow = (Flow *) gpdb::PvCopyObject(pflow);
}
}
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToPlStmt::PflowCTEConsumer
//
// @doc:
// Retrieve the flow of the shared input scan of the cte consumers. If
// multiple CTE consumers have a flow then ensure that they are of the
// same type
//---------------------------------------------------------------------------
Flow *
CTranslatorDXLToPlStmt::PflowCTEConsumer
(
List *plshscanCTEConsumer
)
{
Flow *pflow = NULL;
ListCell *plcShscanCTEConsumer = NULL;
ForEach (plcShscanCTEConsumer, plshscanCTEConsumer)
{
ShareInputScan *pshscanConsumer = (ShareInputScan *) lfirst(plcShscanCTEConsumer);
Flow *pflowCte = (pshscanConsumer->plan).flow;
if (NULL != pflowCte)
{
if (NULL == pflow)
{
pflow = (Flow *) gpdb::PvCopyObject(pflowCte);
}
else
{
GPOS_ASSERT(pflow->flotype == pflowCte->flotype);
}
}
}
if (NULL == pflow)
{
pflow = MakeNode(Flow);
pflow->flotype = FLOW_UNDEFINED; // default flow
}
return pflow;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToPlStmt::PshscanFromDXLCTEConsumer
//
// @doc:
// Translate DXL CTE Consumer node into GPDB share input scan plan node
//
//---------------------------------------------------------------------------
Plan *
CTranslatorDXLToPlStmt::PshscanFromDXLCTEConsumer
(
const CDXLNode *pdxlnCTEConsumer,
CDXLTranslateContext *pdxltrctxOut,
Plan *pplanParent,
DrgPdxltrctx *pdrgpdxltrctxPrevSiblings
)
{
CDXLPhysicalCTEConsumer *pdxlopCTEConsumer = CDXLPhysicalCTEConsumer::PdxlopConvert(pdxlnCTEConsumer->Pdxlop());
ULONG ulCTEId = pdxlopCTEConsumer->UlId();
ShareInputScan *pshscanCTEConsumer = MakeNode(ShareInputScan);
pshscanCTEConsumer->share_id = ulCTEId;
Plan *pplan = &(pshscanCTEConsumer->plan);
pplan->plan_node_id = m_pctxdxltoplstmt->UlNextPlanId();
pplan->plan_parent_node_id = IPlanId(pplanParent);
// translate operator costs
TranslatePlanCosts
(
CDXLPhysicalProperties::PdxlpropConvert(pdxlnCTEConsumer->Pdxlprop())->Pdxlopcost(),
&(pplan->startup_cost),
&(pplan->total_cost),
&(pplan->plan_rows),
&(pplan->plan_width)
);
#ifdef GPOS_DEBUG
DrgPul *pdrgpulCTEColId = pdxlopCTEConsumer->PdrgpulColIds();
#endif
// generate the target list of the CTE Consumer
pplan->targetlist = NIL;
CDXLNode *pdxlnPrL = (*pdxlnCTEConsumer)[0];
const ULONG ulLenPrL = pdxlnPrL->UlArity();
GPOS_ASSERT(ulLenPrL == pdrgpulCTEColId->UlLength());
for (ULONG ul = 0; ul < ulLenPrL; ul++)
{
CDXLNode *pdxlnPrE = (*pdxlnPrL)[ul];
CDXLScalarProjElem *pdxlopPrE = CDXLScalarProjElem::PdxlopConvert(pdxlnPrE->Pdxlop());
ULONG ulColId = pdxlopPrE->UlId();
GPOS_ASSERT(ulColId == *(*pdrgpulCTEColId)[ul]);
CDXLNode *pdxlnScIdent = (*pdxlnPrE)[0];
CDXLScalarIdent *pdxlopScIdent = CDXLScalarIdent::PdxlopConvert(pdxlnScIdent->Pdxlop());
OID oidType = CMDIdGPDB::PmdidConvert(pdxlopScIdent->PmdidType())->OidObjectId();
Var *pvar = gpdb::PvarMakeVar(OUTER, (AttrNumber) (ul + 1), oidType, -1 /* vartypmod */, 0 /* varlevelsup */);
CHAR *szResname = CTranslatorUtils::SzFromWsz(pdxlopPrE->PmdnameAlias()->Pstr()->Wsz());
TargetEntry *pte = gpdb::PteMakeTargetEntry((Expr *) pvar, (AttrNumber) (ul + 1), szResname, false /* resjunk */);
pplan->targetlist = gpdb::PlAppendElement(pplan->targetlist, pte);
pdxltrctxOut->InsertMapping(ulColId, pte);
}
pplan->qual = NULL;
SetParamIds(pplan);
// store share scan node for the translation of CTE Consumers
m_pctxdxltoplstmt->AddCTEConsumerInfo(ulCTEId, pshscanCTEConsumer);
return (Plan *) pshscanCTEConsumer;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToPlStmt::PplanSequence
//
// @doc:
// Translate DXL sequence node into GPDB Sequence plan node
//
//---------------------------------------------------------------------------
Plan *
CTranslatorDXLToPlStmt::PplanSequence
(
const CDXLNode *pdxlnSequence,
CDXLTranslateContext *pdxltrctxOut,
Plan *pplanParent,
DrgPdxltrctx *pdrgpdxltrctxPrevSiblings
)
{
// create append plan node
Sequence *psequence = MakeNode(Sequence);
Plan *pplan = &(psequence->plan);
pplan->plan_node_id = m_pctxdxltoplstmt->UlNextPlanId();
pplan->plan_parent_node_id = IPlanId(pplanParent);
// translate operator costs
TranslatePlanCosts
(
CDXLPhysicalProperties::PdxlpropConvert(pdxlnSequence->Pdxlprop())->Pdxlopcost(),
&(pplan->startup_cost),
&(pplan->total_cost),
&(pplan->plan_rows),
&(pplan->plan_width)
);
ULONG ulArity = pdxlnSequence->UlArity();
// translate last child
// since last child may be a DynamicIndexScan with outer references,
// we pass the context received from parent to translate outer refs here
CDXLNode *pdxlnLastChild = (*pdxlnSequence)[ulArity - 1];
CDXLTranslateContext dxltrctxChild(m_pmp, false, pdxltrctxOut->PhmColParam());
Plan *pplanLastChild = PplFromDXL(pdxlnLastChild, &dxltrctxChild, pplan, pdrgpdxltrctxPrevSiblings);
pplan->nMotionNodes = pplanLastChild->nMotionNodes;
CDXLNode *pdxlnPrL = (*pdxlnSequence)[0];
DrgPdxltrctx *pdrgpdxltrctx = GPOS_NEW(m_pmp) DrgPdxltrctx(m_pmp);
pdrgpdxltrctx->Append(const_cast<CDXLTranslateContext*>(&dxltrctxChild));
// translate proj list
pplan->targetlist = PlTargetListFromProjList
(
pdxlnPrL,
NULL, // base table translation context
pdrgpdxltrctx,
pdxltrctxOut,
pplan
);
// translate the rest of the children
for (ULONG ul = 1; ul < ulArity - 1; ul++)
{
CDXLNode *pdxlnChild = (*pdxlnSequence)[ul];
Plan *pplanChild = PplFromDXL(pdxlnChild, &dxltrctxChild, pplan, pdrgpdxltrctxPrevSiblings);
psequence->subplans = gpdb::PlAppendElement(psequence->subplans, pplanChild);
pplan->nMotionNodes += pplanChild->nMotionNodes;
}
psequence->subplans = gpdb::PlAppendElement(psequence->subplans, pplanLastChild);
SetParamIds(pplan);
// cleanup
pdrgpdxltrctx->Release();
return (Plan *) psequence;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToPlStmt::PplanDTS
//
// @doc:
// Translates a DXL dynamic table scan node into a DynamicTableScan node
//
//---------------------------------------------------------------------------
Plan *
CTranslatorDXLToPlStmt::PplanDTS
(
const CDXLNode *pdxlnDTS,
CDXLTranslateContext *pdxltrctxOut,
Plan *pplanParent,
DrgPdxltrctx *pdrgpdxltrctxPrevSiblings
)
{
// translate table descriptor into a range table entry
CDXLPhysicalDynamicTableScan *pdxlop = CDXLPhysicalDynamicTableScan::PdxlopConvert(pdxlnDTS->Pdxlop());
// translation context for column mappings in the base relation
CDXLTranslateContextBaseTable dxltrctxbt(m_pmp);
// add the new range table entry as the last element of the range table
Index iRel = gpdb::UlListLength(m_pctxdxltoplstmt->PlPrte()) + 1;
const IMDRelation *pmdrel = m_pmda->Pmdrel(pdxlop->Pdxltabdesc()->Pmdid());
const ULONG ulRelCols = pmdrel->UlColumns() - pmdrel->UlSystemColumns();
RangeTblEntry *prte = PrteFromTblDescr(pdxlop->Pdxltabdesc(), NULL /*pdxlid*/, ulRelCols, iRel, &dxltrctxbt);
GPOS_ASSERT(NULL != prte);
prte->requiredPerms |= ACL_SELECT;
m_pctxdxltoplstmt->AddRTE(prte);
// create dynamic scan node
DynamicTableScan *pdts = MakeNode(DynamicTableScan);
pdts->scanrelid = iRel;
pdts->partIndex = pdxlop->UlPartIndexId();
pdts->partIndexPrintable = pdxlop->UlPartIndexIdPrintable();
Plan *pplan = &(pdts->plan);
pplan->plan_node_id = m_pctxdxltoplstmt->UlNextPlanId();
pplan->plan_parent_node_id = IPlanId(pplanParent);
pplan->nMotionNodes = 0;
// translate operator costs
TranslatePlanCosts
(
CDXLPhysicalProperties::PdxlpropConvert(pdxlnDTS->Pdxlprop())->Pdxlopcost(),
&(pplan->startup_cost),
&(pplan->total_cost),
&(pplan->plan_rows),
&(pplan->plan_width)
);
GPOS_ASSERT(2 == pdxlnDTS->UlArity());
// translate proj list and filter
CDXLNode *pdxlnPrL = (*pdxlnDTS)[EdxltsIndexProjList];
CDXLNode *pdxlnFilter = (*pdxlnDTS)[EdxltsIndexFilter];
TranslateProjListAndFilter
(
pdxlnPrL,
pdxlnFilter,
&dxltrctxbt, // translate context for the base table
NULL, // pdxltrctxLeft and pdxltrctxRight,
&pplan->targetlist,
&pplan->qual,
pdxltrctxOut,
pplan
);
SetParamIds(pplan);
return (Plan *) pdts;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToPlStmt::PplanDIS
//
// @doc:
// Translates a DXL dynamic index scan node into a DynamicIndexScan node
//
//---------------------------------------------------------------------------
Plan *
CTranslatorDXLToPlStmt::PplanDIS
(
const CDXLNode *pdxlnDIS,
CDXLTranslateContext *pdxltrctxOut,
Plan *pplanParent,
DrgPdxltrctx *pdrgpdxltrctxPrevSiblings
)
{
CDXLPhysicalDynamicIndexScan *pdxlop = CDXLPhysicalDynamicIndexScan::PdxlopConvert(pdxlnDIS->Pdxlop());
// translation context for column mappings in the base relation
CDXLTranslateContextBaseTable dxltrctxbt(m_pmp);
Index iRel = gpdb::UlListLength(m_pctxdxltoplstmt->PlPrte()) + 1;
const IMDRelation *pmdrel = m_pmda->Pmdrel(pdxlop->Pdxltabdesc()->Pmdid());
const ULONG ulRelCols = pmdrel->UlColumns() - pmdrel->UlSystemColumns();
RangeTblEntry *prte = PrteFromTblDescr(pdxlop->Pdxltabdesc(), NULL /*pdxlid*/, ulRelCols, iRel, &dxltrctxbt);
GPOS_ASSERT(NULL != prte);
prte->requiredPerms |= ACL_SELECT;
m_pctxdxltoplstmt->AddRTE(prte);
DynamicIndexScan *pdis = MakeNode(DynamicIndexScan);
pdis->scan.scanrelid = iRel;
pdis->scan.partIndex = pdxlop->UlPartIndexId();
pdis->scan.partIndexPrintable = pdxlop->UlPartIndexIdPrintable();
CMDIdGPDB *pmdidIndex = CMDIdGPDB::PmdidConvert(pdxlop->Pdxlid()->Pmdid());
const IMDIndex *pmdindex = m_pmda->Pmdindex(pmdidIndex);
Oid oidIndex = pmdidIndex->OidObjectId();
GPOS_ASSERT(InvalidOid != oidIndex);
pdis->indexid = oidIndex;
pdis->logicalIndexInfo = gpdb::Plgidxinfo(prte->relid, oidIndex);
Plan *pplan = &(pdis->scan.plan);
pplan->plan_node_id = m_pctxdxltoplstmt->UlNextPlanId();
pplan->plan_parent_node_id = IPlanId(pplanParent);
pplan->nMotionNodes = 0;
// translate operator costs
TranslatePlanCosts
(
CDXLPhysicalProperties::PdxlpropConvert(pdxlnDIS->Pdxlprop())->Pdxlopcost(),
&(pplan->startup_cost),
&(pplan->total_cost),
&(pplan->plan_rows),
&(pplan->plan_width)
);
// an index scan node must have 3 children: projection list, filter and index condition list
GPOS_ASSERT(3 == pdxlnDIS->UlArity());
// translate proj list and filter
CDXLNode *pdxlnPrL = (*pdxlnDIS)[CDXLPhysicalDynamicIndexScan::EdxldisIndexProjList];
CDXLNode *pdxlnFilter = (*pdxlnDIS)[CDXLPhysicalDynamicIndexScan::EdxldisIndexFilter];
CDXLNode *pdxlnIndexCondList = (*pdxlnDIS)[CDXLPhysicalDynamicIndexScan::EdxldisIndexCondition];
// translate proj list
pplan->targetlist = PlTargetListFromProjList(pdxlnPrL, &dxltrctxbt, NULL /*pdrgpdxltrctx*/, pdxltrctxOut, pplan);
// translate index filter
pplan->qual = PlTranslateIndexFilter
(
pdxlnFilter,
pdxltrctxOut,
&dxltrctxbt,
pdrgpdxltrctxPrevSiblings,
pplan
);
pdis->indexorderdir = CTranslatorUtils::Scandirection(pdxlop->EdxlScanDirection());
// translate index condition list
List *plIndexConditions = NIL;
List *plIndexOrigConditions = NIL;
List *plIndexStratgey = NIL;
List *plIndexSubtype = NIL;
TranslateIndexConditions
(
pdxlnIndexCondList,
pdxlop->Pdxltabdesc(),
false, // fIndexOnlyScan
pmdindex,
pmdrel,
pdxltrctxOut,
&dxltrctxbt,
pdrgpdxltrctxPrevSiblings,
pplan,
&plIndexConditions,
&plIndexOrigConditions,
&plIndexStratgey,
&plIndexSubtype
);
pdis->indexqual = plIndexConditions;
pdis->indexqualorig = plIndexOrigConditions;
pdis->indexstrategy = plIndexStratgey;
pdis->indexsubtype = plIndexSubtype;
SetParamIds(pplan);
return (Plan *) pdis;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToPlStmt::PplanDML
//
// @doc:
// Translates a DXL DML node
//
//---------------------------------------------------------------------------
Plan *
CTranslatorDXLToPlStmt::PplanDML
(
const CDXLNode *pdxlnDML,
CDXLTranslateContext *pdxltrctxOut,
Plan *pplanParent,
DrgPdxltrctx *pdrgpdxltrctxPrevSiblings
)
{
// translate table descriptor into a range table entry
CDXLPhysicalDML *pdxlop = CDXLPhysicalDML::PdxlopConvert(pdxlnDML->Pdxlop());
// create DML node
DML *pdml = MakeNode(DML);
Plan *pplan = &(pdml->plan);
AclMode aclmode = ACL_NO_RIGHTS;
switch (pdxlop->EdxlDmlOpType())
{
case gpdxl::Edxldmldelete:
{
m_cmdtype = CMD_DELETE;
aclmode = ACL_DELETE;
break;
}
case gpdxl::Edxldmlupdate:
{
m_cmdtype = CMD_UPDATE;
aclmode = ACL_UPDATE;
break;
}
case gpdxl::Edxldmlinsert:
{
m_cmdtype = CMD_INSERT;
aclmode = ACL_INSERT;
break;
}
}
IMDId *pmdidTargetTable = pdxlop->Pdxltabdesc()->Pmdid();
if (IMDRelation::EreldistrMasterOnly != m_pmda->Pmdrel(pmdidTargetTable)->Ereldistribution())
{
m_fTargetTableDistributed = true;
}
// translation context for column mappings in the base relation
CDXLTranslateContextBaseTable dxltrctxbt(m_pmp);
// add the new range table entry as the last element of the range table
Index iRel = gpdb::UlListLength(m_pctxdxltoplstmt->PlPrte()) + 1;
pdml->scanrelid = iRel;
m_plResultRelations = gpdb::PlAppendInt(m_plResultRelations, iRel);
const IMDRelation *pmdrel = m_pmda->Pmdrel(pdxlop->Pdxltabdesc()->Pmdid());
const ULONG ulRelCols = pmdrel->UlColumns() - pmdrel->UlSystemColumns();
CDXLTableDescr *pdxltabdesc = pdxlop->Pdxltabdesc();
RangeTblEntry *prte = PrteFromTblDescr(pdxltabdesc, NULL /*pdxlid*/, ulRelCols, iRel, &dxltrctxbt);
GPOS_ASSERT(NULL != prte);
prte->requiredPerms |= aclmode;
m_pctxdxltoplstmt->AddRTE(prte);
CDXLNode *pdxlnPrL = (*pdxlnDML)[0];
CDXLNode *pdxlnChild = (*pdxlnDML)[1];
CDXLTranslateContext dxltrctxChild(m_pmp, false, pdxltrctxOut->PhmColParam());
Plan *pplanChild = PplFromDXL(pdxlnChild, &dxltrctxChild, pplan, pdrgpdxltrctxPrevSiblings);
DrgPdxltrctx *pdrgpdxltrctx = GPOS_NEW(m_pmp) DrgPdxltrctx(m_pmp);
pdrgpdxltrctx->Append(&dxltrctxChild);
// translate proj list
List *plTargetListDML = PlTargetListFromProjList
(
pdxlnPrL,
NULL, // translate context for the base table
pdrgpdxltrctx,
pdxltrctxOut,
pplan
);
if (pmdrel->FHasDroppedColumns())
{
// pad DML target list with NULLs for dropped columns for all DML operator types
List *plTargetListWithDroppedCols = PlTargetListWithDroppedCols(plTargetListDML, pmdrel);
gpdb::GPDBFree(plTargetListDML);
plTargetListDML = plTargetListWithDroppedCols;
}
pdml->inputSorted = pdxlop->FInputSorted();
// add ctid, action and oid columns to target list
pdml->oidColIdx = UlAddTargetEntryForColId(&plTargetListDML, &dxltrctxChild, pdxlop->UlOid(), true /*fResjunk*/);
pdml->actionColIdx = UlAddTargetEntryForColId(&plTargetListDML, &dxltrctxChild, pdxlop->UlAction(), true /*fResjunk*/);
pdml->ctidColIdx = UlAddTargetEntryForColId(&plTargetListDML, &dxltrctxChild, pdxlop->UlCtid(), true /*fResjunk*/);
if (pdxlop->FPreserveOids())
{
pdml->tupleoidColIdx = UlAddTargetEntryForColId(&plTargetListDML, &dxltrctxChild, pdxlop->UlTupleOid(), true /*fResjunk*/);
}
else
{
pdml->tupleoidColIdx = 0;
}
GPOS_ASSERT(0 != pdml->actionColIdx);
GPOS_ASSERT(0 != pdml->oidColIdx);
pplan->targetlist = plTargetListDML;
pplan->lefttree = pplanChild;
pplan->nMotionNodes = pplanChild->nMotionNodes;
pplan->plan_node_id = m_pctxdxltoplstmt->UlNextPlanId();
pplan->plan_parent_node_id = IPlanId(pplanParent);
if (CMD_INSERT == m_cmdtype && 0 == pplan->nMotionNodes)
{
List *plDirectDispatchSegIds = PlDirectDispatchSegIds(pdxlop->Pdxlddinfo());
pplan->directDispatch.contentIds = plDirectDispatchSegIds;
pplan->directDispatch.isDirectDispatch = (NIL != plDirectDispatchSegIds);
}
SetParamIds(pplan);
// cleanup
pdrgpdxltrctx->Release();
// translate operator costs
TranslatePlanCosts
(
CDXLPhysicalProperties::PdxlpropConvert(pdxlnDML->Pdxlprop())->Pdxlopcost(),
&(pplan->startup_cost),
&(pplan->total_cost),
&(pplan->plan_rows),
&(pplan->plan_width)
);
return (Plan *) pdml;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToPlStmt::PlDirectDispatchSegIds
//
// @doc:
// Translate the direct dispatch info
//
//---------------------------------------------------------------------------
List *
CTranslatorDXLToPlStmt::PlDirectDispatchSegIds
(
CDXLDirectDispatchInfo *pdxlddinfo
)
{
if (!optimizer_direct_dispatch || NULL == pdxlddinfo)
{
return NIL;
}
DrgPdrgPdxldatum *pdrgpdrgpdxldatum = pdxlddinfo->Pdrgpdrgpdxldatum();
if (0 == pdrgpdrgpdxldatum->UlSafeLength())
{
return NIL;
}
DrgPdxldatum *pdrgpdxldatum = (*pdrgpdrgpdxldatum)[0];
GPOS_ASSERT(0 < pdrgpdxldatum->UlLength());
ULONG ulHashCode = UlCdbHash(pdrgpdxldatum);
const ULONG ulLength = pdrgpdrgpdxldatum->UlLength();
for (ULONG ul = 0; ul < ulLength; ul++)
{
DrgPdxldatum *pdrgpdxldatumDisj = (*pdrgpdrgpdxldatum)[ul];
GPOS_ASSERT(0 < pdrgpdxldatumDisj->UlLength());
ULONG ulHashCodeNew = UlCdbHash(pdrgpdxldatumDisj);
if (ulHashCode != ulHashCodeNew)
{
// values don't hash to the same segment
return NIL;
}
}
List *plSegIds = gpdb::PlAppendInt(NIL, ulHashCode);
return plSegIds;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToPlStmt::UlCdbHash
//
// @doc:
// Hash a DXL datum
//
//---------------------------------------------------------------------------
ULONG
CTranslatorDXLToPlStmt::UlCdbHash
(
DrgPdxldatum *pdrgpdxldatum
)
{
List *plConsts = NIL;
const ULONG ulLength = pdrgpdxldatum->UlLength();
for (ULONG ul = 0; ul < ulLength; ul++)
{
CDXLDatum *pdxldatum = (*pdrgpdxldatum)[ul];
Const *pconst = (Const *) m_pdxlsctranslator->PconstFromDXLDatum(pdxldatum);
plConsts = gpdb::PlAppendElement(plConsts, pconst);
}
ULONG ulHash = gpdb::ICdbHashList(plConsts, m_ulSegments);
gpdb::FreeListDeep(plConsts);
return ulHash;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToPlStmt::PplanSplit
//
// @doc:
// Translates a DXL Split node
//
//---------------------------------------------------------------------------
Plan *
CTranslatorDXLToPlStmt::PplanSplit
(
const CDXLNode *pdxlnSplit,
CDXLTranslateContext *pdxltrctxOut,
Plan *pplanParent,
DrgPdxltrctx *pdrgpdxltrctxPrevSiblings
)
{
CDXLPhysicalSplit *pdxlop = CDXLPhysicalSplit::PdxlopConvert(pdxlnSplit->Pdxlop());
// create SplitUpdate node
SplitUpdate *psplit = MakeNode(SplitUpdate);
Plan *pplan = &(psplit->plan);
CDXLNode *pdxlnPrL = (*pdxlnSplit)[0];
CDXLNode *pdxlnChild = (*pdxlnSplit)[1];
CDXLTranslateContext dxltrctxChild(m_pmp, false, pdxltrctxOut->PhmColParam());
Plan *pplanChild = PplFromDXL(pdxlnChild, &dxltrctxChild, pplan, pdrgpdxltrctxPrevSiblings);
DrgPdxltrctx *pdrgpdxltrctx = GPOS_NEW(m_pmp) DrgPdxltrctx(m_pmp);
pdrgpdxltrctx->Append(&dxltrctxChild);
// translate proj list and filter
pplan->targetlist = PlTargetListFromProjList
(
pdxlnPrL,
NULL, // translate context for the base table
pdrgpdxltrctx,
pdxltrctxOut,
pplan
);
// translate delete and insert columns
DrgPul *pdrgpulDeleteCols = pdxlop->PdrgpulDelete();
DrgPul *pdrgpulInsertCols = pdxlop->PdrgpulInsert();
GPOS_ASSERT(pdrgpulInsertCols->UlLength() == pdrgpulDeleteCols->UlLength());
psplit->deleteColIdx = CTranslatorUtils::PlAttnosFromColids(pdrgpulDeleteCols, &dxltrctxChild);
psplit->insertColIdx = CTranslatorUtils::PlAttnosFromColids(pdrgpulInsertCols, &dxltrctxChild);
const TargetEntry *pteActionCol = pdxltrctxOut->Pte(pdxlop->UlAction());
const TargetEntry *pteCtidCol = pdxltrctxOut->Pte(pdxlop->UlCtid());
const TargetEntry *pteTupleOidCol = pdxltrctxOut->Pte(pdxlop->UlTupleOid());
if (NULL == pteActionCol)
{
GPOS_RAISE(gpdxl::ExmaDXL, gpdxl::ExmiDXL2PlStmtAttributeNotFound, pdxlop->UlAction());
}
if (NULL == pteCtidCol)
{
GPOS_RAISE(gpdxl::ExmaDXL, gpdxl::ExmiDXL2PlStmtAttributeNotFound, pdxlop->UlCtid());
}
psplit->actionColIdx = pteActionCol->resno;
psplit->ctidColIdx = pteCtidCol->resno;
psplit->tupleoidColIdx = FirstLowInvalidHeapAttributeNumber;
if (NULL != pteTupleOidCol)
{
psplit->tupleoidColIdx = pteTupleOidCol->resno;
}
pplan->lefttree = pplanChild;
pplan->nMotionNodes = pplanChild->nMotionNodes;
pplan->plan_node_id = m_pctxdxltoplstmt->UlNextPlanId();
pplan->plan_parent_node_id = IPlanId(pplanParent);
SetParamIds(pplan);
// cleanup
pdrgpdxltrctx->Release();
// translate operator costs
TranslatePlanCosts
(
CDXLPhysicalProperties::PdxlpropConvert(pdxlnSplit->Pdxlprop())->Pdxlopcost(),
&(pplan->startup_cost),
&(pplan->total_cost),
&(pplan->plan_rows),
&(pplan->plan_width)
);
return (Plan *) psplit;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToPlStmt::PplanAssert
//
// @doc:
// Translate DXL assert node into GPDB assert plan node
//
//---------------------------------------------------------------------------
Plan *
CTranslatorDXLToPlStmt::PplanAssert
(
const CDXLNode *pdxlnAssert,
CDXLTranslateContext *pdxltrctxOut,
Plan *pplanParent,
DrgPdxltrctx *pdrgpdxltrctxPrevSiblings
)
{
// create assert plan node
AssertOp *passert = MakeNode(AssertOp);
Plan *pplan = &(passert->plan);
pplan->plan_node_id = m_pctxdxltoplstmt->UlNextPlanId();
pplan->plan_parent_node_id = IPlanId(pplanParent);
CDXLPhysicalAssert *pdxlopAssert = CDXLPhysicalAssert::PdxlopConvert(pdxlnAssert->Pdxlop());
// translate error code into the its internal GPDB representation
const CHAR *szErrorCode = pdxlopAssert->SzSQLState();
GPOS_ASSERT(GPOS_SQLSTATE_LENGTH == clib::UlStrLen(szErrorCode));
passert->errcode = MAKE_SQLSTATE(szErrorCode[0], szErrorCode[1], szErrorCode[2], szErrorCode[3], szErrorCode[4]);
CDXLNode *pdxlnFilter = (*pdxlnAssert)[CDXLPhysicalAssert::EdxlassertIndexFilter];
passert->errmessage = CTranslatorUtils::PlAssertErrorMsgs(pdxlnFilter);
// translate operator costs
TranslatePlanCosts
(
CDXLPhysicalProperties::PdxlpropConvert(pdxlnAssert->Pdxlprop())->Pdxlopcost(),
&(pplan->startup_cost),
&(pplan->total_cost),
&(pplan->plan_rows),
&(pplan->plan_width)
);
CDXLTranslateContext dxltrctxChild(m_pmp, false, pdxltrctxOut->PhmColParam());
// translate child plan
CDXLNode *pdxlnChild = (*pdxlnAssert)[CDXLPhysicalAssert::EdxlassertIndexChild];
Plan *pplanChild = PplFromDXL(pdxlnChild, &dxltrctxChild, pplan, pdrgpdxltrctxPrevSiblings);
GPOS_ASSERT(NULL != pplanChild && "child plan cannot be NULL");
passert->plan.lefttree = pplanChild;
pplan->nMotionNodes = pplanChild->nMotionNodes;
CDXLNode *pdxlnPrL = (*pdxlnAssert)[CDXLPhysicalAssert::EdxlassertIndexProjList];
List *plQuals = NULL;
DrgPdxltrctx *pdrgpdxltrctx = GPOS_NEW(m_pmp) DrgPdxltrctx(m_pmp);
pdrgpdxltrctx->Append(const_cast<CDXLTranslateContext*>(&dxltrctxChild));
// translate proj list
pplan->targetlist = PlTargetListFromProjList
(
pdxlnPrL,
NULL, // translate context for the base table
pdrgpdxltrctx,
pdxltrctxOut,
pplan
);
// translate assert constraints
pplan->qual = PlTranslateAssertConstraints
(
pdxlnFilter,
pdxltrctxOut,
pdrgpdxltrctx,
pplan
);
GPOS_ASSERT(gpdb::UlListLength(pplan->qual) == gpdb::UlListLength(passert->errmessage));
SetParamIds(pplan);
// cleanup
pdrgpdxltrctx->Release();
return (Plan *) passert;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToPlStmt::PplanRowTrigger
//
// @doc:
// Translates a DXL Row Trigger node
//
//---------------------------------------------------------------------------
Plan *
CTranslatorDXLToPlStmt::PplanRowTrigger
(
const CDXLNode *pdxlnRowTrigger,
CDXLTranslateContext *pdxltrctxOut,
Plan *pplanParent,
DrgPdxltrctx *pdrgpdxltrctxPrevSiblings
)
{
CDXLPhysicalRowTrigger *pdxlop = CDXLPhysicalRowTrigger::PdxlopConvert(pdxlnRowTrigger->Pdxlop());
// create RowTrigger node
RowTrigger *prowtrigger = MakeNode(RowTrigger);
Plan *pplan = &(prowtrigger->plan);
CDXLNode *pdxlnPrL = (*pdxlnRowTrigger)[0];
CDXLNode *pdxlnChild = (*pdxlnRowTrigger)[1];
CDXLTranslateContext dxltrctxChild(m_pmp, false, pdxltrctxOut->PhmColParam());
Plan *pplanChild = PplFromDXL(pdxlnChild, &dxltrctxChild, pplan, pdrgpdxltrctxPrevSiblings);
DrgPdxltrctx *pdrgpdxltrctx = GPOS_NEW(m_pmp) DrgPdxltrctx(m_pmp);
pdrgpdxltrctx->Append(&dxltrctxChild);
// translate proj list and filter
pplan->targetlist = PlTargetListFromProjList
(
pdxlnPrL,
NULL, // translate context for the base table
pdrgpdxltrctx,
pdxltrctxOut,
pplan
);
Oid oidRelid = CMDIdGPDB::PmdidConvert(pdxlop->PmdidRel())->OidObjectId();
GPOS_ASSERT(InvalidOid != oidRelid);
prowtrigger->relid = oidRelid;
prowtrigger->eventFlags = pdxlop->IType();
// translate old and new columns
DrgPul *pdrgpulOldCols = pdxlop->PdrgpulOld();
DrgPul *pdrgpulNewCols = pdxlop->PdrgpulNew();
GPOS_ASSERT_IMP(NULL != pdrgpulOldCols && NULL != pdrgpulNewCols,
pdrgpulNewCols->UlLength() == pdrgpulOldCols->UlLength());
if (NULL == pdrgpulOldCols)
{
prowtrigger->oldValuesColIdx = NIL;
}
else
{
prowtrigger->oldValuesColIdx = CTranslatorUtils::PlAttnosFromColids(pdrgpulOldCols, &dxltrctxChild);
}
if (NULL == pdrgpulNewCols)
{
prowtrigger->newValuesColIdx = NIL;
}
else
{
prowtrigger->newValuesColIdx = CTranslatorUtils::PlAttnosFromColids(pdrgpulNewCols, &dxltrctxChild);
}
pplan->lefttree = pplanChild;
pplan->nMotionNodes = pplanChild->nMotionNodes;
pplan->plan_node_id = m_pctxdxltoplstmt->UlNextPlanId();
pplan->plan_parent_node_id = IPlanId(pplanParent);
SetParamIds(pplan);
// cleanup
pdrgpdxltrctx->Release();
// translate operator costs
TranslatePlanCosts
(
CDXLPhysicalProperties::PdxlpropConvert(pdxlnRowTrigger->Pdxlprop())->Pdxlopcost(),
&(pplan->startup_cost),
&(pplan->total_cost),
&(pplan->plan_rows),
&(pplan->plan_width)
);
return (Plan *) prowtrigger;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToPlStmt::PrteFromTblDescr
//
// @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::PrteFromTblDescr
(
const CDXLTableDescr *pdxltabdesc,
const CDXLIndexDescr *pdxlid, // should be NULL unless we have an index-only scan
ULONG ulRelColumns,
Index iRel,
CDXLTranslateContextBaseTable *pdxltrctxbtOut
)
{
RangeTblEntry *prte = MakeNode(RangeTblEntry);
prte->rtekind = RTE_RELATION;
// get the index if given
const IMDIndex *pmdindex = NULL;
if (NULL != pdxlid)
{
pmdindex = m_pmda->Pmdindex(pdxlid->Pmdid());
}
// get oid for table
Oid oid = CMDIdGPDB::PmdidConvert(pdxltabdesc->Pmdid())->OidObjectId();
GPOS_ASSERT(InvalidOid != oid);
prte->relid = oid;
prte->checkAsUser = pdxltabdesc->UlExecuteAsUser();
prte->requiredPerms |= ACL_NO_RIGHTS;
// save oid and range index in translation context
pdxltrctxbtOut->SetOID(oid);
pdxltrctxbtOut->SetIdx(iRel);
Alias *palias = MakeNode(Alias);
palias->colnames = NIL;
// get table alias
palias->aliasname = CTranslatorUtils::SzFromWsz(pdxltabdesc->Pmdname()->Pstr()->Wsz());
// get column names
const ULONG ulArity = pdxltabdesc->UlArity();
INT iLastAttno = 0;
for (ULONG ul = 0; ul < ulArity; ++ul)
{
const CDXLColDescr *pdxlcd = pdxltabdesc->Pdxlcd(ul);
GPOS_ASSERT(NULL != pdxlcd);
INT iAttno = pdxlcd->IAttno();
GPOS_ASSERT(0 != iAttno);
if (0 < iAttno)
{
// if iAttno > iLastAttno + 1, there were dropped attributes
// add those to the RTE as they are required by GPDB
for (INT iDroppedColAttno = iLastAttno + 1; iDroppedColAttno < iAttno; iDroppedColAttno++)
{
Value *pvalDroppedColName = gpdb::PvalMakeString("");
palias->colnames = gpdb::PlAppendElement(palias->colnames, pvalDroppedColName);
}
// non-system attribute
CHAR *szColName = CTranslatorUtils::SzFromWsz(pdxlcd->Pmdname()->Pstr()->Wsz());
Value *pvalColName = gpdb::PvalMakeString(szColName);
palias->colnames = gpdb::PlAppendElement(palias->colnames, pvalColName);
iLastAttno = iAttno;
}
// get the attno from the index, in case of indexonlyscan
if (NULL != pmdindex)
{
iAttno = 1 + pmdindex->UlPosInKey((ULONG) iAttno - 1);
}
// save mapping col id -> index in translate context
(void) pdxltrctxbtOut->FInsertMapping(pdxlcd->UlID(), iAttno);
}
// if there are any dropped columns at the end, add those too to the RangeTblEntry
for (ULONG ul = iLastAttno + 1; ul <= ulRelColumns; ul++)
{
Value *pvalDroppedColName = gpdb::PvalMakeString("");
palias->colnames = gpdb::PlAppendElement(palias->colnames, pvalDroppedColName);
}
prte->eref = palias;
return prte;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToPlStmt::PlTargetListFromProjList
//
// @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 pdxltrctxLeft 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::PlTargetListFromProjList
(
const CDXLNode *pdxlnPrL,
const CDXLTranslateContextBaseTable *pdxltrctxbt,
DrgPdxltrctx *pdrgpdxltrctx,
CDXLTranslateContext *pdxltrctxOut,
Plan *pplanParent
)
{
if (NULL == pdxlnPrL)
{
return NULL;
}
List *plTargetList = NIL;
// translate each DXL project element into a target entry
const ULONG ulArity = pdxlnPrL->UlArity();
for (ULONG ul = 0; ul < ulArity; ++ul)
{
CDXLNode *pdxlnPrEl = (*pdxlnPrL)[ul];
GPOS_ASSERT(EdxlopScalarProjectElem == pdxlnPrEl->Pdxlop()->Edxlop());
CDXLScalarProjElem *pdxlopPrel = CDXLScalarProjElem::PdxlopConvert(pdxlnPrEl->Pdxlop());
GPOS_ASSERT(1 == pdxlnPrEl->UlArity());
// translate proj element expression
CDXLNode *pdxlnExpr = (*pdxlnPrEl)[0];
CMappingColIdVarPlStmt mapcidvarplstmt = CMappingColIdVarPlStmt
(
m_pmp,
pdxltrctxbt,
pdrgpdxltrctx,
pdxltrctxOut,
m_pctxdxltoplstmt,
pplanParent
);
Expr *pexpr = m_pdxlsctranslator->PexprFromDXLNodeScalar(pdxlnExpr, &mapcidvarplstmt);
GPOS_ASSERT(NULL != pexpr);
TargetEntry *pte = MakeNode(TargetEntry);
pte->expr = pexpr;
pte->resname = CTranslatorUtils::SzFromWsz(pdxlopPrel->PmdnameAlias()->Pstr()->Wsz());
pte->resno = (AttrNumber) (ul + 1);
if (IsA(pexpr, 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 (NULL != pdxltrctxbt)
{
// translating project list of a base table
pte->resorigtbl = pdxltrctxbt->OidRel();
pte->resorigcol = ((Var *) pexpr)->varattno;
}
else
{
// not translating a base table proj list: variable must come from
// the left or right child of the operator
GPOS_ASSERT(NULL != pdrgpdxltrctx);
GPOS_ASSERT(0 != pdrgpdxltrctx->UlSafeLength());
ULONG ulColId = CDXLScalarIdent::PdxlopConvert(pdxlnExpr->Pdxlop())->Pdxlcr()->UlID();
const CDXLTranslateContext *pdxltrctxLeft = (*pdrgpdxltrctx)[0];
GPOS_ASSERT(NULL != pdxltrctxLeft);
const TargetEntry *pteOriginal = pdxltrctxLeft->Pte(ulColId);
if (NULL == pteOriginal)
{
// variable not found on the left side
GPOS_ASSERT(2 == pdrgpdxltrctx->UlSafeLength());
const CDXLTranslateContext *pdxltrctxRight = (*pdrgpdxltrctx)[1];
GPOS_ASSERT(NULL != pdxltrctxRight);
pteOriginal = pdxltrctxRight->Pte(ulColId);
}
if (NULL == pteOriginal)
{
GPOS_RAISE(gpdxl::ExmaDXL, gpdxl::ExmiDXL2PlStmtAttributeNotFound, ulColId);
}
pte->resorigtbl = pteOriginal->resorigtbl;
pte->resorigcol = pteOriginal->resorigcol;
}
}
// add column mapping to output translation context
pdxltrctxOut->InsertMapping(pdxlopPrel->UlId(), pte);
plTargetList = gpdb::PlAppendElement(plTargetList, pte);
}
return plTargetList;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToPlStmt::PlTargetListWithDroppedCols
//
// @doc:
// Construct the target list for a DML statement by adding NULL elements
// for dropped columns
//
//---------------------------------------------------------------------------
List *
CTranslatorDXLToPlStmt::PlTargetListWithDroppedCols
(
List *plTargetList,
const IMDRelation *pmdrel
)
{
GPOS_ASSERT(NULL != plTargetList);
GPOS_ASSERT(gpdb::UlListLength(plTargetList) <= pmdrel->UlColumns());
List *plResult = NIL;
ULONG ulLastTLElem = 0;
ULONG ulResno = 1;
const ULONG ulRelCols = pmdrel->UlColumns();
for (ULONG ul = 0; ul < ulRelCols; ul++)
{
const IMDColumn *pmdcol = pmdrel->Pmdcol(ul);
if (pmdcol->FSystemColumn())
{
continue;
}
Expr *pexpr = NULL;
if (pmdcol->FDropped())
{
// add a NULL element
OID oidType = CMDIdGPDB::PmdidConvert(m_pmda->PtMDType<IMDTypeInt4>()->Pmdid())->OidObjectId();
pexpr = (Expr *) gpdb::PnodeMakeNULLConst(oidType);
}
else
{
TargetEntry *pte = (TargetEntry *) gpdb::PvListNth(plTargetList, ulLastTLElem);
pexpr = (Expr *) gpdb::PvCopyObject(pte->expr);
ulLastTLElem++;
}
CHAR *szName = CTranslatorUtils::SzFromWsz(pmdcol->Mdname().Pstr()->Wsz());
TargetEntry *pteNew = gpdb::PteMakeTargetEntry(pexpr, ulResno, szName, false /*resjunk*/);
plResult = gpdb::PlAppendElement(plResult, pteNew);
ulResno++;
}
return plResult;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToPlStmt::PlTargetListForHashNode
//
// @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::PlTargetListForHashNode
(
const CDXLNode *pdxlnPrL,
CDXLTranslateContext *pdxltrctxChild,
CDXLTranslateContext *pdxltrctxOut
)
{
List *plTargetList = NIL;
const ULONG ulArity = pdxlnPrL->UlArity();
for (ULONG ul = 0; ul < ulArity; ul++)
{
CDXLNode *pdxlnPrEl = (*pdxlnPrL)[ul];
CDXLScalarProjElem *pdxlopPrel = CDXLScalarProjElem::PdxlopConvert(pdxlnPrEl->Pdxlop());
const TargetEntry *pteChild = pdxltrctxChild->Pte(pdxlopPrel->UlId());
if (NULL == pteChild)
{
GPOS_RAISE(gpdxl::ExmaDXL, gpdxl::ExmiDXL2PlStmtAttributeNotFound, pdxlopPrel->UlId());
}
// get type oid for project element's expression
GPOS_ASSERT(1 == pdxlnPrEl->UlArity());
// find column type
OID oidType = gpdb::OidExprType((Node*) pteChild->expr);
// find the original varno and attno for this column
Index idxVarnoold = 0;
AttrNumber attnoOld = 0;
if (IsA(pteChild->expr, Var))
{
Var *pv = (Var*) pteChild->expr;
idxVarnoold = pv->varnoold;
attnoOld = pv->varoattno;
}
else
{
idxVarnoold = OUTER;
attnoOld = pteChild->resno;
}
// create a Var expression for this target list entry expression
Var *pvar = gpdb::PvarMakeVar
(
OUTER,
pteChild->resno,
oidType,
-1, // vartypmod
0 // varlevelsup
);
// set old varno and varattno since makeVar does not set them
pvar->varnoold = idxVarnoold;
pvar->varoattno = attnoOld;
CHAR *szResname = CTranslatorUtils::SzFromWsz(pdxlopPrel->PmdnameAlias()->Pstr()->Wsz());
TargetEntry *pte = gpdb::PteMakeTargetEntry
(
(Expr *) pvar,
(AttrNumber) (ul + 1),
szResname,
false // resjunk
);
plTargetList = gpdb::PlAppendElement(plTargetList, pte);
pdxltrctxOut->InsertMapping(pdxlopPrel->UlId(), pte);
}
return plTargetList;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToPlStmt::PlQualFromFilter
//
// @doc:
// Translates a DXL filter node into a Qual list.
//
//---------------------------------------------------------------------------
List *
CTranslatorDXLToPlStmt::PlQualFromFilter
(
const CDXLNode * pdxlnFilter,
const CDXLTranslateContextBaseTable *pdxltrctxbt,
DrgPdxltrctx *pdrgpdxltrctx,
CDXLTranslateContext *pdxltrctxOut,
Plan *pplanParent
)
{
const ULONG ulArity = pdxlnFilter->UlArity();
if (0 == ulArity)
{
return NIL;
}
GPOS_ASSERT(1 == ulArity);
CDXLNode *pdxlnFilterCond = (*pdxlnFilter)[0];
GPOS_ASSERT(CTranslatorDXLToScalar::FBoolean(pdxlnFilterCond, m_pmda));
return PlQualFromScalarCondNode(pdxlnFilterCond, pdxltrctxbt, pdrgpdxltrctx, pdxltrctxOut, pplanParent);
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToPlStmt::PlQualFromScalarCondNode
//
// @doc:
// Translates a DXL scalar condition node node into a Qual list.
//
//---------------------------------------------------------------------------
List *
CTranslatorDXLToPlStmt::PlQualFromScalarCondNode
(
const CDXLNode *pdxlnCond,
const CDXLTranslateContextBaseTable *pdxltrctxbt,
DrgPdxltrctx *pdrgpdxltrctx,
CDXLTranslateContext *pdxltrctxOut,
Plan *pplanParent
)
{
List *plQuals = NIL;
GPOS_ASSERT(CTranslatorDXLToScalar::FBoolean(const_cast<CDXLNode*>(pdxlnCond), m_pmda));
CMappingColIdVarPlStmt mapcidvarplstmt = CMappingColIdVarPlStmt
(
m_pmp,
pdxltrctxbt,
pdrgpdxltrctx,
pdxltrctxOut,
m_pctxdxltoplstmt,
pplanParent
);
Expr *pexpr = m_pdxlsctranslator->PexprFromDXLNodeScalar
(
pdxlnCond,
&mapcidvarplstmt
);
plQuals = gpdb::PlAppendElement(plQuals, pexpr);
return plQuals;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToPlStmt::TranslatePlanCosts
//
// @doc:
// Translates DXL plan costs into the GPDB cost variables
//
//---------------------------------------------------------------------------
void
CTranslatorDXLToPlStmt::TranslatePlanCosts
(
const CDXLOperatorCost *pdxlopcost,
Cost *pcostStartupOut,
Cost *pcostTotalOut,
Cost *pcostRowsOut,
INT * piWidthOut
)
{
*pcostStartupOut = CostFromStr(pdxlopcost->PstrStartupCost());
*pcostTotalOut = CostFromStr(pdxlopcost->PstrTotalCost());
*pcostRowsOut = CostFromStr(pdxlopcost->PstrRows());
*piWidthOut = CTranslatorUtils::IFromStr(pdxlopcost->PstrWidth());
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToPlStmt::TranslateProjListAndFilter
//
// @doc:
// Translates DXL proj list and filter into GPDB's target and qual lists,
// respectively
//
//---------------------------------------------------------------------------
void
CTranslatorDXLToPlStmt::TranslateProjListAndFilter
(
const CDXLNode *pdxlnPrL,
const CDXLNode *pdxlnFilter,
const CDXLTranslateContextBaseTable *pdxltrctxbt,
DrgPdxltrctx *pdrgpdxltrctx,
List **pplTargetListOut,
List **pplQualOut,
CDXLTranslateContext *pdxltrctxOut,
Plan *pplanParent
)
{
// translate proj list
*pplTargetListOut = PlTargetListFromProjList
(
pdxlnPrL,
pdxltrctxbt, // base table translation context
pdrgpdxltrctx,
pdxltrctxOut,
pplanParent
);
// translate filter
*pplQualOut = PlQualFromFilter
(
pdxlnFilter,
pdxltrctxbt, // base table translation context
pdrgpdxltrctx,
pdxltrctxOut,
pplanParent
);
}
//---------------------------------------------------------------------------
// @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 *pdxlnHashExprList,
const CDXLTranslateContext *pdxltrctxChild,
List **pplHashExprOut,
List **pplHashExprTypesOut,
CDXLTranslateContext *pdxltrctxOut,
Plan *pplanParent
)
{
GPOS_ASSERT(NIL == *pplHashExprOut);
GPOS_ASSERT(NIL == *pplHashExprTypesOut);
List *plHashExpr = NIL;
List *plHashExprTypes = NIL;
DrgPdxltrctx *pdrgpdxltrctx = GPOS_NEW(m_pmp) DrgPdxltrctx(m_pmp);
pdrgpdxltrctx->Append(pdxltrctxChild);
const ULONG ulArity = pdxlnHashExprList->UlArity();
for (ULONG ul = 0; ul < ulArity; ul++)
{
CDXLNode *pdxlnHashExpr = (*pdxlnHashExprList)[ul];
CDXLScalarHashExpr *pdxlopHashExpr = CDXLScalarHashExpr::PdxlopConvert(pdxlnHashExpr->Pdxlop());
// the type of the hash expression in GPDB is computed as the left operand
// of the equality operator of the actual hash expression type
const IMDType *pmdtype = m_pmda->Pmdtype(pdxlopHashExpr->PmdidType());
const IMDScalarOp *pmdscop = m_pmda->Pmdscop(pmdtype->PmdidCmp(IMDType::EcmptEq));
const IMDId *pmdidHashType = pmdscop->PmdidTypeLeft();
plHashExprTypes = gpdb::PlAppendOid(plHashExprTypes, CMDIdGPDB::PmdidConvert(pmdidHashType)->OidObjectId());
GPOS_ASSERT(1 == pdxlnHashExpr->UlArity());
CDXLNode *pdxlnExpr = (*pdxlnHashExpr)[0];
CMappingColIdVarPlStmt mapcidvarplstmt = CMappingColIdVarPlStmt
(
m_pmp,
NULL,
pdrgpdxltrctx,
pdxltrctxOut,
m_pctxdxltoplstmt,
pplanParent
);
Expr *pexpr = m_pdxlsctranslator->PexprFromDXLNodeScalar(pdxlnExpr, &mapcidvarplstmt);
plHashExpr = gpdb::PlAppendElement(plHashExpr, pexpr);
GPOS_ASSERT((ULONG) gpdb::UlListLength(plHashExpr) == ul + 1);
}
*pplHashExprOut = plHashExpr;
*pplHashExprTypesOut = plHashExprTypes;
// cleanup
pdrgpdxltrctx->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 *pdxlnSortColList,
const CDXLTranslateContext *pdxltrctxChild,
AttrNumber *pattnoSortColIds,
Oid *poidSortOpIds
)
{
const ULONG ulArity = pdxlnSortColList->UlArity();
for (ULONG ul = 0; ul < ulArity; ul++)
{
CDXLNode *pdxlnSortCol = (*pdxlnSortColList)[ul];
CDXLScalarSortCol *pdxlopSortCol = CDXLScalarSortCol::PdxlopConvert(pdxlnSortCol->Pdxlop());
ULONG ulSortColId = pdxlopSortCol->UlColId();
const TargetEntry *pteSortCol = pdxltrctxChild->Pte(ulSortColId);
if (NULL == pteSortCol)
{
GPOS_RAISE(gpdxl::ExmaDXL, gpdxl::ExmiDXL2PlStmtAttributeNotFound, ulSortColId);
}
pattnoSortColIds[ul] = pteSortCol->resno;
poidSortOpIds[ul] = CMDIdGPDB::PmdidConvert(pdxlopSortCol->PmdidSortOp())->OidObjectId();
}
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToPlStmt::CostFromStr
//
// @doc:
// Parses a cost value from a string
//
//---------------------------------------------------------------------------
Cost
CTranslatorDXLToPlStmt::CostFromStr
(
const CWStringBase *pstr
)
{
CHAR *sz = CTranslatorUtils::SzFromWsz(pstr->Wsz());
return gpos::clib::DStrToD(sz);
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToPlStmt::FTargetTableDistributed
//
// @doc:
// Check if given operator is a DML on a distributed table
//
//---------------------------------------------------------------------------
BOOL
CTranslatorDXLToPlStmt::FTargetTableDistributed
(
CDXLOperator *pdxlop
)
{
if (EdxlopPhysicalDML != pdxlop->Edxlop())
{
return false;
}
CDXLPhysicalDML *pdxlopDML = CDXLPhysicalDML::PdxlopConvert(pdxlop);
IMDId *pmdid = pdxlopDML->Pdxltabdesc()->Pmdid();
return IMDRelation::EreldistrMasterOnly != m_pmda->Pmdrel(pmdid)->Ereldistribution();
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToPlStmt::IAddTargetEntryForColId
//
// @doc:
// Add a new target entry for the given colid to the given target list and
// return the position of the new entry
//
//---------------------------------------------------------------------------
ULONG
CTranslatorDXLToPlStmt::UlAddTargetEntryForColId
(
List **pplTargetList,
CDXLTranslateContext *pdxltrctx,
ULONG ulColId,
BOOL fResjunk
)
{
GPOS_ASSERT(NULL != pplTargetList);
const TargetEntry *pte = pdxltrctx->Pte(ulColId);
if (NULL == pte)
{
// colid not found in translate context
return 0;
}
// TODO: antova - Oct 29, 2012; see if entry already exists in the target list
OID oidExpr = gpdb::OidExprType((Node*) pte->expr);
Var *pvar = gpdb::PvarMakeVar
(
OUTER,
pte->resno,
oidExpr,
-1, // vartypmod
0 // varlevelsup
);
ULONG ulResNo = gpdb::UlListLength(*pplTargetList) + 1;
CHAR *szResName = PStrDup(pte->resname);
TargetEntry *pteNew = gpdb::PteMakeTargetEntry((Expr*) pvar, ulResNo, szResName, fResjunk);
*pplTargetList = gpdb::PlAppendElement(*pplTargetList, pteNew);
return pte->resno;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToPlStmt::JtFromEdxljt
//
// @doc:
// Translates the join type from its DXL representation into the GPDB one
//
//---------------------------------------------------------------------------
JoinType
CTranslatorDXLToPlStmt::JtFromEdxljt
(
EdxlJoinType edxljt
)
{
GPOS_ASSERT(EdxljtSentinel > edxljt);
JoinType jt = JOIN_INNER;
switch (edxljt)
{
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_IN;
break;
case EdxljtLeftAntiSemijoin:
jt = JOIN_LASJ;
break;
case EdxljtLeftAntiSemijoinNotIn:
jt = JOIN_LASJ_NOTIN;
break;
default:
GPOS_ASSERT(!"Unrecognized join type");
}
return jt;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToPlStmt::PplanCTAS
//
// @doc:
// Sets the vartypmod fields in the target entries of the given target list
//
//---------------------------------------------------------------------------
void
CTranslatorDXLToPlStmt::SetVarTypMod
(
const CDXLPhysicalCTAS *pdxlop,
List *plTargetList
)
{
GPOS_ASSERT(NULL != plTargetList);
DrgPi *pdrgpi = pdxlop->PdrgpiVarTypeMod();
GPOS_ASSERT(pdrgpi->UlLength() == gpdb::UlListLength(plTargetList));
ULONG ul = 0;
ListCell *plc = NULL;
ForEach (plc, plTargetList)
{
TargetEntry *pte = (TargetEntry *) lfirst(plc);
GPOS_ASSERT(IsA(pte, TargetEntry));
if (IsA(pte->expr, Var))
{
pte->expr;
Var *var = (Var*) pte->expr;
var->vartypmod = *(*pdrgpi)[ul];
}
++ul;
}
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToPlStmt::PplanCTAS
//
// @doc:
// Translates a DXL CTAS node
//
//---------------------------------------------------------------------------
Plan *
CTranslatorDXLToPlStmt::PplanCTAS
(
const CDXLNode *pdxlnCTAS,
CDXLTranslateContext *pdxltrctxOut,
Plan *pplanParent,
DrgPdxltrctx *pdrgpdxltrctxPrevSiblings
)
{
CDXLPhysicalCTAS *pdxlop = CDXLPhysicalCTAS::PdxlopConvert(pdxlnCTAS->Pdxlop());
CDXLNode *pdxlnPrL = (*pdxlnCTAS)[0];
CDXLNode *pdxlnChild = (*pdxlnCTAS)[1];
GPOS_ASSERT(NULL == pdxlop->Pdxlctasopt()->Pdrgpctasopt());
CDXLTranslateContext dxltrctxChild(m_pmp, false, pdxltrctxOut->PhmColParam());
Plan *pplan = PplFromDXL(pdxlnChild, &dxltrctxChild, pplanParent, pdrgpdxltrctxPrevSiblings);
// fix target list to match the required column names
DrgPdxltrctx *pdrgpdxltrctx = GPOS_NEW(m_pmp) DrgPdxltrctx(m_pmp);
pdrgpdxltrctx->Append(&dxltrctxChild);
List *plTargetList = PlTargetListFromProjList
(
pdxlnPrL,
NULL, // pdxltrctxbt
pdrgpdxltrctx,
pdxltrctxOut,
pplan
);
SetVarTypMod(pdxlop, plTargetList);
SetParamIds(pplan);
// cleanup
pdrgpdxltrctx->Release();
// translate operator costs
TranslatePlanCosts
(
CDXLPhysicalProperties::PdxlpropConvert(pdxlnCTAS->Pdxlprop())->Pdxlopcost(),
&(pplan->startup_cost),
&(pplan->total_cost),
&(pplan->plan_rows),
&(pplan->plan_width)
);
IntoClause *pintocl = PintoclFromCtas(pdxlop);
GpPolicy *pdistrpolicy = PdistrpolicyFromCtas(pdxlop);
m_pctxdxltoplstmt->AddCtasInfo(pintocl, pdistrpolicy);
GPOS_ASSERT(IMDRelation::EreldistrMasterOnly != pdxlop->Ereldistrpolicy());
m_fTargetTableDistributed = true;
// Add a result node on top with the correct projection list
Result *presult = MakeNode(Result);
Plan *pplanResult = &(presult->plan);
pplanResult->plan_node_id = m_pctxdxltoplstmt->UlNextPlanId();
pplanResult->plan_parent_node_id = IPlanId(pplanParent);
pplanResult->nMotionNodes = pplan->nMotionNodes;
pplanResult->lefttree = pplan;
pplan->plan_parent_node_id = IPlanId(pplanResult);
pplanResult->targetlist = plTargetList;
SetParamIds(pplanResult);
pplan = (Plan *) presult;
return (Plan *) pplan;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToPlStmt::PintoclFromCtas
//
// @doc:
// Translates a DXL CTAS into clause
//
//---------------------------------------------------------------------------
IntoClause *
CTranslatorDXLToPlStmt::PintoclFromCtas
(
const CDXLPhysicalCTAS *pdxlop
)
{
IntoClause *pintocl = MakeNode(IntoClause);
pintocl->rel = MakeNode(RangeVar);
pintocl->rel->istemp = pdxlop->FTemporary();
pintocl->rel->relname = CTranslatorUtils::SzFromWsz(pdxlop->Pmdname()->Pstr()->Wsz());
pintocl->rel->schemaname = NULL;
if (NULL != pdxlop->PmdnameSchema())
{
pintocl->rel->schemaname = CTranslatorUtils::SzFromWsz(pdxlop->PmdnameSchema()->Pstr()->Wsz());
}
CDXLCtasStorageOptions *pdxlctasopt = pdxlop->Pdxlctasopt();
if (NULL != pdxlctasopt->PmdnameTablespace())
{
pintocl->tableSpaceName = CTranslatorUtils::SzFromWsz(pdxlop->Pdxlctasopt()->PmdnameTablespace()->Pstr()->Wsz());
}
pintocl->onCommit = (OnCommitAction) pdxlctasopt->Ectascommit();
pintocl->options = PlCtasOptions(pdxlctasopt->Pdrgpctasopt());
// get column names
DrgPdxlcd *pdrgpdxlcd = pdxlop->Pdrgpdxlcd();
const ULONG ulCols = pdrgpdxlcd->UlLength();
pintocl->colNames = NIL;
for (ULONG ul = 0; ul < ulCols; ++ul)
{
const CDXLColDescr *pdxlcd = (*pdrgpdxlcd)[ul];
CHAR *szColName = CTranslatorUtils::SzFromWsz(pdxlcd->Pmdname()->Pstr()->Wsz());
ColumnDef *pcoldef = MakeNode(ColumnDef);
pcoldef->colname = szColName;
pcoldef->is_local = true;
pintocl->colNames = gpdb::PlAppendElement(pintocl->colNames, pcoldef);
}
return pintocl;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToPlStmt::PdistrpolicyFromCtas
//
// @doc:
// Translates distribution policy given by a physical CTAS operator
//
//---------------------------------------------------------------------------
GpPolicy *
CTranslatorDXLToPlStmt::PdistrpolicyFromCtas
(
const CDXLPhysicalCTAS *pdxlop
)
{
DrgPul *pdrgpulDistrCols = pdxlop->PdrgpulDistr();
const ULONG ulDistrCols = pdrgpulDistrCols->UlSafeLength();
ULONG ulDistrColsAlloc = 1;
if (0 < ulDistrCols)
{
ulDistrColsAlloc = ulDistrCols;
}
GpPolicy *pdistrpolicy = (GpPolicy *) gpdb::GPDBAlloc(sizeof(GpPolicy) +
ulDistrColsAlloc * sizeof(AttrNumber));
GPOS_ASSERT(IMDRelation::EreldistrHash == pdxlop->Ereldistrpolicy() ||
IMDRelation::EreldistrRandom == pdxlop->Ereldistrpolicy());
pdistrpolicy->ptype = POLICYTYPE_PARTITIONED;
pdistrpolicy->nattrs = 0;
if (IMDRelation::EreldistrHash == pdxlop->Ereldistrpolicy())
{
GPOS_ASSERT(0 < ulDistrCols);
pdistrpolicy->nattrs = ulDistrCols;
for (ULONG ul = 0; ul < ulDistrCols; ul++)
{
ULONG ulColPos = *((*pdrgpulDistrCols)[ul]);
pdistrpolicy->attrs[ul] = ulColPos + 1;
}
}
return pdistrpolicy;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToPlStmt::PlCtasOptions
//
// @doc:
// Translates CTAS options
//
//---------------------------------------------------------------------------
List *
CTranslatorDXLToPlStmt::PlCtasOptions
(
CDXLCtasStorageOptions::DrgPctasOpt *pdrgpctasopt
)
{
if (NULL == pdrgpctasopt)
{
return NIL;
}
const ULONG ulOptions = pdrgpctasopt->UlLength();
List *plOptions = NIL;
for (ULONG ul = 0; ul < ulOptions; ul++)
{
CDXLCtasStorageOptions::CDXLCtasOption *pdxlopt = (*pdrgpctasopt)[ul];
CWStringBase *pstrName = pdxlopt->m_pstrName;
CWStringBase *pstrValue = pdxlopt->m_pstrValue;
DefElem *pdefelem = MakeNode(DefElem);
pdefelem->defname = CTranslatorUtils::SzFromWsz(pstrName->Wsz());
if (!pdxlopt->m_fNull)
{
NodeTag argType = (NodeTag) pdxlopt->m_ulType;
GPOS_ASSERT(T_Integer == argType || T_String == argType);
if (T_Integer == argType)
{
pdefelem->arg = (Node *) gpdb::PvalMakeInteger(CTranslatorUtils::LFromStr(pstrValue));
}
else
{
pdefelem->arg = (Node *) gpdb::PvalMakeString(CTranslatorUtils::SzFromWsz(pstrValue->Wsz()));
}
}
plOptions = gpdb::PlAppendElement(plOptions, pdefelem);
}
return plOptions;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToPlStmt::PplanBitmapTableScan
//
// @doc:
// Translates a DXL bitmap table scan node into a BitmapTableScan node
//
//---------------------------------------------------------------------------
Plan *
CTranslatorDXLToPlStmt::PplanBitmapTableScan
(
const CDXLNode *pdxlnBitmapScan,
CDXLTranslateContext *pdxltrctxOut,
Plan *pplanParent,
DrgPdxltrctx *pdrgpdxltrctxPrevSiblings
)
{
ULONG ulPartIndex = INVALID_PART_INDEX;
ULONG ulPartIndexPrintable = INVALID_PART_INDEX;
const CDXLTableDescr *pdxltabdesc = NULL;
BOOL fDynamic = false;
CDXLOperator *pdxlop = pdxlnBitmapScan->Pdxlop();
if (EdxlopPhysicalBitmapTableScan == pdxlop->Edxlop())
{
pdxltabdesc = CDXLPhysicalBitmapTableScan::PdxlopConvert(pdxlop)->Pdxltabdesc();
}
else
{
GPOS_ASSERT(EdxlopPhysicalDynamicBitmapTableScan == pdxlop->Edxlop());
CDXLPhysicalDynamicBitmapTableScan *pdxlopDynamic =
CDXLPhysicalDynamicBitmapTableScan::PdxlopConvert(pdxlop);
pdxltabdesc = pdxlopDynamic->Pdxltabdesc();
ulPartIndex = pdxlopDynamic->UlPartIndexId();
ulPartIndexPrintable = pdxlopDynamic->UlPartIndexIdPrintable();
fDynamic = true;
}
// translation context for column mappings in the base relation
CDXLTranslateContextBaseTable dxltrctxbt(m_pmp);
// add the new range table entry as the last element of the range table
Index iRel = gpdb::UlListLength(m_pctxdxltoplstmt->PlPrte()) + 1;
const IMDRelation *pmdrel = m_pmda->Pmdrel(pdxltabdesc->Pmdid());
const ULONG ulRelCols = pmdrel->UlColumns() - pmdrel->UlSystemColumns();
RangeTblEntry *prte = PrteFromTblDescr(pdxltabdesc, NULL /*pdxlid*/, ulRelCols, iRel, &dxltrctxbt);
GPOS_ASSERT(NULL != prte);
prte->requiredPerms |= ACL_SELECT;
m_pctxdxltoplstmt->AddRTE(prte);
BitmapTableScan *pdbts = MakeNode(BitmapTableScan);
pdbts->scan.scanrelid = iRel;
pdbts->scan.partIndex = ulPartIndex;
pdbts->scan.partIndexPrintable = ulPartIndexPrintable;
Plan *pplan = &(pdbts->scan.plan);
pplan->plan_node_id = m_pctxdxltoplstmt->UlNextPlanId();
pplan->plan_parent_node_id = IPlanId(pplanParent);
pplan->nMotionNodes = 0;
// translate operator costs
TranslatePlanCosts
(
CDXLPhysicalProperties::PdxlpropConvert(pdxlnBitmapScan->Pdxlprop())->Pdxlopcost(),
&(pplan->startup_cost),
&(pplan->total_cost),
&(pplan->plan_rows),
&(pplan->plan_width)
);
GPOS_ASSERT(4 == pdxlnBitmapScan->UlArity());
// translate proj list and filter
CDXLNode *pdxlnPrL = (*pdxlnBitmapScan)[0];
CDXLNode *pdxlnFilter = (*pdxlnBitmapScan)[1];
CDXLNode *pdxlnRecheckCond = (*pdxlnBitmapScan)[2];
CDXLNode *pdxlnBitmapAccessPath = (*pdxlnBitmapScan)[3];
List *plQuals = NULL;
TranslateProjListAndFilter
(
pdxlnPrL,
pdxlnFilter,
&dxltrctxbt, // translate context for the base table
pdrgpdxltrctxPrevSiblings,
&pplan->targetlist,
&plQuals,
pdxltrctxOut,
pplan
);
pplan->qual = plQuals;
pdbts->bitmapqualorig = PlQualFromFilter
(
pdxlnRecheckCond,
&dxltrctxbt,
pdrgpdxltrctxPrevSiblings,
pdxltrctxOut,
pplan
);
pdbts->scan.plan.lefttree = PplanBitmapAccessPath
(
pdxlnBitmapAccessPath,
pdxltrctxOut,
pmdrel,
pdxltabdesc,
&dxltrctxbt,
pdrgpdxltrctxPrevSiblings,
pdbts
);
SetParamIds(pplan);
return (Plan *) pdbts;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToPlStmt::PplanBitmapAccessPath
//
// @doc:
// Translate the tree of bitmap index operators that are under the given
// (dynamic) bitmap table scan.
//
//---------------------------------------------------------------------------
Plan *
CTranslatorDXLToPlStmt::PplanBitmapAccessPath
(
const CDXLNode *pdxlnBitmapAccessPath,
CDXLTranslateContext *pdxltrctxOut,
const IMDRelation *pmdrel,
const CDXLTableDescr *pdxltabdesc,
CDXLTranslateContextBaseTable *pdxltrctxbt,
DrgPdxltrctx *pdrgpdxltrctxPrevSiblings,
BitmapTableScan *pdbts
)
{
Edxlopid edxlopid = pdxlnBitmapAccessPath->Pdxlop()->Edxlop();
if (EdxlopScalarBitmapIndexProbe == edxlopid)
{
return PplanBitmapIndexProbe
(
pdxlnBitmapAccessPath,
pdxltrctxOut,
pmdrel,
pdxltabdesc,
pdxltrctxbt,
pdrgpdxltrctxPrevSiblings,
pdbts
);
}
GPOS_ASSERT(EdxlopScalarBitmapBoolOp == edxlopid);
return PplanBitmapBoolOp
(
pdxlnBitmapAccessPath,
pdxltrctxOut,
pmdrel,
pdxltabdesc,
pdxltrctxbt,
pdrgpdxltrctxPrevSiblings,
pdbts
);
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToScalar::PplanBitmapBoolOp
//
// @doc:
// Translates a DML bitmap bool op expression
//
//---------------------------------------------------------------------------
Plan *
CTranslatorDXLToPlStmt::PplanBitmapBoolOp
(
const CDXLNode *pdxlnBitmapBoolOp,
CDXLTranslateContext *pdxltrctxOut,
const IMDRelation *pmdrel,
const CDXLTableDescr *pdxltabdesc,
CDXLTranslateContextBaseTable *pdxltrctxbt,
DrgPdxltrctx *pdrgpdxltrctxPrevSiblings,
BitmapTableScan *pdbts
)
{
GPOS_ASSERT(NULL != pdxlnBitmapBoolOp);
GPOS_ASSERT(EdxlopScalarBitmapBoolOp == pdxlnBitmapBoolOp->Pdxlop()->Edxlop());
CDXLScalarBitmapBoolOp *pdxlop = CDXLScalarBitmapBoolOp::PdxlopConvert(pdxlnBitmapBoolOp->Pdxlop());
CDXLNode *pdxlnLeft = (*pdxlnBitmapBoolOp)[0];
CDXLNode *pdxlnRight = (*pdxlnBitmapBoolOp)[1];
Plan *pplanLeft = PplanBitmapAccessPath
(
pdxlnLeft,
pdxltrctxOut,
pmdrel,
pdxltabdesc,
pdxltrctxbt,
pdrgpdxltrctxPrevSiblings,
pdbts
);
Plan *pplanRight = PplanBitmapAccessPath
(
pdxlnRight,
pdxltrctxOut,
pmdrel,
pdxltabdesc,
pdxltrctxbt,
pdrgpdxltrctxPrevSiblings,
pdbts
);
List *plChildPlans = ListMake2(pplanLeft, pplanRight);
Plan *pplan = NULL;
if (CDXLScalarBitmapBoolOp::EdxlbitmapAnd == pdxlop->Edxlbitmapboolop())
{
BitmapAnd *bitmapand = MakeNode(BitmapAnd);
bitmapand->bitmapplans = plChildPlans;
bitmapand->plan.targetlist = NULL;
bitmapand->plan.qual = NULL;
pplan = (Plan *) bitmapand;
}
else
{
BitmapOr *bitmapor = MakeNode(BitmapOr);
bitmapor->bitmapplans = plChildPlans;
bitmapor->plan.targetlist = NULL;
bitmapor->plan.qual = NULL;
pplan = (Plan *) bitmapor;
}
return pplan;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToPlStmt::PplanBitmapIndexProbe
//
// @doc:
// Translate CDXLScalarBitmapIndexProbe into BitmapIndexScan
//
//---------------------------------------------------------------------------
Plan *
CTranslatorDXLToPlStmt::PplanBitmapIndexProbe
(
const CDXLNode *pdxlnBitmapIndexProbe,
CDXLTranslateContext *pdxltrctxOut,
const IMDRelation *pmdrel,
const CDXLTableDescr *pdxltabdesc,
CDXLTranslateContextBaseTable *pdxltrctxbt,
DrgPdxltrctx *pdrgpdxltrctxPrevSiblings,
BitmapTableScan *pdbts
)
{
CDXLScalarBitmapIndexProbe *pdxlopScalar =
CDXLScalarBitmapIndexProbe::PdxlopConvert(pdxlnBitmapIndexProbe->Pdxlop());
BitmapIndexScan *pbis = MakeNode(BitmapIndexScan);
pbis->scan.scanrelid = pdbts->scan.scanrelid;
pbis->scan.partIndex = pdbts->scan.partIndex;
CMDIdGPDB *pmdidIndex = CMDIdGPDB::PmdidConvert(pdxlopScalar->Pdxlid()->Pmdid());
const IMDIndex *pmdindex = m_pmda->Pmdindex(pmdidIndex);
Oid oidIndex = pmdidIndex->OidObjectId();
GPOS_ASSERT(InvalidOid != oidIndex);
Plan *pplanParent = (Plan *) pdbts;
pbis->indexid = oidIndex;
OID oidRel = CMDIdGPDB::PmdidConvert(pdxltabdesc->Pmdid())->OidObjectId();
pbis->logicalIndexInfo = gpdb::Plgidxinfo(oidRel, oidIndex);
Plan *pplan = &(pbis->scan.plan);
pplan->plan_node_id = m_pctxdxltoplstmt->UlNextPlanId();
pplan->plan_parent_node_id = IPlanId(pplanParent);
pplan->nMotionNodes = 0;
GPOS_ASSERT(1 == pdxlnBitmapIndexProbe->UlArity());
CDXLNode *pdxlnIndexCondList = (*pdxlnBitmapIndexProbe)[0];
List *plIndexConditions = NIL;
List *plIndexOrigConditions = NIL;
List *plIndexStratgey = NIL;
List *plIndexSubtype = NIL;
TranslateIndexConditions
(
pdxlnIndexCondList,
pdxltabdesc,
false /*fIndexOnlyScan*/,
pmdindex,
pmdrel,
pdxltrctxOut,
pdxltrctxbt,
pdrgpdxltrctxPrevSiblings,
pplan,
&plIndexConditions,
&plIndexOrigConditions,
&plIndexStratgey,
&plIndexSubtype
);
pbis->indexqual = plIndexConditions;
pbis->indexqualorig = plIndexOrigConditions;
pbis->indexstrategy = plIndexStratgey;
pbis->indexsubtype = plIndexSubtype;
SetParamIds(pplan);
return pplan;
}
// EOF