blob: 2985378ad59b9d10a0b97d84df9cbf77347b0e10 [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:
// CTranslatorQueryToDXL.cpp
//
// @doc:
// Implementation of the methods used to translate a query into DXL tree.
// All translator methods allocate memory in the provided memory pool, and
// the caller is responsible for freeing it
//
// @test:
//
//---------------------------------------------------------------------------
#include "postgres.h"
#include "access/sysattr.h"
#include "nodes/plannodes.h"
#include "nodes/parsenodes.h"
#include "nodes/makefuncs.h"
#include "optimizer/walkers.h"
#include "gpos/base.h"
#include "gpos/common/CAutoTimer.h"
#include "gpopt/base/CUtils.h"
#include "gpopt/mdcache/CMDAccessor.h"
#include "gpopt/translate/CCTEListEntry.h"
#include "gpopt/translate/CQueryMutators.h"
#include "gpopt/translate/CTranslatorUtils.h"
#include "gpopt/translate/CTranslatorQueryToDXL.h"
#include "gpopt/translate/CTranslatorDXLToPlStmt.h"
#include "gpopt/translate/CTranslatorRelcacheToDXL.h"
#include "naucrates/exception.h"
#include "naucrates/dxl/CDXLUtils.h"
#include "naucrates/dxl/operators/dxlops.h"
#include "naucrates/dxl/operators/CDXLScalarBooleanTest.h"
#include "naucrates/dxl/operators/CDXLDatumInt8.h"
#include "naucrates/dxl/xml/dxltokens.h"
#include "naucrates/md/IMDScalarOp.h"
#include "naucrates/md/IMDAggregate.h"
#include "naucrates/md/IMDTypeBool.h"
#include "naucrates/md/IMDTypeInt8.h"
#include "naucrates/md/CMDIdGPDBCtas.h"
#include "naucrates/traceflags/traceflags.h"
#include "gpopt/gpdbwrappers.h"
using namespace gpdxl;
using namespace gpos;
using namespace gpopt;
using namespace gpnaucrates;
using namespace gpmd;
extern bool optimizer_enable_ctas;
extern bool optimizer_dml_triggers;
extern bool optimizer_dml_constraints;
extern bool optimizer_enable_multiple_distinct_aggs;
// OIDs of variants of LEAD window function
const OID rgOIDLead[] =
{
7011, 7074, 7075, 7310, 7312,
7314, 7316, 7318,
7320, 7322, 7324, 7326, 7328,
7330, 7332, 7334, 7336, 7338,
7340, 7342, 7344, 7346, 7348,
7350, 7352, 7354, 7356, 7358,
7360, 7362, 7364, 7366, 7368,
7370, 7372, 7374, 7376, 7378,
7380, 7382, 7384, 7386, 7388,
7390, 7392, 7394, 7396, 7398,
7400, 7402, 7404, 7406, 7408,
7410, 7412, 7414, 7416, 7418,
7420, 7422, 7424, 7426, 7428,
7430, 7432, 7434, 7436, 7438,
7440, 7442, 7444, 7446, 7448,
7450, 7452, 7454, 7456, 7458,
7460, 7462, 7464, 7466, 7468,
7470, 7472, 7474, 7476, 7478,
7480, 7482, 7484, 7486, 7488,
7214, 7215, 7216, 7220, 7222,
7224, 7244, 7246, 7248, 7260,
7262, 7264
};
// OIDs of variants of LAG window function
const OID rgOIDLag[] =
{
7675, 7491, 7493, 7495, 7497, 7499,
7501, 7503, 7505, 7507, 7509,
7511, 7513, 7515, 7517, 7519,
7521, 7523, 7525, 7527, 7529,
7531, 7533, 7535, 7537, 7539,
7541, 7543, 7545, 7547, 7549,
7551, 7553, 7555, 7557, 7559,
7561, 7563, 7565, 7567, 7569,
7571, 7573, 7575, 7577, 7579,
7581, 7583, 7585, 7587, 7589,
7591, 7593, 7595, 7597, 7599,
7601, 7603, 7605, 7607, 7609,
7611, 7613, 7615, 7617, 7619,
7621, 7623, 7625, 7627, 7629,
7631, 7633, 7635, 7637, 7639,
7641, 7643, 7645, 7647, 7649,
7651, 7653, 7655, 7657, 7659,
7661, 7663, 7665, 7667, 7669,
7671, 7673,
7211, 7212, 7213, 7226, 7228,
7230, 7250, 7252, 7254, 7266,
7268, 7270
};
//---------------------------------------------------------------------------
// @function:
// CTranslatorQueryToDXL::CTranslatorQueryToDXL
//
// @doc:
// Ctor
//
//---------------------------------------------------------------------------
CTranslatorQueryToDXL::CTranslatorQueryToDXL
(
IMemoryPool *pmp,
CMDAccessor *pmda,
CIdGenerator *pidgtorColId,
CIdGenerator *pidgtorCTE,
CMappingVarColId *pmapvarcolid,
Query *pquery,
ULONG ulQueryLevel,
BOOL fTopDMLQuery,
HMUlCTEListEntry *phmulCTEEntries
)
:
m_pmp(pmp),
m_sysid(IMDId::EmdidGPDB, GPMD_GPDB_SYSID),
m_pmda(pmda),
m_pidgtorCol(pidgtorColId),
m_pidgtorCTE(pidgtorCTE),
m_pmapvarcolid(pmapvarcolid),
m_ulQueryLevel(ulQueryLevel),
m_fHasDistributedTables(false),
m_fTopDMLQuery(fTopDMLQuery),
m_fCTASQuery(false),
m_phmulCTEEntries(NULL),
m_pdrgpdxlnQueryOutput(NULL),
m_pdrgpdxlnCTE(NULL),
m_phmulfCTEProducers(NULL)
{
GPOS_ASSERT(NULL != pquery);
CheckSupportedCmdType(pquery);
m_phmulCTEEntries = GPOS_NEW(m_pmp) HMUlCTEListEntry(m_pmp);
m_pdrgpdxlnCTE = GPOS_NEW(m_pmp) DrgPdxln(m_pmp);
m_phmulfCTEProducers = GPOS_NEW(m_pmp) HMUlF(m_pmp);
if (NULL != phmulCTEEntries)
{
HMIterUlCTEListEntry hmiterullist(phmulCTEEntries);
while (hmiterullist.FAdvance())
{
ULONG ulCTEQueryLevel = *(hmiterullist.Pk());
CCTEListEntry *pctelistentry = const_cast<CCTEListEntry *>(hmiterullist.Pt());
// CTE's that have been defined before the m_ulQueryLevel
// should only be inserted into the hash map
// For example:
// WITH ab as (SELECT a as a, b as b from foo)
// SELECT *
// FROM
// (WITH aEq10 as (SELECT b from ab ab1 where ab1.a = 10)
// SELECT *
// FROM (WITH aEq20 as (SELECT b from ab ab2 where ab2.a = 20)
// SELECT * FROM aEq10 WHERE b > (SELECT min(b) from aEq20)
// ) dtInner
// ) dtOuter
// When translating the from expression containing "aEq10" in the derived table "dtInner"
// we have already seen three CTE namely: "ab", "aEq10" and "aEq20". BUT when we expand aEq10
// in the dt1, we should only have access of CTE's defined prior to its level namely "ab".
if (ulCTEQueryLevel < ulQueryLevel && NULL != pctelistentry)
{
pctelistentry->AddRef();
#ifdef GPOS_DEBUG
BOOL fRes =
#endif
m_phmulCTEEntries->FInsert(GPOS_NEW(pmp) ULONG(ulCTEQueryLevel), pctelistentry);
GPOS_ASSERT(fRes);
}
}
}
// check if the query has any unsupported node types
CheckUnsupportedNodeTypes(pquery);
// check if the query has SIRV functions in the targetlist without a FROM clause
CheckSirvFuncsWithoutFromClause(pquery);
// first normalize the query
m_pquery = CQueryMutators::PqueryNormalize(m_pmp, m_pmda, pquery, ulQueryLevel);
if (NULL != m_pquery->cteList)
{
ConstructCTEProducerList(m_pquery->cteList, ulQueryLevel);
}
m_psctranslator = GPOS_NEW(m_pmp) CTranslatorScalarToDXL
(
m_pmp,
m_pmda,
m_pidgtorCol,
m_pidgtorCTE,
m_ulQueryLevel,
true, /* m_fQuery */
NULL, /* m_pplstmt */
NULL /* m_pmappv */,
m_phmulCTEEntries,
m_pdrgpdxlnCTE
);
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorQueryToDXL::PtrquerytodxlInstance
//
// @doc:
// Factory function
//
//---------------------------------------------------------------------------
CTranslatorQueryToDXL *
CTranslatorQueryToDXL::PtrquerytodxlInstance
(
IMemoryPool *pmp,
CMDAccessor *pmda,
CIdGenerator *pidgtorColId,
CIdGenerator *pidgtorCTE,
CMappingVarColId *pmapvarcolid,
Query *pquery,
ULONG ulQueryLevel,
HMUlCTEListEntry *phmulCTEEntries
)
{
return GPOS_NEW(pmp) CTranslatorQueryToDXL
(
pmp,
pmda,
pidgtorColId,
pidgtorCTE,
pmapvarcolid,
pquery,
ulQueryLevel,
false, // fTopDMLQuery
phmulCTEEntries
);
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorQueryToDXL::~CTranslatorQueryToDXL
//
// @doc:
// Dtor
//
//---------------------------------------------------------------------------
CTranslatorQueryToDXL::~CTranslatorQueryToDXL()
{
GPOS_DELETE(m_psctranslator);
GPOS_DELETE(m_pmapvarcolid);
gpdb::GPDBFree(m_pquery);
m_phmulCTEEntries->Release();
m_pdrgpdxlnCTE->Release();
m_phmulfCTEProducers->Release();
CRefCount::SafeRelease(m_pdrgpdxlnQueryOutput);
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorQueryToDXL::CheckUnsupportedNodeTypes
//
// @doc:
// Check for unsupported node types, and throws an exception when found
//
//---------------------------------------------------------------------------
void
CTranslatorQueryToDXL::CheckUnsupportedNodeTypes
(
Query *pquery
)
{
SUnsupportedFeature rgUnsupported[] =
{
{T_RowExpr, GPOS_WSZ_LIT("ROW EXPRESSION")},
{T_RowCompareExpr, GPOS_WSZ_LIT("ROW COMPARE")},
{T_FieldSelect, GPOS_WSZ_LIT("FIELDSELECT")},
{T_FieldStore, GPOS_WSZ_LIT("FIELDSTORE")},
{T_CoerceToDomainValue, GPOS_WSZ_LIT("COERCETODOMAINVALUE")},
{T_GroupId, GPOS_WSZ_LIT("GROUPID")},
{T_PercentileExpr, GPOS_WSZ_LIT("PERCENTILE")},
{T_CurrentOfExpr, GPOS_WSZ_LIT("CURRENT OF")},
};
List *plUnsupported = NIL;
for (ULONG ul = 0; ul < GPOS_ARRAY_SIZE(rgUnsupported); ul++)
{
plUnsupported = gpdb::PlAppendInt(plUnsupported, rgUnsupported[ul].ent);
}
INT iUnsupported = gpdb::IFindNodes((Node *) pquery, plUnsupported);
gpdb::GPDBFree(plUnsupported);
if (0 <= iUnsupported)
{
GPOS_RAISE(gpdxl::ExmaDXL, gpdxl::ExmiQuery2DXLUnsupportedFeature, rgUnsupported[iUnsupported].m_wsz);
}
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorQueryToDXL::CheckSirvFuncsWithoutFromClause
//
// @doc:
// Check for SIRV functions in the target list without a FROM clause, and
// throw an exception when found
//
//---------------------------------------------------------------------------
void
CTranslatorQueryToDXL::CheckSirvFuncsWithoutFromClause
(
Query *pquery
)
{
// if there is a FROM clause or if target list is empty, look no further
if ((NULL != pquery->jointree && 0 < gpdb::UlListLength(pquery->jointree->fromlist))
|| NIL == pquery->targetList)
{
return;
}
// see if we have SIRV functions in the target list
if (FHasSirvFunctions((Node *) pquery->targetList))
{
GPOS_RAISE(gpdxl::ExmaDXL, gpdxl::ExmiQuery2DXLUnsupportedFeature, GPOS_WSZ_LIT("SIRV functions"));
}
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorQueryToDXL::FHasSirvFunctions
//
// @doc:
// Check for SIRV functions in the tree rooted at the given node
//
//---------------------------------------------------------------------------
BOOL
CTranslatorQueryToDXL::FHasSirvFunctions
(
Node *pnode
)
const
{
GPOS_ASSERT(NULL != pnode);
List *plFunctions = gpdb::PlExtractNodesExpression(pnode, T_FuncExpr, true /*descendIntoSubqueries*/);
ListCell *plc = NULL;
BOOL fHasSirv = false;
ForEach (plc, plFunctions)
{
FuncExpr *pfuncexpr = (FuncExpr *) lfirst(plc);
if (CTranslatorUtils::FSirvFunc(m_pmp, m_pmda, pfuncexpr->funcid))
{
fHasSirv = true;
break;
}
}
gpdb::FreeList(plFunctions);
return fHasSirv;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorQueryToDXL::CheckSupportedCmdType
//
// @doc:
// Check for supported command types, throws an exception when command
// type not yet supported
//---------------------------------------------------------------------------
void
CTranslatorQueryToDXL::CheckSupportedCmdType
(
Query *pquery
)
{
if (NULL != pquery->utilityStmt)
{
GPOS_RAISE(gpdxl::ExmaDXL, gpdxl::ExmiQuery2DXLUnsupportedFeature, GPOS_WSZ_LIT("UTILITY command"));
}
if (CMD_SELECT == pquery->commandType)
{
if (!optimizer_enable_ctas && NULL != pquery->intoClause)
{
GPOS_RAISE(gpdxl::ExmaDXL, gpdxl::ExmiQuery2DXLUnsupportedFeature, GPOS_WSZ_LIT("CTAS"));
}
// supported: regular select or CTAS when it is enabled
return;
}
SCmdNameElem rgStrMap[] =
{
{CMD_UTILITY, GPOS_WSZ_LIT("UTILITY command")}
};
const ULONG ulLen = GPOS_ARRAY_SIZE(rgStrMap);
for (ULONG ul = 0; ul < ulLen; ul++)
{
SCmdNameElem mapelem = rgStrMap[ul];
if (mapelem.m_cmdtype == pquery->commandType)
{
GPOS_RAISE(gpdxl::ExmaDXL, gpdxl::ExmiQuery2DXLUnsupportedFeature, mapelem.m_wsz);
}
}
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorQueryToDXL::PdrgpdxlnQueryOutput
//
// @doc:
// Return the list of query output columns
//
//---------------------------------------------------------------------------
DrgPdxln *
CTranslatorQueryToDXL::PdrgpdxlnQueryOutput() const
{
return m_pdrgpdxlnQueryOutput;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorQueryToDXL::PdrgpdxlnCTE
//
// @doc:
// Return the list of CTEs
//
//---------------------------------------------------------------------------
DrgPdxln *
CTranslatorQueryToDXL::PdrgpdxlnCTE() const
{
return m_pdrgpdxlnCTE;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorQueryToDXL::PdxlnFromQueryInternal
//
// @doc:
// Translates a Query into a DXL tree. The function allocates memory in
// the translator memory pool, and caller is responsible for freeing it.
//
//---------------------------------------------------------------------------
CDXLNode *
CTranslatorQueryToDXL::PdxlnFromQueryInternal()
{
CTranslatorUtils::CheckRTEPermissions(m_pquery->rtable);
CDXLNode *pdxlnChild = NULL;
HMIUl *phmiulSortGroupColsColId = GPOS_NEW(m_pmp) HMIUl(m_pmp);
HMIUl *phmiulOutputCols = GPOS_NEW(m_pmp) HMIUl(m_pmp);
// construct CTEAnchor operators for the CTEs defined at the top level
CDXLNode *pdxlnCTEAnchorTop = NULL;
CDXLNode *pdxlnCTEAnchorBottom = NULL;
ConstructCTEAnchors(m_pdrgpdxlnCTE, &pdxlnCTEAnchorTop, &pdxlnCTEAnchorBottom);
GPOS_ASSERT_IMP(0 < m_pdrgpdxlnCTE->UlSafeLength(),
NULL != pdxlnCTEAnchorTop && NULL != pdxlnCTEAnchorBottom);
GPOS_ASSERT_IMP(NULL != m_pquery->setOperations, 0 == gpdb::UlListLength(m_pquery->windowClause));
if (NULL != m_pquery->setOperations)
{
List *plTargetList = m_pquery->targetList;
// translate set operations
pdxlnChild = PdxlnFromSetOp(m_pquery->setOperations, plTargetList, phmiulOutputCols);
CDXLLogicalSetOp *pdxlop = CDXLLogicalSetOp::PdxlopConvert(pdxlnChild->Pdxlop());
const DrgPdxlcd *pdrgpdxlcd = pdxlop->Pdrgpdxlcd();
ListCell *plcTE = NULL;
ULONG ulResNo = 1;
ForEach (plcTE, plTargetList)
{
TargetEntry *pte = (TargetEntry *) lfirst(plcTE);
if (0 < pte->ressortgroupref)
{
ULONG ulColId = ((*pdrgpdxlcd)[ulResNo - 1])->UlID();
AddSortingGroupingColumn(pte, phmiulSortGroupColsColId, ulColId);
}
ulResNo++;
}
}
else if (0 != gpdb::UlListLength(m_pquery->windowClause)) // translate window clauses
{
CDXLNode *pdxln = PdxlnFromGPDBFromExpr(m_pquery->jointree);
GPOS_ASSERT(NULL == m_pquery->groupClause);
pdxlnChild = PdxlnWindow
(
pdxln,
m_pquery->targetList,
m_pquery->windowClause,
m_pquery->sortClause,
phmiulSortGroupColsColId,
phmiulOutputCols
);
}
else
{
pdxlnChild = PdxlnGroupingSets(m_pquery->jointree, m_pquery->targetList, m_pquery->groupClause, m_pquery->hasAggs, phmiulSortGroupColsColId, phmiulOutputCols);
}
// translate limit clause
CDXLNode *pdxlnLimit = PdxlnLgLimit(m_pquery->sortClause, m_pquery->limitCount, m_pquery->limitOffset, pdxlnChild, phmiulSortGroupColsColId);
if (NULL == m_pquery->targetList)
{
m_pdrgpdxlnQueryOutput = GPOS_NEW(m_pmp) DrgPdxln(m_pmp);
}
else
{
m_pdrgpdxlnQueryOutput = PdrgpdxlnConstructOutputCols(m_pquery->targetList, phmiulOutputCols);
}
// cleanup
CRefCount::SafeRelease(phmiulSortGroupColsColId);
phmiulOutputCols->Release();
// add CTE anchors if needed
CDXLNode *pdxlnResult = pdxlnLimit;
if (NULL != pdxlnCTEAnchorTop)
{
GPOS_ASSERT(NULL != pdxlnCTEAnchorBottom);
pdxlnCTEAnchorBottom->AddChild(pdxlnResult);
pdxlnResult = pdxlnCTEAnchorTop;
}
return pdxlnResult;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorQueryToDXL::PdxlnSPJ
//
// @doc:
// Construct a DXL SPJ tree from the given query parts
//
//---------------------------------------------------------------------------
CDXLNode *
CTranslatorQueryToDXL::PdxlnSPJ
(
List *plTargetList,
FromExpr *pfromexpr,
HMIUl *phmiulSortGroupColsColId,
HMIUl *phmiulOutputCols,
List *plGroupClause
)
{
CDXLNode *pdxlnJoinTree = PdxlnFromGPDBFromExpr(pfromexpr);
// translate target list entries into a logical project
return PdxlnLgProjectFromGPDBTL(plTargetList, pdxlnJoinTree, phmiulSortGroupColsColId, phmiulOutputCols, plGroupClause);
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorQueryToDXL::PdxlnSPJForGroupingSets
//
// @doc:
// Construct a DXL SPJ tree from the given query parts, and keep variables
// appearing in aggregates in the project list
//
//---------------------------------------------------------------------------
CDXLNode *
CTranslatorQueryToDXL::PdxlnSPJForGroupingSets
(
List *plTargetList,
FromExpr *pfromexpr,
HMIUl *phmiulSortGroupColsColId,
HMIUl *phmiulOutputCols,
List *plGroupClause
)
{
CDXLNode *pdxlnJoinTree = PdxlnFromGPDBFromExpr(pfromexpr);
// translate target list entries into a logical project
return PdxlnLgProjectFromGPDBTL(plTargetList, pdxlnJoinTree, phmiulSortGroupColsColId, phmiulOutputCols, plGroupClause, true /*fExpandAggrefExpr*/);
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorQueryToDXL::PdxlnFromQuery
//
// @doc:
// Main driver
//
//---------------------------------------------------------------------------
CDXLNode *
CTranslatorQueryToDXL::PdxlnFromQuery()
{
CAutoTimer at("\n[OPT]: Query To DXL Translation Time", GPOS_FTRACE(EopttracePrintOptStats));
switch (m_pquery->commandType)
{
case CMD_SELECT:
if (NULL == m_pquery->intoClause)
{
return PdxlnFromQueryInternal();
}
return PdxlnCTAS();
case CMD_INSERT:
return PdxlnInsert();
case CMD_DELETE:
return PdxlnDelete();
case CMD_UPDATE:
return PdxlnUpdate();
default:
GPOS_ASSERT(!"Statement type not supported");
return NULL;
}
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorQueryToDXL::PdxlnInsert
//
// @doc:
// Translate an insert stmt
//
//---------------------------------------------------------------------------
CDXLNode *
CTranslatorQueryToDXL::PdxlnInsert()
{
GPOS_ASSERT(CMD_INSERT == m_pquery->commandType);
GPOS_ASSERT(0 < m_pquery->resultRelation);
CDXLNode *pdxlnQuery = PdxlnFromQueryInternal();
const RangeTblEntry *prte = (RangeTblEntry *) gpdb::PvListNth(m_pquery->rtable, m_pquery->resultRelation - 1);
CDXLTableDescr *pdxltabdesc = CTranslatorUtils::Pdxltabdesc(m_pmp, m_pmda, m_pidgtorCol, prte, &m_fHasDistributedTables);
const IMDRelation *pmdrel = m_pmda->Pmdrel(pdxltabdesc->Pmdid());
if (!optimizer_dml_triggers && CTranslatorUtils::FRelHasTriggers(m_pmp, m_pmda, pmdrel, Edxldmlinsert))
{
GPOS_RAISE(gpdxl::ExmaDXL, gpdxl::ExmiQuery2DXLUnsupportedFeature, GPOS_WSZ_LIT("INSERT with triggers"));
}
BOOL fRelHasConstraints = CTranslatorUtils::FRelHasConstraints(pmdrel);
if (!optimizer_dml_constraints && fRelHasConstraints)
{
GPOS_RAISE(gpdxl::ExmaDXL, gpdxl::ExmiQuery2DXLUnsupportedFeature, GPOS_WSZ_LIT("INSERT with constraints"));
}
const ULONG ulLenTblCols = pmdrel->UlColumns() - pmdrel->UlSystemColumns();
const ULONG ulLenTL = gpdb::UlListLength(m_pquery->targetList);
GPOS_ASSERT(ulLenTblCols >= ulLenTL);
GPOS_ASSERT(ulLenTL == m_pdrgpdxlnQueryOutput->UlLength());
CDXLNode *pdxlnPrL = NULL;
const ULONG ulLenNonDroppedCols = pmdrel->UlNonDroppedCols() - pmdrel->UlSystemColumns();
if (ulLenNonDroppedCols > ulLenTL)
{
// missing target list entries
pdxlnPrL = GPOS_NEW(m_pmp) CDXLNode(m_pmp, GPOS_NEW(m_pmp) CDXLScalarProjList(m_pmp));
}
DrgPul *pdrgpulSource = GPOS_NEW(m_pmp) DrgPul(m_pmp);
ULONG ulPosTL = 0;
for (ULONG ul = 0; ul < ulLenTblCols; ul++)
{
const IMDColumn *pmdcol = pmdrel->Pmdcol(ul);
GPOS_ASSERT(!pmdcol->FSystemColumn());
if (pmdcol->FDropped())
{
continue;
}
if (ulPosTL < ulLenTL)
{
INT iAttno = pmdcol->IAttno();
TargetEntry *pte = (TargetEntry *) gpdb::PvListNth(m_pquery->targetList, ulPosTL);
AttrNumber iResno = pte->resno;
if (iAttno == iResno)
{
CDXLNode *pdxlnCol = (*m_pdrgpdxlnQueryOutput)[ulPosTL];
CDXLScalarIdent *pdxlopIdent = CDXLScalarIdent::PdxlopConvert(pdxlnCol->Pdxlop());
pdrgpulSource->Append(GPOS_NEW(m_pmp) ULONG(pdxlopIdent->Pdxlcr()->UlID()));
ulPosTL++;
continue;
}
}
// target entry corresponding to the tables column not found, therefore
// add a project element with null value scalar child
CDXLNode *pdxlnPrE = CTranslatorUtils::PdxlnPrElNull(m_pmp, m_pmda, m_pidgtorCol, pmdcol);
ULONG ulColId = CDXLScalarProjElem::PdxlopConvert(pdxlnPrE->Pdxlop())->UlId();
pdxlnPrL->AddChild(pdxlnPrE);
pdrgpulSource->Append(GPOS_NEW(m_pmp) ULONG(ulColId));
}
CDXLLogicalInsert *pdxlopInsert = GPOS_NEW(m_pmp) CDXLLogicalInsert(m_pmp, pdxltabdesc, pdrgpulSource);
if (NULL != pdxlnPrL)
{
GPOS_ASSERT(0 < pdxlnPrL->UlArity());
CDXLNode *pdxlnProject = GPOS_NEW(m_pmp) CDXLNode(m_pmp, GPOS_NEW(m_pmp) CDXLLogicalProject(m_pmp));
pdxlnProject->AddChild(pdxlnPrL);
pdxlnProject->AddChild(pdxlnQuery);
pdxlnQuery = pdxlnProject;
}
return GPOS_NEW(m_pmp) CDXLNode(m_pmp, pdxlopInsert, pdxlnQuery);
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorQueryToDXL::PdxlnCTAS
//
// @doc:
// Translate a CTAS
//
//---------------------------------------------------------------------------
CDXLNode *
CTranslatorQueryToDXL::PdxlnCTAS()
{
GPOS_ASSERT(CMD_SELECT == m_pquery->commandType);
GPOS_ASSERT(NULL != m_pquery->intoClause);
m_fCTASQuery = true;
CDXLNode *pdxlnQuery = PdxlnFromQueryInternal();
IntoClause *pintocl = m_pquery->intoClause;
CMDName *pmdnameRel = CDXLUtils::PmdnameFromSz(m_pmp, pintocl->rel->relname);
DrgPdxlcd *pdrgpdxlcd = GPOS_NEW(m_pmp) DrgPdxlcd(m_pmp);
const ULONG ulColumns = gpdb::UlListLength(m_pquery->targetList);
DrgPul *pdrgpulSource = GPOS_NEW(m_pmp) DrgPul(m_pmp);
DrgPi* pdrgpiVarTypMod = GPOS_NEW(m_pmp) DrgPi(m_pmp);
List *plColnames = pintocl->colNames;
for (ULONG ul = 0; ul < ulColumns; ul++)
{
TargetEntry *pte = (TargetEntry *) gpdb::PvListNth(m_pquery->targetList, ul);
if (pte->resjunk)
{
continue;
}
AttrNumber iResno = pte->resno;
int iVarTypMod = gpdb::IExprTypeMod((Node*)pte->expr);
pdrgpiVarTypMod->Append(GPOS_NEW(m_pmp) INT(iVarTypMod));
CDXLNode *pdxlnCol = (*m_pdrgpdxlnQueryOutput)[ul];
CDXLScalarIdent *pdxlopIdent = CDXLScalarIdent::PdxlopConvert(pdxlnCol->Pdxlop());
pdrgpulSource->Append(GPOS_NEW(m_pmp) ULONG(pdxlopIdent->Pdxlcr()->UlID()));
CMDName *pmdnameCol = NULL;
if (NULL != plColnames && ul < gpdb::UlListLength(plColnames))
{
ColumnDef *pcoldef = (ColumnDef *) gpdb::PvListNth(plColnames, ul);
pmdnameCol = CDXLUtils::PmdnameFromSz(m_pmp, pcoldef->colname);
}
else
{
pmdnameCol = GPOS_NEW(m_pmp) CMDName(m_pmp, pdxlopIdent->Pdxlcr()->Pmdname()->Pstr());
}
GPOS_ASSERT(NULL != pmdnameCol);
IMDId *pmdid = pdxlopIdent->PmdidType();
pmdid->AddRef();
CDXLColDescr *pdxlcd = GPOS_NEW(m_pmp) CDXLColDescr
(
m_pmp,
pmdnameCol,
m_pidgtorCol->UlNextId(),
iResno /* iAttno */,
pmdid,
false /* fDropped */
);
pdrgpdxlcd->Append(pdxlcd);
}
IMDRelation::Ereldistrpolicy ereldistrpolicy = IMDRelation::EreldistrRandom;
DrgPul *pdrgpulDistr = NULL;
if (NULL != m_pquery->intoPolicy)
{
ereldistrpolicy = CTranslatorRelcacheToDXL::Ereldistribution(m_pquery->intoPolicy);
if (IMDRelation::EreldistrHash == ereldistrpolicy)
{
pdrgpulDistr = GPOS_NEW(m_pmp) DrgPul(m_pmp);
for (ULONG ul = 0; ul < (ULONG) m_pquery->intoPolicy->nattrs; ul++)
{
AttrNumber attno = m_pquery->intoPolicy->attrs[ul];
GPOS_ASSERT(0 < attno);
pdrgpulDistr->Append(GPOS_NEW(m_pmp) ULONG(attno - 1));
}
}
}
else
{
elog(NOTICE, "Table doesn't have 'distributed by' clause. Creating a NULL policy entry.");
}
GPOS_ASSERT(IMDRelation::EreldistrMasterOnly != ereldistrpolicy);
m_fHasDistributedTables = true;
// TODO: antova - Mar 5, 2014; reserve an OID
OID oid = 1;
CMDIdGPDB *pmdid = GPOS_NEW(m_pmp) CMDIdGPDBCtas(oid);
CMDName *pmdnameTableSpace = NULL;
if (NULL != pintocl->tableSpaceName)
{
pmdnameTableSpace = CDXLUtils::PmdnameFromSz(m_pmp, pintocl->tableSpaceName);
}
CMDName *pmdnameSchema = NULL;
if (NULL != pintocl->rel->schemaname)
{
pmdnameSchema = CDXLUtils::PmdnameFromSz(m_pmp, pintocl->rel->schemaname);
}
CDXLCtasStorageOptions::ECtasOnCommitAction ectascommit = (CDXLCtasStorageOptions::ECtasOnCommitAction) pintocl->onCommit;
IMDRelation::Erelstoragetype erelstorage = IMDRelation::ErelstorageHeap;
CDXLCtasStorageOptions::DrgPctasOpt *pdrgpctasopt = Pdrgpctasopt(pintocl->options, &erelstorage);
BOOL fHasOids = gpdb::FInterpretOidsOption(pintocl->options);
CDXLLogicalCTAS *pdxlopCTAS = GPOS_NEW(m_pmp) CDXLLogicalCTAS
(
m_pmp,
pmdid,
pmdnameSchema,
pmdnameRel,
pdrgpdxlcd,
GPOS_NEW(m_pmp) CDXLCtasStorageOptions(pmdnameTableSpace, ectascommit, pdrgpctasopt),
ereldistrpolicy,
pdrgpulDistr,
pintocl->rel->istemp,
fHasOids,
erelstorage,
pdrgpulSource,
pdrgpiVarTypMod
);
return GPOS_NEW(m_pmp) CDXLNode(m_pmp, pdxlopCTAS, pdxlnQuery);
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorQueryToDXL::Pdrgpctasopt
//
// @doc:
// Translate CTAS storage options
//
//---------------------------------------------------------------------------
CDXLCtasStorageOptions::DrgPctasOpt *
CTranslatorQueryToDXL::Pdrgpctasopt
(
List *plOptions,
IMDRelation::Erelstoragetype *perelstoragetype // output parameter: storage type
)
{
if (NULL == plOptions)
{
return NULL;
}
GPOS_ASSERT(NULL != perelstoragetype);
CDXLCtasStorageOptions::DrgPctasOpt *pdrgpctasopt = GPOS_NEW(m_pmp) CDXLCtasStorageOptions::DrgPctasOpt(m_pmp);
ListCell *plc = NULL;
BOOL fAO = false;
BOOL fAOCO = false;
BOOL fParquet = false;
CWStringConst strAppendOnly(GPOS_WSZ_LIT("appendonly"));
CWStringConst strOrientation(GPOS_WSZ_LIT("orientation"));
CWStringConst strOrientationParquet(GPOS_WSZ_LIT("parquet"));
CWStringConst strOrientationColumn(GPOS_WSZ_LIT("column"));
ForEach (plc, plOptions)
{
DefElem *pdefelem = (DefElem *) lfirst(plc);
CWStringDynamic *pstrName = CDXLUtils::PstrFromSz(m_pmp, pdefelem->defname);
CWStringDynamic *pstrValue = NULL;
BOOL fNullArg = (NULL == pdefelem->arg);
// pdefelem->arg is NULL for queries of the form "create table t with (oids) as ... "
if (fNullArg)
{
// we represent null options as an empty arg string and set the IsNull flag on
pstrValue = GPOS_NEW(m_pmp) CWStringDynamic(m_pmp);
}
else
{
pstrValue = PstrExtractOptionValue(pdefelem);
if (pstrName->FEquals(&strAppendOnly) && pstrValue->FEquals(CDXLTokens::PstrToken(EdxltokenTrue)))
{
fAO = true;
}
if (pstrName->FEquals(&strOrientation) && pstrValue->FEquals(&strOrientationColumn))
{
GPOS_ASSERT(!fParquet);
fAOCO = true;
}
if (pstrName->FEquals(&strOrientation) && pstrValue->FEquals(&strOrientationParquet))
{
GPOS_ASSERT(!fAOCO);
fParquet = true;
}
}
NodeTag argType = T_Null;
if (!fNullArg)
{
argType = pdefelem->arg->type;
}
CDXLCtasStorageOptions::CDXLCtasOption *pdxlctasopt =
GPOS_NEW(m_pmp) CDXLCtasStorageOptions::CDXLCtasOption(argType, pstrName, pstrValue, fNullArg);
pdrgpctasopt->Append(pdxlctasopt);
}
if (fAOCO)
{
*perelstoragetype = IMDRelation::ErelstorageAppendOnlyCols;
}
else if (fAO)
{
*perelstoragetype = IMDRelation::ErelstorageAppendOnlyRows;
}
else if (fParquet)
{
*perelstoragetype = IMDRelation::ErelstorageAppendOnlyParquet;
}
return pdrgpctasopt;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorQueryToDXL::PstrExtractOptionValue
//
// @doc:
// Extract value for storage option
//
//---------------------------------------------------------------------------
CWStringDynamic *
CTranslatorQueryToDXL::PstrExtractOptionValue
(
DefElem *pdefelem
)
{
GPOS_ASSERT(NULL != pdefelem);
BOOL fNeedsFree = false;
CHAR *szValue = gpdb::SzDefGetString(pdefelem, &fNeedsFree);
CWStringDynamic *pstrResult = CDXLUtils::PstrFromSz(m_pmp, szValue);
if (fNeedsFree)
{
gpdb::GPDBFree(szValue);
}
return pstrResult;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorQueryToDXL::GetCtidAndSegmentId
//
// @doc:
// Obtains the ids of the ctid and segmentid columns for the target
// table of a DML query
//
//---------------------------------------------------------------------------
void
CTranslatorQueryToDXL::GetCtidAndSegmentId
(
ULONG *pulCtid,
ULONG *pulSegmentId
)
{
// ctid column id
IMDId *pmdid = CTranslatorUtils::PmdidSystemColType(m_pmp, SelfItemPointerAttributeNumber);
*pulCtid = CTranslatorUtils::UlColId(m_ulQueryLevel, m_pquery->resultRelation, SelfItemPointerAttributeNumber, pmdid, m_pmapvarcolid);
pmdid->Release();
// segmentid column id
pmdid = CTranslatorUtils::PmdidSystemColType(m_pmp, GpSegmentIdAttributeNumber);
*pulSegmentId = CTranslatorUtils::UlColId(m_ulQueryLevel, m_pquery->resultRelation, GpSegmentIdAttributeNumber, pmdid, m_pmapvarcolid);
pmdid->Release();
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorQueryToDXL::UlTupleOidColId
//
// @doc:
// Obtains the id of the tuple oid column for the target table of a DML
// update
//
//---------------------------------------------------------------------------
ULONG
CTranslatorQueryToDXL::UlTupleOidColId()
{
IMDId *pmdid = CTranslatorUtils::PmdidSystemColType(m_pmp, ObjectIdAttributeNumber);
ULONG ulTupleOidColId = CTranslatorUtils::UlColId(m_ulQueryLevel, m_pquery->resultRelation, ObjectIdAttributeNumber, pmdid, m_pmapvarcolid);
pmdid->Release();
return ulTupleOidColId;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorQueryToDXL::PdxlnDelete
//
// @doc:
// Translate a delete stmt
//
//---------------------------------------------------------------------------
CDXLNode *
CTranslatorQueryToDXL::PdxlnDelete()
{
GPOS_ASSERT(CMD_DELETE == m_pquery->commandType);
GPOS_ASSERT(0 < m_pquery->resultRelation);
CDXLNode *pdxlnQuery = PdxlnFromQueryInternal();
const RangeTblEntry *prte = (RangeTblEntry *) gpdb::PvListNth(m_pquery->rtable, m_pquery->resultRelation - 1);
CDXLTableDescr *pdxltabdesc = CTranslatorUtils::Pdxltabdesc(m_pmp, m_pmda, m_pidgtorCol, prte, &m_fHasDistributedTables);
const IMDRelation *pmdrel = m_pmda->Pmdrel(pdxltabdesc->Pmdid());
if (!optimizer_dml_triggers && CTranslatorUtils::FRelHasTriggers(m_pmp, m_pmda, pmdrel, Edxldmldelete))
{
GPOS_RAISE(gpdxl::ExmaDXL, gpdxl::ExmiQuery2DXLUnsupportedFeature, GPOS_WSZ_LIT("DELETE with triggers"));
}
ULONG ulCtid = 0;
ULONG ulSegmentId = 0;
GetCtidAndSegmentId(&ulCtid, &ulSegmentId);
DrgPul *pdrgpulDelete = GPOS_NEW(m_pmp) DrgPul(m_pmp);
const ULONG ulRelColumns = pmdrel->UlColumns();
for (ULONG ul = 0; ul < ulRelColumns; ul++)
{
const IMDColumn *pmdcol = pmdrel->Pmdcol(ul);
if (pmdcol->FSystemColumn() || pmdcol->FDropped())
{
continue;
}
ULONG ulColId = CTranslatorUtils::UlColId(m_ulQueryLevel, m_pquery->resultRelation, pmdcol->IAttno(), pmdcol->PmdidType(), m_pmapvarcolid);
pdrgpulDelete->Append(GPOS_NEW(m_pmp) ULONG(ulColId));
}
CDXLLogicalDelete *pdxlopdelete = GPOS_NEW(m_pmp) CDXLLogicalDelete(m_pmp, pdxltabdesc, ulCtid, ulSegmentId, pdrgpulDelete);
return GPOS_NEW(m_pmp) CDXLNode(m_pmp, pdxlopdelete, pdxlnQuery);
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorQueryToDXL::PdxlnUpdate
//
// @doc:
// Translate an update stmt
//
//---------------------------------------------------------------------------
CDXLNode *
CTranslatorQueryToDXL::PdxlnUpdate()
{
GPOS_ASSERT(CMD_UPDATE == m_pquery->commandType);
GPOS_ASSERT(0 < m_pquery->resultRelation);
CDXLNode *pdxlnQuery = PdxlnFromQueryInternal();
const RangeTblEntry *prte = (RangeTblEntry *) gpdb::PvListNth(m_pquery->rtable, m_pquery->resultRelation - 1);
CDXLTableDescr *pdxltabdesc = CTranslatorUtils::Pdxltabdesc(m_pmp, m_pmda, m_pidgtorCol, prte, &m_fHasDistributedTables);
const IMDRelation *pmdrel = m_pmda->Pmdrel(pdxltabdesc->Pmdid());
if (!optimizer_dml_triggers && CTranslatorUtils::FRelHasTriggers(m_pmp, m_pmda, pmdrel, Edxldmlupdate))
{
GPOS_RAISE(gpdxl::ExmaDXL, gpdxl::ExmiQuery2DXLUnsupportedFeature, GPOS_WSZ_LIT("UPDATE with triggers"));
}
if (!optimizer_dml_constraints && CTranslatorUtils::FRelHasConstraints(pmdrel))
{
GPOS_RAISE(gpdxl::ExmaDXL, gpdxl::ExmiQuery2DXLUnsupportedFeature, GPOS_WSZ_LIT("UPDATE with constraints"));
}
ULONG ulCtidColId = 0;
ULONG ulSegmentIdColId = 0;
GetCtidAndSegmentId(&ulCtidColId, &ulSegmentIdColId);
ULONG ulTupleOidColId = 0;
BOOL fHasOids = pmdrel->FHasOids();
if (fHasOids)
{
ulTupleOidColId = UlTupleOidColId();
}
// get (resno -> colId) mapping of columns to be updated
HMIUl *phmiulUpdateCols = PhmiulUpdateCols();
const ULONG ulRelColumns = pmdrel->UlColumns();
DrgPul *pdrgpulInsert = GPOS_NEW(m_pmp) DrgPul(m_pmp);
DrgPul *pdrgpulDelete = GPOS_NEW(m_pmp) DrgPul(m_pmp);
for (ULONG ul = 0; ul < ulRelColumns; ul++)
{
const IMDColumn *pmdcol = pmdrel->Pmdcol(ul);
if (pmdcol->FSystemColumn() || pmdcol->FDropped())
{
continue;
}
INT iAttno = pmdcol->IAttno();
ULONG *pulColId = phmiulUpdateCols->PtLookup(&iAttno);
ULONG ulColId = CTranslatorUtils::UlColId(m_ulQueryLevel, m_pquery->resultRelation, iAttno, pmdcol->PmdidType(), m_pmapvarcolid);
// if the column is in the query outputs then use it
// otherwise get the column id created by the child query
if (NULL != pulColId)
{
pdrgpulInsert->Append(GPOS_NEW(m_pmp) ULONG(*pulColId));
}
else
{
pdrgpulInsert->Append(GPOS_NEW(m_pmp) ULONG(ulColId));
}
pdrgpulDelete->Append(GPOS_NEW(m_pmp) ULONG(ulColId));
}
phmiulUpdateCols->Release();
CDXLLogicalUpdate *pdxlopupdate = GPOS_NEW(m_pmp) CDXLLogicalUpdate(m_pmp, pdxltabdesc, ulCtidColId, ulSegmentIdColId, pdrgpulDelete, pdrgpulInsert, fHasOids, ulTupleOidColId);
return GPOS_NEW(m_pmp) CDXLNode(m_pmp, pdxlopupdate, pdxlnQuery);
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorQueryToDXL::PhmiulUpdateCols
//
// @doc:
// Return resno -> colId mapping of columns to be updated
//
//---------------------------------------------------------------------------
HMIUl *
CTranslatorQueryToDXL::PhmiulUpdateCols()
{
GPOS_ASSERT((ULONG)gpdb::UlListLength(m_pquery->targetList) == m_pdrgpdxlnQueryOutput->UlLength());
HMIUl *phmiulUpdateCols = GPOS_NEW(m_pmp) HMIUl(m_pmp);
ListCell *plc = NULL;
ULONG ul = 0;
ForEach (plc, m_pquery->targetList)
{
TargetEntry *pte = (TargetEntry *) lfirst(plc);
GPOS_ASSERT(IsA(pte, TargetEntry));
ULONG ulResno = pte->resno;
GPOS_ASSERT(0 < ulResno);
CDXLNode *pdxlnCol = (*m_pdrgpdxlnQueryOutput)[ul];
CDXLScalarIdent *pdxlopIdent = CDXLScalarIdent::PdxlopConvert(pdxlnCol->Pdxlop());
ULONG ulColId = pdxlopIdent->Pdxlcr()->UlID();
StoreAttnoColIdMapping(phmiulUpdateCols, ulResno, ulColId);
ul++;
}
return phmiulUpdateCols;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorQueryToDXL::FOIDFound
//
// @doc:
// Helper to check if OID is included in given array of OIDs
//
//---------------------------------------------------------------------------
BOOL
CTranslatorQueryToDXL::FOIDFound
(
OID oid,
const OID rgOID[],
ULONG ulSize
)
{
BOOL fFound = false;
for (ULONG ul = 0; !fFound && ul < ulSize; ul++)
{
fFound = (rgOID[ul] == oid);
}
return fFound;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorQueryToDXL::FLeadWindowFunc
//
// @doc:
// Check if given operator is LEAD window function
//
//---------------------------------------------------------------------------
BOOL
CTranslatorQueryToDXL::FLeadWindowFunc
(
CDXLOperator *pdxlop
)
{
BOOL fLead = false;
if (EdxlopScalarWindowRef == pdxlop->Edxlop())
{
CDXLScalarWindowRef *pdxlopWinref = CDXLScalarWindowRef::PdxlopConvert(pdxlop);
const CMDIdGPDB *pmdidgpdb = CMDIdGPDB::PmdidConvert(pdxlopWinref->PmdidFunc());
OID oid = pmdidgpdb->OidObjectId();
fLead = FOIDFound(oid, rgOIDLead, GPOS_ARRAY_SIZE(rgOIDLead));
}
return fLead;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorQueryToDXL::FLagWindowFunc
//
// @doc:
// Check if given operator is LAG window function
//
//---------------------------------------------------------------------------
BOOL
CTranslatorQueryToDXL::FLagWindowFunc
(
CDXLOperator *pdxlop
)
{
BOOL fLag = false;
if (EdxlopScalarWindowRef == pdxlop->Edxlop())
{
CDXLScalarWindowRef *pdxlopWinref = CDXLScalarWindowRef::PdxlopConvert(pdxlop);
const CMDIdGPDB *pmdidgpdb = CMDIdGPDB::PmdidConvert(pdxlopWinref->PmdidFunc());
OID oid = pmdidgpdb->OidObjectId();
fLag = FOIDFound(oid, rgOIDLag, GPOS_ARRAY_SIZE(rgOIDLag));
}
return fLag;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorQueryToDXL::PdxlwfLeadLag
//
// @doc:
// Manufacture window frame for lead/lag functions
//
//---------------------------------------------------------------------------
CDXLWindowFrame *
CTranslatorQueryToDXL::PdxlwfLeadLag
(
BOOL fLead,
CDXLNode *pdxlnOffset
)
const
{
EdxlFrameBoundary edxlfbLead = EdxlfbBoundedFollowing;
EdxlFrameBoundary edxlfbTrail = EdxlfbBoundedFollowing;
if (!fLead)
{
edxlfbLead = EdxlfbBoundedPreceding;
edxlfbTrail = EdxlfbBoundedPreceding;
}
CDXLNode *pdxlnLeadEdge = NULL;
CDXLNode *pdxlnTrailEdge = NULL;
if (NULL == pdxlnOffset)
{
pdxlnLeadEdge = GPOS_NEW(m_pmp) CDXLNode(m_pmp, GPOS_NEW(m_pmp) CDXLScalarWindowFrameEdge(m_pmp, true /* fLeading */, edxlfbLead));
pdxlnTrailEdge = GPOS_NEW(m_pmp) CDXLNode(m_pmp, GPOS_NEW(m_pmp) CDXLScalarWindowFrameEdge(m_pmp, false /* fLeading */, edxlfbTrail));
pdxlnLeadEdge->AddChild(CTranslatorUtils::PdxlnInt4Const(m_pmp, m_pmda, 1 /*iVal*/));
pdxlnTrailEdge->AddChild(CTranslatorUtils::PdxlnInt4Const(m_pmp, m_pmda, 1 /*iVal*/));
}
else
{
// overwrite frame edge types based on specified offset type
if (EdxlopScalarConstValue != pdxlnOffset->Pdxlop()->Edxlop())
{
if (fLead)
{
edxlfbLead = EdxlfbDelayedBoundedFollowing;
edxlfbTrail = EdxlfbDelayedBoundedFollowing;
}
else
{
edxlfbLead = EdxlfbDelayedBoundedPreceding;
edxlfbTrail = EdxlfbDelayedBoundedPreceding;
}
}
pdxlnLeadEdge = GPOS_NEW(m_pmp) CDXLNode(m_pmp, GPOS_NEW(m_pmp) CDXLScalarWindowFrameEdge(m_pmp, true /* fLeading */, edxlfbLead));
pdxlnTrailEdge = GPOS_NEW(m_pmp) CDXLNode(m_pmp, GPOS_NEW(m_pmp) CDXLScalarWindowFrameEdge(m_pmp, false /* fLeading */, edxlfbTrail));
pdxlnOffset->AddRef();
pdxlnLeadEdge->AddChild(pdxlnOffset);
pdxlnOffset->AddRef();
pdxlnTrailEdge->AddChild(pdxlnOffset);
}
// manufacture a frame for LEAD/LAG function
return GPOS_NEW(m_pmp) CDXLWindowFrame
(
m_pmp,
EdxlfsRow, // frame specification
EdxlfesNulls, // frame exclusion strategy is set to exclude NULLs in GPDB
pdxlnLeadEdge,
pdxlnTrailEdge
);
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorQueryToDXL::UpdateLeadLagWinSpecPos
//
// @doc:
// LEAD/LAG window functions need special frames to get executed correctly;
// these frames are system-generated and cannot be specified in query text;
// this function adds new entries to the list of window specs holding these
// manufactured frames, and updates window spec references of LEAD/LAG
// functions accordingly
//
//
//---------------------------------------------------------------------------
void
CTranslatorQueryToDXL::UpdateLeadLagWinSpecPos
(
CDXLNode *pdxlnPrL, // project list holding WinRef nodes
DrgPdxlws *pdrgpdxlws // original list of window spec
)
const
{
GPOS_ASSERT(NULL != pdxlnPrL);
GPOS_ASSERT(NULL != pdrgpdxlws);
const ULONG ulArity = pdxlnPrL->UlArity();
for (ULONG ul = 0; ul < ulArity; ul++)
{
CDXLNode *pdxlnChild = (*(*pdxlnPrL)[ul])[0];
CDXLOperator *pdxlop = pdxlnChild->Pdxlop();
BOOL fLead = FLeadWindowFunc(pdxlop);
BOOL fLag = FLagWindowFunc(pdxlop);
if (fLead || fLag)
{
CDXLScalarWindowRef *pdxlopWinref = CDXLScalarWindowRef::PdxlopConvert(pdxlop);
CDXLWindowSpec *pdxlws = (*pdrgpdxlws)[pdxlopWinref->UlWinSpecPos()];
CMDName *pmdname = NULL;
if (NULL != pdxlws->Pmdname())
{
pmdname = GPOS_NEW(m_pmp) CMDName(m_pmp, pdxlws->Pmdname()->Pstr());
}
// find if an offset is specified
CDXLNode *pdxlnOffset = NULL;
if (1 < pdxlnChild->UlArity())
{
pdxlnOffset = (*pdxlnChild)[1];
}
// create LEAD/LAG frame
CDXLWindowFrame *pdxlwf = PdxlwfLeadLag(fLead, pdxlnOffset);
// create new window spec object
pdxlws->PdrgulPartColList()->AddRef();
pdxlws->PdxlnSortColList()->AddRef();
CDXLWindowSpec *pdxlwsNew =
GPOS_NEW(m_pmp) CDXLWindowSpec
(
m_pmp,
pdxlws->PdrgulPartColList(),
pmdname,
pdxlws->PdxlnSortColList(),
pdxlwf
);
pdrgpdxlws->Append(pdxlwsNew);
// update win spec pos of LEAD/LAG function
pdxlopWinref->SetWinSpecPos(pdrgpdxlws->UlLength() - 1);
}
}
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorQueryToDXL::Pdrgpdxlws
//
// @doc:
// Translate window specs
//
//---------------------------------------------------------------------------
DrgPdxlws *
CTranslatorQueryToDXL::Pdrgpdxlws
(
List *plWindowClause,
HMIUl *phmiulSortColsColId,
CDXLNode *pdxlnScPrL
)
{
GPOS_ASSERT(NULL != plWindowClause);
GPOS_ASSERT(NULL != phmiulSortColsColId);
GPOS_ASSERT(NULL != pdxlnScPrL);
DrgPdxlws *pdrgpdxlws = GPOS_NEW(m_pmp) DrgPdxlws(m_pmp);
// translate window specification
ListCell *plcWindowSpec = NULL;
ForEach (plcWindowSpec, plWindowClause)
{
WindowSpec *pwindowspec = (WindowSpec *) lfirst(plcWindowSpec);
DrgPul *pdrgppulPartCol = PdrgpulPartCol(pwindowspec->partition, phmiulSortColsColId);
CDXLNode *pdxlnSortColList = NULL;
CMDName *pmdname = NULL;
CDXLWindowFrame *pdxlwf = NULL;
if (NULL != pwindowspec->name)
{
CWStringDynamic *pstrAlias = CDXLUtils::PstrFromSz(m_pmp, pwindowspec->name);
pmdname = GPOS_NEW(m_pmp) CMDName(m_pmp, pstrAlias);
GPOS_DELETE(pstrAlias);
}
if (0 < gpdb::UlListLength(pwindowspec->order))
{
// create a sorting col list
pdxlnSortColList = GPOS_NEW(m_pmp) CDXLNode(m_pmp, GPOS_NEW(m_pmp) CDXLScalarSortColList(m_pmp));
DrgPdxln *pdrgpdxlnSortCol = PdrgpdxlnSortCol(pwindowspec->order, phmiulSortColsColId);
const ULONG ulSize = pdrgpdxlnSortCol->UlLength();
for (ULONG ul = 0; ul < ulSize; ul++)
{
CDXLNode *pdxlnSortClause = (*pdrgpdxlnSortCol)[ul];
pdxlnSortClause->AddRef();
pdxlnSortColList->AddChild(pdxlnSortClause);
}
pdrgpdxlnSortCol->Release();
}
if (NULL != pwindowspec->frame)
{
pdxlwf = m_psctranslator->Pdxlwf((Expr *) pwindowspec->frame, m_pmapvarcolid, pdxlnScPrL, &m_fHasDistributedTables);
}
CDXLWindowSpec *pdxlws = GPOS_NEW(m_pmp) CDXLWindowSpec(m_pmp, pdrgppulPartCol, pmdname, pdxlnSortColList, pdxlwf);
pdrgpdxlws->Append(pdxlws);
}
return pdrgpdxlws;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorQueryToDXL::PdxlnWindow
//
// @doc:
// Translate a window operator
//
//---------------------------------------------------------------------------
CDXLNode *
CTranslatorQueryToDXL::PdxlnWindow
(
CDXLNode *pdxlnChild,
List *plTargetList,
List *plWindowClause,
List *plSortClause,
HMIUl *phmiulSortColsColId,
HMIUl *phmiulOutputCols
)
{
if (0 == gpdb::UlListLength(plWindowClause))
{
return pdxlnChild;
}
// translate target list entries
CDXLNode *pdxlnPrL = GPOS_NEW(m_pmp) CDXLNode(m_pmp, GPOS_NEW(m_pmp) CDXLScalarProjList(m_pmp));
CDXLNode *pdxlnNewChildScPrL = GPOS_NEW(m_pmp) CDXLNode(m_pmp, GPOS_NEW(m_pmp) CDXLScalarProjList(m_pmp));
ListCell *plcTE = NULL;
ULONG ulResno = 1;
// target entries that are result of flattening join alias and
// are equivalent to a defined Window specs target entry
List *plTEOmitted = NIL;
List *plResno = NIL;
ForEach (plcTE, plTargetList)
{
BOOL fInsertSortInfo = true;
TargetEntry *pte = (TargetEntry *) lfirst(plcTE);
GPOS_ASSERT(IsA(pte, TargetEntry));
// create the DXL node holding the target list entry
CDXLNode *pdxlnPrEl = PdxlnPrEFromGPDBExpr(pte->expr, pte->resname);
ULONG ulColId = CDXLScalarProjElem::PdxlopConvert(pdxlnPrEl->Pdxlop())->UlId();
if (IsA(pte->expr, WindowRef))
{
CTranslatorUtils::CheckAggregateWindowFn((Node*) pte->expr);
}
if (!pte->resjunk)
{
if (IsA(pte->expr, Var) || IsA(pte->expr, WindowRef))
{
// add window functions and non-computed columns to the project list of the window operator
pdxlnPrL->AddChild(pdxlnPrEl);
StoreAttnoColIdMapping(phmiulOutputCols, ulResno, ulColId);
}
else if (CTranslatorUtils::FWindowSpec(pte, plWindowClause))
{
// add computed column used in window specification needed in the output columns
// to the child's project list
pdxlnNewChildScPrL->AddChild(pdxlnPrEl);
// construct a scalar identifier that points to the computed column and
// add it to the project list of the window operator
CMDName *pmdnameAlias = GPOS_NEW(m_pmp) CMDName
(
m_pmp,
CDXLScalarProjElem::PdxlopConvert(pdxlnPrEl->Pdxlop())->PmdnameAlias()->Pstr()
);
CDXLNode *pdxlnPrElNew = GPOS_NEW(m_pmp) CDXLNode
(
m_pmp,
GPOS_NEW(m_pmp) CDXLScalarProjElem(m_pmp, ulColId, pmdnameAlias)
);
CMDIdGPDB *pmdidExprType = CTranslatorUtils::PmdidWithVersion(m_pmp, gpdb::OidExprType((Node*) pte->expr));
CDXLNode *pdxlnPrElNewChild = GPOS_NEW(m_pmp) CDXLNode
(
m_pmp,
GPOS_NEW(m_pmp) CDXLScalarIdent
(
m_pmp,
GPOS_NEW(m_pmp) CDXLColRef
(
m_pmp,
GPOS_NEW(m_pmp) CMDName(m_pmp, pmdnameAlias->Pstr()), ulColId
),
pmdidExprType
)
);
pdxlnPrElNew->AddChild(pdxlnPrElNewChild);
pdxlnPrL->AddChild(pdxlnPrElNew);
StoreAttnoColIdMapping(phmiulOutputCols, ulResno, ulColId);
}
else
{
fInsertSortInfo = false;
plTEOmitted = gpdb::PlAppendElement(plTEOmitted, pte);
plResno = gpdb::PlAppendInt(plResno, ulResno);
pdxlnPrEl->Release();
}
}
else if (IsA(pte->expr, WindowRef))
{
// computed columns used in the order by clause
pdxlnPrL->AddChild(pdxlnPrEl);
}
else if (!IsA(pte->expr, Var))
{
GPOS_ASSERT(CTranslatorUtils::FWindowSpec(pte, plWindowClause));
// computed columns used in the window specification
pdxlnNewChildScPrL->AddChild(pdxlnPrEl);
}
else
{
pdxlnPrEl->Release();
}
if (fInsertSortInfo)
{
AddSortingGroupingColumn(pte, phmiulSortColsColId, ulColId);
}
ulResno++;
}
plcTE = NULL;
// process target entries that are a result of flattening join alias
ListCell *plcResno = NULL;
ForBoth (plcTE, plTEOmitted,
plcResno, plResno)
{
TargetEntry *pte = (TargetEntry *) lfirst(plcTE);
INT iResno = (INT) lfirst_int(plcResno);
INT iSortGroupRef = (INT) pte->ressortgroupref;
TargetEntry *pteWindowSpec = CTranslatorUtils::PteWindowSpec( (Node*) pte->expr, plWindowClause, plTargetList);
if (NULL != pteWindowSpec)
{
const ULONG ulColId = CTranslatorUtils::UlColId( (INT) pteWindowSpec->ressortgroupref, phmiulSortColsColId);
StoreAttnoColIdMapping(phmiulOutputCols, iResno, ulColId);
AddSortingGroupingColumn(pte, phmiulSortColsColId, ulColId);
}
}
if (NIL != plTEOmitted)
{
gpdb::GPDBFree(plTEOmitted);
}
// translate window spec
DrgPdxlws *pdrgpdxlws = Pdrgpdxlws(plWindowClause, phmiulSortColsColId, pdxlnNewChildScPrL);
CDXLNode *pdxlnNewChild = NULL;
if (0 < pdxlnNewChildScPrL->UlArity())
{
// create a project list for the computed columns used in the window specification
pdxlnNewChild = GPOS_NEW(m_pmp) CDXLNode(m_pmp, GPOS_NEW(m_pmp) CDXLLogicalProject(m_pmp));
pdxlnNewChild->AddChild(pdxlnNewChildScPrL);
pdxlnNewChild->AddChild(pdxlnChild);
pdxlnChild = pdxlnNewChild;
}
else
{
// clean up
pdxlnNewChildScPrL->Release();
}
if (!CTranslatorUtils::FHasProjElem(pdxlnPrL, EdxlopScalarWindowRef))
{
pdxlnPrL->Release();
pdrgpdxlws->Release();
return pdxlnChild;
}
// update window spec positions of LEAD/LAG functions
UpdateLeadLagWinSpecPos(pdxlnPrL, pdrgpdxlws);
CDXLLogicalWindow *pdxlopWindow = GPOS_NEW(m_pmp) CDXLLogicalWindow(m_pmp, pdrgpdxlws);
CDXLNode *pdxln = GPOS_NEW(m_pmp) CDXLNode(m_pmp, pdxlopWindow);
pdxln->AddChild(pdxlnPrL);
pdxln->AddChild(pdxlnChild);
return pdxln;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorQueryToDXL::PdrgpulPartCol
//
// @doc:
// Translate the list of partition-by column identifiers
//
//---------------------------------------------------------------------------
DrgPul *
CTranslatorQueryToDXL::PdrgpulPartCol
(
List *plPartCl,
HMIUl *phmiulColColId
)
const
{
DrgPul *pdrgpul = GPOS_NEW(m_pmp) DrgPul(m_pmp);
ListCell *plcPartCl = NULL;
ForEach (plcPartCl, plPartCl)
{
Node *pnodePartCl = (Node*) lfirst(plcPartCl);
GPOS_ASSERT(NULL != pnodePartCl);
GPOS_ASSERT(IsA(pnodePartCl, SortClause));
SortClause *psortcl = (SortClause*) pnodePartCl;
// get the colid of the partition-by column
ULONG ulColId = CTranslatorUtils::UlColId((INT) psortcl->tleSortGroupRef, phmiulColColId);
pdrgpul->Append(GPOS_NEW(m_pmp) ULONG(ulColId));
}
return pdrgpul;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorQueryToDXL::PdrgpdxlnSortCol
//
// @doc:
// Translate the list of sorting columns
//
//---------------------------------------------------------------------------
DrgPdxln *
CTranslatorQueryToDXL::PdrgpdxlnSortCol
(
List *plSortCl,
HMIUl *phmiulColColId
)
const
{
DrgPdxln *pdrgpdxln = GPOS_NEW(m_pmp) DrgPdxln(m_pmp);
ListCell *plcSortCl = NULL;
ForEach (plcSortCl, plSortCl)
{
Node *pnodeSortCl = (Node*) lfirst(plcSortCl);
GPOS_ASSERT(NULL != pnodeSortCl);
GPOS_ASSERT(IsA(pnodeSortCl, SortClause));
SortClause *psortcl = (SortClause*) pnodeSortCl;
// get the colid of the sorting column
const ULONG ulColId = CTranslatorUtils::UlColId((INT) psortcl->tleSortGroupRef, phmiulColColId);
OID oid = psortcl->sortop;
// get operator name
CMDIdGPDB *pmdidScOp = CTranslatorUtils::PmdidWithVersion(m_pmp, oid);
const IMDScalarOp *pmdscop = m_pmda->Pmdscop(pmdidScOp);
const CWStringConst *pstr = pmdscop->Mdname().Pstr();
GPOS_ASSERT(NULL != pstr);
CDXLScalarSortCol *pdxlop = GPOS_NEW(m_pmp) CDXLScalarSortCol
(
m_pmp,
ulColId,
pmdidScOp,
GPOS_NEW(m_pmp) CWStringConst(pstr->Wsz()),
false
);
// create the DXL node holding the sorting col
CDXLNode *pdxlnSortCol = GPOS_NEW(m_pmp) CDXLNode(m_pmp, pdxlop);
pdrgpdxln->Append(pdxlnSortCol);
}
return pdrgpdxln;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorQueryToDXL::PdxlnLgLimit
//
// @doc:
// Translate the list of sorting columns, limit offset and limit count
// into a CDXLLogicalGroupBy node
//
//---------------------------------------------------------------------------
CDXLNode *
CTranslatorQueryToDXL::PdxlnLgLimit
(
List *plSortCl,
Node *pnodeLimitCount,
Node *pnodeLimitOffset,
CDXLNode *pdxlnChild,
HMIUl *phmiulGrpColsColId
)
{
if (0 == gpdb::UlListLength(plSortCl) && NULL == pnodeLimitCount && NULL == pnodeLimitOffset)
{
return pdxlnChild;
}
// do not remove limit if it is immediately under a DML (JIRA: GPSQL-2669)
// otherwise we may increase the storage size because there are less opportunities for compression
BOOL fTopLevelLimit = (m_fTopDMLQuery && 1 == m_ulQueryLevel) || (m_fCTASQuery && 0 == m_ulQueryLevel);
CDXLNode *pdxlnLimit =
GPOS_NEW(m_pmp) CDXLNode(m_pmp, GPOS_NEW(m_pmp) CDXLLogicalLimit(m_pmp, fTopLevelLimit));
// create a sorting col list
CDXLNode *pdxlnSortColList = GPOS_NEW(m_pmp) CDXLNode(m_pmp, GPOS_NEW(m_pmp) CDXLScalarSortColList(m_pmp));
DrgPdxln *pdrgpdxlnSortCol = PdrgpdxlnSortCol(plSortCl, phmiulGrpColsColId);
const ULONG ulSize = pdrgpdxlnSortCol->UlLength();
for (ULONG ul = 0; ul < ulSize; ul++)
{
CDXLNode *pdxlnSortCol = (*pdrgpdxlnSortCol)[ul];
pdxlnSortCol->AddRef();
pdxlnSortColList->AddChild(pdxlnSortCol);
}
pdrgpdxlnSortCol->Release();
// create limit count
CDXLNode *pdxlnLimitCount = GPOS_NEW(m_pmp) CDXLNode
(
m_pmp,
GPOS_NEW(m_pmp) CDXLScalarLimitCount(m_pmp)
);
if (NULL != pnodeLimitCount)
{
pdxlnLimitCount->AddChild(PdxlnScFromGPDBExpr((Expr*) pnodeLimitCount));
}
// create limit offset
CDXLNode *pdxlnLimitOffset = GPOS_NEW(m_pmp) CDXLNode
(
m_pmp,
GPOS_NEW(m_pmp) CDXLScalarLimitOffset(m_pmp)
);
if (NULL != pnodeLimitOffset)
{
pdxlnLimitOffset->AddChild(PdxlnScFromGPDBExpr((Expr*) pnodeLimitOffset));
}
pdxlnLimit->AddChild(pdxlnSortColList);
pdxlnLimit->AddChild(pdxlnLimitCount);
pdxlnLimit->AddChild(pdxlnLimitOffset);
pdxlnLimit->AddChild(pdxlnChild);
return pdxlnLimit;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorQueryToDXL::AddSortingGroupingColumn
//
// @doc:
// Add sorting and grouping column into the hash map
//
//---------------------------------------------------------------------------
void
CTranslatorQueryToDXL::AddSortingGroupingColumn
(
TargetEntry *pte,
HMIUl *phmiulSortgrouprefColId,
ULONG ulColId
)
const
{
if (0 < pte->ressortgroupref)
{
INT *piKey = GPOS_NEW(m_pmp) INT(pte->ressortgroupref);
ULONG *pulValue = GPOS_NEW(m_pmp) ULONG(ulColId);
// insert idx-colid mapping in the hash map
#ifdef GPOS_DEBUG
BOOL fRes =
#endif // GPOS_DEBUG
phmiulSortgrouprefColId->FInsert(piKey, pulValue);
GPOS_ASSERT(fRes);
}
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorQueryToDXL::PdxlnSimpleGroupBy
//
// @doc:
// Translate a query with grouping clause into a CDXLLogicalGroupBy node
//
//---------------------------------------------------------------------------
CDXLNode *
CTranslatorQueryToDXL::PdxlnSimpleGroupBy
(
List *plTargetList,
List *plGroupClause,
CBitSet *pbsGroupByCols,
BOOL fHasAggs,
BOOL fGroupingSets,
CDXLNode *pdxlnChild,
HMIUl *phmiulSortgrouprefColId,
HMIUl *phmiulChild,
HMIUl *phmiulOutputCols
)
{
if (NULL == pbsGroupByCols)
{
GPOS_ASSERT(!fHasAggs);
if (!fGroupingSets)
{
// no group by needed and not part of a grouping sets query:
// propagate child columns to output columns
HMIUlIter mi(phmiulChild);
while (mi.FAdvance())
{
#ifdef GPOS_DEBUG
BOOL fResult =
#endif // GPOS_DEBUG
phmiulOutputCols->FInsert(GPOS_NEW(m_pmp) INT(*(mi.Pk())), GPOS_NEW(m_pmp) ULONG(*(mi.Pt())));
GPOS_ASSERT(fResult);
}
}
// else:
// in queries with grouping sets we may generate a branch corresponding to GB grouping sets ();
// in that case do not propagate the child columns to the output hash map, as later
// processing may introduce NULLs for those
return pdxlnChild;
}
List *plDQA = NIL;
// construct the project list of the group-by operator
CDXLNode *pdxlnPrLGrpBy = GPOS_NEW(m_pmp) CDXLNode(m_pmp, GPOS_NEW(m_pmp) CDXLScalarProjList(m_pmp));
ListCell *plcTE = NULL;
ULONG ulDQAs = 0;
ForEach (plcTE, plTargetList)
{
TargetEntry *pte = (TargetEntry *) lfirst(plcTE);
GPOS_ASSERT(IsA(pte, TargetEntry));
GPOS_ASSERT(0 < pte->resno);
ULONG ulResNo = pte->resno;
TargetEntry *pteEquivalent = CTranslatorUtils::PteGroupingColumn( (Node *) pte->expr, plGroupClause, plTargetList);
BOOL fGroupingCol = pbsGroupByCols->FBit(pte->ressortgroupref) || (NULL != pteEquivalent && pbsGroupByCols->FBit(pteEquivalent->ressortgroupref));
ULONG ulColId = 0;
if (fGroupingCol)
{
// find colid for grouping column
ulColId = CTranslatorUtils::UlColId(ulResNo, phmiulChild);
}
else if (IsA(pte->expr, Aggref) || IsA(pte->expr, PercentileExpr))
{
if (IsA(pte->expr, Aggref) && ((Aggref *) pte->expr)->aggdistinct && !FDuplicateDqaArg(plDQA, (Aggref *) pte->expr))
{
plDQA = gpdb::PlAppendElement(plDQA, gpdb::PvCopyObject(pte->expr));
ulDQAs++;
}
// create a project element for aggregate
CDXLNode *pdxlnPrEl = PdxlnPrEFromGPDBExpr(pte->expr, pte->resname);
pdxlnPrLGrpBy->AddChild(pdxlnPrEl);
ulColId = CDXLScalarProjElem::PdxlopConvert(pdxlnPrEl->Pdxlop())->UlId();
AddSortingGroupingColumn(pte, phmiulSortgrouprefColId, ulColId);
}
if (fGroupingCol || IsA(pte->expr, Aggref) || IsA(pte->expr, PercentileExpr))
{
// add to the list of output columns
StoreAttnoColIdMapping(phmiulOutputCols, ulResNo, ulColId);
}
else if (0 == pbsGroupByCols->CElements() && !fGroupingSets && !fHasAggs)
{
StoreAttnoColIdMapping(phmiulOutputCols, ulResNo, ulColId);
}
}
if (1 < ulDQAs && !optimizer_enable_multiple_distinct_aggs)
{
GPOS_RAISE(gpdxl::ExmaDXL, gpdxl::ExmiQuery2DXLUnsupportedFeature, GPOS_WSZ_LIT("Multiple Distinct Qualified Aggregates are disabled in the optimizer"));
}
// initialize the array of grouping columns
DrgPul *pdrgpul = CTranslatorUtils::PdrgpulGroupingCols(m_pmp, pbsGroupByCols, phmiulSortgrouprefColId);
// clean up
if (NIL != plDQA)
{
gpdb::FreeList(plDQA);
}
return GPOS_NEW(m_pmp) CDXLNode
(
m_pmp,
GPOS_NEW(m_pmp) CDXLLogicalGroupBy(m_pmp, pdrgpul),
pdxlnPrLGrpBy,
pdxlnChild
);
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorQueryToDXL::FDuplicateDqaArg
//
// @doc:
// Check if the argument of a DQA has already being used by another DQA
//---------------------------------------------------------------------------
BOOL
CTranslatorQueryToDXL::FDuplicateDqaArg
(
List *plDQA,
Aggref *paggref
)
{
GPOS_ASSERT(NULL != paggref);
if (NIL == plDQA || 0 == gpdb::UlListLength(plDQA))
{
return false;
}
ListCell *plc = NULL;
ForEach (plc, plDQA)
{
Node *pnode = (Node *) lfirst(plc);
GPOS_ASSERT(IsA(pnode, Aggref));
if (gpdb::FEqual(paggref->args, ((Aggref *) pnode)->args))
{
return true;
}
}
return false;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorQueryToDXL::PdxlnGroupingSets
//
// @doc:
// Translate a query with grouping sets
//
//---------------------------------------------------------------------------
CDXLNode *
CTranslatorQueryToDXL::PdxlnGroupingSets
(
FromExpr *pfromexpr,
List *plTargetList,
List *plGroupClause,
BOOL fHasAggs,
HMIUl *phmiulSortgrouprefColId,
HMIUl *phmiulOutputCols
)
{
const ULONG ulCols = gpdb::UlListLength(plTargetList) + 1;
if (NULL == plGroupClause)
{
HMIUl *phmiulChild = GPOS_NEW(m_pmp) HMIUl(m_pmp);
CDXLNode *pdxlnSPJ = PdxlnSPJ(plTargetList, pfromexpr, phmiulSortgrouprefColId, phmiulChild, plGroupClause);
CBitSet *pbs = NULL;
if (fHasAggs)
{
pbs = GPOS_NEW(m_pmp) CBitSet(m_pmp);
}
// in case of aggregates, construct a group by operator
CDXLNode *pdxlnResult = PdxlnSimpleGroupBy
(
plTargetList,
plGroupClause,
pbs,
fHasAggs,
false, // fGroupingSets
pdxlnSPJ,
phmiulSortgrouprefColId,
phmiulChild,
phmiulOutputCols
);
// cleanup
phmiulChild->Release();
CRefCount::SafeRelease(pbs);
return pdxlnResult;
}
// grouping functions refer to grouping col positions, so construct a map pos->grouping column
// while processing the grouping clause
HMUlUl *phmululGrpColPos = GPOS_NEW(m_pmp) HMUlUl(m_pmp);
CBitSet *pbsUniqueueGrpCols = GPOS_NEW(m_pmp) CBitSet(m_pmp, ulCols);
DrgPbs *pdrgpbs = CTranslatorUtils::PdrgpbsGroupBy(m_pmp, plGroupClause, ulCols, phmululGrpColPos, pbsUniqueueGrpCols);
const ULONG ulGroupingSets = pdrgpbs->UlLength();
if (1 == ulGroupingSets)
{
// simple group by
HMIUl *phmiulChild = GPOS_NEW(m_pmp) HMIUl(m_pmp);
CDXLNode *pdxlnSPJ = PdxlnSPJ(plTargetList, pfromexpr, phmiulSortgrouprefColId, phmiulChild, plGroupClause);
// translate the groupby clauses into a logical group by operator
CBitSet *pbs = (*pdrgpbs)[0];
CDXLNode *pdxlnGroupBy = PdxlnSimpleGroupBy
(
plTargetList,
plGroupClause,
pbs,
fHasAggs,
false, // fGroupingSets
pdxlnSPJ,
phmiulSortgrouprefColId,
phmiulChild,
phmiulOutputCols
);
CDXLNode *pdxlnResult = PdxlnProjectGroupingFuncs
(
plTargetList,
pdxlnGroupBy,
pbs,
phmiulOutputCols,
phmululGrpColPos,
phmiulSortgrouprefColId
);
phmiulChild->Release();
pdrgpbs->Release();
pbsUniqueueGrpCols->Release();
phmululGrpColPos->Release();
return pdxlnResult;
}
CDXLNode *pdxlnResult = PdxlnUnionAllForGroupingSets
(
pfromexpr,
plTargetList,
plGroupClause,
fHasAggs,
pdrgpbs,
phmiulSortgrouprefColId,
phmiulOutputCols,
phmululGrpColPos
);
pbsUniqueueGrpCols->Release();
phmululGrpColPos->Release();
return pdxlnResult;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorQueryToDXL::PdxlnUnionAllForGroupingSets
//
// @doc:
// Construct a union all for the given grouping sets
//
//---------------------------------------------------------------------------
CDXLNode *
CTranslatorQueryToDXL::PdxlnUnionAllForGroupingSets
(
FromExpr *pfromexpr,
List *plTargetList,
List *plGroupClause,
BOOL fHasAggs,
DrgPbs *pdrgpbs,
HMIUl *phmiulSortgrouprefColId,
HMIUl *phmiulOutputCols,
HMUlUl *phmululGrpColPos // mapping pos->unique grouping columns for grouping func arguments
)
{
GPOS_ASSERT(NULL != pdrgpbs);
const ULONG ulGroupingSets = pdrgpbs->UlLength();
GPOS_ASSERT(1 < ulGroupingSets);
CDXLNode *pdxlnUnionAll = NULL;
DrgPul *pdrgpulColIdsInner = NULL;
const ULONG ulCTEId = m_pidgtorCTE->UlNextId();
// construct a CTE producer on top of the SPJ query
HMIUl *phmiulSPJ = GPOS_NEW(m_pmp) HMIUl(m_pmp);
HMIUl *phmiulSortgrouprefColIdProducer = GPOS_NEW(m_pmp) HMIUl(m_pmp);
CDXLNode *pdxlnSPJ = PdxlnSPJForGroupingSets(plTargetList, pfromexpr, phmiulSortgrouprefColIdProducer, phmiulSPJ, plGroupClause);
// construct output colids
DrgPul *pdrgpulCTEProducer = PdrgpulExtractColIds(m_pmp, phmiulSPJ);
GPOS_ASSERT (NULL != m_pdrgpdxlnCTE);
CDXLLogicalCTEProducer *pdxlopCTEProducer = GPOS_NEW(m_pmp) CDXLLogicalCTEProducer(m_pmp, ulCTEId, pdrgpulCTEProducer);
CDXLNode *pdxlnCTEProducer = GPOS_NEW(m_pmp) CDXLNode(m_pmp, pdxlopCTEProducer, pdxlnSPJ);
m_pdrgpdxlnCTE->Append(pdxlnCTEProducer);
CMappingVarColId *pmapvarcolidOriginal = m_pmapvarcolid->PmapvarcolidCopy(m_pmp);
for (ULONG ul = 0; ul < ulGroupingSets; ul++)
{
CBitSet *pbsGroupingSet = (*pdrgpbs)[ul];
// remap columns
DrgPul *pdrgpulCTEConsumer = PdrgpulGenerateColIds(m_pmp, pdrgpulCTEProducer->UlLength());
// reset col mapping with new consumer columns
GPOS_DELETE(m_pmapvarcolid);
m_pmapvarcolid = pmapvarcolidOriginal->PmapvarcolidRemap(m_pmp, pdrgpulCTEProducer, pdrgpulCTEConsumer);
HMIUl *phmiulSPJConsumer = PhmiulRemapColIds(m_pmp, phmiulSPJ, pdrgpulCTEProducer, pdrgpulCTEConsumer);
HMIUl *phmiulSortgrouprefColIdConsumer = PhmiulRemapColIds(m_pmp, phmiulSortgrouprefColIdProducer, pdrgpulCTEProducer, pdrgpulCTEConsumer);
// construct a CTE consumer
CDXLNode *pdxlnCTEConsumer = GPOS_NEW(m_pmp) CDXLNode(m_pmp, GPOS_NEW(m_pmp) CDXLLogicalCTEConsumer(m_pmp, ulCTEId, pdrgpulCTEConsumer));
HMIUl *phmiulGroupBy = GPOS_NEW(m_pmp) HMIUl(m_pmp);
CDXLNode *pdxlnGroupBy = PdxlnSimpleGroupBy
(
plTargetList,
plGroupClause,
pbsGroupingSet,
fHasAggs,
true, // fGroupingSets
pdxlnCTEConsumer,
phmiulSortgrouprefColIdConsumer,
phmiulSPJConsumer,
phmiulGroupBy
);
// add a project list for the NULL values
CDXLNode *pdxlnProject = PdxlnProjectNullsForGroupingSets(plTargetList, pdxlnGroupBy, pbsGroupingSet, phmiulSortgrouprefColIdConsumer, phmiulGroupBy, phmululGrpColPos);
DrgPul *pdrgpulColIdsOuter = CTranslatorUtils::PdrgpulColIds(m_pmp, plTargetList, phmiulGroupBy);
if (NULL != pdxlnUnionAll)
{
GPOS_ASSERT(NULL != pdrgpulColIdsInner);
DrgPdxlcd *pdrgpdxlcd = CTranslatorUtils::Pdrgpdxlcd(m_pmp, plTargetList, pdrgpulColIdsOuter, true /* fKeepResjunked */);
pdrgpulColIdsOuter->AddRef();
DrgPdrgPul *pdrgpdrgulInputColIds = GPOS_NEW(m_pmp) DrgPdrgPul(m_pmp);
pdrgpdrgulInputColIds->Append(pdrgpulColIdsOuter);
pdrgpdrgulInputColIds->Append(pdrgpulColIdsInner);
CDXLLogicalSetOp *pdxlopSetop = GPOS_NEW(m_pmp) CDXLLogicalSetOp(m_pmp, EdxlsetopUnionAll, pdrgpdxlcd, pdrgpdrgulInputColIds, false);
pdxlnUnionAll = GPOS_NEW(m_pmp) CDXLNode(m_pmp, pdxlopSetop, pdxlnProject, pdxlnUnionAll);
}
else
{
pdxlnUnionAll = pdxlnProject;
}
pdrgpulColIdsInner = pdrgpulColIdsOuter;
if (ul == ulGroupingSets - 1)
{
// add the sortgroup columns to output map of the last column
ULONG ulTargetEntryPos = 0;
ListCell *plcTE = NULL;
ForEach (plcTE, plTargetList)
{
TargetEntry *pte = (TargetEntry *) lfirst(plcTE);
INT iSortGrpRef = INT (pte->ressortgroupref);
if (0 < iSortGrpRef && NULL != phmiulSortgrouprefColIdConsumer->PtLookup(&iSortGrpRef))
{
// add the mapping information for sorting columns
AddSortingGroupingColumn(pte, phmiulSortgrouprefColId, *(*pdrgpulColIdsInner)[ulTargetEntryPos]);
}
ulTargetEntryPos++;
}
}
// cleanup
phmiulGroupBy->Release();
phmiulSPJConsumer->Release();
phmiulSortgrouprefColIdConsumer->Release();
}
// cleanup
phmiulSPJ->Release();
phmiulSortgrouprefColIdProducer->Release();
GPOS_DELETE(pmapvarcolidOriginal);
pdrgpulColIdsInner->Release();
// compute output columns
CDXLLogicalSetOp *pdxlopUnion = CDXLLogicalSetOp::PdxlopConvert(pdxlnUnionAll->Pdxlop());
ListCell *plcTE = NULL;
ULONG ulOutputColIndex = 0;
ForEach (plcTE, plTargetList)
{
TargetEntry *pte = (TargetEntry *) lfirst(plcTE);
GPOS_ASSERT(IsA(pte, TargetEntry));
GPOS_ASSERT(0 < pte->resno);
ULONG ulResNo = pte->resno;
// note that all target list entries are kept in union all's output column
// this is achieved by the fKeepResjunked flag in CTranslatorUtils::Pdrgpdxlcd
const CDXLColDescr *pdxlcd = pdxlopUnion->Pdxlcd(ulOutputColIndex);
const ULONG ulColId = pdxlcd->UlID();
ulOutputColIndex++;
if (!pte->resjunk)
{
// add non-resjunk columns to the hash map that maintains the output columns
StoreAttnoColIdMapping(phmiulOutputCols, ulResNo, ulColId);
}
}
// cleanup
pdrgpbs->Release();
// construct a CTE anchor operator on top of the union all
return GPOS_NEW(m_pmp) CDXLNode(m_pmp, GPOS_NEW(m_pmp) CDXLLogicalCTEAnchor(m_pmp, ulCTEId), pdxlnUnionAll);
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorQueryToDXL::PdxlnConstTableGet
//
// @doc:
// Create a dummy constant table get (CTG) with a boolean true value
//
//---------------------------------------------------------------------------
CDXLNode *
CTranslatorQueryToDXL::PdxlnConstTableGet() const
{
// construct the schema of the const table
DrgPdxlcd *pdrgpdxlcd = GPOS_NEW(m_pmp) DrgPdxlcd(m_pmp);
const CMDTypeBoolGPDB *pmdtypeBool = dynamic_cast<const CMDTypeBoolGPDB *>(m_pmda->PtMDType<IMDTypeBool>(m_sysid));
const CMDIdGPDB *pmdid = CMDIdGPDB::PmdidConvert(pmdtypeBool->Pmdid());
// empty column name
CWStringConst strUnnamedCol(GPOS_WSZ_LIT(""));
CMDName *pmdname = GPOS_NEW(m_pmp) CMDName(m_pmp, &strUnnamedCol);
CDXLColDescr *pdxlcd = GPOS_NEW(m_pmp) CDXLColDescr
(
m_pmp,
pmdname,
m_pidgtorCol->UlNextId(),
1 /* iAttno */,
CTranslatorUtils::PmdidWithVersion(m_pmp, pmdid->OidObjectId()),
false /* fDropped */
);
pdrgpdxlcd->Append(pdxlcd);
// create the array of datum arrays
DrgPdrgPdxldatum *pdrgpdrgpdxldatum = GPOS_NEW(m_pmp) DrgPdrgPdxldatum(m_pmp);
// create a datum array
DrgPdxldatum *pdrgpdxldatum = GPOS_NEW(m_pmp) DrgPdxldatum(m_pmp);
Const *pconst = (Const*) gpdb::PnodeMakeBoolConst(true /*value*/, false /*isnull*/);
CDXLDatum *pdxldatum = m_psctranslator->Pdxldatum(pconst);
gpdb::GPDBFree(pconst);
pdrgpdxldatum->Append(pdxldatum);
pdrgpdrgpdxldatum->Append(pdrgpdxldatum);
CDXLLogicalConstTable *pdxlop = GPOS_NEW(m_pmp) CDXLLogicalConstTable(m_pmp, pdrgpdxlcd, pdrgpdrgpdxldatum);
return GPOS_NEW(m_pmp) CDXLNode(m_pmp, pdxlop);
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorQueryToDXL::PdxlnFromSetOp
//
// @doc:
// Translate a set operation
//
//---------------------------------------------------------------------------
CDXLNode *
CTranslatorQueryToDXL::PdxlnFromSetOp
(
Node *pnodeSetOp,
List *plTargetList,
HMIUl *phmiulOutputCols
)
{
GPOS_ASSERT(IsA(pnodeSetOp, SetOperationStmt));
SetOperationStmt *psetopstmt = (SetOperationStmt*) pnodeSetOp;
GPOS_ASSERT(SETOP_NONE != psetopstmt->op);
EdxlSetOpType edxlsetop = CTranslatorUtils::Edxlsetop(psetopstmt->op, psetopstmt->all);
// translate the left and right child
DrgPul *pdrgpulLeft = GPOS_NEW(m_pmp) DrgPul(m_pmp);
DrgPul *pdrgpulRight = GPOS_NEW(m_pmp) DrgPul(m_pmp);
DrgPmdid *pdrgpmdidLeft = GPOS_NEW(m_pmp) DrgPmdid(m_pmp);
DrgPmdid *pdrgpmdidRight = GPOS_NEW(m_pmp) DrgPmdid(m_pmp);
CDXLNode *pdxlnLeftChild = PdxlnSetOpChild(psetopstmt->larg, pdrgpulLeft, pdrgpmdidLeft, plTargetList);
CDXLNode *pdxlnRightChild = PdxlnSetOpChild(psetopstmt->rarg, pdrgpulRight, pdrgpmdidRight, plTargetList);
// mark outer references in input columns from left child
ULONG *pulColId = GPOS_NEW_ARRAY(m_pmp, ULONG, pdrgpulLeft->UlLength());
BOOL *pfOuterRef = GPOS_NEW_ARRAY(m_pmp, BOOL, pdrgpulLeft->UlLength());
const ULONG ulSize = pdrgpulLeft->UlLength();
for (ULONG ul = 0; ul < ulSize; ul++)
{
pulColId[ul] = *(*pdrgpulLeft)[ul];
pfOuterRef[ul] = true;
}
CTranslatorUtils::MarkOuterRefs(pulColId, pfOuterRef, ulSize, pdxlnLeftChild);
DrgPdrgPul *pdrgpdrgulInputColIds = GPOS_NEW(m_pmp) DrgPdrgPul(m_pmp);
pdrgpdrgulInputColIds->Append(pdrgpulLeft);
pdrgpdrgulInputColIds->Append(pdrgpulRight);
DrgPul *pdrgpulOutput = CTranslatorUtils::PdrgpulGenerateColIds
(
m_pmp,
plTargetList,
pdrgpmdidLeft,
pdrgpulLeft,
pfOuterRef,
m_pidgtorCol
);
GPOS_ASSERT(pdrgpulOutput->UlLength() == pdrgpulLeft->UlLength());
GPOS_DELETE_ARRAY(pulColId);
GPOS_DELETE_ARRAY(pfOuterRef);
BOOL fCastAcrossInput = FCast(plTargetList, pdrgpmdidLeft) || FCast(plTargetList, pdrgpmdidRight);
DrgPdxln *pdrgpdxlnChildren = GPOS_NEW(m_pmp) DrgPdxln(m_pmp);
pdrgpdxlnChildren->Append(pdxlnLeftChild);
pdrgpdxlnChildren->Append(pdxlnRightChild);
CDXLNode *pdxln = PdxlnSetOp
(
edxlsetop,
plTargetList,
pdrgpulOutput,
pdrgpdrgulInputColIds,
pdrgpdxlnChildren,
fCastAcrossInput,
false /* fKeepResjunked */
);
CDXLLogicalSetOp *pdxlop = CDXLLogicalSetOp::PdxlopConvert(pdxln->Pdxlop());
const DrgPdxlcd *pdrgpdxlcd = pdxlop->Pdrgpdxlcd();
ULONG ulOutputColIndex = 0;
ListCell *plcTE = NULL;
ForEach (plcTE, plTargetList)
{
TargetEntry *pte = (TargetEntry *) lfirst(plcTE);
GPOS_ASSERT(IsA(pte, TargetEntry));
GPOS_ASSERT(0 < pte->resno);
ULONG ulResNo = pte->resno;
if (!pte->resjunk)
{
const CDXLColDescr *pdxlcdNew = (*pdrgpdxlcd)[ulOutputColIndex];
ULONG ulColId = pdxlcdNew->UlID();
StoreAttnoColIdMapping(phmiulOutputCols, ulResNo, ulColId);
ulOutputColIndex++;
}
}
// clean up
pdrgpulOutput->Release();
pdrgpmdidLeft->Release();
pdrgpmdidRight->Release();
return pdxln;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorQueryToDXL::PdxlSetOp
//
// @doc:
// Create a set op after adding dummy cast on input columns where needed
//---------------------------------------------------------------------------
CDXLNode *
CTranslatorQueryToDXL::PdxlnSetOp
(
EdxlSetOpType edxlsetop,
List *plTargetListOutput,
DrgPul *pdrgpulOutput,
DrgPdrgPul *pdrgpdrgulInputColIds,
DrgPdxln *pdrgpdxlnChildren,
BOOL fCastAcrossInput,
BOOL fKeepResjunked
)
const
{
GPOS_ASSERT(NULL != plTargetListOutput);
GPOS_ASSERT(NULL != pdrgpulOutput);
GPOS_ASSERT(NULL != pdrgpdrgulInputColIds);
GPOS_ASSERT(NULL != pdrgpdxlnChildren);
GPOS_ASSERT(1 < pdrgpdrgulInputColIds->UlLength());
GPOS_ASSERT(1 < pdrgpdxlnChildren->UlLength());
// positions of output columns in the target list
DrgPul *pdrgpulTLPos = CTranslatorUtils::PdrgpulPosInTargetList(m_pmp, plTargetListOutput, fKeepResjunked);
const ULONG ulCols = pdrgpulOutput->UlLength();
DrgPul *pdrgpulInputFirstChild = (*pdrgpdrgulInputColIds)[0];
GPOS_ASSERT(ulCols == pdrgpulInputFirstChild->UlLength());
GPOS_ASSERT(ulCols == pdrgpulOutput->UlLength());
CBitSet *pbs = GPOS_NEW(m_pmp) CBitSet(m_pmp);
// project list to maintain the casting of the duplicate input columns
CDXLNode *pdxlnNewChildScPrL = GPOS_NEW(m_pmp) CDXLNode(m_pmp, GPOS_NEW(m_pmp) CDXLScalarProjList(m_pmp));
DrgPul *pdrgpulInputFirstChildNew = GPOS_NEW(m_pmp) DrgPul (m_pmp);
DrgPdxlcd *pdrgpdxlcdOutput = GPOS_NEW(m_pmp) DrgPdxlcd(m_pmp);
for (ULONG ul = 0; ul < ulCols; ul++)
{
ULONG ulColIdOutput = *(*pdrgpulOutput)[ul];
ULONG ulColIdInput = *(*pdrgpulInputFirstChild)[ul];
BOOL fColExists = pbs->FBit(ulColIdInput);
BOOL fCastedCol = (ulColIdOutput != ulColIdInput);
ULONG ulTLPos = *(*pdrgpulTLPos)[ul];
TargetEntry *pte = (TargetEntry*) gpdb::PvListNth(plTargetListOutput, ulTLPos);
GPOS_ASSERT(NULL != pte);
CDXLColDescr *pdxlcdOutput = NULL;
if (!fColExists)
{
pbs->FExchangeSet(ulColIdInput);
pdrgpulInputFirstChildNew->Append(GPOS_NEW(m_pmp) ULONG(ulColIdInput));
pdxlcdOutput = CTranslatorUtils::Pdxlcd(m_pmp, pte, ulColIdOutput, ul + 1);
}
else
{
// we add a dummy-cast to distinguish between the output columns of the union
ULONG ulColIdNew = m_pidgtorCol->UlNextId();
pdrgpulInputFirstChildNew->Append(GPOS_NEW(m_pmp) ULONG(ulColIdNew));
ULONG ulColIdUnionOutput = ulColIdNew;
if (fCastedCol)
{
// create new output column id since current colid denotes its duplicate
ulColIdUnionOutput = m_pidgtorCol->UlNextId();
}
pdxlcdOutput = CTranslatorUtils::Pdxlcd(m_pmp, pte, ulColIdUnionOutput, ul + 1);
CDXLNode *pdxlnPrEl = CTranslatorUtils::PdxlnDummyPrElem(m_pmp, ulColIdInput, ulColIdNew, pdxlcdOutput);
pdxlnNewChildScPrL->AddChild(pdxlnPrEl);
}
pdrgpdxlcdOutput->Append(pdxlcdOutput);
}
pdrgpdrgulInputColIds->Replace(0, pdrgpulInputFirstChildNew);
if (0 < pdxlnNewChildScPrL->UlArity())
{
// create a project node for the dummy casted columns
CDXLNode *pdxlnFirstChild = (*pdrgpdxlnChildren)[0];
pdxlnFirstChild->AddRef();
CDXLNode *pdxlnNewChild = GPOS_NEW(m_pmp) CDXLNode(m_pmp, GPOS_NEW(m_pmp) CDXLLogicalProject(m_pmp));
pdxlnNewChild->AddChild(pdxlnNewChildScPrL);
pdxlnNewChild->AddChild(pdxlnFirstChild);
pdrgpdxlnChildren->Replace(0, pdxlnNewChild);
}
else
{
pdxlnNewChildScPrL->Release();
}
CDXLLogicalSetOp *pdxlop = GPOS_NEW(m_pmp) CDXLLogicalSetOp
(
m_pmp,
edxlsetop,
pdrgpdxlcdOutput,
pdrgpdrgulInputColIds,
fCastAcrossInput
);
CDXLNode *pdxln = GPOS_NEW(m_pmp) CDXLNode(m_pmp, pdxlop, pdrgpdxlnChildren);
pbs->Release();
pdrgpulTLPos->Release();
return pdxln;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorQueryToDXL::FCast
//
// @doc:
// Check if the set operation need to cast any of its input columns
//
//---------------------------------------------------------------------------
BOOL
CTranslatorQueryToDXL::FCast
(
List *plTargetList,
DrgPmdid *pdrgpmdid
)
const
{
GPOS_ASSERT(NULL != pdrgpmdid);
GPOS_ASSERT(NULL != plTargetList);
GPOS_ASSERT(pdrgpmdid->UlLength() <= gpdb::UlListLength(plTargetList)); // there may be resjunked columns
ULONG ulColPos = 0;
ListCell *plcTE = NULL;
ForEach (plcTE, plTargetList)
{
TargetEntry *pte = (TargetEntry *) lfirst(plcTE);
OID oidExprType = gpdb::OidExprType((Node*) pte->expr);
if (!pte->resjunk)
{
IMDId *pmdid = (*pdrgpmdid)[ulColPos];
if (CMDIdGPDB::PmdidConvert(pmdid)->OidObjectId() != oidExprType)
{
return true;
}
ulColPos++;
}
}
return false;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorQueryToDXL::PdxlnSetOpChild
//
// @doc:
// Translate the child of a set operation
//
//---------------------------------------------------------------------------
CDXLNode *
CTranslatorQueryToDXL::PdxlnSetOpChild
(
Node *pnodeChild,
DrgPul *pdrgpul,
DrgPmdid *pdrgpmdid,
List *plTargetList
)
{
GPOS_ASSERT(NULL != pdrgpul);
GPOS_ASSERT(NULL != pdrgpmdid);
if (IsA(pnodeChild, RangeTblRef))
{
RangeTblRef *prtref = (RangeTblRef*) pnodeChild;
const ULONG ulRTIndex = prtref->rtindex;
const RangeTblEntry *prte = (RangeTblEntry *) gpdb::PvListNth(m_pquery->rtable, ulRTIndex - 1);
if (RTE_SUBQUERY == prte->rtekind)
{
Query *pqueryDerTbl = CTranslatorUtils::PqueryFixUnknownTypeConstant(prte->subquery, plTargetList);
GPOS_ASSERT(NULL != pqueryDerTbl);
CMappingVarColId *pmapvarcolid = m_pmapvarcolid->PmapvarcolidCopy(m_pmp);
CTranslatorQueryToDXL trquerytodxl
(
m_pmp,
m_pmda,
m_pidgtorCol,
m_pidgtorCTE,
pmapvarcolid,
pqueryDerTbl,
m_ulQueryLevel + 1,
FDMLQuery(),
m_phmulCTEEntries
);
// translate query representing the derived table to its DXL representation
CDXLNode *pdxln = trquerytodxl.PdxlnFromQueryInternal();
GPOS_ASSERT(NULL != pdxln);
DrgPdxln *pdrgpdxlnCTE = trquerytodxl.PdrgpdxlnCTE();
CUtils::AddRefAppend(m_pdrgpdxlnCTE, pdrgpdxlnCTE);
m_fHasDistributedTables = m_fHasDistributedTables || trquerytodxl.FHasDistributedTables();
// get the output columns of the derived table
DrgPdxln *pdrgpdxln = trquerytodxl.PdrgpdxlnQueryOutput();
GPOS_ASSERT(pdrgpdxln != NULL);
const ULONG ulLen = pdrgpdxln->UlLength();
for (ULONG ul = 0; ul < ulLen; ul++)
{
CDXLNode *pdxlnCurr = (*pdrgpdxln)[ul];
CDXLScalarIdent *pdxlnIdent = CDXLScalarIdent::PdxlopConvert(pdxlnCurr->Pdxlop());
ULONG *pulColId = GPOS_NEW(m_pmp) ULONG(pdxlnIdent->Pdxlcr()->UlID());
pdrgpul->Append(pulColId);
IMDId *pmdidCol = pdxlnIdent->PmdidType();
GPOS_ASSERT(NULL != pmdidCol);
pmdidCol->AddRef();
pdrgpmdid->Append(pmdidCol);
}
return pdxln;
}
}
else if (IsA(pnodeChild, SetOperationStmt))
{
HMIUl *phmiulOutputCols = GPOS_NEW(m_pmp) HMIUl(m_pmp);
CDXLNode *pdxln = PdxlnFromSetOp(pnodeChild, plTargetList, phmiulOutputCols);
// cleanup
phmiulOutputCols->Release();
const DrgPdxlcd *pdrgpdxlcd = CDXLLogicalSetOp::PdxlopConvert(pdxln->Pdxlop())->Pdrgpdxlcd();
GPOS_ASSERT(NULL != pdrgpdxlcd);
const ULONG ulLen = pdrgpdxlcd->UlLength();
for (ULONG ul = 0; ul < ulLen; ul++)
{
const CDXLColDescr *pdxlcd = (*pdrgpdxlcd)[ul];
ULONG *pulColId = GPOS_NEW(m_pmp) ULONG(pdxlcd->UlID());
pdrgpul->Append(pulColId);
IMDId *pmdidCol = pdxlcd->PmdidType();
GPOS_ASSERT(NULL != pmdidCol);
pmdidCol->AddRef();
pdrgpmdid->Append(pmdidCol);
}
return pdxln;
}
CHAR *sz = (CHAR*) gpdb::SzNodeToString(const_cast<Node*>(pnodeChild));
CWStringDynamic *pstr = CDXLUtils::PstrFromSz(m_pmp, sz);
GPOS_RAISE(gpdxl::ExmaDXL, gpdxl::ExmiQuery2DXLUnsupportedFeature, pstr->Wsz());
return NULL;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorQueryToDXL::PdxlnFromGPDBFromExpr
//
// @doc:
// Translate the FromExpr on a GPDB query into either a CDXLLogicalJoin
// or a CDXLLogicalGet
//
//---------------------------------------------------------------------------
CDXLNode *
CTranslatorQueryToDXL::PdxlnFromGPDBFromExpr
(
FromExpr *pfromexpr
)
{
CDXLNode *pdxln = NULL;
if (0 == gpdb::UlListLength(pfromexpr->fromlist))
{
pdxln = PdxlnConstTableGet();
}
else
{
if (1 == gpdb::UlListLength(pfromexpr->fromlist))
{
Node *pnode = (Node*) gpdb::PvListNth(pfromexpr->fromlist, 0);
GPOS_ASSERT(NULL != pnode);
pdxln = PdxlnFromGPDBFromClauseEntry(pnode);
}
else
{
// In DXL, we represent an n-ary join (where n>2) by an inner join with condition true.
// The join conditions represented in the FromExpr->quals is translated
// into a CDXLLogicalSelect on top of the CDXLLogicalJoin
pdxln = GPOS_NEW(m_pmp) CDXLNode(m_pmp, GPOS_NEW(m_pmp) CDXLLogicalJoin(m_pmp, EdxljtInner));
ListCell *plc = NULL;
ForEach (plc, pfromexpr->fromlist)
{
Node *pnode = (Node*) lfirst(plc);
CDXLNode *pdxlnChild = PdxlnFromGPDBFromClauseEntry(pnode);
pdxln->AddChild(pdxlnChild);
}
}
}
// translate the quals
Node *pnodeQuals = pfromexpr->quals;
CDXLNode *pdxlnCond = NULL;
if (NULL != pnodeQuals)
{
pdxlnCond = PdxlnScFromGPDBExpr( (Expr*) pnodeQuals);
}
if (1 >= gpdb::UlListLength(pfromexpr->fromlist))
{
if (NULL != pdxlnCond)
{
CDXLNode *pdxlnSelect = GPOS_NEW(m_pmp) CDXLNode(m_pmp, GPOS_NEW(m_pmp) CDXLLogicalSelect(m_pmp));
pdxlnSelect->AddChild(pdxlnCond);
pdxlnSelect->AddChild(pdxln);
pdxln = pdxlnSelect;
}
}
else //n-ary joins
{
if (NULL == pdxlnCond)
{
// A cross join (the scalar condition is true)
pdxlnCond = PdxlnScConstValueTrue();
}
pdxln->AddChild(pdxlnCond);
}
return pdxln;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorQueryToDXL::PdxlnFromGPDBFromClauseEntry
//
// @doc:
// Returns a CDXLNode representing a from clause entry which can either be
// (1) a fromlist entry in the FromExpr or (2) left/right child of a JoinExpr
//
//---------------------------------------------------------------------------
CDXLNode *
CTranslatorQueryToDXL::PdxlnFromGPDBFromClauseEntry
(
Node *pnode
)
{
GPOS_ASSERT(NULL != pnode);
if (IsA(pnode, RangeTblRef))
{
RangeTblRef *prtref = (RangeTblRef *) pnode;
ULONG ulRTIndex = prtref->rtindex ;
const RangeTblEntry *prte = (RangeTblEntry *) gpdb::PvListNth(m_pquery->rtable, ulRTIndex - 1);
GPOS_ASSERT(NULL != prte);
if (prte->forceDistRandom)
{
GPOS_RAISE(gpdxl::ExmaDXL, gpdxl::ExmiQuery2DXLUnsupportedFeature, GPOS_WSZ_LIT("gp_dist_random"));
}
SRTETranslator rgTranslators[] =
{
{RTE_RELATION, &CTranslatorQueryToDXL::PdxlnFromRelation},
{RTE_VALUES, &CTranslatorQueryToDXL::PdxlnFromValues},
{RTE_CTE, &CTranslatorQueryToDXL::PdxlnFromCTE},
{RTE_SUBQUERY, &CTranslatorQueryToDXL::PdxlnFromDerivedTable},
{RTE_FUNCTION, &CTranslatorQueryToDXL::PdxlnFromTVF},
};
const ULONG ulTranslators = GPOS_ARRAY_SIZE(rgTranslators);
// find translator for the rtekind
PfPdxlnLogical pf = NULL;
for (ULONG ul = 0; ul < ulTranslators; ul++)
{
SRTETranslator elem = rgTranslators[ul];
if (prte->rtekind == elem.m_rtekind)
{
pf = elem.pf;
break;
}
}
if (NULL == pf)
{
UnsupportedRTEKind(prte->rtekind);
return NULL;
}
return (this->*pf)(prte, ulRTIndex, m_ulQueryLevel);
}
if (IsA(pnode, JoinExpr))
{
return PdxlnLgJoinFromGPDBJoinExpr((JoinExpr*) pnode);
}
CHAR *sz = (CHAR*) gpdb::SzNodeToString(const_cast<Node*>(pnode));
CWStringDynamic *pstr = CDXLUtils::PstrFromSz(m_pmp, sz);
GPOS_RAISE(gpdxl::ExmaDXL, gpdxl::ExmiQuery2DXLUnsupportedFeature, pstr->Wsz());
return NULL;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorQueryToDXL::UnsupportedRTEKind
//
// @doc:
// Raise exception for unsupported RangeTblEntries of a particular kind
//---------------------------------------------------------------------------
void
CTranslatorQueryToDXL::UnsupportedRTEKind
(
RTEKind rtekind
)
const
{
GPOS_ASSERT(!(RTE_RELATION == rtekind || RTE_CTE == rtekind
|| RTE_FUNCTION == rtekind || RTE_SUBQUERY == rtekind
|| RTE_VALUES == rtekind));
SRTENameElem rgStrMap[] =
{
{RTE_JOIN, GPOS_WSZ_LIT("RangeTableEntry of type Join")},
{RTE_SPECIAL, GPOS_WSZ_LIT("RangeTableEntry of type Special")},
{RTE_VOID, GPOS_WSZ_LIT("RangeTableEntry of type Void")},
{RTE_TABLEFUNCTION, GPOS_WSZ_LIT("RangeTableEntry of type Table Function")}
};
const ULONG ulLen = GPOS_ARRAY_SIZE(rgStrMap);
for (ULONG ul = 0; ul < ulLen; ul++)
{
SRTENameElem mapelem = rgStrMap[ul];
if (mapelem.m_rtekind == rtekind)
{
GPOS_RAISE(gpdxl::ExmaDXL, gpdxl::ExmiQuery2DXLUnsupportedFeature, mapelem.m_wsz);
}
}
GPOS_ASSERT(!"Unrecognized RTE kind");
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorQueryToDXL::PdxlnFromRelation
//
// @doc:
// Returns a CDXLNode representing a from relation range table entry
//
//---------------------------------------------------------------------------
CDXLNode *
CTranslatorQueryToDXL::PdxlnFromRelation
(
const RangeTblEntry *prte,
ULONG ulRTIndex,
ULONG //ulCurrQueryLevel
)
{
// construct table descriptor for the scan node from the range table entry
CDXLTableDescr *pdxltabdesc = CTranslatorUtils::Pdxltabdesc(m_pmp, m_pmda, m_pidgtorCol, prte, &m_fHasDistributedTables);
CDXLLogicalGet *pdxlop = NULL;
const IMDRelation *pmdrel = m_pmda->Pmdrel(pdxltabdesc->Pmdid());
if (IMDRelation::ErelstorageExternal == pmdrel->Erelstorage())
{
pdxlop = GPOS_NEW(m_pmp) CDXLLogicalExternalGet(m_pmp, pdxltabdesc);
}
else
{
pdxlop = GPOS_NEW(m_pmp) CDXLLogicalGet(m_pmp, pdxltabdesc);
}
CDXLNode *pdxlnGet = GPOS_NEW(m_pmp) CDXLNode(m_pmp, pdxlop);
// make note of new columns from base relation
m_pmapvarcolid->LoadTblColumns(m_ulQueryLevel, ulRTIndex, pdxltabdesc);
return pdxlnGet;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorQueryToDXL::PdxlnFromValues
//
// @doc:
// Returns a CDXLNode representing a range table entry of values
//
//---------------------------------------------------------------------------
CDXLNode *
CTranslatorQueryToDXL::PdxlnFromValues
(
const RangeTblEntry *prte,
ULONG ulRTIndex,
ULONG ulCurrQueryLevel
)
{
List *plTuples = prte->values_lists;
GPOS_ASSERT(NULL != plTuples);
const ULONG ulValues = gpdb::UlListLength(plTuples);
GPOS_ASSERT(0 < ulValues);
// children of the UNION ALL
DrgPdxln *pdrgpdxln = GPOS_NEW(m_pmp) DrgPdxln(m_pmp);
// array of input colid arrays
DrgPdrgPul *pdrgpdrgulInputColIds = GPOS_NEW(m_pmp) DrgPdrgPul(m_pmp);
// array of column descriptor for the UNION ALL operator
DrgPdxlcd *pdrgpdxlcd = GPOS_NEW(m_pmp) DrgPdxlcd(m_pmp);
// translate the tuples in the value scan
ULONG ulTuplePos = 0;
ListCell *plcTuple = NULL;
GPOS_ASSERT(NULL != prte->eref);
ForEach (plcTuple, plTuples)
{
List *plTuple = (List *) lfirst(plcTuple);
GPOS_ASSERT(IsA(plTuple, List));
// array of column colids
DrgPul *pdrgpulColIds = GPOS_NEW(m_pmp) DrgPul(m_pmp);
// array of project elements (for expression elements)
DrgPdxln *pdrgpdxlnPrEl = GPOS_NEW(m_pmp) DrgPdxln(m_pmp);
// array of datum (for datum constant values)
DrgPdxldatum *pdrgpdxldatum = GPOS_NEW(m_pmp) DrgPdxldatum(m_pmp);
// array of column descriptors for the CTG containing the datum array
DrgPdxlcd *pdrgpdxlcdCTG = GPOS_NEW(m_pmp) DrgPdxlcd(m_pmp);
List *plColnames = prte->eref->colnames;
GPOS_ASSERT(NULL != plColnames);
GPOS_ASSERT(gpdb::UlListLength(plTuple) == gpdb::UlListLength(plColnames));
// translate the columns
ULONG ulColPos = 0;
ListCell *plcColumn = NULL;
ForEach (plcColumn, plTuple)
{
Expr *pexpr = (Expr *) lfirst(plcColumn);
CHAR *szColName = (CHAR *) strVal(gpdb::PvListNth(plColnames, ulColPos));
ULONG ulColId = ULONG_MAX;
if (IsA(pexpr, Const))
{
// extract the datum
Const *pconst = (Const *) pexpr;
CDXLDatum *pdxldatum = m_psctranslator->Pdxldatum(pconst);
pdrgpdxldatum->Append(pdxldatum);
ulColId = m_pidgtorCol->UlNextId();
CWStringDynamic *pstrAlias = CDXLUtils::PstrFromSz(m_pmp, szColName);
CMDName *pmdname = GPOS_NEW(m_pmp) CMDName(m_pmp, pstrAlias);
GPOS_DELETE(pstrAlias);
CDXLColDescr *pdxlcd = GPOS_NEW(m_pmp) CDXLColDescr
(
m_pmp,
pmdname,
ulColId,
ulColPos + 1 /* iAttno */,
CTranslatorUtils::PmdidWithVersion(m_pmp, pconst->consttype),
false /* fDropped */
);
if (0 == ulTuplePos)
{
pdxlcd->AddRef();
pdrgpdxlcd->Append(pdxlcd);
}
pdrgpdxlcdCTG->Append(pdxlcd);
}
else
{
// translate the scalar expression into a project element
CDXLNode *pdxlnPrE = PdxlnPrEFromGPDBExpr(pexpr, szColName, true /* fInsistNewColIds */ );
pdrgpdxlnPrEl->Append(pdxlnPrE);
ulColId = CDXLScalarProjElem::PdxlopConvert(pdxlnPrE->Pdxlop())->UlId();
if (0 == ulTuplePos)
{
CWStringDynamic *pstrAlias = CDXLUtils::PstrFromSz(m_pmp, szColName);
CMDName *pmdname = GPOS_NEW(m_pmp) CMDName(m_pmp, pstrAlias);
GPOS_DELETE(pstrAlias);
CDXLColDescr *pdxlcd = GPOS_NEW(m_pmp) CDXLColDescr
(
m_pmp,
pmdname,
ulColId,
ulColPos + 1 /* iAttno */,
CTranslatorUtils::PmdidWithVersion(m_pmp, gpdb::OidExprType((Node*) pexpr)),
false /* fDropped */
);
pdrgpdxlcd->Append(pdxlcd);
}
}
GPOS_ASSERT(ULONG_MAX != ulColId);
pdrgpulColIds->Append(GPOS_NEW(m_pmp) ULONG(ulColId));
ulColPos++;
}
pdrgpdxln->Append(PdxlnFromColumnValues(pdrgpdxldatum, pdrgpdxlcdCTG, pdrgpdxlnPrEl));
pdrgpdrgulInputColIds->Append(pdrgpulColIds);
ulTuplePos++;
// cleanup
pdrgpdxldatum->Release();
pdrgpdxlnPrEl->Release();
pdrgpdxlcdCTG->Release();
}
GPOS_ASSERT(NULL != pdrgpdxlcd);
if (1 < ulValues)
{
// create a UNION ALL operator
CDXLLogicalSetOp *pdxlop = GPOS_NEW(m_pmp) CDXLLogicalSetOp(m_pmp, EdxlsetopUnionAll, pdrgpdxlcd, pdrgpdrgulInputColIds, false);
CDXLNode *pdxln = GPOS_NEW(m_pmp) CDXLNode(m_pmp, pdxlop, pdrgpdxln);
// make note of new columns from UNION ALL
m_pmapvarcolid->LoadColumns(m_ulQueryLevel, ulRTIndex, pdxlop->Pdrgpdxlcd());
return pdxln;
}
GPOS_ASSERT(1 == pdrgpdxln->UlLength());
CDXLNode *pdxln = (*pdrgpdxln)[0];
pdxln->AddRef();
// make note of new columns
m_pmapvarcolid->LoadColumns(m_ulQueryLevel, ulRTIndex, pdrgpdxlcd);
//cleanup
pdrgpdxln->Release();
pdrgpdrgulInputColIds->Release();
pdrgpdxlcd->Release();
return pdxln;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorQueryToDXL::PdxlnFromColumnValues
//
// @doc:
// Generate a DXL node from column values, where each column value is
// either a datum or scalar expression represented as project element.
// Each datum is associated with a column descriptors used by the CTG
//---------------------------------------------------------------------------
CDXLNode *
CTranslatorQueryToDXL::PdxlnFromColumnValues
(
DrgPdxldatum *pdrgpdxldatumCTG,
DrgPdxlcd *pdrgpdxlcdCTG,
DrgPdxln *pdrgpdxlnPrEl
)
const
{
GPOS_ASSERT(NULL != pdrgpdxldatumCTG);
GPOS_ASSERT(NULL != pdrgpdxlnPrEl);
CDXLNode *pdxlnCTG = NULL;
if (0 == pdrgpdxldatumCTG->UlLength())
{
// add a dummy CTG
pdxlnCTG = PdxlnConstTableGet();
}
else
{
// create the array of datum arrays
DrgPdrgPdxldatum *pdrgpdrgpdxldatumCTG = GPOS_NEW(m_pmp) DrgPdrgPdxldatum(m_pmp);
pdrgpdxldatumCTG->AddRef();
pdrgpdrgpdxldatumCTG->Append(pdrgpdxldatumCTG);
pdrgpdxlcdCTG->AddRef();
CDXLLogicalConstTable *pdxlop = GPOS_NEW(m_pmp) CDXLLogicalConstTable(m_pmp, pdrgpdxlcdCTG, pdrgpdrgpdxldatumCTG);
pdxlnCTG = GPOS_NEW(m_pmp) CDXLNode(m_pmp, pdxlop);
}
if (0 == pdrgpdxlnPrEl->UlLength())
{
return pdxlnCTG;
}
// create a project node for the list of project elements
pdrgpdxlnPrEl->AddRef();
CDXLNode *pdxlnPrL = GPOS_NEW(m_pmp) CDXLNode
(
m_pmp,
GPOS_NEW(m_pmp) CDXLScalarProjList(m_pmp),
pdrgpdxlnPrEl
);
CDXLNode *pdxlnProject = GPOS_NEW(m_pmp) CDXLNode
(
m_pmp,
GPOS_NEW(m_pmp) CDXLLogicalProject(m_pmp),
pdxlnPrL,
pdxlnCTG
);
return pdxlnProject;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorQueryToDXL::PdxlnFromTVF
//
// @doc:
// Returns a CDXLNode representing a from relation range table entry
//---------------------------------------------------------------------------
CDXLNode *
CTranslatorQueryToDXL::PdxlnFromTVF
(
const RangeTblEntry *prte,
ULONG ulRTIndex,
ULONG //ulCurrQueryLevel
)
{
GPOS_ASSERT(NULL != prte->funcexpr);
// if this is a folded function expression, generate a project over a CTG
if (!IsA(prte->funcexpr, FuncExpr))
{
CDXLNode *pdxlnCTG = PdxlnConstTableGet();
CDXLNode *pdxlnPrL = GPOS_NEW(m_pmp) CDXLNode(m_pmp, GPOS_NEW(m_pmp) CDXLScalarProjList(m_pmp));
CDXLNode *pdxlnPrEl = PdxlnPrEFromGPDBExpr((Expr *) prte->funcexpr, prte->eref->aliasname, true /* fInsistNewColIds */);
pdxlnPrL->AddChild(pdxlnPrEl);
CDXLNode *pdxlnProject = GPOS_NEW(m_pmp) CDXLNode(m_pmp, GPOS_NEW(m_pmp) CDXLLogicalProject(m_pmp));
pdxlnProject->AddChild(pdxlnPrL);
pdxlnProject->AddChild(pdxlnCTG);
m_pmapvarcolid->LoadProjectElements(m_ulQueryLevel, ulRTIndex, pdxlnPrL);
return pdxlnProject;
}
CDXLLogicalTVF *pdxlopTVF = CTranslatorUtils::Pdxltvf(m_pmp, m_pmda, m_pidgtorCol, prte);
CDXLNode *pdxlnTVF = GPOS_NEW(m_pmp) CDXLNode(m_pmp, pdxlopTVF);
// make note of new columns from function
m_pmapvarcolid->LoadColumns(m_ulQueryLevel, ulRTIndex, pdxlopTVF->Pdrgpdxlcd());
FuncExpr *pfuncexpr = (FuncExpr *) prte->funcexpr;
BOOL fSubqueryInArgs = false;
// check if arguments contain SIRV functions
if (NIL != pfuncexpr->args && FHasSirvFunctions((Node *) pfuncexpr->args))
{
GPOS_RAISE(gpdxl::ExmaDXL, gpdxl::ExmiQuery2DXLUnsupportedFeature, GPOS_WSZ_LIT("SIRV functions"));
}
ListCell *plc = NULL;
ForEach (plc, pfuncexpr->args)
{
Node *pnodeArg = (Node *) lfirst(plc);
fSubqueryInArgs = fSubqueryInArgs || CTranslatorUtils::FHasSubquery(pnodeArg);
CDXLNode *pdxlnFuncExprArg =
m_psctranslator->PdxlnScOpFromExpr((Expr *) pnodeArg, m_pmapvarcolid, &m_fHasDistributedTables);
GPOS_ASSERT(NULL != pdxlnFuncExprArg);
pdxlnTVF->AddChild(pdxlnFuncExprArg);
}
CMDIdGPDB *pmdidFunc = CTranslatorUtils::PmdidWithVersion(m_pmp, pfuncexpr->funcid);
const IMDFunction *pmdfunc = m_pmda->Pmdfunc(pmdidFunc);
if (fSubqueryInArgs && IMDFunction::EfsVolatile == pmdfunc->EfsStability())
{
GPOS_RAISE(gpdxl::ExmaDXL, gpdxl::ExmiQuery2DXLUnsupportedFeature, GPOS_WSZ_LIT("Volatile functions with subqueries in arguments"));
}
pmdidFunc->Release();
return pdxlnTVF;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorQueryToDXL::PdxlnFromCTE
//
// @doc:
// Translate a common table expression into CDXLNode
//
//---------------------------------------------------------------------------
CDXLNode *
CTranslatorQueryToDXL::PdxlnFromCTE
(
const RangeTblEntry *prte,
ULONG ulRTIndex,
ULONG ulCurrQueryLevel
)
{
const ULONG ulCteQueryLevel = ulCurrQueryLevel - prte->ctelevelsup;
const CCTEListEntry *pctelistentry = m_phmulCTEEntries->PtLookup(&ulCteQueryLevel);
if (NULL == pctelistentry)
{
// TODO: raghav, Sept 09 2013, remove temporary fix (revert exception to assert) to avoid crash during algebrization
GPOS_RAISE
(
gpdxl::ExmaDXL,
gpdxl::ExmiQuery2DXLError,
GPOS_WSZ_LIT("No CTE")
);
}
const CDXLNode *pdxlnCTEProducer = pctelistentry->PdxlnCTEProducer(prte->ctename);
const List *plCTEProducerTargetList = pctelistentry->PlCTEProducerTL(prte->ctename);
GPOS_ASSERT(NULL != pdxlnCTEProducer && NULL != plCTEProducerTargetList);
CDXLLogicalCTEProducer *pdxlopProducer = CDXLLogicalCTEProducer::PdxlopConvert(pdxlnCTEProducer->Pdxlop());
ULONG ulCTEId = pdxlopProducer->UlId();
DrgPul *pdrgpulCTEProducer = pdxlopProducer->PdrgpulColIds();
// construct output column array
DrgPul *pdrgpulCTEConsumer = PdrgpulGenerateColIds(m_pmp, pdrgpulCTEProducer->UlLength());
// load the new columns from the CTE
m_pmapvarcolid->LoadCTEColumns(ulCurrQueryLevel, ulRTIndex, pdrgpulCTEConsumer, const_cast<List *>(plCTEProducerTargetList));
CDXLLogicalCTEConsumer *pdxlopCTEConsumer = GPOS_NEW(m_pmp) CDXLLogicalCTEConsumer(m_pmp, ulCTEId, pdrgpulCTEConsumer);
CDXLNode *pdxlnCTE = GPOS_NEW(m_pmp) CDXLNode(m_pmp, pdxlopCTEConsumer);
return pdxlnCTE;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorQueryToDXL::PdxlnFromDerivedTable
//
// @doc:
// Translate a derived table into CDXLNode
//
//---------------------------------------------------------------------------
CDXLNode *
CTranslatorQueryToDXL::PdxlnFromDerivedTable
(
const RangeTblEntry *prte,
ULONG ulRTIndex,
ULONG ulCurrQueryLevel
)
{
Query *pqueryDerTbl = prte->subquery;
GPOS_ASSERT(NULL != pqueryDerTbl);
CMappingVarColId *pmapvarcolid = m_pmapvarcolid->PmapvarcolidCopy(m_pmp);
CTranslatorQueryToDXL trquerytodxl
(
m_pmp,
m_pmda,
m_pidgtorCol,
m_pidgtorCTE,
pmapvarcolid,
pqueryDerTbl,
m_ulQueryLevel + 1,
FDMLQuery(),
m_phmulCTEEntries
);
// translate query representing the derived table to its DXL representation
CDXLNode *pdxlnDerTbl = trquerytodxl.PdxlnFromQueryInternal();
// get the output columns of the derived table
DrgPdxln *pdrgpdxlnQueryOutputDerTbl = trquerytodxl.PdrgpdxlnQueryOutput();
DrgPdxln *pdrgpdxlnCTE = trquerytodxl.PdrgpdxlnCTE();
GPOS_ASSERT(NULL != pdxlnDerTbl && pdrgpdxlnQueryOutputDerTbl != NULL);
CUtils::AddRefAppend(m_pdrgpdxlnCTE, pdrgpdxlnCTE);
m_fHasDistributedTables = m_fHasDistributedTables || trquerytodxl.FHasDistributedTables();
// make note of new columns from derived table
m_pmapvarcolid->LoadDerivedTblColumns(ulCurrQueryLevel, ulRTIndex, pdrgpdxlnQueryOutputDerTbl, trquerytodxl.Pquery()->targetList);
return pdxlnDerTbl;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorQueryToDXL::PdxlnScFromGPDBExpr
//
// @doc:
// Translate the Expr into a CDXLScalar node
//
//---------------------------------------------------------------------------
CDXLNode *
CTranslatorQueryToDXL::PdxlnScFromGPDBExpr
(
Expr *pexpr
)
{
CDXLNode *pdxlnScalar = m_psctranslator->PdxlnScOpFromExpr(pexpr, m_pmapvarcolid, &m_fHasDistributedTables);
GPOS_ASSERT(NULL != pdxlnScalar);
return pdxlnScalar;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorQueryToDXL::PdxlnLgJoinFromGPDBJoinExpr
//
// @doc:
// Translate the JoinExpr on a GPDB query into a CDXLLogicalJoin node
//
//---------------------------------------------------------------------------
CDXLNode *
CTranslatorQueryToDXL::PdxlnLgJoinFromGPDBJoinExpr
(
JoinExpr *pjoinexpr
)
{
GPOS_ASSERT(NULL != pjoinexpr);
CDXLNode *pdxlnLeftChild = PdxlnFromGPDBFromClauseEntry(pjoinexpr->larg);
CDXLNode *pdxlnRightChild = PdxlnFromGPDBFromClauseEntry(pjoinexpr->rarg);
EdxlJoinType edxljt = CTranslatorUtils::EdxljtFromJoinType(pjoinexpr->jointype);
CDXLNode *pdxlnJoin = GPOS_NEW(m_pmp) CDXLNode(m_pmp, GPOS_NEW(m_pmp) CDXLLogicalJoin(m_pmp, edxljt));
GPOS_ASSERT(NULL != pdxlnLeftChild && NULL != pdxlnRightChild);
pdxlnJoin->AddChild(pdxlnLeftChild);
pdxlnJoin->AddChild(pdxlnRightChild);
Node* pnode = pjoinexpr->quals;
// translate the join condition
if (NULL != pnode)
{
pdxlnJoin->AddChild(PdxlnScFromGPDBExpr( (Expr*) pnode));
}
else
{
// a cross join therefore add a CDXLScalarConstValue representing the value "true"
pdxlnJoin->AddChild(PdxlnScConstValueTrue());
}
// extract the range table entry for the join expr to:
// 1. Process the alias names of the columns
// 2. Generate a project list for the join expr and maintain it in our hash map
const ULONG ulRtIndex = pjoinexpr->rtindex;
RangeTblEntry *prte = (RangeTblEntry *) gpdb::PvListNth(m_pquery->rtable, ulRtIndex - 1);
GPOS_ASSERT(NULL != prte);
Alias *palias = prte->eref;
GPOS_ASSERT(NULL != palias);
GPOS_ASSERT(NULL != palias->colnames && 0 < gpdb::UlListLength(palias->colnames));
GPOS_ASSERT(gpdb::UlListLength(prte->joinaliasvars) == gpdb::UlListLength(palias->colnames));
CDXLNode *pdxlnPrLComputedColumns = GPOS_NEW(m_pmp) CDXLNode(m_pmp, GPOS_NEW(m_pmp) CDXLScalarProjList(m_pmp));
CDXLNode *pdxlnPrL = GPOS_NEW(m_pmp) CDXLNode(m_pmp, GPOS_NEW(m_pmp) CDXLScalarProjList(m_pmp));
// construct a proj element node for each entry in the joinaliasvars
ListCell *plcNode = NULL;
ListCell *plcColName = NULL;
ForBoth (plcNode, prte->joinaliasvars,
plcColName, palias->colnames)
{
Node *pnodeJoinAlias = (Node *) lfirst(plcNode);
GPOS_ASSERT(IsA(pnodeJoinAlias, Var) || IsA(pnodeJoinAlias, CoalesceExpr));
Value *pvalue = (Value *) lfirst(plcColName);
CHAR *szColName = strVal(pvalue);
// create the DXL node holding the target list entry and add it to proj list
CDXLNode *pdxlnPrEl = PdxlnPrEFromGPDBExpr( (Expr*) pnodeJoinAlias, szColName);
pdxlnPrL->AddChild(pdxlnPrEl);
if (IsA(pnodeJoinAlias, CoalesceExpr))
{
// add coalesce expression to the computed columns
pdxlnPrEl->AddRef();
pdxlnPrLComputedColumns->AddChild(pdxlnPrEl);
}
}
m_pmapvarcolid->LoadProjectElements(m_ulQueryLevel, ulRtIndex, pdxlnPrL);
pdxlnPrL->Release();
if (0 == pdxlnPrLComputedColumns->UlArity())
{
pdxlnPrLComputedColumns->Release();
return pdxlnJoin;
}
CDXLNode *pdxlnProject = GPOS_NEW(m_pmp) CDXLNode(m_pmp, GPOS_NEW(m_pmp) CDXLLogicalProject(m_pmp));
pdxlnProject->AddChild(pdxlnPrLComputedColumns);
pdxlnProject->AddChild(pdxlnJoin);
return pdxlnProject;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorQueryToDXL::PdxlnLgProjectFromGPDBTL
//
// @doc:
// Create a DXL project list from the target list. The function allocates
// memory in the translator memory pool and caller responsible for freeing it.
//
//---------------------------------------------------------------------------
CDXLNode *
CTranslatorQueryToDXL::PdxlnLgProjectFromGPDBTL
(
List *plTargetList,
CDXLNode *pdxlnChild,
HMIUl *phmiulSortgrouprefColId,
HMIUl *phmiulOutputCols,
List *plgrpcl,
BOOL fExpandAggrefExpr
)
{
BOOL fGroupBy = (0 != gpdb::UlListLength(m_pquery->groupClause) || m_pquery->hasAggs);
CDXLNode *pdxlnPrL = GPOS_NEW(m_pmp) CDXLNode(m_pmp, GPOS_NEW(m_pmp) CDXLScalarProjList(m_pmp));
// construct a proj element node for each entry in the target list
ListCell *plcTE = NULL;
// target entries that are result of flattening join alias
// and are equivalent to a defined grouping column target entry
List *plOmittedTE = NIL;
// list for all vars used in aggref expressions
List *plVars = NULL;
ULONG ulResno = 0;
ForEach(plcTE, plTargetList)
{
TargetEntry *pte = (TargetEntry *) lfirst(plcTE);
GPOS_ASSERT(IsA(pte, TargetEntry));
GPOS_ASSERT(0 < pte->resno);
ulResno = pte->resno;
BOOL fGroupingCol = CTranslatorUtils::FGroupingColumn(pte, plgrpcl);
if (!fGroupBy || (fGroupBy && fGroupingCol))
{
CDXLNode *pdxlnPrEl = PdxlnPrEFromGPDBExpr(pte->expr, pte->resname);
ULONG ulColId = CDXLScalarProjElem::PdxlopConvert(pdxlnPrEl->Pdxlop())->UlId();
AddSortingGroupingColumn(pte, phmiulSortgrouprefColId, ulColId);
// add column to the list of output columns of the query
StoreAttnoColIdMapping(phmiulOutputCols, ulResno, ulColId);
if (!IsA(pte->expr, Var))
{
// only add computed columns to the project list
pdxlnPrL->AddChild(pdxlnPrEl);
}
else
{
pdxlnPrEl->Release();
}
}
else if (fExpandAggrefExpr && IsA(pte->expr, Aggref))
{
plVars = gpdb::PlConcat(plVars, gpdb::PlExtractNodesExpression((Node *) pte->expr, T_Var, false /*descendIntoSubqueries*/));
}
else if (!IsA(pte->expr, Aggref))
{
plOmittedTE = gpdb::PlAppendElement(plOmittedTE, pte);
}
}
// process target entries that are a result of flattening join alias
plcTE = NULL;
ForEach(plcTE, plOmittedTE)
{
TargetEntry *pte = (TargetEntry *) lfirst(plcTE);
INT iSortGroupRef = (INT) pte->ressortgroupref;
TargetEntry *pteGroupingColumn = CTranslatorUtils::PteGroupingColumn( (Node*) pte->expr, plgrpcl, plTargetList);
if (NULL != pteGroupingColumn)
{
const ULONG ulColId = CTranslatorUtils::UlColId((INT) pteGroupingColumn->ressortgroupref, phmiulSortgrouprefColId);
StoreAttnoColIdMapping(phmiulOutputCols, pte->resno, ulColId);
if (0 < iSortGroupRef && 0 < ulColId && NULL == phmiulSortgrouprefColId->PtLookup(&iSortGroupRef))
{
AddSortingGroupingColumn(pte, phmiulSortgrouprefColId, ulColId);
}
}
}
if (NIL != plOmittedTE)
{
gpdb::GPDBFree(plOmittedTE);
}
GPOS_ASSERT_IMP(!fExpandAggrefExpr, NULL == plVars);
// process all additional vars in aggref expressions
ListCell *plcVar = NULL;
ForEach (plcVar, plVars)
{
ulResno++;
Var *pvar = (Var *) lfirst(plcVar);
// TODO: antova - Dec 28, 2012; figure out column's name
CDXLNode *pdxlnPrEl = PdxlnPrEFromGPDBExpr((Expr*) pvar, "?col?");
ULONG ulColId = CDXLScalarProjElem::PdxlopConvert(pdxlnPrEl->Pdxlop())->UlId();
// add column to the list of output columns of the query
StoreAttnoColIdMapping(phmiulOutputCols, ulResno, ulColId);
pdxlnPrEl->Release();
}
if (0 < pdxlnPrL->UlArity())
{
// create a node with the CDXLLogicalProject operator and add as its children:
// the CDXLProjectList node and the node representing the input to the project node
CDXLNode *pdxlnProject = GPOS_NEW(m_pmp) CDXLNode(m_pmp, GPOS_NEW(m_pmp) CDXLLogicalProject(m_pmp));
pdxlnProject->AddChild(pdxlnPrL);
pdxlnProject->AddChild(pdxlnChild);
GPOS_ASSERT(NULL != pdxlnProject);
return pdxlnProject;
}
pdxlnPrL->Release();
return pdxlnChild;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorQueryToDXL::PdxlnProjectNullsForGroupingSets
//
// @doc:
// Construct a DXL project node projecting NULL values for the columns in the
// given bitset
//
//---------------------------------------------------------------------------
CDXLNode *
CTranslatorQueryToDXL::PdxlnProjectNullsForGroupingSets
(
List *plTargetList,
CDXLNode *pdxlnChild,
CBitSet *pbs, // group by columns
HMIUl *phmiulSortgrouprefCols, // mapping of sorting and grouping columns
HMIUl *phmiulOutputCols, // mapping of output columns
HMUlUl *phmululGrpColPos // mapping of unique grouping col positions
)
const
{
CDXLNode *pdxlnPrL = GPOS_NEW(m_pmp) CDXLNode(m_pmp, GPOS_NEW(m_pmp) CDXLScalarProjList(m_pmp));
// construct a proj element node for those non-aggregate entries in the target list which
// are not included in the grouping set
ListCell *plcTE = NULL;
ForEach (plcTE, plTargetList)
{
TargetEntry *pte = (TargetEntry *) lfirst(plcTE);
GPOS_ASSERT(IsA(pte, TargetEntry));
BOOL fGroupingCol = pbs->FBit(pte->ressortgroupref);
ULONG ulResno = pte->resno;
ULONG ulColId = 0;
if (IsA(pte->expr, GroupingFunc))
{
ulColId = m_pidgtorCol->UlNextId();
CDXLNode *pdxlnGroupingFunc = PdxlnGroupingFunc(pte->expr, pbs, phmululGrpColPos);
CMDName *pmdnameAlias = NULL;
if (NULL == pte->resname)
{
CWStringConst strUnnamedCol(GPOS_WSZ_LIT("grouping"));
pmdnameAlias = GPOS_NEW(m_pmp) CMDName(m_pmp, &strUnnamedCol);
}
else
{
CWStringDynamic *pstrAlias = CDXLUtils::PstrFromSz(m_pmp, pte->resname);
pmdnameAlias = GPOS_NEW(m_pmp) CMDName(m_pmp, pstrAlias);
GPOS_DELETE(pstrAlias);
}
CDXLNode *pdxlnPrEl = GPOS_NEW(m_pmp) CDXLNode(m_pmp, GPOS_NEW(m_pmp) CDXLScalarProjElem(m_pmp, ulColId, pmdnameAlias), pdxlnGroupingFunc);
pdxlnPrL->AddChild(pdxlnPrEl);
StoreAttnoColIdMapping(phmiulOutputCols, ulResno, ulColId);
}
else if (!fGroupingCol && !IsA(pte->expr, Aggref))
{
OID oidType = gpdb::OidExprType((Node *) pte->expr);
ulColId = m_pidgtorCol->UlNextId();
CMDIdGPDB *pmdid = CTranslatorUtils::PmdidWithVersion(m_pmp, oidType);
CDXLNode *pdxlnPrEl = CTranslatorUtils::PdxlnPrElNull(m_pmp, m_pmda, pmdid, ulColId, pte->resname);
pmdid->Release();
pdxlnPrL->AddChild(pdxlnPrEl);
StoreAttnoColIdMapping(phmiulOutputCols, ulResno, ulColId);
}
INT iSortGroupRef = INT (pte->ressortgroupref);
GPOS_ASSERT_IMP(0 == phmiulSortgrouprefCols, NULL != phmiulSortgrouprefCols->PtLookup(&iSortGroupRef) && "Grouping column with no mapping");
if (0 < iSortGroupRef && 0 < ulColId && NULL == phmiulSortgrouprefCols->PtLookup(&iSortGroupRef))
{
AddSortingGroupingColumn(pte, phmiulSortgrouprefCols, ulColId);
}
}
if (0 == pdxlnPrL->UlArity())
{
// no project necessary
pdxlnPrL->Release();
return pdxlnChild;
}
return GPOS_NEW(m_pmp) CDXLNode(m_pmp, GPOS_NEW(m_pmp) CDXLLogicalProject(m_pmp), pdxlnPrL, pdxlnChild);
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorQueryToDXL::PdxlnProjectGroupingFuncs
//
// @doc:
// Construct a DXL project node projecting values for the grouping funcs in
// the target list
//
//---------------------------------------------------------------------------
CDXLNode *
CTranslatorQueryToDXL::PdxlnProjectGroupingFuncs
(
List *plTargetList,
CDXLNode *pdxlnChild,
CBitSet *pbs,
HMIUl *phmiulOutputCols,
HMUlUl *phmululGrpColPos,
HMIUl *phmiulSortgrouprefColId
)
const
{
CDXLNode *pdxlnPrL = GPOS_NEW(m_pmp) CDXLNode(m_pmp, GPOS_NEW(m_pmp) CDXLScalarProjList(m_pmp));
// construct a proj element node for those non-aggregate entries in the target list which
// are not included in the grouping set
ListCell *plcTE = NULL;
ForEach (plcTE, plTargetList)
{
TargetEntry *pte = (TargetEntry *) lfirst(plcTE);
GPOS_ASSERT(IsA(pte, TargetEntry));
BOOL fGroupingCol = pbs->FBit(pte->ressortgroupref);
ULONG ulResno = pte->resno;
if (IsA(pte->expr, GroupingFunc))
{
ULONG ulColId = m_pidgtorCol->UlNextId();
CDXLNode *pdxlnGroupingFunc = PdxlnGroupingFunc(pte->expr, pbs, phmululGrpColPos);
CMDName *pmdnameAlias = NULL;
if (NULL == pte->resname)
{
CWStringConst strUnnamedCol(GPOS_WSZ_LIT("grouping"));
pmdnameAlias = GPOS_NEW(m_pmp) CMDName(m_pmp, &strUnnamedCol);
}
else
{
CWStringDynamic *pstrAlias = CDXLUtils::PstrFromSz(m_pmp, pte->resname);
pmdnameAlias = GPOS_NEW(m_pmp) CMDName(m_pmp, pstrAlias);
GPOS_DELETE(pstrAlias);
}
CDXLNode *pdxlnPrEl = GPOS_NEW(m_pmp) CDXLNode(m_pmp, GPOS_NEW(m_pmp) CDXLScalarProjElem(m_pmp, ulColId, pmdnameAlias), pdxlnGroupingFunc);
pdxlnPrL->AddChild(pdxlnPrEl);
StoreAttnoColIdMapping(phmiulOutputCols, ulResno, ulColId);
AddSortingGroupingColumn(pte, phmiulSortgrouprefColId, ulColId);
}
}
if (0 == pdxlnPrL->UlArity())
{
// no project necessary
pdxlnPrL->Release();
return pdxlnChild;
}
return GPOS_NEW(m_pmp) CDXLNode(m_pmp, GPOS_NEW(m_pmp) CDXLLogicalProject(m_pmp), pdxlnPrL, pdxlnChild);
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorQueryToDXL::StoreAttnoColIdMapping
//
// @doc:
// Store mapping between attno and generate colid
//
//---------------------------------------------------------------------------
void
CTranslatorQueryToDXL::StoreAttnoColIdMapping
(
HMIUl *phmiul,
INT iAttno,
ULONG ulColId
)
const
{
GPOS_ASSERT(NULL != phmiul);
#ifdef GPOS_DEBUG
BOOL fResult =
#endif // GPOS_DEBUG
phmiul->FInsert(GPOS_NEW(m_pmp) INT(iAttno), GPOS_NEW(m_pmp) ULONG(ulColId));
GPOS_ASSERT(fResult);
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorQueryToDXL::PdrgpdxlnConstructOutputCols
//
// @doc:
// Construct an array of DXL nodes representing the query output
//
//---------------------------------------------------------------------------
DrgPdxln *
CTranslatorQueryToDXL::PdrgpdxlnConstructOutputCols
(
List *plTargetList,
HMIUl *phmiulAttnoColId
)
const
{
GPOS_ASSERT(NULL != plTargetList);
GPOS_ASSERT(NULL != phmiulAttnoColId);
DrgPdxln *pdrgpdxln = GPOS_NEW(m_pmp) DrgPdxln(m_pmp);
ListCell *plc = NULL;
ForEach (plc, plTargetList)
{
TargetEntry *pte = (TargetEntry *) lfirst(plc);
GPOS_ASSERT(0 < pte->resno);
ULONG ulResNo = pte->resno;
if (pte->resjunk)
{
continue;
}
GPOS_ASSERT(NULL != pte);
CMDName *pmdname = NULL;
if (NULL == pte->resname)
{
CWStringConst strUnnamedCol(GPOS_WSZ_LIT("?column?"));
pmdname = GPOS_NEW(m_pmp) CMDName(m_pmp, &strUnnamedCol);
}
else
{
CWStringDynamic *pstrAlias = CDXLUtils::PstrFromSz(m_pmp, pte->resname);
pmdname = GPOS_NEW(m_pmp) CMDName(m_pmp, pstrAlias);
// CName constructor copies string
GPOS_DELETE(pstrAlias);
}
const ULONG ulColId = CTranslatorUtils::UlColId(ulResNo, phmiulAttnoColId);
// create a column reference
CDXLColRef *pdxlcr = GPOS_NEW(m_pmp) CDXLColRef(m_pmp, pmdname, ulColId);
CMDIdGPDB *pmdidExprType = CTranslatorUtils::PmdidWithVersion(m_pmp, gpdb::OidExprType( (Node*) pte->expr));
CDXLScalarIdent *pdxlopIdent = GPOS_NEW(m_pmp) CDXLScalarIdent(m_pmp, pdxlcr, pmdidExprType);
// create the DXL node holding the scalar ident operator
CDXLNode *pdxln = GPOS_NEW(m_pmp) CDXLNode(m_pmp, pdxlopIdent);
pdrgpdxln->Append(pdxln);
}
return pdrgpdxln;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorQueryToDXL::PdxlnPrEFromGPDBExpr
//
// @doc:
// Create a DXL project element node from the target list entry or var.
// The function allocates memory in the translator memory pool, and the caller
// is responsible for freeing it.
//---------------------------------------------------------------------------
CDXLNode *
CTranslatorQueryToDXL::PdxlnPrEFromGPDBExpr
(
Expr *pexpr,
CHAR *szAliasName,
BOOL fInsistNewColIds
)
{
GPOS_ASSERT(NULL != pexpr);
// construct a scalar operator
CDXLNode *pdxlnChild = PdxlnScFromGPDBExpr(pexpr);
// get the id and alias for the proj elem
ULONG ulPrElId;
CMDName *pmdnameAlias = NULL;
if (NULL == szAliasName)
{
CWStringConst strUnnamedCol(GPOS_WSZ_LIT("?column?"));
pmdnameAlias = GPOS_NEW(m_pmp) CMDName(m_pmp, &strUnnamedCol);
}
else
{
CWStringDynamic *pstrAlias = CDXLUtils::PstrFromSz(m_pmp, szAliasName);
pmdnameAlias = GPOS_NEW(m_pmp) CMDName(m_pmp, pstrAlias);
GPOS_DELETE(pstrAlias);
}
if (IsA(pexpr, Var) && !fInsistNewColIds)
{
// project elem is a a reference to a column - use the colref id
GPOS_ASSERT(EdxlopScalarIdent == pdxlnChild->Pdxlop()->Edxlop());
CDXLScalarIdent *pdxlopIdent = (CDXLScalarIdent *) pdxlnChild->Pdxlop();
ulPrElId = pdxlopIdent->Pdxlcr()->UlID();
}
else
{
// project elem is a defined column - get a new id
ulPrElId = m_pidgtorCol->UlNextId();
}
CDXLNode *pdxlnPrEl = GPOS_NEW(m_pmp) CDXLNode(m_pmp, GPOS_NEW(m_pmp) CDXLScalarProjElem(m_pmp, ulPrElId, pmdnameAlias));
pdxlnPrEl->AddChild(pdxlnChild);
return pdxlnPrEl;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorQueryToDXL::PdxlnScConstValueTrue
//
// @doc:
// Returns a CDXLNode representing scalar condition "true"
//---------------------------------------------------------------------------
CDXLNode *
CTranslatorQueryToDXL::PdxlnScConstValueTrue()
{
Const *pconst = (Const*) gpdb::PnodeMakeBoolConst(true /*value*/, false /*isnull*/);
CDXLNode *pdxln = PdxlnScFromGPDBExpr((Expr*) pconst);
gpdb::GPDBFree(pconst);
return pdxln;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorQueryToDXL::PdxlnGroupingFunc
//
// @doc:
// Translate grouping func
//
//---------------------------------------------------------------------------
CDXLNode *
CTranslatorQueryToDXL::PdxlnGroupingFunc
(
const Expr *pexpr,
CBitSet *pbs,
HMUlUl *phmululGrpColPos
)
const
{
GPOS_ASSERT(IsA(pexpr, GroupingFunc));
GPOS_ASSERT(NULL != phmululGrpColPos);
const GroupingFunc *pgroupingfunc = (GroupingFunc *) pexpr;
if (1 < gpdb::UlListLength(pgroupingfunc->args))
{
GPOS_RAISE(gpdxl::ExmaDXL, gpdxl::ExmiQuery2DXLUnsupportedFeature, GPOS_WSZ_LIT("Grouping function with multiple arguments"));
}
Node *pnode = (Node *) gpdb::PvListNth(pgroupingfunc->args, 0);
ULONG ulGroupingIndex = gpdb::IValue(pnode);
// generate a constant value for the result of the grouping function as follows:
// if the grouping function argument is a group-by column, result is 0
// otherwise, the result is 1
LINT lValue = 0;
ULONG *pulSortGrpRef = phmululGrpColPos->PtLookup(&ulGroupingIndex);
GPOS_ASSERT(NULL != pulSortGrpRef);
BOOL fGroupingCol = pbs->FBit(*pulSortGrpRef);
if (!fGroupingCol)
{
// not a grouping column
lValue = 1;
}
const IMDType *pmdtype = m_pmda->PtMDType<IMDTypeInt8>(m_sysid);
CMDIdGPDB *pmdidMDC = CMDIdGPDB::PmdidConvert(pmdtype->Pmdid());
CMDIdGPDB *pmdid = GPOS_NEW(m_pmp) CMDIdGPDB(*pmdidMDC);
CDXLDatum *pdxldatum = GPOS_NEW(m_pmp) CDXLDatumInt8(m_pmp, pmdid, false /* fNull */, lValue);
CDXLScalarConstValue *pdxlop = GPOS_NEW(m_pmp) CDXLScalarConstValue(m_pmp, pdxldatum);
return GPOS_NEW(m_pmp) CDXLNode(m_pmp, pdxlop);
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorQueryToDXL::ConstructCTEProducerList
//
// @doc:
// Construct a list of CTE producers from the query's CTE list
//
//---------------------------------------------------------------------------
void
CTranslatorQueryToDXL::ConstructCTEProducerList
(
List *plCTE,
ULONG ulCteQueryLevel
)
{
GPOS_ASSERT(NULL != m_pdrgpdxlnCTE && "CTE Producer list not initialized");
if (NULL == plCTE)
{
return;
}
ListCell *plc = NULL;
ForEach (plc, plCTE)
{
CommonTableExpr *pcte = (CommonTableExpr *) lfirst(plc);
GPOS_ASSERT(IsA(pcte->ctequery, Query));
Query *pqueryCte = CQueryMutators::PqueryNormalize(m_pmp, m_pmda, (Query *) pcte->ctequery, ulCteQueryLevel + 1);
// the query representing the cte can only access variables defined in the current level as well as
// those defined at prior query levels
CMappingVarColId *pmapvarcolid = m_pmapvarcolid->PmapvarcolidCopy(ulCteQueryLevel);
CTranslatorQueryToDXL trquerytodxl
(
m_pmp,
m_pmda,
m_pidgtorCol,
m_pidgtorCTE,
pmapvarcolid,
pqueryCte,
ulCteQueryLevel + 1,
FDMLQuery(),
m_phmulCTEEntries
);
// translate query representing the cte table to its DXL representation
CDXLNode *pdxlnCteChild = trquerytodxl.PdxlnFromQueryInternal();
// get the output columns of the cte table
DrgPdxln *pdrgpdxlnQueryOutputCte = trquerytodxl.PdrgpdxlnQueryOutput();
DrgPdxln *pdrgpdxlnCTE = trquerytodxl.PdrgpdxlnCTE();
m_fHasDistributedTables = m_fHasDistributedTables || trquerytodxl.FHasDistributedTables();
GPOS_ASSERT(NULL != pdxlnCteChild && NULL != pdrgpdxlnQueryOutputCte && NULL != pdrgpdxlnCTE);
// append any nested CTE
CUtils::AddRefAppend(m_pdrgpdxlnCTE, pdrgpdxlnCTE);
DrgPul *pdrgpulColIds = GPOS_NEW(m_pmp) DrgPul(m_pmp);
const ULONG ulOutputCols = pdrgpdxlnQueryOutputCte->UlLength();
for (ULONG ul = 0; ul < ulOutputCols; ul++)
{
CDXLNode *pdxlnOutputCol = (*pdrgpdxlnQueryOutputCte)[ul];
CDXLScalarIdent *pdxlnIdent = CDXLScalarIdent::PdxlopConvert(pdxlnOutputCol->Pdxlop());
pdrgpulColIds->Append(GPOS_NEW(m_pmp) ULONG(pdxlnIdent->Pdxlcr()->UlID()));
}
CDXLLogicalCTEProducer *pdxlop = GPOS_NEW(m_pmp) CDXLLogicalCTEProducer(m_pmp, m_pidgtorCTE->UlNextId(), pdrgpulColIds);
CDXLNode *pdxlnCTEProducer = GPOS_NEW(m_pmp) CDXLNode(m_pmp, pdxlop, pdxlnCteChild);
m_pdrgpdxlnCTE->Append(pdxlnCTEProducer);
#ifdef GPOS_DEBUG
BOOL fResult =
#endif
m_phmulfCTEProducers->FInsert(GPOS_NEW(m_pmp) ULONG(pdxlop->UlId()), GPOS_NEW(m_pmp) BOOL(true));
GPOS_ASSERT(fResult);
// update CTE producer mappings
CCTEListEntry *pctelistentry = m_phmulCTEEntries->PtLookup(&ulCteQueryLevel);
if (NULL == pctelistentry)
{
pctelistentry = GPOS_NEW(m_pmp) CCTEListEntry (m_pmp, ulCteQueryLevel, pcte, pdxlnCTEProducer);
#ifdef GPOS_DEBUG
BOOL fRes =
#endif
m_phmulCTEEntries->FInsert(GPOS_NEW(m_pmp) ULONG(ulCteQueryLevel), pctelistentry);
GPOS_ASSERT(fRes);
}
else
{
pctelistentry->AddCTEProducer(m_pmp, pcte, pdxlnCTEProducer);
}
}
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorQueryToDXL::ConstructCTEAnchors
//
// @doc:
// Construct a stack of CTE anchors for each CTE producer in the given array
//
//---------------------------------------------------------------------------
void
CTranslatorQueryToDXL::ConstructCTEAnchors
(
DrgPdxln *pdrgpdxln,
CDXLNode **ppdxlnCTEAnchorTop,
CDXLNode **ppdxlnCTEAnchorBottom
)
{
GPOS_ASSERT(NULL == *ppdxlnCTEAnchorTop);
GPOS_ASSERT(NULL == *ppdxlnCTEAnchorBottom);
if (NULL == pdrgpdxln || 0 == pdrgpdxln->UlLength())
{
return;
}
const ULONG ulCTEs = pdrgpdxln->UlLength();
for (ULONG ul = ulCTEs; ul > 0; ul--)
{
// construct a new CTE anchor on top of the previous one
CDXLNode *pdxlnCTEProducer = (*pdrgpdxln)[ul-1];
CDXLLogicalCTEProducer *pdxlopCTEProducer = CDXLLogicalCTEProducer::PdxlopConvert(pdxlnCTEProducer->Pdxlop());
ULONG ulCTEProducerId = pdxlopCTEProducer->UlId();
if (NULL == m_phmulfCTEProducers->PtLookup(&ulCTEProducerId))
{
// cte not defined at this level: CTE anchor was already added
continue;
}
CDXLNode *pdxlnCTEAnchorNew = GPOS_NEW(m_pmp) CDXLNode(m_pmp, GPOS_NEW(m_pmp) CDXLLogicalCTEAnchor(m_pmp, ulCTEProducerId));
if (NULL == *ppdxlnCTEAnchorBottom)
{
*ppdxlnCTEAnchorBottom = pdxlnCTEAnchorNew;
}
if (NULL != *ppdxlnCTEAnchorTop)
{
pdxlnCTEAnchorNew->AddChild(*ppdxlnCTEAnchorTop);
}
*ppdxlnCTEAnchorTop = pdxlnCTEAnchorNew;
}
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorQueryToDXL::PdrgpulGenerateColIds
//
// @doc:
// Generate an array of new column ids of the given size
//
//---------------------------------------------------------------------------
DrgPul *
CTranslatorQueryToDXL::PdrgpulGenerateColIds
(
IMemoryPool *pmp,
ULONG ulSize
)
const
{
DrgPul *pdrgpul = GPOS_NEW(pmp) DrgPul(pmp);
for (ULONG ul = 0; ul < ulSize; ul++)
{
pdrgpul->Append(GPOS_NEW(pmp) ULONG(m_pidgtorCol->UlNextId()));
}
return pdrgpul;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorQueryToDXL::PdrgpulExtractColIds
//
// @doc:
// Extract column ids from the given mapping
//
//---------------------------------------------------------------------------
DrgPul *
CTranslatorQueryToDXL::PdrgpulExtractColIds
(
IMemoryPool *pmp,
HMIUl *phmiul
)
const
{
HMUlUl *phmulul = GPOS_NEW(pmp) HMUlUl(pmp);
DrgPul *pdrgpul = GPOS_NEW(pmp) DrgPul(pmp);
HMIUlIter mi(phmiul);
while (mi.FAdvance())
{
ULONG ulColId = *(mi.Pt());
// do not insert colid if already inserted
if (NULL == phmulul->PtLookup(&ulColId))
{
pdrgpul->Append(GPOS_NEW(m_pmp) ULONG(ulColId));
phmulul->FInsert(GPOS_NEW(m_pmp) ULONG(ulColId), GPOS_NEW(m_pmp) ULONG(ulColId));
}
}
phmulul->Release();
return pdrgpul;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorQueryToDXL::PhmiulRemapColIds
//
// @doc:
// Construct a new hashmap which replaces the values in the From array
// with the corresponding value in the To array
//
//---------------------------------------------------------------------------
HMIUl *
CTranslatorQueryToDXL::PhmiulRemapColIds
(
IMemoryPool *pmp,
HMIUl *phmiul,
DrgPul *pdrgpulFrom,
DrgPul *pdrgpulTo
)
const
{
GPOS_ASSERT(NULL != phmiul);
GPOS_ASSERT(NULL != pdrgpulFrom && NULL != pdrgpulTo);
GPOS_ASSERT(pdrgpulFrom->UlLength() == pdrgpulTo->UlLength());
// compute a map of the positions in the from array
HMUlUl *phmulul = GPOS_NEW(pmp) HMUlUl(pmp);
const ULONG ulSize = pdrgpulFrom->UlLength();
for (ULONG ul = 0; ul < ulSize; ul++)
{
#ifdef GPOS_DEBUG
BOOL fResult =
#endif // GPOS_DEBUG
phmulul->FInsert(GPOS_NEW(pmp) ULONG(*((*pdrgpulFrom)[ul])), GPOS_NEW(pmp) ULONG(*((*pdrgpulTo)[ul])));
GPOS_ASSERT(fResult);
}
HMIUl *phmiulResult = GPOS_NEW(pmp) HMIUl(pmp);
HMIUlIter mi(phmiul);
while (mi.FAdvance())
{
INT *piKey = GPOS_NEW(pmp) INT(*(mi.Pk()));
const ULONG *pulValue = mi.Pt();
GPOS_ASSERT(NULL != pulValue);
ULONG *pulValueRemapped = GPOS_NEW(pmp) ULONG(*(phmulul->PtLookup(pulValue)));
phmiulResult->FInsert(piKey, pulValueRemapped);
}
phmulul->Release();
return phmiulResult;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorQueryToDXL::PhmiulRemapColIds
//
// @doc:
// True iff this query or one of its ancestors is a DML query
//
//---------------------------------------------------------------------------
BOOL
CTranslatorQueryToDXL::FDMLQuery()
{
return (m_fTopDMLQuery || m_pquery->resultRelation != 0);
}
// EOF