blob: b1bfbb0b8fce86e6adfeb7b19d90be751e32526b [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:
// CTranslatorScalarToDXL.cpp
//
// @doc:
// Implementing the methods needed to translate a GPDB Scalar Operation (in a Query / PlStmt object)
// into a DXL trees
//
// @test:
//
//---------------------------------------------------------------------------
#include "postgres.h"
#include "gpopt/translate/CTranslatorScalarToDXL.h"
#include "gpopt/translate/CTranslatorQueryToDXL.h"
#include "gpopt/translate/CTranslatorUtils.h"
#include "gpopt/translate/CCTEListEntry.h"
#include "nodes/plannodes.h"
#include "nodes/parsenodes.h"
#include "nodes/primnodes.h"
#include "utils/datum.h"
#include "utils/date.h"
#include "utils/numeric.h"
#include "gpos/base.h"
#include "gpos/common/CAutoP.h"
#include "gpos/string/CWStringDynamic.h"
#include "naucrates/dxl/CDXLUtils.h"
#include "naucrates/dxl/xml/dxltokens.h"
#include "gpopt/base/CUtils.h"
#include "gpopt/mdcache/CMDAccessor.h"
#include "naucrates/dxl/operators/CDXLDatumBool.h"
#include "naucrates/dxl/operators/CDXLDatumInt2.h"
#include "naucrates/dxl/operators/CDXLDatumInt4.h"
#include "naucrates/dxl/operators/CDXLDatumInt8.h"
#include "naucrates/dxl/operators/CDXLDatumOid.h"
#include "naucrates/md/IMDAggregate.h"
#include "naucrates/md/IMDScalarOp.h"
#include "naucrates/md/IMDType.h"
#include "naucrates/md/CMDTypeGenericGPDB.h"
#include "gpopt/gpdbwrappers.h"
using namespace gpdxl;
using namespace gpopt;
//---------------------------------------------------------------------------
// @function:
// CTranslatorScalarToDXL::CTranslatorScalarToDXL
//
// @doc:
// Ctor
//---------------------------------------------------------------------------
CTranslatorScalarToDXL::CTranslatorScalarToDXL
(
IMemoryPool *pmp,
CMDAccessor *pmda,
CIdGenerator *pulidgtorCol,
CIdGenerator *pulidgtorCTE,
ULONG ulQueryLevel,
BOOL fQuery,
PlannedStmt *pplstmt,
CMappingParamIdScalarId *pmapps,
HMUlCTEListEntry *phmulCTEEntries,
DrgPdxln *pdrgpdxlnCTE
)
:
m_pmp(pmp),
m_pmda(pmda),
m_pidgtorCol(pulidgtorCol),
m_pidgtorCTE(pulidgtorCTE),
m_ulQueryLevel(ulQueryLevel),
m_fHasDistributedTables(false),
m_fQuery(fQuery),
m_pplstmt(pplstmt),
m_pparammapping(pmapps),
m_eplsphoptype(EpspotNone),
m_phmulCTEEntries(phmulCTEEntries),
m_pdrgpdxlnCTE(pdrgpdxlnCTE)
{
GPOS_ASSERT_IMP(!fQuery, pplstmt);
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorScalarToDXL::EdxlbooltypeFromGPDBBoolType
//
// @doc:
// Return the EdxlBoolExprType for a given GPDB BoolExprType
//---------------------------------------------------------------------------
EdxlBoolExprType
CTranslatorScalarToDXL::EdxlbooltypeFromGPDBBoolType
(
BoolExprType boolexprtype
)
const
{
ULONG rgrgulMapping[][2] =
{
{NOT_EXPR, Edxlnot},
{AND_EXPR, Edxland},
{OR_EXPR, Edxlor},
};
EdxlBoolExprType edxlbt = EdxlBoolExprTypeSentinel;
const ULONG ulArity = GPOS_ARRAY_SIZE(rgrgulMapping);
for (ULONG ul = 0; ul < ulArity; ul++)
{
ULONG *pulElem = rgrgulMapping[ul];
if ((ULONG) boolexprtype == pulElem[0])
{
edxlbt = (EdxlBoolExprType) pulElem[1];
break;
}
}
GPOS_ASSERT(EdxlBoolExprTypeSentinel != edxlbt && "Invalid bool expr type");
return edxlbt;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorScalarToDXL::PdxlnScIdFromVar
//
// @doc:
// Create a DXL node for a scalar ident expression from a GPDB Var expression.
// This function can be used for constructing a scalar ident operator appearing in a
// base node (e.g. a scan node) or in an intermediate plan nodes.
// The function allocates memory in the translator memory pool, and the caller
// is responsible for freeing it
//---------------------------------------------------------------------------
CDXLNode *
CTranslatorScalarToDXL::PdxlnScIdFromVar
(
const Expr *pexpr,
const CMappingVarColId* pmapvarcolid
)
{
GPOS_ASSERT(IsA(pexpr, Var));
const Var * pvar = (Var *) pexpr;
if (pvar->varattno == 0)
{
GPOS_RAISE(gpdxl::ExmaDXL, gpdxl::ExmiQuery2DXLUnsupportedFeature, GPOS_WSZ_LIT("Whole-row variable"));
}
// column name
const CWStringBase *pstr = pmapvarcolid->PstrColName(m_ulQueryLevel, pvar, m_eplsphoptype);
// column id
ULONG ulId;
if(pvar->varattno != 0 || EpspotIndexScan == m_eplsphoptype || EpspotIndexOnlyScan == m_eplsphoptype)
{
ulId = pmapvarcolid->UlColId(m_ulQueryLevel, pvar, m_eplsphoptype);
}
else
{
ulId = m_pidgtorCol->UlNextId();
}
CMDName *pmdname = GPOS_NEW(m_pmp) CMDName(m_pmp, pstr);
// create a column reference for the given var
CDXLColRef *pdxlcr = GPOS_NEW(m_pmp) CDXLColRef(m_pmp, pmdname, ulId);
// create the scalar ident operator
CDXLScalarIdent *pdxlopIdent = GPOS_NEW(m_pmp) CDXLScalarIdent
(
m_pmp,
pdxlcr,
CTranslatorUtils::PmdidWithVersion(m_pmp, pvar->vartype)
);
// create the DXL node holding the scalar ident operator
CDXLNode *pdxln = GPOS_NEW(m_pmp) CDXLNode(m_pmp, pdxlopIdent);
return pdxln;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorScalarToDXL::PdxlnScIdFromParam
//
// @doc:
// Create a DXL node for a scalar ident expression from a GPDB Param expression.
// If no mapping can be found, return NULL
//---------------------------------------------------------------------------
CDXLNode *
CTranslatorScalarToDXL::PdxlnScIdFromParam
(
const Param * pparam
)
const
{
GPOS_ASSERT(IsA(pparam, Param));
if (NULL == m_pparammapping)
{
return NULL;
}
CDXLScalarIdent *pdxlopIdent = m_pparammapping->Pscid(pparam->paramid);
if (NULL == pdxlopIdent)
{
return NULL;
}
return GPOS_NEW(m_pmp) CDXLNode(m_pmp, pdxlopIdent);
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorScalarToDXL::PdxlnScOpFromExpr
//
// @doc:
// Create a DXL node for a scalar expression from a GPDB expression node.
// This function can be used for constructing a scalar operator appearing in a
// base node (e.g. a scan node), or in an intermediate plan nodes.
// The function allocates memory in the translator memory pool, and the caller
// is responsible for freeing it
//---------------------------------------------------------------------------
CDXLNode *
CTranslatorScalarToDXL::PdxlnScOpFromExpr
(
const Expr *pexpr,
const CMappingVarColId* pmapvarcolid,
BOOL *pfHasDistributedTables // output
)
{
STranslatorElem rgTranslators[] =
{
{T_Var, &CTranslatorScalarToDXL::PdxlnScIdFromVar},
{T_OpExpr, &CTranslatorScalarToDXL::PdxlnScOpExprFromExpr},
{T_ScalarArrayOpExpr, &CTranslatorScalarToDXL::PdxlnArrayOpExpr},
{T_DistinctExpr, &CTranslatorScalarToDXL::PdxlnScDistCmpFromDistExpr},
{T_Const, &CTranslatorScalarToDXL::PdxlnScConstFromExpr},
{T_BoolExpr, &CTranslatorScalarToDXL::PdxlnScBoolExprFromExpr},
{T_BooleanTest, &CTranslatorScalarToDXL::PdxlnScBooleanTestFromExpr},
{T_CaseExpr, &CTranslatorScalarToDXL::PdxlnScCaseStmtFromExpr},
{T_CaseTestExpr, &CTranslatorScalarToDXL::PdxlnScCaseTestFromExpr},
{T_CoalesceExpr, &CTranslatorScalarToDXL::PdxlnScCoalesceFromExpr},
{T_MinMaxExpr, &CTranslatorScalarToDXL::PdxlnScMinMaxFromExpr},
{T_FuncExpr, &CTranslatorScalarToDXL::PdxlnScFuncExprFromFuncExpr},
{T_Aggref, &CTranslatorScalarToDXL::PdxlnScAggrefFromAggref},
{T_WindowRef, &CTranslatorScalarToDXL::PdxlnScWindowref},
{T_NullTest, &CTranslatorScalarToDXL::PdxlnScNullTestFromNullTest},
{T_NullIfExpr, &CTranslatorScalarToDXL::PdxlnScNullIfFromExpr},
{T_RelabelType, &CTranslatorScalarToDXL::PdxlnScCastFromRelabelType},
{T_CoerceToDomain, &CTranslatorScalarToDXL::PdxlnScCoerceFromCoerce},
{T_SubLink, &CTranslatorScalarToDXL::PdxlnFromSublink},
{T_ArrayExpr, &CTranslatorScalarToDXL::PdxlnArray},
{T_ArrayRef, &CTranslatorScalarToDXL::PdxlnArrayRef},
};
const ULONG ulTranslators = GPOS_ARRAY_SIZE(rgTranslators);
NodeTag ent = pexpr->type;
// if an output variable is provided, we need to reset the member variable
if (NULL != pfHasDistributedTables)
{
m_fHasDistributedTables = false;
}
// save old value for distributed tables flag
BOOL fHasDistributedTablesOld = m_fHasDistributedTables;
// find translator for the expression type
PfPdxln pf = NULL;
for (ULONG ul = 0; ul < ulTranslators; ul++)
{
STranslatorElem elem = rgTranslators[ul];
if (ent == elem.ent)
{
pf = elem.pf;
break;
}
}
if (NULL == pf)
{
CHAR *sz = (CHAR*) gpdb::SzNodeToString(const_cast<Expr*>(pexpr));
CWStringDynamic *pstr = CDXLUtils::PstrFromSz(m_pmp, sz);
GPOS_RAISE(gpdxl::ExmaDXL, gpdxl::ExmiPlStmt2DXLConversion, pstr->Wsz());
}
CDXLNode *pdxlnReturn = (this->*pf)(pexpr, pmapvarcolid);
// combine old and current values for distributed tables flag
m_fHasDistributedTables = m_fHasDistributedTables || fHasDistributedTablesOld;
if (NULL != pfHasDistributedTables && m_fHasDistributedTables)
{
*pfHasDistributedTables = true;
}
return pdxlnReturn;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorScalarToDXL::PdxlnScDistCmpFromDistExpr
//
// @doc:
// Create a DXL node for a scalar distinct comparison expression from a GPDB
// DistinctExpr.
// This function can be used for constructing a scalar comparison operator appearing in a
// base node (e.g. a scan node), or in an intermediate plan nodes.
// The function allocates memory in the translator memory pool, and the caller
// is responsible for freeing it
//---------------------------------------------------------------------------
CDXLNode *
CTranslatorScalarToDXL::PdxlnScDistCmpFromDistExpr
(
const Expr *pexpr,
const CMappingVarColId* pmapvarcolid
)
{
GPOS_ASSERT(IsA(pexpr, DistinctExpr));
const DistinctExpr *pdistexpr = (DistinctExpr *) pexpr;
// process arguments of op expr
GPOS_ASSERT(2 == gpdb::UlListLength(pdistexpr->args));
CDXLNode *pdxlnLeft = PdxlnScOpFromExpr
(
(Expr *) gpdb::PvListNth(pdistexpr->args, 0),
pmapvarcolid
);
CDXLNode *pdxlnRight = PdxlnScOpFromExpr
(
(Expr *) gpdb::PvListNth(pdistexpr->args, 1),
pmapvarcolid
);
GPOS_ASSERT(NULL != pdxlnLeft);
GPOS_ASSERT(NULL != pdxlnRight);
CDXLScalarDistinctComp *pdxlop = GPOS_NEW(m_pmp) CDXLScalarDistinctComp(m_pmp,
CTranslatorUtils::PmdidWithVersion(m_pmp, pdistexpr->opno));
// create the DXL node holding the scalar distinct comparison operator
CDXLNode *pdxln = GPOS_NEW(m_pmp) CDXLNode(m_pmp, pdxlop);
// add children in the right order
pdxln->AddChild(pdxlnLeft);
pdxln->AddChild(pdxlnRight);
return pdxln;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorScalarToDXL::PdxlnScCmpFromOpExpr
//
// @doc:
// Create a DXL node for a scalar comparison expression from a GPDB OpExpr.
// This function can be used for constructing a scalar comparison operator appearing in a
// base node (e.g. a scan node), or in an intermediate plan nodes.
// The function allocates memory in the translator memory pool, and the caller
// is responsible for freeing it
//---------------------------------------------------------------------------
CDXLNode *
CTranslatorScalarToDXL::PdxlnScCmpFromOpExpr
(
const Expr *pexpr,
const CMappingVarColId* pmapvarcolid
)
{
GPOS_ASSERT(IsA(pexpr, OpExpr));
const OpExpr *popexpr = (OpExpr *) pexpr;
// process arguments of op expr
GPOS_ASSERT(2 == gpdb::UlListLength(popexpr->args));
Expr *pexprLeft = (Expr *) gpdb::PvListNth(popexpr->args, 0);
Expr *pexprRight = (Expr *) gpdb::PvListNth(popexpr->args, 1);
CDXLNode *pdxlnLeft = PdxlnScOpFromExpr(pexprLeft, pmapvarcolid);
CDXLNode *pdxlnRight = PdxlnScOpFromExpr(pexprRight, pmapvarcolid);
GPOS_ASSERT(NULL != pdxlnLeft);
GPOS_ASSERT(NULL != pdxlnRight);
CMDIdGPDB *pmdid = CTranslatorUtils::PmdidWithVersion(m_pmp, popexpr->opno);
// get operator name
const CWStringConst *pstr = PstrOpName(pmdid);
CDXLScalarComp *pdxlop = GPOS_NEW(m_pmp) CDXLScalarComp(m_pmp, pmdid, GPOS_NEW(m_pmp) CWStringConst(pstr->Wsz()));
// create the DXL node holding the scalar comparison operator
CDXLNode *pdxln = GPOS_NEW(m_pmp) CDXLNode(m_pmp, pdxlop);
// add children in the right order
pdxln->AddChild(pdxlnLeft);
pdxln->AddChild(pdxlnRight);
return pdxln;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorScalarToDXL::PdxlnScOpExprFromExpr
//
// @doc:
// Create a DXL node for a scalar opexpr from a GPDB OpExpr.
// This function can be used for constructing a scalar opexpr operator appearing in a
// base node (e.g. a scan node), or in an intermediate plan nodes.
// The function allocates memory in the translator memory pool, and the caller
// is responsible for freeing it
//---------------------------------------------------------------------------
CDXLNode *
CTranslatorScalarToDXL::PdxlnScOpExprFromExpr
(
const Expr *pexpr,
const CMappingVarColId* pmapvarcolid
)
{
GPOS_ASSERT(IsA(pexpr, OpExpr));
const OpExpr *popexpr = (OpExpr *) pexpr;
// check if this is a scalar comparison
CMDIdGPDB *pmdidReturnType = CTranslatorUtils::PmdidWithVersion(m_pmp, ((OpExpr *) pexpr)->opresulttype);
const IMDType *pmdtype= m_pmda->Pmdtype(pmdidReturnType);
const ULONG ulArgs = gpdb::UlListLength(popexpr->args);
if (IMDType::EtiBool == pmdtype->Eti() && 2 == ulArgs)
{
pmdidReturnType->Release();
return PdxlnScCmpFromOpExpr(pexpr, pmapvarcolid);
}
// get operator name and id
IMDId *pmdid = CTranslatorUtils::PmdidWithVersion(m_pmp, popexpr->opno);
const CWStringConst *pstr = PstrOpName(pmdid);
CDXLScalarOpExpr *pdxlop = GPOS_NEW(m_pmp) CDXLScalarOpExpr(m_pmp, pmdid, pmdidReturnType, GPOS_NEW(m_pmp) CWStringConst(pstr->Wsz()));
// create the DXL node holding the scalar opexpr
CDXLNode *pdxln = GPOS_NEW(m_pmp) CDXLNode(m_pmp, pdxlop);
// process arguments
TranslateScalarChildren(pdxln, popexpr->args, pmapvarcolid);
return pdxln;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorScalarToDXL::PdxlnScNullIfFromExpr
//
// @doc:
// Create a DXL node for a scalar nullif from a GPDB Expr
//---------------------------------------------------------------------------
CDXLNode *
CTranslatorScalarToDXL::PdxlnScNullIfFromExpr
(
const Expr *pexpr,
const CMappingVarColId* pmapvarcolid
)
{
GPOS_ASSERT(IsA(pexpr, NullIfExpr));
const NullIfExpr *pnullifexpr = (NullIfExpr *) pexpr;
GPOS_ASSERT(2 == gpdb::UlListLength(pnullifexpr->args));
CDXLScalarNullIf *pdxlop = GPOS_NEW(m_pmp) CDXLScalarNullIf
(
m_pmp,
CTranslatorUtils::PmdidWithVersion(m_pmp, pnullifexpr->opno),
CTranslatorUtils::PmdidWithVersion(m_pmp, gpdb::OidExprType((Node *)pnullifexpr))
);
CDXLNode *pdxln = GPOS_NEW(m_pmp) CDXLNode(m_pmp, pdxlop);
// process arguments
TranslateScalarChildren(pdxln, pnullifexpr->args, pmapvarcolid);
return pdxln;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorScalarToDXL::PdxlnArrayOpExpr
//
// @doc:
// Create a DXL node for a scalar array expression from a GPDB OpExpr
//---------------------------------------------------------------------------
CDXLNode *
CTranslatorScalarToDXL::PdxlnArrayOpExpr
(
const Expr *pexpr,
const CMappingVarColId* pmapvarcolid
)
{
return PdxlnScArrayCompFromExpr(pexpr, pmapvarcolid);
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorScalarToDXL::PdxlnScArrayCompFromExpr
//
// @doc:
// Create a DXL node for a scalar array comparison from a GPDB OpExpr
//---------------------------------------------------------------------------
CDXLNode *
CTranslatorScalarToDXL::PdxlnScArrayCompFromExpr
(
const Expr *pexpr,
const CMappingVarColId* pmapvarcolid
)
{
GPOS_ASSERT(IsA(pexpr, ScalarArrayOpExpr));
const ScalarArrayOpExpr *pscarrayopexpr = (ScalarArrayOpExpr *) pexpr;
// process arguments of op expr
GPOS_ASSERT(2 == gpdb::UlListLength(pscarrayopexpr->args));
Expr *pexprLeft = (Expr*) gpdb::PvListNth(pscarrayopexpr->args, 0);
CDXLNode *pdxlnLeft = PdxlnScOpFromExpr(pexprLeft, pmapvarcolid);
Expr *pexprRight = (Expr*) gpdb::PvListNth(pscarrayopexpr->args, 1);
CDXLNode *pdxlnRight = PdxlnScOpFromExpr(pexprRight, pmapvarcolid);
GPOS_ASSERT(NULL != pdxlnLeft);
GPOS_ASSERT(NULL != pdxlnRight);
// get operator name
CMDIdGPDB *pmdidOp = CTranslatorUtils::PmdidWithVersion(m_pmp, pscarrayopexpr->opno);
const IMDScalarOp *pmdscop = m_pmda->Pmdscop(pmdidOp);
pmdidOp->Release();
const CWStringConst *pstr = pmdscop->Mdname().Pstr();
GPOS_ASSERT(NULL != pstr);
EdxlArrayCompType edxlarraycomptype = Edxlarraycomptypeany;
if(!pscarrayopexpr->useOr)
{
edxlarraycomptype = Edxlarraycomptypeall;
}
CDXLScalarArrayComp *pdxlop = GPOS_NEW(m_pmp) CDXLScalarArrayComp
(
m_pmp,
CTranslatorUtils::PmdidWithVersion(m_pmp, pscarrayopexpr->opno),
GPOS_NEW(m_pmp) CWStringConst(pstr->Wsz()),
edxlarraycomptype
);
// create the DXL node holding the scalar opexpr
CDXLNode *pdxln = GPOS_NEW(m_pmp) CDXLNode(m_pmp, pdxlop);
// add children in the right order
pdxln->AddChild(pdxlnLeft);
pdxln->AddChild(pdxlnRight);
return pdxln;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorScalarToDXL::PdxlnScConstFromExpr
//
// @doc:
// Create a DXL node for a scalar const value from a GPDB Const
//---------------------------------------------------------------------------
CDXLNode *
CTranslatorScalarToDXL::PdxlnScConstFromExpr
(
const Expr *pexpr,
const CMappingVarColId * // pmapvarcolid
)
{
GPOS_ASSERT(IsA(pexpr, Const));
const Const *pconst = (Const *) pexpr;
CDXLNode *pdxln = GPOS_NEW(m_pmp) CDXLNode
(
m_pmp,
GPOS_NEW(m_pmp) CDXLScalarConstValue
(
m_pmp,
Pdxldatum(pconst)
)
);
return pdxln;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorScalarToDXL::Pdxldatum
//
// @doc:
// Create a DXL datum from a GPDB Const
//---------------------------------------------------------------------------
CDXLDatum *
CTranslatorScalarToDXL::Pdxldatum
(
IMemoryPool *pmp,
CMDAccessor *mda,
const Const *pconst
)
{
CMDIdGPDB *pmdid = CTranslatorUtils::PmdidWithVersion(pmp, pconst->consttype);
const IMDType *pmdtype= mda->Pmdtype(pmdid);
pmdid->Release();
// translate gpdb datum into a DXL datum
CDXLDatum *pdxldatum = CTranslatorScalarToDXL::Pdxldatum(pmp, pmdtype, pconst->constisnull, pconst->constlen, pconst->constvalue);
return pdxldatum;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorScalarToDXL::Pdxldatum
//
// @doc:
// Create a DXL datum from a GPDB Const
//---------------------------------------------------------------------------
CDXLDatum *
CTranslatorScalarToDXL::Pdxldatum
(
const Const *pconst
)
const
{
return Pdxldatum(m_pmp, m_pmda, pconst);
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorScalarToDXL::PdxlnScBoolExprFromExpr
//
// @doc:
// Create a DXL node for a scalar boolean expression from a GPDB OpExpr.
// This function can be used for constructing a scalar boolexpr operator appearing in a
// base node (e.g. a scan node), or in an intermediate plan nodes.
// The function allocates memory in the translator memory pool, and the caller
// is responsible for freeing it
//---------------------------------------------------------------------------
CDXLNode *
CTranslatorScalarToDXL::PdxlnScBoolExprFromExpr
(
const Expr *pexpr,
const CMappingVarColId* pmapvarcolid
)
{
GPOS_ASSERT(IsA(pexpr, BoolExpr));
const BoolExpr *pboolexpr = (BoolExpr *) pexpr;
GPOS_ASSERT(0 < gpdb::UlListLength(pboolexpr->args));
EdxlBoolExprType boolexptype = EdxlbooltypeFromGPDBBoolType(pboolexpr->boolop);
GPOS_ASSERT(EdxlBoolExprTypeSentinel != boolexptype);
// create the DXL node holding the scalar boolean operator
CDXLNode *pdxln = GPOS_NEW(m_pmp) CDXLNode(m_pmp, GPOS_NEW(m_pmp) CDXLScalarBoolExpr(m_pmp, boolexptype));
ULONG ulCount = gpdb::UlListLength(pboolexpr->args);
if ((NOT_EXPR != pboolexpr->boolop) && (2 > ulCount))
{
GPOS_RAISE
(
gpdxl::ExmaDXL,
gpdxl::ExmiPlStmt2DXLConversion,
GPOS_WSZ_LIT("Boolean Expression (OR / AND): Incorrect Number of Children ")
);
}
else if ((NOT_EXPR == pboolexpr->boolop) && (1 != ulCount))
{
GPOS_RAISE
(
gpdxl::ExmaDXL,
gpdxl::ExmiPlStmt2DXLConversion,
GPOS_WSZ_LIT("Boolean Expression (NOT): Incorrect Number of Children ")
);
}
TranslateScalarChildren(pdxln, pboolexpr->args, pmapvarcolid);
return pdxln;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorScalarToDXL::PdxlnScBooleanTestFromExpr
//
// @doc:
// Create a DXL node for a scalar boolean test from a GPDB OpExpr.
// This function can be used for constructing a scalar boolexpr operator appearing in a
// base node (e.g. a scan node), or in an intermediate plan nodes.
// The function allocates memory in the translator memory pool, and the caller
// is responsible for freeing it
//---------------------------------------------------------------------------
CDXLNode *
CTranslatorScalarToDXL::PdxlnScBooleanTestFromExpr
(
const Expr *pexpr,
const CMappingVarColId* pmapvarcolid
)
{
GPOS_ASSERT(IsA(pexpr, BooleanTest));
const BooleanTest *pbooleantest = (BooleanTest *) pexpr;
GPOS_ASSERT(NULL != pbooleantest->arg);
ULONG rgrgulMapping[][2] =
{
{IS_TRUE, EdxlbooleantestIsTrue},
{IS_NOT_TRUE, EdxlbooleantestIsNotTrue},
{IS_FALSE, EdxlbooleantestIsFalse},
{IS_NOT_FALSE, EdxlbooleantestIsNotFalse},
{IS_UNKNOWN, EdxlbooleantestIsUnknown},
{IS_NOT_UNKNOWN, EdxlbooleantestIsNotUnknown},
};
EdxlBooleanTestType edxlbt = EdxlbooleantestSentinel;
const ULONG ulArity = GPOS_ARRAY_SIZE(rgrgulMapping);
for (ULONG ul = 0; ul < ulArity; ul++)
{
ULONG *pulElem = rgrgulMapping[ul];
if ((ULONG) pbooleantest->booltesttype == pulElem[0])
{
edxlbt = (EdxlBooleanTestType) pulElem[1];
break;
}
}
GPOS_ASSERT(EdxlbooleantestSentinel != edxlbt && "Invalid boolean test type");
// create the DXL node holding the scalar boolean test operator
CDXLNode *pdxln = GPOS_NEW(m_pmp) CDXLNode
(
m_pmp,
GPOS_NEW(m_pmp) CDXLScalarBooleanTest(m_pmp,edxlbt)
);
CDXLNode *pdxlnArg = PdxlnScOpFromExpr(pbooleantest->arg, pmapvarcolid);
GPOS_ASSERT(NULL != pdxlnArg);
pdxln->AddChild(pdxlnArg);
return pdxln;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorScalarToDXL::PdxlnScNullTestFromNullTest
//
// @doc:
// Create a DXL node for a scalar nulltest expression from a GPDB OpExpr
//---------------------------------------------------------------------------
CDXLNode *
CTranslatorScalarToDXL::PdxlnScNullTestFromNullTest
(
const Expr *pexpr,
const CMappingVarColId* pmapvarcolid
)
{
GPOS_ASSERT(IsA(pexpr, NullTest));
const NullTest *pnulltest = (NullTest *) pexpr;
GPOS_ASSERT(NULL != pnulltest->arg);
CDXLNode *pdxlnChild = PdxlnScOpFromExpr(pnulltest->arg, pmapvarcolid);
GPOS_ASSERT(NULL != pdxlnChild);
GPOS_ASSERT(IS_NULL == pnulltest->nulltesttype || IS_NOT_NULL == pnulltest->nulltesttype);
BOOL fIsNull = false;
if (IS_NULL == pnulltest->nulltesttype)
{
fIsNull = true;
}
// create the DXL node holding the scalar NullTest operator
CDXLNode *pdxln = GPOS_NEW(m_pmp) CDXLNode(m_pmp, GPOS_NEW(m_pmp) CDXLScalarNullTest(m_pmp, fIsNull));
pdxln->AddChild(pdxlnChild);
return pdxln;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorScalarToDXL::PdxlnScCoalesceFromExpr
//
// @doc:
// Create a DXL node for a coalesce function from a GPDB OpExpr
//---------------------------------------------------------------------------
CDXLNode *
CTranslatorScalarToDXL::PdxlnScCoalesceFromExpr
(
const Expr *pexpr,
const CMappingVarColId* pmapvarcolid
)
{
GPOS_ASSERT(IsA(pexpr, CoalesceExpr));
CoalesceExpr *pcoalesceexpr = (CoalesceExpr *) pexpr;
GPOS_ASSERT(NULL != pcoalesceexpr->args);
CDXLScalarCoalesce *pdxlop = GPOS_NEW(m_pmp) CDXLScalarCoalesce
(
m_pmp,
CTranslatorUtils::PmdidWithVersion(m_pmp, pcoalesceexpr->coalescetype)
);
CDXLNode *pdxln = GPOS_NEW(m_pmp) CDXLNode(m_pmp, pdxlop);
TranslateScalarChildren(pdxln, pcoalesceexpr->args, pmapvarcolid);
return pdxln;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorScalarToDXL::PdxlnScMinMaxFromExpr
//
// @doc:
// Create a DXL node for a min/max operator from a GPDB OpExpr
//---------------------------------------------------------------------------
CDXLNode *
CTranslatorScalarToDXL::PdxlnScMinMaxFromExpr
(
const Expr *pexpr,
const CMappingVarColId* pmapvarcolid
)
{
GPOS_ASSERT(IsA(pexpr, MinMaxExpr));
MinMaxExpr *pminmaxexpr = (MinMaxExpr *) pexpr;
GPOS_ASSERT(NULL != pminmaxexpr->args);
CDXLScalarMinMax::EdxlMinMaxType emmt = CDXLScalarMinMax::EmmtSentinel;
if (IS_GREATEST == pminmaxexpr->op)
{
emmt = CDXLScalarMinMax::EmmtMax;
}
else
{
GPOS_ASSERT(IS_LEAST == pminmaxexpr->op);
emmt = CDXLScalarMinMax::EmmtMin;
}
CDXLScalarMinMax *pdxlop = GPOS_NEW(m_pmp) CDXLScalarMinMax
(
m_pmp,
GPOS_NEW(m_pmp) CMDIdGPDB(pminmaxexpr->minmaxtype),
emmt
);
CDXLNode *pdxln = GPOS_NEW(m_pmp) CDXLNode(m_pmp, pdxlop);
TranslateScalarChildren(pdxln, pminmaxexpr->args, pmapvarcolid);
return pdxln;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorScalarToDXL::TranslateScalarChildren
//
// @doc:
// Translate list elements and add them as children of the DXL node
//---------------------------------------------------------------------------
void
CTranslatorScalarToDXL::TranslateScalarChildren
(
CDXLNode *pdxln,
List *plist,
const CMappingVarColId* pmapvarcolid,
BOOL *pfHasDistributedTables // output
)
{
ListCell *plc = NULL;
ForEach (plc, plist)
{
Expr *pexprChild = (Expr *) lfirst(plc);
CDXLNode *pdxlnChild = PdxlnScOpFromExpr(pexprChild, pmapvarcolid, pfHasDistributedTables);
GPOS_ASSERT(NULL != pdxlnChild);
pdxln->AddChild(pdxlnChild);
}
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorScalarToDXL::PdxlnScCaseStmtFromExpr
//
// @doc:
// Create a DXL node for a case statement from a GPDB OpExpr.
// This function can be used for constructing a scalar opexpr operator appearing in a
// base node (e.g. a scan node), or in an intermediate plan nodes.
// The function allocates memory in the translator memory pool, and the caller
// is responsible for freeing it
//---------------------------------------------------------------------------
CDXLNode *
CTranslatorScalarToDXL::PdxlnScCaseStmtFromExpr
(
const Expr *pexpr,
const CMappingVarColId* pmapvarcolid
)
{
GPOS_ASSERT(IsA(pexpr, CaseExpr));
const CaseExpr *pcaseexpr = (CaseExpr *) pexpr;
if (NULL == pcaseexpr->args)
{
GPOS_RAISE
(
gpdxl::ExmaDXL,
gpdxl::ExmiPlStmt2DXLConversion,
GPOS_WSZ_LIT("Do not support SIMPLE CASE STATEMENT")
);
return NULL;
}
if (NULL == pcaseexpr->arg)
{
return PdxlnScIfStmtFromCaseExpr(pcaseexpr, pmapvarcolid);
}
return PdxlnScSwitchFromCaseExpr(pcaseexpr, pmapvarcolid);
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorScalarToDXL::PdxlnScSwitchFromCaseExpr
//
// @doc:
// Create a DXL Switch node from a GPDB CaseExpr.
//
//---------------------------------------------------------------------------
CDXLNode *
CTranslatorScalarToDXL::PdxlnScSwitchFromCaseExpr
(
const CaseExpr *pcaseexpr,
const CMappingVarColId* pmapvarcolid
)
{
GPOS_ASSERT (NULL != pcaseexpr->arg);
CDXLScalarSwitch *pdxlop = GPOS_NEW(m_pmp) CDXLScalarSwitch
(
m_pmp,
CTranslatorUtils::PmdidWithVersion(m_pmp, pcaseexpr->casetype)
);
CDXLNode *pdxlnSwitch = GPOS_NEW(m_pmp) CDXLNode(m_pmp, pdxlop);
// translate the switch expression
CDXLNode *pdxlnArg = PdxlnScOpFromExpr(pcaseexpr->arg, pmapvarcolid);
pdxlnSwitch->AddChild(pdxlnArg);
// translate the cases
ListCell *plc = NULL;
ForEach (plc, pcaseexpr->args)
{
CaseWhen *pexpr = (CaseWhen *) lfirst(plc);
CDXLScalarSwitchCase *pdxlopCase = GPOS_NEW(m_pmp) CDXLScalarSwitchCase(m_pmp);
CDXLNode *pdxlnCase = GPOS_NEW(m_pmp) CDXLNode(m_pmp, pdxlopCase);
CDXLNode *pdxlnCmpExpr = PdxlnScOpFromExpr(pexpr->expr, pmapvarcolid);
GPOS_ASSERT(NULL != pdxlnCmpExpr);
CDXLNode *pdxlnResult = PdxlnScOpFromExpr(pexpr->result, pmapvarcolid);
GPOS_ASSERT(NULL != pdxlnResult);
pdxlnCase->AddChild(pdxlnCmpExpr);
pdxlnCase->AddChild(pdxlnResult);
// add current case to switch node
pdxlnSwitch->AddChild(pdxlnCase);
}
// translate the "else" clause
if (NULL != pcaseexpr->defresult)
{
CDXLNode *pdxlnDefaultResult = PdxlnScOpFromExpr(pcaseexpr->defresult, pmapvarcolid);
GPOS_ASSERT(NULL != pdxlnDefaultResult);
pdxlnSwitch->AddChild(pdxlnDefaultResult);
}
return pdxlnSwitch;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorScalarToDXL::PdxlnScCaseTestFromExpr
//
// @doc:
// Create a DXL node for a case test from a GPDB Expr
//---------------------------------------------------------------------------
CDXLNode *
CTranslatorScalarToDXL::PdxlnScCaseTestFromExpr
(
const Expr *pexpr,
const CMappingVarColId* //pmapvarcolid
)
{
GPOS_ASSERT(IsA(pexpr, CaseTestExpr));
const CaseTestExpr *pcasetestexpr = (CaseTestExpr *) pexpr;
CDXLScalarCaseTest *pdxlop = GPOS_NEW(m_pmp) CDXLScalarCaseTest
(
m_pmp,
CTranslatorUtils::PmdidWithVersion(m_pmp, pcasetestexpr->typeId)
);
return GPOS_NEW(m_pmp) CDXLNode(m_pmp, pdxlop);
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorScalarToDXL::PdxlnScIfStmtFromCaseExpr
//
// @doc:
// Create a DXL If node from a GPDB CaseExpr
//---------------------------------------------------------------------------
CDXLNode *
CTranslatorScalarToDXL::PdxlnScIfStmtFromCaseExpr
(
const CaseExpr *pcaseexpr,
const CMappingVarColId* pmapvarcolid
)
{
GPOS_ASSERT (NULL == pcaseexpr->arg);
const ULONG ulWhenClauseCount = gpdb::UlListLength(pcaseexpr->args);
CDXLNode *pdxlnRootIfTree = NULL;
CDXLNode *pdxlnCurr = NULL;
for (ULONG ul = 0; ul < ulWhenClauseCount; ul++)
{
CDXLScalarIfStmt *pdxlopIfstmtNew = GPOS_NEW(m_pmp) CDXLScalarIfStmt
(
m_pmp,
CTranslatorUtils::PmdidWithVersion(m_pmp, pcaseexpr->casetype)
);
CDXLNode *pdxlnIfStmtNew = GPOS_NEW(m_pmp) CDXLNode(m_pmp, pdxlopIfstmtNew);
CaseWhen *pexpr = (CaseWhen *) gpdb::PvListNth(pcaseexpr->args, ul);
GPOS_ASSERT(IsA(pexpr, CaseWhen));
CDXLNode *pdxlnCond = PdxlnScOpFromExpr(pexpr->expr, pmapvarcolid);
CDXLNode *pdxlnResult = PdxlnScOpFromExpr(pexpr->result, pmapvarcolid);
GPOS_ASSERT(NULL != pdxlnCond);
GPOS_ASSERT(NULL != pdxlnResult);
pdxlnIfStmtNew->AddChild(pdxlnCond);
pdxlnIfStmtNew->AddChild(pdxlnResult);
if(NULL == pdxlnRootIfTree)
{
pdxlnRootIfTree = pdxlnIfStmtNew;
}
else
{
pdxlnCurr->AddChild(pdxlnIfStmtNew);
}
pdxlnCurr = pdxlnIfStmtNew;
}
if (NULL != pcaseexpr->defresult)
{
CDXLNode *pdxlnDefaultResult = PdxlnScOpFromExpr(pcaseexpr->defresult, pmapvarcolid);
GPOS_ASSERT(NULL != pdxlnDefaultResult);
pdxlnCurr->AddChild(pdxlnDefaultResult);
}
return pdxlnRootIfTree;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorScalarToDXL::PdxlnScCastFromRelabelType
//
// @doc:
// Create a DXL node for a scalar RelabelType expression from a GPDB RelabelType
//---------------------------------------------------------------------------
CDXLNode *
CTranslatorScalarToDXL::PdxlnScCastFromRelabelType
(
const Expr *pexpr,
const CMappingVarColId* pmapvarcolid
)
{
GPOS_ASSERT(IsA(pexpr, RelabelType));
const RelabelType *prelabeltype = (RelabelType *) pexpr;
GPOS_ASSERT(NULL != prelabeltype->arg);
CDXLNode *pdxlnChild = PdxlnScOpFromExpr(prelabeltype->arg, pmapvarcolid);
GPOS_ASSERT(NULL != pdxlnChild);
// create the DXL node holding the scalar boolean operator
CDXLNode *pdxln = GPOS_NEW(m_pmp) CDXLNode
(
m_pmp,
GPOS_NEW(m_pmp) CDXLScalarCast
(
m_pmp,
CTranslatorUtils::PmdidWithVersion(m_pmp, prelabeltype->resulttype),
CTranslatorUtils::PmdidWithVersion(m_pmp, 0) // casting function oid
)
);
pdxln->AddChild(pdxlnChild);
return pdxln;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorScalarToDXL::PdxlnScCoerceFromCoerce
//
// @doc:
// Create a DXL node for a scalar coerce expression from a
// GPDB coerce expression
//---------------------------------------------------------------------------
CDXLNode *
CTranslatorScalarToDXL::PdxlnScCoerceFromCoerce
(
const Expr *pexpr,
const CMappingVarColId* pmapvarcolid
)
{
GPOS_ASSERT(IsA(pexpr, CoerceToDomain));
const CoerceToDomain *pcoerce = (CoerceToDomain *) pexpr;
GPOS_ASSERT(NULL != pcoerce->arg);
CDXLNode *pdxlnChild = PdxlnScOpFromExpr(pcoerce->arg, pmapvarcolid);
GPOS_ASSERT(NULL != pdxlnChild);
// create the DXL node holding the scalar boolean operator
CDXLNode *pdxln = GPOS_NEW(m_pmp) CDXLNode
(
m_pmp,
GPOS_NEW(m_pmp) CDXLScalarCoerceToDomain
(
m_pmp,
CTranslatorUtils::PmdidWithVersion(m_pmp, pcoerce->resulttype),
pcoerce->resulttypmod,
(EdxlCoercionForm) pcoerce->coercionformat,
pcoerce->location
)
);
pdxln->AddChild(pdxlnChild);
return pdxln;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorScalarToDXL::PdxlnScFuncExprFromFuncExpr
//
// @doc:
// Create a DXL node for a scalar funcexpr from a GPDB FuncExpr
//---------------------------------------------------------------------------
CDXLNode *
CTranslatorScalarToDXL::PdxlnScFuncExprFromFuncExpr
(
const Expr *pexpr,
const CMappingVarColId* pmapvarcolid
)
{
GPOS_ASSERT(IsA(pexpr, FuncExpr));
const FuncExpr *pfuncexpr = (FuncExpr *) pexpr;
CMDIdGPDB *pmdidFunc = CTranslatorUtils::PmdidWithVersion(m_pmp, pfuncexpr->funcid);
// create the DXL node holding the scalar funcexpr
CDXLNode *pdxln = GPOS_NEW(m_pmp) CDXLNode
(
m_pmp,
GPOS_NEW(m_pmp) CDXLScalarFuncExpr
(
m_pmp,
pmdidFunc,
CTranslatorUtils::PmdidWithVersion(m_pmp, pfuncexpr->funcresulttype),
pfuncexpr->funcretset
)
);
const IMDFunction *pmdfunc = m_pmda->Pmdfunc(pmdidFunc);
if (IMDFunction::EfsVolatile == pmdfunc->EfsStability())
{
ListCell *plc = NULL;
ForEach (plc, pfuncexpr->args)
{
Node *pnodeArg = (Node *) lfirst(plc);
if (CTranslatorUtils::FHasSubquery(pnodeArg))
{
GPOS_RAISE(gpdxl::ExmaDXL, gpdxl::ExmiQuery2DXLUnsupportedFeature,
GPOS_WSZ_LIT("Volatile functions with subqueries in arguments"));
}
}
}
TranslateScalarChildren(pdxln, pfuncexpr->args, pmapvarcolid);
return pdxln;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorScalarToDXL::PdxlnScAggrefFromAggref
//
// @doc:
// Create a DXL node for a scalar aggref from a GPDB FuncExpr
//---------------------------------------------------------------------------
CDXLNode *
CTranslatorScalarToDXL::PdxlnScAggrefFromAggref
(
const Expr *pexpr,
const CMappingVarColId* pmapvarcolid
)
{
GPOS_ASSERT(IsA(pexpr, Aggref));
const Aggref *paggref = (Aggref *) pexpr;
ULONG rgrgulMapping[][2] =
{
{AGGSTAGE_NORMAL, EdxlaggstageNormal},
{AGGSTAGE_PARTIAL, EdxlaggstagePartial},
{AGGSTAGE_INTERMEDIATE, EdxlaggstageIntermediate},
{AGGSTAGE_FINAL, EdxlaggstageFinal},
};
EdxlAggrefStage edxlaggstage = EdxlaggstageSentinel;
const ULONG ulArity = GPOS_ARRAY_SIZE(rgrgulMapping);
for (ULONG ul = 0; ul < ulArity; ul++)
{
ULONG *pulElem = rgrgulMapping[ul];
if ((ULONG) paggref->aggstage == pulElem[0])
{
edxlaggstage = (EdxlAggrefStage) pulElem[1];
break;
}
}
GPOS_ASSERT(EdxlaggstageSentinel != edxlaggstage && "Invalid agg stage");
CMDIdGPDB *pmdidAgg = CTranslatorUtils::PmdidWithVersion(m_pmp, paggref->aggfnoid);
const IMDAggregate *pmdagg = m_pmda->Pmdagg(pmdidAgg);
if (pmdagg->FOrdered())
{
GPOS_ASSERT_IMP(NULL == paggref->aggorder, pmdagg->FOrdered());
GPOS_RAISE
(
gpdxl::ExmaDXL,
gpdxl::ExmiPlStmt2DXLConversion,
GPOS_WSZ_LIT("Ordered aggregates")
);
}
if (0 != paggref->agglevelsup)
{
// TODO: raghav, Feb 05 2015, remove temporary fix to avoid erroring out during execution
GPOS_RAISE(gpdxl::ExmaDXL, gpdxl::ExmiQuery2DXLError, GPOS_WSZ_LIT("Aggregate functions with outer references"));
}
IMDId *pmdidRetType = CScalarAggFunc::PmdidLookupReturnType(pmdidAgg, (EdxlaggstageNormal == edxlaggstage), m_pmda);
IMDId *pmdidResolvedRetType = NULL;
if (m_pmda->Pmdtype(pmdidRetType)->FAmbiguous())
{
// if return type given by MD cache is ambiguous, use type provided by aggref node
pmdidResolvedRetType = CTranslatorUtils::PmdidWithVersion(m_pmp, paggref->aggtype);
}
CDXLScalarAggref *pdxlopAggref = GPOS_NEW(m_pmp) CDXLScalarAggref(m_pmp, pmdidAgg, pmdidResolvedRetType, paggref->aggdistinct, edxlaggstage);
// create the DXL node holding the scalar aggref
CDXLNode *pdxln = GPOS_NEW(m_pmp) CDXLNode(m_pmp, pdxlopAggref);
TranslateScalarChildren(pdxln, paggref->args, pmapvarcolid);
return pdxln;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorScalarToDXL::Edxlfb
//
// @doc:
// Return the DXL representation of window frame boundary
//---------------------------------------------------------------------------
EdxlFrameBoundary
CTranslatorScalarToDXL::Edxlfb
(
WindowBoundingKind kind,
Node *pnode
)
const
{
ULONG rgrgulMapping[][2] =
{
{WINDOW_UNBOUND_PRECEDING, EdxlfbUnboundedPreceding},
{WINDOW_BOUND_PRECEDING, EdxlfbBoundedPreceding},
{WINDOW_CURRENT_ROW, EdxlfbCurrentRow},
{WINDOW_BOUND_FOLLOWING, EdxlfbBoundedFollowing},
{WINDOW_UNBOUND_FOLLOWING, EdxlfbUnboundedFollowing},
{WINDOW_DELAYED_BOUND_PRECEDING, EdxlfbDelayedBoundedPreceding},
{WINDOW_DELAYED_BOUND_FOLLOWING, EdxlfbDelayedBoundedFollowing}
};
const ULONG ulArity = GPOS_ARRAY_SIZE(rgrgulMapping);
EdxlFrameBoundary edxlfb = EdxlfbSentinel;
for (ULONG ul = 0; ul < ulArity; ul++)
{
ULONG *pulElem = rgrgulMapping[ul];
if ((ULONG) kind == pulElem[0])
{
edxlfb = (EdxlFrameBoundary) pulElem[1];
if ((WINDOW_BOUND_FOLLOWING == kind) && ((NULL == pnode) || !IsA(pnode, Const)))
{
edxlfb = EdxlfbDelayedBoundedFollowing;
}
if ((WINDOW_BOUND_PRECEDING == kind) && ((NULL == pnode) || !IsA(pnode, Const)))
{
edxlfb = EdxlfbDelayedBoundedPreceding;
}
break;
}
}
GPOS_ASSERT(EdxlfbSentinel != edxlfb && "Invalid window frame boundary");
return edxlfb;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorScalarToDXL::Pdxlwf
//
// @doc:
// Create a DXL window frame from a GPDB WindowFrame
//---------------------------------------------------------------------------
CDXLWindowFrame *
CTranslatorScalarToDXL::Pdxlwf
(
const Expr *pexpr,
const CMappingVarColId* pmapvarcolid,
CDXLNode *pdxlnNewChildScPrL,
BOOL *pfHasDistributedTables // output
)
{
GPOS_ASSERT(IsA(pexpr, WindowFrame));
const WindowFrame *pwindowframe = (WindowFrame *) pexpr;
EdxlFrameSpec edxlfs = EdxlfsRow;
if (!pwindowframe->is_rows)
{
edxlfs = EdxlfsRange;
}
EdxlFrameBoundary edxlfbLead = Edxlfb(pwindowframe->lead->kind, pwindowframe->lead->val);
EdxlFrameBoundary edxlfbTrail = Edxlfb(pwindowframe->trail->kind, pwindowframe->trail->val);
ULONG rgrgulExclusionMapping[][2] =
{
{WINDOW_EXCLUSION_NULL, EdxlfesNulls},
{WINDOW_EXCLUSION_CUR_ROW, EdxlfesCurrentRow},
{WINDOW_EXCLUSION_GROUP, EdxlfesGroup},
{WINDOW_EXCLUSION_TIES, EdxlfesTies},
{WINDOW_EXCLUSION_NO_OTHERS, EdxlfesNone},
};
const ULONG ulArityExclusion = GPOS_ARRAY_SIZE(rgrgulExclusionMapping);
EdxlFrameExclusionStrategy edxlfes = EdxlfesSentinel;
for (ULONG ul = 0; ul < ulArityExclusion; ul++)
{
ULONG *pulElem = rgrgulExclusionMapping[ul];
if ((ULONG) pwindowframe->exclude == pulElem[0])
{
edxlfes = (EdxlFrameExclusionStrategy) pulElem[1];
break;
}
}
GPOS_ASSERT(EdxlfesSentinel != edxlfes && "Invalid window frame exclusion");
CDXLNode *pdxlnLeadEdge = GPOS_NEW(m_pmp) CDXLNode(m_pmp, GPOS_NEW(m_pmp) CDXLScalarWindowFrameEdge(m_pmp, true /* fLeading */, edxlfbLead));
CDXLNode *pdxlnTrailEdge = GPOS_NEW(m_pmp) CDXLNode(m_pmp, GPOS_NEW(m_pmp) CDXLScalarWindowFrameEdge(m_pmp, false /* fLeading */, edxlfbTrail));
// translate the lead and trail value
if (NULL != pwindowframe->lead->val)
{
pdxlnLeadEdge->AddChild(PdxlnWindowFrameEdgeVal(pwindowframe->lead->val, pmapvarcolid, pdxlnNewChildScPrL, pfHasDistributedTables));
}
if (NULL != pwindowframe->trail->val)
{
pdxlnTrailEdge->AddChild(PdxlnWindowFrameEdgeVal(pwindowframe->trail->val, pmapvarcolid, pdxlnNewChildScPrL, pfHasDistributedTables));
}
CDXLWindowFrame *pdxlWf = GPOS_NEW(m_pmp) CDXLWindowFrame(m_pmp, edxlfs, edxlfes, pdxlnLeadEdge, pdxlnTrailEdge);
return pdxlWf;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorScalarToDXL::PdxlnWindowFrameEdgeVal
//
// @doc:
// Translate the window frame edge, if the column used in the edge is a
// computed column then add it to the project list
//---------------------------------------------------------------------------
CDXLNode *
CTranslatorScalarToDXL::PdxlnWindowFrameEdgeVal
(
const Node *pnode,
const CMappingVarColId* pmapvarcolid,
CDXLNode *pdxlnNewChildScPrL,
BOOL *pfHasDistributedTables
)
{
CDXLNode *pdxlnVal = PdxlnScOpFromExpr((Expr *) pnode, pmapvarcolid, pfHasDistributedTables);
if (m_fQuery && !IsA(pnode, Var) && !IsA(pnode, Const))
{
GPOS_ASSERT(NULL != pdxlnNewChildScPrL);
CWStringConst strUnnamedCol(GPOS_WSZ_LIT("?column?"));
CMDName *pmdnameAlias = GPOS_NEW(m_pmp) CMDName(m_pmp, &strUnnamedCol);
ULONG ulPrElId = m_pidgtorCol->UlNextId();
// construct a projection element
CDXLNode *pdxlnPrEl = GPOS_NEW(m_pmp) CDXLNode(m_pmp, GPOS_NEW(m_pmp) CDXLScalarProjElem(m_pmp, ulPrElId, pmdnameAlias));
pdxlnPrEl->AddChild(pdxlnVal);
// add it to the computed columns project list
pdxlnNewChildScPrL->AddChild(pdxlnPrEl);
// construct a new scalar ident
CDXLScalarIdent *pdxlopIdent = GPOS_NEW(m_pmp) CDXLScalarIdent
(
m_pmp,
GPOS_NEW(m_pmp) CDXLColRef
(
m_pmp,
GPOS_NEW(m_pmp) CMDName(m_pmp, &strUnnamedCol),
ulPrElId
),
CTranslatorUtils::PmdidWithVersion(m_pmp, gpdb::OidExprType(const_cast<Node*>(pnode)))
);
pdxlnVal = GPOS_NEW(m_pmp) CDXLNode(m_pmp, pdxlopIdent);
}
return pdxlnVal;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorScalarToDXL::PdxlnScWindowref
//
// @doc:
// Create a DXL node for a scalar window ref from a GPDB WindowRef
//
//---------------------------------------------------------------------------
CDXLNode *
CTranslatorScalarToDXL::PdxlnScWindowref
(
const Expr *pexpr,
const CMappingVarColId* pmapvarcolid
)
{
GPOS_ASSERT(IsA(pexpr, WindowRef));
const WindowRef *pwindowref = (WindowRef *) pexpr;
ULONG rgrgulMapping[][2] =
{
{WINSTAGE_IMMEDIATE, EdxlwinstageImmediate},
{WINSTAGE_PRELIMINARY, EdxlwinstagePreliminary},
{WINSTAGE_ROWKEY, EdxlwinstageRowKey},
};
const ULONG ulArity = GPOS_ARRAY_SIZE(rgrgulMapping);
EdxlWinStage edxlwinstage = EdxlwinstageSentinel;
for (ULONG ul = 0; ul < ulArity; ul++)
{
ULONG *pulElem = rgrgulMapping[ul];
if ((ULONG) pwindowref->winstage == pulElem[0])
{
edxlwinstage = (EdxlWinStage) pulElem[1];
break;
}
}
ULONG ulWinSpecPos = (ULONG) pwindowref->winlevel;
if (m_fQuery)
{
ulWinSpecPos = (ULONG) pwindowref->winspec;
}
GPOS_ASSERT(EdxlwinstageSentinel != edxlwinstage && "Invalid window stage");
if (0 != pwindowref->winlevelsup)
{
GPOS_RAISE(gpdxl::ExmaDXL, gpdxl::ExmiQuery2DXLUnsupportedFeature, GPOS_WSZ_LIT("Window functions with outer references"));
}
CDXLScalarWindowRef *pdxlopWinref = GPOS_NEW(m_pmp) CDXLScalarWindowRef
(
m_pmp,
CTranslatorUtils::PmdidWithVersion(m_pmp, pwindowref->winfnoid),
CTranslatorUtils::PmdidWithVersion(m_pmp, pwindowref->restype),
pwindowref->windistinct,
edxlwinstage,
ulWinSpecPos
);
// create the DXL node holding the scalar aggref
CDXLNode *pdxln = GPOS_NEW(m_pmp) CDXLNode(m_pmp, pdxlopWinref);
TranslateScalarChildren(pdxln, pwindowref->args, pmapvarcolid);
return pdxln;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorScalarToDXL::PdxlnScCondFromQual
//
// @doc:
// Create a DXL scalar boolean operator node from a GPDB qual list.
// The function allocates memory in the translator memory pool, and the caller
// is responsible for freeing it
//---------------------------------------------------------------------------
CDXLNode *
CTranslatorScalarToDXL::PdxlnScCondFromQual
(
List *plQual,
const CMappingVarColId* pmapvarcolid,
BOOL *pfHasDistributedTables
)
{
if (NULL == plQual || 0 == gpdb::UlListLength(plQual))
{
return NULL;
}
if (1 == gpdb::UlListLength(plQual))
{
Expr *pexpr = (Expr *) gpdb::PvListNth(plQual, 0);
return PdxlnScOpFromExpr(pexpr, pmapvarcolid, pfHasDistributedTables);
}
else
{
// GPDB assumes that if there are a list of qual conditions then it is an implicit AND operation
// Here we build the left deep AND tree
CDXLNode *pdxln = GPOS_NEW(m_pmp) CDXLNode(m_pmp, GPOS_NEW(m_pmp) CDXLScalarBoolExpr(m_pmp, Edxland));
TranslateScalarChildren(pdxln, plQual, pmapvarcolid, pfHasDistributedTables);
return pdxln;
}
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorScalarToDXL::PdxlnFilterFromQual
//
// @doc:
// Create a DXL scalar filter node from a GPDB qual list.
// The function allocates memory in the translator memory pool, and the caller
// is responsible for freeing it
//---------------------------------------------------------------------------
CDXLNode *
CTranslatorScalarToDXL::PdxlnFilterFromQual
(
List *plQual,
const CMappingVarColId* pmapvarcolid,
Edxlopid edxlopFilterType,
BOOL *pfHasDistributedTables // output
)
{
CDXLScalarFilter *pdxlop = NULL;
switch (edxlopFilterType)
{
case EdxlopScalarFilter:
pdxlop = GPOS_NEW(m_pmp) CDXLScalarFilter(m_pmp);
break;
case EdxlopScalarJoinFilter:
pdxlop = GPOS_NEW(m_pmp) CDXLScalarJoinFilter(m_pmp);
break;
case EdxlopScalarOneTimeFilter:
pdxlop = GPOS_NEW(m_pmp) CDXLScalarOneTimeFilter(m_pmp);
break;
default:
GPOS_ASSERT(!"Unrecognized filter type");
}
CDXLNode *pdxlnFilter = GPOS_NEW(m_pmp) CDXLNode(m_pmp, pdxlop);
CDXLNode *pdxlnCond = PdxlnScCondFromQual(plQual, pmapvarcolid, pfHasDistributedTables);
if (NULL != pdxlnCond)
{
pdxlnFilter->AddChild(pdxlnCond);
}
return pdxlnFilter;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorScalarToDXL::PdxlnFromSublink
//
// @doc:
// Create a DXL node from a GPDB sublink node.
//
//---------------------------------------------------------------------------
CDXLNode *
CTranslatorScalarToDXL::PdxlnFromSublink
(
const Expr *pexpr,
const CMappingVarColId* pmapvarcolid
)
{
const SubLink *psublink = (SubLink *) pexpr;
switch (psublink->subLinkType)
{
case EXPR_SUBLINK:
return PdxlnScSubqueryFromSublink(psublink, pmapvarcolid);
case ALL_SUBLINK:
case ANY_SUBLINK:
return PdxlnQuantifiedSubqueryFromSublink(psublink, pmapvarcolid);
case EXISTS_SUBLINK:
return PdxlnExistSubqueryFromSublink(psublink, pmapvarcolid);
default:
{
GPOS_RAISE(gpdxl::ExmaDXL, gpdxl::ExmiQuery2DXLUnsupportedFeature, GPOS_WSZ_LIT("Non-Scalar Subquery"));
return NULL;
}
}
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorScalarToDXL::PdxlnQuantifiedSubqueryFromSublink
//
// @doc:
// Create ANY / ALL quantified sub query from a GPDB sublink node
//---------------------------------------------------------------------------
CDXLNode *
CTranslatorScalarToDXL::PdxlnQuantifiedSubqueryFromSublink
(
const SubLink *psublink,
const CMappingVarColId* pmapvarcolid
)
{
CMappingVarColId *pmapvarcolidCopy = pmapvarcolid->PmapvarcolidCopy(m_pmp);
CAutoP<CTranslatorQueryToDXL> ptrquerytodxl;
ptrquerytodxl = CTranslatorQueryToDXL::PtrquerytodxlInstance
(
m_pmp,
m_pmda,
m_pidgtorCol,
m_pidgtorCTE,
pmapvarcolidCopy,
(Query *) psublink->subselect,
m_ulQueryLevel + 1,
m_phmulCTEEntries
);
CDXLNode *pdxlnInner = ptrquerytodxl->PdxlnFromQueryInternal();
DrgPdxln *pdrgpdxlnQueryOutput = ptrquerytodxl->PdrgpdxlnQueryOutput();
DrgPdxln *pdrgpdxlnCTE = ptrquerytodxl->PdrgpdxlnCTE();
CUtils::AddRefAppend(m_pdrgpdxlnCTE, pdrgpdxlnCTE);
if (1 != pdrgpdxlnQueryOutput->UlLength())
{
GPOS_RAISE(gpdxl::ExmaDXL, gpdxl::ExmiQuery2DXLUnsupportedFeature, GPOS_WSZ_LIT("Non-Scalar Subquery"));
}
m_fHasDistributedTables = m_fHasDistributedTables || ptrquerytodxl->FHasDistributedTables();
CDXLNode *pdxlnIdent = (*pdrgpdxlnQueryOutput)[0];
GPOS_ASSERT(NULL != pdxlnIdent);
// get dxl scalar identifier
CDXLScalarIdent *pdxlopIdent = dynamic_cast<CDXLScalarIdent *>(pdxlnIdent->Pdxlop());
// get the dxl column reference
const CDXLColRef *pdxlcr = pdxlopIdent->Pdxlcr();
const ULONG ulColId = pdxlcr->UlID();
// get the test expression
GPOS_ASSERT(IsA(psublink->testexpr, OpExpr));
OpExpr *popexpr = (OpExpr*) psublink->testexpr;
IMDId *pmdid = CTranslatorUtils::PmdidWithVersion(m_pmp, popexpr->opno);
// get operator name
const CWStringConst *pstr = PstrOpName(pmdid);
// translate left hand side of the expression
GPOS_ASSERT(NULL != popexpr->args);
Expr* pexprLHS = (Expr*) gpdb::PvListNth(popexpr->args, 0);
CDXLNode *pdxlnOuter = PdxlnScOpFromExpr(pexprLHS, pmapvarcolid);
CDXLNode *pdxln = NULL;
CDXLScalar *pdxlopSubquery = NULL;
GPOS_ASSERT(ALL_SUBLINK == psublink->subLinkType || ANY_SUBLINK == psublink->subLinkType);
if (ALL_SUBLINK == psublink->subLinkType)
{
pdxlopSubquery = GPOS_NEW(m_pmp) CDXLScalarSubqueryAll
(
m_pmp,
pmdid,
GPOS_NEW(m_pmp) CMDName(m_pmp, pstr),
ulColId
);
}
else
{
pdxlopSubquery = GPOS_NEW(m_pmp) CDXLScalarSubqueryAny
(
m_pmp,
pmdid,
GPOS_NEW(m_pmp) CMDName(m_pmp, pstr),
ulColId
);
}
pdxln = GPOS_NEW(m_pmp) CDXLNode(m_pmp, pdxlopSubquery);
pdxln->AddChild(pdxlnOuter);
pdxln->AddChild(pdxlnInner);
#ifdef GPOS_DEBUG
pdxln->Pdxlop()->AssertValid(pdxln, false /* fValidateChildren */);
#endif
return pdxln;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorScalarToDXL::PdxlnScSubqueryFromSublink
//
// @doc:
// Create a scalar subquery from a GPDB sublink node
//---------------------------------------------------------------------------
CDXLNode *
CTranslatorScalarToDXL::PdxlnScSubqueryFromSublink
(
const SubLink *psublink,
const CMappingVarColId *pmapvarcolid
)
{
CMappingVarColId *pmapvarcolidCopy = pmapvarcolid->PmapvarcolidCopy(m_pmp);
Query *pquerySublink = (Query *) psublink->subselect;
CAutoP<CTranslatorQueryToDXL> ptrquerytodxl;
ptrquerytodxl = CTranslatorQueryToDXL::PtrquerytodxlInstance
(
m_pmp,
m_pmda,
m_pidgtorCol,
m_pidgtorCTE,
pmapvarcolidCopy,
pquerySublink,
m_ulQueryLevel + 1,
m_phmulCTEEntries
);
CDXLNode *pdxlnSubQuery = ptrquerytodxl->PdxlnFromQueryInternal();
DrgPdxln *pdrgpdxlnQueryOutput = ptrquerytodxl->PdrgpdxlnQueryOutput();
GPOS_ASSERT(1 == pdrgpdxlnQueryOutput->UlLength());
DrgPdxln *pdrgpdxlnCTE = ptrquerytodxl->PdrgpdxlnCTE();
CUtils::AddRefAppend(m_pdrgpdxlnCTE, pdrgpdxlnCTE);
m_fHasDistributedTables = m_fHasDistributedTables || ptrquerytodxl->FHasDistributedTables();
// get dxl scalar identifier
CDXLNode *pdxlnIdent = (*pdrgpdxlnQueryOutput)[0];
GPOS_ASSERT(NULL != pdxlnIdent);
CDXLScalarIdent *pdxlopIdent = CDXLScalarIdent::PdxlopConvert(pdxlnIdent->Pdxlop());
// get the dxl column reference
const CDXLColRef *pdxlcr = pdxlopIdent->Pdxlcr();
const ULONG ulColId = pdxlcr->UlID();
CDXLNode *pdxln = GPOS_NEW(m_pmp) CDXLNode(m_pmp, GPOS_NEW(m_pmp) CDXLScalarSubquery(m_pmp, ulColId));
pdxln->AddChild(pdxlnSubQuery);
return pdxln;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorScalarToDXL::PdxlnArray
//
// @doc:
// Translate array
//
//---------------------------------------------------------------------------
CDXLNode *
CTranslatorScalarToDXL::PdxlnArray
(
const Expr *pexpr,
const CMappingVarColId* pmapvarcolid
)
{
GPOS_ASSERT(IsA(pexpr, ArrayExpr));
const ArrayExpr *parrayexpr = (ArrayExpr *) pexpr;
CDXLScalarArray *pdxlop =
GPOS_NEW(m_pmp) CDXLScalarArray
(
m_pmp,
CTranslatorUtils::PmdidWithVersion(m_pmp, parrayexpr->element_typeid),
CTranslatorUtils::PmdidWithVersion(m_pmp, parrayexpr->array_typeid),
parrayexpr->multidims
);
CDXLNode *pdxln = GPOS_NEW(m_pmp) CDXLNode(m_pmp, pdxlop);
TranslateScalarChildren(pdxln, parrayexpr->elements, pmapvarcolid);
return pdxln;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorScalarToDXL::PdxlnArrayRef
//
// @doc:
// Translate arrayref
//
//---------------------------------------------------------------------------
CDXLNode *
CTranslatorScalarToDXL::PdxlnArrayRef
(
const Expr *pexpr,
const CMappingVarColId* pmapvarcolid
)
{
GPOS_ASSERT(IsA(pexpr, ArrayRef));
const ArrayRef *parrayref = (ArrayRef *) pexpr;
CDXLScalarArrayRef *pdxlop =
GPOS_NEW(m_pmp) CDXLScalarArrayRef
(
m_pmp,
CTranslatorUtils::PmdidWithVersion(m_pmp, parrayref->refelemtype),
CTranslatorUtils::PmdidWithVersion(m_pmp, parrayref->refarraytype),
CTranslatorUtils::PmdidWithVersion(m_pmp, parrayref->refrestype)
);
CDXLNode *pdxln = GPOS_NEW(m_pmp) CDXLNode(m_pmp, pdxlop);
// add children
AddArrayIndexList(pdxln, parrayref->reflowerindexpr, CDXLScalarArrayRefIndexList::EilbLower, pmapvarcolid);
AddArrayIndexList(pdxln, parrayref->refupperindexpr, CDXLScalarArrayRefIndexList::EilbUpper, pmapvarcolid);
pdxln->AddChild(PdxlnScOpFromExpr(parrayref->refexpr, pmapvarcolid));
if (NULL != parrayref->refassgnexpr)
{
pdxln->AddChild(PdxlnScOpFromExpr(parrayref->refassgnexpr, pmapvarcolid));
}
return pdxln;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorScalarToDXL::AddArrayIndexList
//
// @doc:
// Add an indexlist to the given DXL arrayref node
//
//---------------------------------------------------------------------------
void
CTranslatorScalarToDXL::AddArrayIndexList
(
CDXLNode *pdxln,
List *plist,
CDXLScalarArrayRefIndexList::EIndexListBound eilb,
const CMappingVarColId* pmapvarcolid
)
{
GPOS_ASSERT(NULL != pdxln);
GPOS_ASSERT(EdxlopScalarArrayRef == pdxln->Pdxlop()->Edxlop());
GPOS_ASSERT(CDXLScalarArrayRefIndexList::EilbSentinel > eilb);
CDXLNode *pdxlnIndexList =
GPOS_NEW(m_pmp) CDXLNode
(
m_pmp,
GPOS_NEW(m_pmp) CDXLScalarArrayRefIndexList(m_pmp, eilb)
);
TranslateScalarChildren(pdxlnIndexList, plist, pmapvarcolid);
pdxln->AddChild(pdxlnIndexList);
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorScalarToDXL::PstrOpName
//
// @doc:
// Get the operator name
//
//---------------------------------------------------------------------------
const CWStringConst *
CTranslatorScalarToDXL::PstrOpName
(
IMDId *pmdid
)
const
{
// get operator name
const IMDScalarOp *pmdscop = m_pmda->Pmdscop(pmdid);
const CWStringConst *pstr = pmdscop->Mdname().Pstr();
return pstr;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorScalarToDXL::PdxlnExistSubqueryFromSublink
//
// @doc:
// Create a DXL EXISTS subquery node from the respective GPDB
// sublink node
//---------------------------------------------------------------------------
CDXLNode *
CTranslatorScalarToDXL::PdxlnExistSubqueryFromSublink
(
const SubLink *psublink,
const CMappingVarColId* pmapvarcolid
)
{
GPOS_ASSERT(NULL != psublink);
CMappingVarColId *pmapvarcolidCopy = pmapvarcolid->PmapvarcolidCopy(m_pmp);
CAutoP<CTranslatorQueryToDXL> ptrquerytodxl;
ptrquerytodxl = CTranslatorQueryToDXL::PtrquerytodxlInstance
(
m_pmp,
m_pmda,
m_pidgtorCol,
m_pidgtorCTE,
pmapvarcolidCopy,
(Query *) psublink->subselect,
m_ulQueryLevel + 1,
m_phmulCTEEntries
);
CDXLNode *pdxlnRoot = ptrquerytodxl->PdxlnFromQueryInternal();
DrgPdxln *pdrgpdxlnCTE = ptrquerytodxl->PdrgpdxlnCTE();
CUtils::AddRefAppend(m_pdrgpdxlnCTE, pdrgpdxlnCTE);
m_fHasDistributedTables = m_fHasDistributedTables || ptrquerytodxl->FHasDistributedTables();
CDXLNode *pdxln = GPOS_NEW(m_pmp) CDXLNode(m_pmp, GPOS_NEW(m_pmp) CDXLScalarSubqueryExists(m_pmp));
pdxln->AddChild(pdxlnRoot);
return pdxln;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorScalarToDXL::Pdatum
//
// @doc:
// Create CDXLDatum from GPDB datum
//---------------------------------------------------------------------------
CDXLDatum *
CTranslatorScalarToDXL::Pdxldatum
(
IMemoryPool *pmp,
const IMDType *pmdtype,
BOOL fNull,
ULONG ulLen,
Datum datum
)
{
SDXLDatumTranslatorElem rgTranslators[] =
{
{IMDType::EtiInt2 , &CTranslatorScalarToDXL::PdxldatumInt2},
{IMDType::EtiInt4 , &CTranslatorScalarToDXL::PdxldatumInt4},
{IMDType::EtiInt8 , &CTranslatorScalarToDXL::PdxldatumInt8},
{IMDType::EtiBool , &CTranslatorScalarToDXL::PdxldatumBool},
{IMDType::EtiOid , &CTranslatorScalarToDXL::PdxldatumOid},
};
const ULONG ulTranslators = GPOS_ARRAY_SIZE(rgTranslators);
// find translator for the datum type
PfPdxldatumFromDatum *pf = NULL;
for (ULONG ul = 0; ul < ulTranslators; ul++)
{
SDXLDatumTranslatorElem elem = rgTranslators[ul];
if (pmdtype->Eti() == elem.eti)
{
pf = elem.pf;
break;
}
}
if (NULL == pf)
{
// generate a datum of generic type
return PdxldatumGeneric(pmp, pmdtype, fNull, ulLen, datum);
}
else
{
return (*pf)(pmp, pmdtype, fNull, ulLen, datum);
}
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorScalarToDXL::PdxldatumGeneric
//
// @doc:
// Translate a datum of generic type
//---------------------------------------------------------------------------
CDXLDatum *
CTranslatorScalarToDXL::PdxldatumGeneric
(
IMemoryPool *pmp,
const IMDType *pmdtype,
BOOL fNull,
ULONG ulLen,
Datum datum
)
{
CMDIdGPDB *pmdidMDC = CMDIdGPDB::PmdidConvert(pmdtype->Pmdid());
CMDIdGPDB *pmdid = GPOS_NEW(pmp) CMDIdGPDB(*pmdidMDC);
BOOL fConstByVal = pmdtype->FByValue();
BYTE *pba = Pba(pmp, pmdtype, fNull, ulLen, datum);
ULONG ulLength = 0;
if (!fNull)
{
ulLength = (ULONG) gpdb::SDatumSize(datum, pmdtype->FByValue(), ulLen);
}
CDouble dValue(0);
if (CMDTypeGenericGPDB::FHasByteDoubleMapping(pmdid))
{
dValue = DValue(pmdid, fNull, pba, datum);
}
LINT lValue = 0;
if (CMDTypeGenericGPDB::FHasByteLintMapping(pmdid))
{
lValue = LValue(pmdid, fNull, pba, ulLength);
}
return CMDTypeGenericGPDB::Pdxldatum(pmp, pmdid, fConstByVal, fNull, pba, ulLength, lValue, dValue);
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorScalarToDXL::PdxldatumBool
//
// @doc:
// Translate a datum of type bool
//---------------------------------------------------------------------------
CDXLDatum *
CTranslatorScalarToDXL::PdxldatumBool
(
IMemoryPool *pmp,
const IMDType *pmdtype,
BOOL fNull,
ULONG , //ulLen,
Datum datum
)
{
GPOS_ASSERT(pmdtype->FByValue());
CMDIdGPDB *pmdidMDC = CMDIdGPDB::PmdidConvert(pmdtype->Pmdid());
CMDIdGPDB *pmdid = GPOS_NEW(pmp) CMDIdGPDB(*pmdidMDC);
return GPOS_NEW(pmp) CDXLDatumBool(pmp, pmdid, fNull, gpdb::FBoolFromDatum(datum));
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorScalarToDXL::PdxldatumOid
//
// @doc:
// Translate a datum of type oid
//---------------------------------------------------------------------------
CDXLDatum *
CTranslatorScalarToDXL::PdxldatumOid
(
IMemoryPool *pmp,
const IMDType *pmdtype,
BOOL fNull,
ULONG , //ulLen,
Datum datum
)
{
GPOS_ASSERT(pmdtype->FByValue());
CMDIdGPDB *pmdidMDC = CMDIdGPDB::PmdidConvert(pmdtype->Pmdid());
CMDIdGPDB *pmdid = GPOS_NEW(pmp) CMDIdGPDB(*pmdidMDC);
return GPOS_NEW(pmp) CDXLDatumOid(pmp, pmdid, fNull, gpdb::OidFromDatum(datum));
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorScalarToDXL::PdxldatumInt2
//
// @doc:
// Translate a datum of type int2
//---------------------------------------------------------------------------
CDXLDatum *
CTranslatorScalarToDXL::PdxldatumInt2
(
IMemoryPool *pmp,
const IMDType *pmdtype,
BOOL fNull,
ULONG , //ulLen,
Datum datum
)
{
GPOS_ASSERT(pmdtype->FByValue());
CMDIdGPDB *pmdidMDC = CMDIdGPDB::PmdidConvert(pmdtype->Pmdid());
CMDIdGPDB *pmdid = GPOS_NEW(pmp) CMDIdGPDB(*pmdidMDC);
return GPOS_NEW(pmp) CDXLDatumInt2(pmp, pmdid, fNull, gpdb::SInt16FromDatum(datum));
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorScalarToDXL::PdxldatumInt4
//
// @doc:
// Translate a datum of type int4
//---------------------------------------------------------------------------
CDXLDatum *
CTranslatorScalarToDXL::PdxldatumInt4
(
IMemoryPool *pmp,
const IMDType *pmdtype,
BOOL fNull,
ULONG , //ulLen,
Datum datum
)
{
GPOS_ASSERT(pmdtype->FByValue());
CMDIdGPDB *pmdidMDC = CMDIdGPDB::PmdidConvert(pmdtype->Pmdid());
CMDIdGPDB *pmdid = GPOS_NEW(pmp) CMDIdGPDB(*pmdidMDC);
return GPOS_NEW(pmp) CDXLDatumInt4(pmp, pmdid, fNull, gpdb::IInt32FromDatum(datum));
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorScalarToDXL::PdxldatumInt8
//
// @doc:
// Translate a datum of type int8
//---------------------------------------------------------------------------
CDXLDatum *
CTranslatorScalarToDXL::PdxldatumInt8
(
IMemoryPool *pmp,
const IMDType *pmdtype,
BOOL fNull,
ULONG , //ulLen,
Datum datum
)
{
GPOS_ASSERT(pmdtype->FByValue());
CMDIdGPDB *pmdidMDC = CMDIdGPDB::PmdidConvert(pmdtype->Pmdid());
CMDIdGPDB *pmdid = GPOS_NEW(pmp) CMDIdGPDB(*pmdidMDC);
return GPOS_NEW(pmp) CDXLDatumInt8(pmp, pmdid, fNull, gpdb::LlInt64FromDatum(datum));
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorScalarToDXL::DValue
//
// @doc:
// Extract the double value of the datum
//---------------------------------------------------------------------------
CDouble
CTranslatorScalarToDXL::DValue
(
IMDId *pmdid,
BOOL fNull,
BYTE *pba,
Datum datum
)
{
GPOS_ASSERT(CMDTypeGenericGPDB::FHasByteDoubleMapping(pmdid));
double d = 0;
if (fNull)
{
return CDouble(d);
}
if (pmdid->FEquals(&CMDIdGPDB::m_mdidNumeric))
{
Numeric num = (Numeric) (pba);
if (NUMERIC_IS_NAN(num))
{
// in GPDB NaN is considered the largest numeric number.
return CDouble(GPOS_FP_ABS_MAX);
}
d = gpdb::DNumericToDoubleNoOverflow(num);
}
else if (pmdid->FEquals(&CMDIdGPDB::m_mdidFloat4))
{
float4 f = gpdb::FpFloat4FromDatum(datum);
if (isnan(f))
{
d = GPOS_FP_ABS_MAX;
}
else
{
d = (double) f;
}
}
else if (pmdid->FEquals(&CMDIdGPDB::m_mdidFloat8))
{
d = gpdb::DFloat8FromDatum(datum);
if (isnan(d))
{
d = GPOS_FP_ABS_MAX;
}
}
else if (CMDTypeGenericGPDB::FTimeRelatedType(pmdid))
{
d = gpdb::DConvertTimeValueToScalar(datum, CMDIdGPDB::PmdidConvert(pmdid)->OidObjectId());
}
else if (CMDTypeGenericGPDB::FNetworkRelatedType(pmdid))
{
d = gpdb::DConvertNetworkToScalar(datum, CMDIdGPDB::PmdidConvert(pmdid)->OidObjectId());
}
return CDouble(d);
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorScalarToDXL::Pba
//
// @doc:
// Extract the byte array value of the datum. The result is NULL if datum is NULL
//---------------------------------------------------------------------------
BYTE *
CTranslatorScalarToDXL::Pba
(
IMemoryPool *pmp,
const IMDType *pmdtype,
BOOL fNull,
ULONG ulLen,
Datum datum
)
{
ULONG ulLength = 0;
BYTE *pba = NULL;
if (fNull)
{
return pba;
}
ulLength = (ULONG) gpdb::SDatumSize(datum, pmdtype->FByValue(), ulLen);
GPOS_ASSERT(ulLength > 0);
pba = GPOS_NEW_ARRAY(pmp, BYTE, ulLength);
if (pmdtype->FByValue())
{
GPOS_ASSERT(ulLength <= ULONG(sizeof(Datum)));
clib::PvMemCpy(pba, &datum, ulLength);
}
else
{
clib::PvMemCpy(pba, gpdb::PvPointerFromDatum(datum), ulLength);
}
return pba;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorScalarToDXL::LValue
//
// @doc:
// Extract the long int value of a datum
//---------------------------------------------------------------------------
LINT
CTranslatorScalarToDXL::LValue
(
IMDId *pmdid,
BOOL fNull,
BYTE *pba,
ULONG ulLength
)
{
GPOS_ASSERT(CMDTypeGenericGPDB::FHasByteLintMapping(pmdid));
LINT lValue = 0;
if (fNull)
{
return lValue;
}
if (pmdid->FEquals(&CMDIdGPDB::m_mdidCash))
{
// cash is a pass-by-ref type
Datum datumConstVal = (Datum) 0;
clib::PvMemCpy(&datumConstVal, pba, ulLength);
// Date is internally represented as an int32
lValue = (LINT) (gpdb::IInt32FromDatum(datumConstVal));
}
else
{
// use hash value
ULONG ulHash = 0;
if (fNull)
{
ulHash = gpos::UlHash<ULONG>(&ulHash);
}
else
{
ulHash = gpos::UlHash<BYTE>(pba);
for (ULONG ul = 1; ul < ulLength; ul++)
{
ulHash = gpos::UlCombineHashes(ulHash, gpos::UlHash<BYTE>(&pba[ul]));
}
}
lValue = (LINT) (ulHash / 4);
}
return lValue;
}
//---------------------------------------------------------------------------
// @function:
// CTranslatorScalarToDXL::Pdatum
//
// @doc:
// Create IDatum from GPDB datum
//---------------------------------------------------------------------------
IDatum *
CTranslatorScalarToDXL::Pdatum
(
IMemoryPool *pmp,
const IMDType *pmdtype,
BOOL fNull,
Datum datum
)
{
ULONG ulLength = pmdtype->UlLength();
if (!pmdtype->FByValue() && !fNull)
{
INT iLen = dynamic_cast<const CMDTypeGenericGPDB *>(pmdtype)->ILength();
ulLength = (ULONG) gpdb::SDatumSize(datum, pmdtype->FByValue(), iLen);
}
GPOS_ASSERT(fNull || ulLength > 0);
CDXLDatum *pdxldatum = CTranslatorScalarToDXL::Pdxldatum(pmp, pmdtype, fNull, ulLength, datum);
IDatum *pdatum = pmdtype->Pdatum(pmp, pdxldatum);
pdxldatum->Release();
return pdatum;
}
// EOF