//--------------------------------------------------------------------------- // Greenplum Database // Copyright (C) 2011 Greenplum, Inc. // // @filename: // CTranslatorScalarToDXL.cpp // // @doc: // Implementing the methods needed to translate a GPDB Scalar Operation (in a Query / PlStmt object) // into a DXL trees // // @test: // //--------------------------------------------------------------------------- extern "C" { #include "postgres.h" #include "nodes/parsenodes.h" #include "nodes/plannodes.h" #include "nodes/primnodes.h" #include "utils/date.h" #include "utils/datum.h" #include "utils/guc.h" #include "utils/uuid.h" /* PG18 compat: GPDB-only GUC and constants */ #ifndef optimizer_enable_query_parameter static const bool optimizer_enable_query_parameter = false; #endif } #include #include "gpos/base.h" #include "gpos/common/CAutoP.h" #include "gpos/string/CWStringDynamic.h" #include "gpopt/base/CUtils.h" #include "gpopt/gpdbwrappers.h" #include "gpopt/mdcache/CMDAccessor.h" #include "gpopt/translate/CCTEListEntry.h" #include "gpopt/translate/CTranslatorQueryToDXL.h" #include "gpopt/translate/CTranslatorScalarToDXL.h" #include "gpopt/translate/CTranslatorUtils.h" #include "naucrates/dxl/CDXLUtils.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/dxl/operators/CDXLScalarAggref.h" #include "naucrates/dxl/operators/CDXLScalarArray.h" #include "naucrates/dxl/operators/CDXLScalarArrayCoerceExpr.h" #include "naucrates/dxl/operators/CDXLScalarArrayComp.h" #include "naucrates/dxl/operators/CDXLScalarArrayRef.h" #include "naucrates/dxl/operators/CDXLScalarBooleanTest.h" #include "naucrates/dxl/operators/CDXLScalarCaseTest.h" #include "naucrates/dxl/operators/CDXLScalarCast.h" #include "naucrates/dxl/operators/CDXLScalarCoalesce.h" #include "naucrates/dxl/operators/CDXLScalarCoerceToDomain.h" #include "naucrates/dxl/operators/CDXLScalarCoerceViaIO.h" #include "naucrates/dxl/operators/CDXLScalarDistinctComp.h" #include "naucrates/dxl/operators/CDXLScalarFieldSelect.h" #include "naucrates/dxl/operators/CDXLScalarFilter.h" #include "naucrates/dxl/operators/CDXLScalarFuncExpr.h" #include "naucrates/dxl/operators/CDXLScalarIdent.h" #include "naucrates/dxl/operators/CDXLScalarIfStmt.h" #include "naucrates/dxl/operators/CDXLScalarJoinFilter.h" #include "naucrates/dxl/operators/CDXLScalarMinMax.h" #include "naucrates/dxl/operators/CDXLScalarNullIf.h" #include "naucrates/dxl/operators/CDXLScalarNullTest.h" #include "naucrates/dxl/operators/CDXLScalarOneTimeFilter.h" #include "naucrates/dxl/operators/CDXLScalarOpExpr.h" #include "naucrates/dxl/operators/CDXLScalarParam.h" #include "naucrates/dxl/operators/CDXLScalarProjElem.h" #include "naucrates/dxl/operators/CDXLScalarSortGroupClause.h" #include "naucrates/dxl/operators/CDXLScalarSubquery.h" #include "naucrates/dxl/operators/CDXLScalarSubqueryAll.h" #include "naucrates/dxl/operators/CDXLScalarSubqueryAny.h" #include "naucrates/dxl/operators/CDXLScalarSubqueryExists.h" #include "naucrates/dxl/operators/CDXLScalarSwitch.h" #include "naucrates/dxl/operators/CDXLScalarSwitchCase.h" #include "naucrates/dxl/operators/CDXLScalarValuesList.h" #include "naucrates/dxl/operators/CDXLScalarWindowFrameEdge.h" #include "naucrates/dxl/operators/CDXLScalarWindowRef.h" #include "naucrates/dxl/xml/dxltokens.h" #include "naucrates/exception.h" #include "naucrates/md/CMDTypeGenericGPDB.h" #include "naucrates/md/IMDAggregate.h" #include "naucrates/md/IMDScalarOp.h" #include "naucrates/md/IMDType.h" using namespace gpdxl; using namespace gpopt; //--------------------------------------------------------------------------- // @function: // CTranslatorScalarToDXL::CTranslatorScalarToDXL // // @doc: // Ctor //--------------------------------------------------------------------------- CTranslatorScalarToDXL::CTranslatorScalarToDXL(CContextQueryToDXL *context, CMDAccessor *md_accessor, ULONG query_level, HMUlCTEListEntry *cte_entries, CDXLNodeArray *cte_dxlnode_array) : m_context(context), m_mp(context->m_mp), m_md_accessor(md_accessor), m_query_level(query_level), m_op_type(EpspotNone), m_cte_entries(cte_entries), m_cte_producers(cte_dxlnode_array) { } //--------------------------------------------------------------------------- // @function: // CTranslatorScalarToDXL::CTranslatorScalarToDXL // // @doc: // Private constructor for TranslateStandaloneExprToDXL //--------------------------------------------------------------------------- CTranslatorScalarToDXL::CTranslatorScalarToDXL(CMemoryPool *mp, CMDAccessor *mda) : m_context(nullptr), m_mp(mp), m_md_accessor(mda), m_query_level(0), m_op_type(EpspotNone), m_cte_entries(nullptr), m_cte_producers(nullptr) { } //--------------------------------------------------------------------------- // @function: // CTranslatorScalarToDXL::CreateSubqueryTranslator // // @doc: // Construct a new CTranslatorQueryToDXL object, for translating // a subquery of the current query. //--------------------------------------------------------------------------- CTranslatorQueryToDXL * CTranslatorScalarToDXL::CreateSubqueryTranslator( Query *subquery, const CMappingVarColId *var_colid_mapping) { if (m_context == nullptr) { // This is a stand-alone expression. Subqueries are not allowed. GPOS_RAISE(gpdxl::ExmaDXL, gpdxl::ExmiQuery2DXLError, GPOS_WSZ_LIT("Subquery in a stand-alone expression")); } return GPOS_NEW(m_context->m_mp) CTranslatorQueryToDXL(m_context, m_md_accessor, var_colid_mapping, subquery, m_query_level + 1, false, // is_top_query_dml m_cte_entries); } CDXLNode * CTranslatorScalarToDXL::TranslateStandaloneExprToDXL( CMemoryPool *mp, CMDAccessor *mda, const CMappingVarColId *var_colid_mapping, const Expr *expr) { CTranslatorScalarToDXL scalar_translator(mp, mda); return scalar_translator.TranslateScalarToDXL(expr, var_colid_mapping); } //--------------------------------------------------------------------------- // @function: // CTranslatorScalarToDXL::EdxlbooltypeFromGPDBBoolType // // @doc: // Return the EdxlBoolExprType for a given GPDB BoolExprType //--------------------------------------------------------------------------- EdxlBoolExprType CTranslatorScalarToDXL::EdxlbooltypeFromGPDBBoolType(BoolExprType boolexprtype) { static ULONG mapping[][2] = { {NOT_EXPR, Edxlnot}, {AND_EXPR, Edxland}, {OR_EXPR, Edxlor}, }; EdxlBoolExprType type = EdxlBoolExprTypeSentinel; const ULONG arity = GPOS_ARRAY_SIZE(mapping); for (ULONG ul = 0; ul < arity; ul++) { ULONG *elem = mapping[ul]; if ((ULONG) boolexprtype == elem[0]) { type = (EdxlBoolExprType) elem[1]; break; } } GPOS_ASSERT(EdxlBoolExprTypeSentinel != type && "Invalid bool expr type"); return type; } //--------------------------------------------------------------------------- // @function: // CTranslatorScalarToDXL::TranslateVarToDXL // // @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::TranslateVarToDXL( const Expr *expr, const CMappingVarColId *var_colid_mapping) { GPOS_ASSERT(IsA(expr, Var)); const Var *var = (Var *) expr; if (var->varattno == 0) { GPOS_RAISE(gpdxl::ExmaDXL, gpdxl::ExmiQuery2DXLUnsupportedFeature, GPOS_WSZ_LIT("Whole-row variable")); } // column name const CWStringBase *str = var_colid_mapping->GetOptColName(m_query_level, var, m_op_type); // column id ULONG id; if (var->varattno != 0 || EpspotIndexScan == m_op_type || EpspotIndexOnlyScan == m_op_type) { id = var_colid_mapping->GetColId(m_query_level, var, m_op_type); } else { if (m_context == nullptr) { GPOS_RAISE( gpdxl::ExmaDXL, gpdxl::ExmiQuery2DXLUnsupportedFeature, GPOS_WSZ_LIT( "Var with no existing mapping in a stand-alone context")); } id = m_context->m_colid_counter->next_id(); } CMDName *mdname = GPOS_NEW(m_mp) CMDName(m_mp, str); // create a column reference for the given var CDXLColRef *dxl_colref = GPOS_NEW(m_mp) CDXLColRef( mdname, id, GPOS_NEW(m_mp) CMDIdGPDB(IMDId::EmdidGeneral, var->vartype), var->vartypmod); // create the scalar ident operator CDXLScalarIdent *scalar_ident = GPOS_NEW(m_mp) CDXLScalarIdent(m_mp, dxl_colref); // create the DXL node holding the scalar ident operator CDXLNode *dxlnode = GPOS_NEW(m_mp) CDXLNode(m_mp, scalar_ident); return dxlnode; } //--------------------------------------------------------------------------- // @function: // CTranslatorScalarToDXL::TranslateParamToDXL // // @doc: // Create a DXL node for a scalar param expression from a GPDB Param //--------------------------------------------------------------------------- CDXLNode * CTranslatorScalarToDXL::TranslateParamToDXL( const Expr *expr, const CMappingVarColId *var_colid_mapping) { GPOS_ASSERT(IsA(expr, Param)); const Param *param = (Param *) expr; CDXLScalarParam *scalar_param = GPOS_NEW(m_mp) CDXLScalarParam( m_mp, param->paramid, GPOS_NEW(m_mp) CMDIdGPDB(IMDId::EmdidGeneral, param->paramtype), param->paramtypmod); // create the DXL node holding the scalar param operator CDXLNode *dxlnode = GPOS_NEW(m_mp) CDXLNode(m_mp, scalar_param); return dxlnode; } //--------------------------------------------------------------------------- // @function: // CTranslatorScalarToDXL::TranslateScalarToDXL // // @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::TranslateScalarToDXL( const Expr *expr, const CMappingVarColId *var_colid_mapping) { NodeTag tag = expr->type; switch (tag) { default: { // This expression is not supported. Check for a few common cases, to // give a better message. CHAR *str = (CHAR *) gpdb::NodeToString(const_cast(expr)); CWStringDynamic *wcstr = CDXLUtils::CreateDynamicStringFromCharArray(m_mp, str); GPOS_RAISE(gpdxl::ExmaDXL, gpdxl::ExmiQuery2DXLUnsupportedFeature, wcstr->GetBuffer()); } case T_Param: { if (!optimizer_enable_query_parameter) { GPOS_RAISE( gpdxl::ExmaDXL, gpdxl::ExmiQuery2DXLUnsupportedFeature, GPOS_WSZ_LIT( "Use optimizer_enable_query_parameter to enable Orca with query parameters")); } return CTranslatorScalarToDXL::TranslateParamToDXL( expr, var_colid_mapping); } case T_Var: { return CTranslatorScalarToDXL::TranslateVarToDXL(expr, var_colid_mapping); } case T_OpExpr: { return CTranslatorScalarToDXL::TranslateOpExprToDXL( expr, var_colid_mapping); } case T_ScalarArrayOpExpr: { return CTranslatorScalarToDXL::TranslateScalarArrayOpExprToDXL( expr, var_colid_mapping); } case T_DistinctExpr: { return CTranslatorScalarToDXL::TranslateDistinctExprToDXL( expr, var_colid_mapping); } case T_Const: { return CTranslatorScalarToDXL::TranslateConstToDXL( expr, var_colid_mapping); } case T_BoolExpr: { return CTranslatorScalarToDXL::TranslateBoolExprToDXL( expr, var_colid_mapping); } case T_BooleanTest: { return CTranslatorScalarToDXL::TranslateBooleanTestToDXL( expr, var_colid_mapping); } case T_CaseExpr: { return CTranslatorScalarToDXL::TranslateCaseExprToDXL( expr, var_colid_mapping); } case T_CaseTestExpr: { return CTranslatorScalarToDXL::TranslateCaseTestExprToDXL( expr, var_colid_mapping); } case T_CoalesceExpr: { return CTranslatorScalarToDXL::TranslateCoalesceExprToDXL( expr, var_colid_mapping); } case T_MinMaxExpr: { return CTranslatorScalarToDXL::TranslateMinMaxExprToDXL( expr, var_colid_mapping); } case T_FuncExpr: { return CTranslatorScalarToDXL::TranslateFuncExprToDXL( expr, var_colid_mapping); } case T_Aggref: { return CTranslatorScalarToDXL::TranslateAggrefToDXL( expr, var_colid_mapping); } case T_WindowFunc: { return CTranslatorScalarToDXL::TranslateWindowFuncToDXL( expr, var_colid_mapping); } case T_NullTest: { return CTranslatorScalarToDXL::TranslateNullTestToDXL( expr, var_colid_mapping); } case T_NullIfExpr: { return CTranslatorScalarToDXL::TranslateNullIfExprToDXL( expr, var_colid_mapping); } case T_RelabelType: { return CTranslatorScalarToDXL::TranslateRelabelTypeToDXL( expr, var_colid_mapping); } case T_CoerceToDomain: { return CTranslatorScalarToDXL::TranslateCoerceToDomainToDXL( expr, var_colid_mapping); } case T_CoerceViaIO: { return CTranslatorScalarToDXL::TranslateCoerceViaIOToDXL( expr, var_colid_mapping); } case T_ArrayCoerceExpr: { return CTranslatorScalarToDXL::TranslateArrayCoerceExprToDXL( expr, var_colid_mapping); } case T_SubLink: { return CTranslatorScalarToDXL::TranslateSubLinkToDXL( expr, var_colid_mapping); } case T_ArrayExpr: { return CTranslatorScalarToDXL::TranslateArrayExprToDXL( expr, var_colid_mapping); } case T_SubscriptingRef: { return CTranslatorScalarToDXL::TranslateArrayRefToDXL( expr, var_colid_mapping); } case T_SortGroupClause: { return CTranslatorScalarToDXL::TranslateSortGroupClauseToDXL( expr, var_colid_mapping); } case T_FieldSelect: { return CTranslatorScalarToDXL::TranslateFieldSelectToDXL( expr, var_colid_mapping); } } } //--------------------------------------------------------------------------- // @function: // CTranslatorScalarToDXL::TranslateDistinctExprToDXL // // @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::TranslateDistinctExprToDXL( const Expr *expr, const CMappingVarColId *var_colid_mapping) { GPOS_ASSERT(IsA(expr, DistinctExpr)); const DistinctExpr *distinct_expr = (DistinctExpr *) expr; // process arguments of op expr GPOS_ASSERT(2 == gpdb::ListLength(distinct_expr->args)); CDXLNode *left_node = TranslateScalarToDXL( (Expr *) gpdb::ListNth(distinct_expr->args, 0), var_colid_mapping); CDXLNode *right_node = TranslateScalarToDXL( (Expr *) gpdb::ListNth(distinct_expr->args, 1), var_colid_mapping); GPOS_ASSERT(nullptr != left_node); GPOS_ASSERT(nullptr != right_node); CDXLScalarDistinctComp *dxlop = GPOS_NEW(m_mp) CDXLScalarDistinctComp( m_mp, GPOS_NEW(m_mp) CMDIdGPDB(IMDId::EmdidGeneral, distinct_expr->opno)); // create the DXL node holding the scalar distinct comparison operator CDXLNode *dxlnode = GPOS_NEW(m_mp) CDXLNode(m_mp, dxlop); // add children in the right order dxlnode->AddChild(left_node); dxlnode->AddChild(right_node); return dxlnode; } //--------------------------------------------------------------------------- // @function: // CTranslatorScalarToDXL::CreateScalarCmpFromOpExpr // // @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::CreateScalarCmpFromOpExpr( const Expr *expr, const CMappingVarColId *var_colid_mapping) { GPOS_ASSERT(IsA(expr, OpExpr)); const OpExpr *op_expr = (OpExpr *) expr; // process arguments of op expr GPOS_ASSERT(2 == gpdb::ListLength(op_expr->args)); Expr *left_expr = (Expr *) gpdb::ListNth(op_expr->args, 0); Expr *right_expr = (Expr *) gpdb::ListNth(op_expr->args, 1); CDXLNode *left_node = TranslateScalarToDXL(left_expr, var_colid_mapping); CDXLNode *right_node = TranslateScalarToDXL(right_expr, var_colid_mapping); GPOS_ASSERT(nullptr != left_node); GPOS_ASSERT(nullptr != right_node); CMDIdGPDB *mdid = GPOS_NEW(m_mp) CMDIdGPDB(IMDId::EmdidGeneral, op_expr->opno); // get operator name const CWStringConst *str = GetDXLArrayCmpType(mdid); CDXLScalarComp *dxlop = GPOS_NEW(m_mp) CDXLScalarComp( m_mp, mdid, GPOS_NEW(m_mp) CWStringConst(m_mp, str->GetBuffer())); // create the DXL node holding the scalar comparison operator CDXLNode *dxlnode = GPOS_NEW(m_mp) CDXLNode(m_mp, dxlop); // add children in the right order dxlnode->AddChild(left_node); dxlnode->AddChild(right_node); return dxlnode; } //--------------------------------------------------------------------------- // @function: // CTranslatorScalarToDXL::TranslateOpExprToDXL // // @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::TranslateOpExprToDXL( const Expr *expr, const CMappingVarColId *var_colid_mapping) { GPOS_ASSERT(IsA(expr, OpExpr)); const OpExpr *op_expr = (OpExpr *) expr; // check if this is a scalar comparison CMDIdGPDB *return_type_mdid = GPOS_NEW(m_mp) CMDIdGPDB(IMDId::EmdidGeneral, ((OpExpr *) expr)->opresulttype); const IMDType *md_type = m_md_accessor->RetrieveType(return_type_mdid); const ULONG num_args = gpdb::ListLength(op_expr->args); if (IMDType::EtiBool == md_type->GetDatumType() && 2 == num_args) { return_type_mdid->Release(); return CreateScalarCmpFromOpExpr(expr, var_colid_mapping); } // get operator name and id IMDId *mdid = GPOS_NEW(m_mp) CMDIdGPDB(IMDId::EmdidGeneral, op_expr->opno); const CWStringConst *str = GetDXLArrayCmpType(mdid); CDXLScalarOpExpr *dxlop = GPOS_NEW(m_mp) CDXLScalarOpExpr(m_mp, mdid, return_type_mdid, GPOS_NEW(m_mp) CWStringConst(m_mp, str->GetBuffer())); // create the DXL node holding the scalar opexpr CDXLNode *dxlnode = GPOS_NEW(m_mp) CDXLNode(m_mp, dxlop); // process arguments TranslateScalarChildren(dxlnode, op_expr->args, var_colid_mapping); return dxlnode; } //--------------------------------------------------------------------------- // @function: // CTranslatorScalarToDXL::TranslateNullIfExprToDXL // // @doc: // Create a DXL node for a scalar nullif from a GPDB Expr //--------------------------------------------------------------------------- CDXLNode * CTranslatorScalarToDXL::TranslateNullIfExprToDXL( const Expr *expr, const CMappingVarColId *var_colid_mapping) { GPOS_ASSERT(IsA(expr, NullIfExpr)); const NullIfExpr *null_if_expr = (NullIfExpr *) expr; GPOS_ASSERT(2 == gpdb::ListLength(null_if_expr->args)); CDXLScalarNullIf *dxlop = GPOS_NEW(m_mp) CDXLScalarNullIf( m_mp, GPOS_NEW(m_mp) CMDIdGPDB(IMDId::EmdidGeneral, null_if_expr->opno), GPOS_NEW(m_mp) CMDIdGPDB(IMDId::EmdidGeneral, null_if_expr->opresulttype)); CDXLNode *dxlnode = GPOS_NEW(m_mp) CDXLNode(m_mp, dxlop); // process arguments TranslateScalarChildren(dxlnode, null_if_expr->args, var_colid_mapping); return dxlnode; } //--------------------------------------------------------------------------- // @function: // CTranslatorScalarToDXL::TranslateScalarArrayOpExprToDXL // // @doc: // Create a DXL node for a scalar array expression from a GPDB OpExpr //--------------------------------------------------------------------------- CDXLNode * CTranslatorScalarToDXL::TranslateScalarArrayOpExprToDXL( const Expr *expr, const CMappingVarColId *var_colid_mapping) { return CreateScalarArrayCompFromExpr(expr, var_colid_mapping); } //--------------------------------------------------------------------------- // @function: // CTranslatorScalarToDXL::CreateScalarArrayCompFromExpr // // @doc: // Create a DXL node for a scalar array comparison from a GPDB OpExpr //--------------------------------------------------------------------------- CDXLNode * CTranslatorScalarToDXL::CreateScalarArrayCompFromExpr( const Expr *expr, const CMappingVarColId *var_colid_mapping) { GPOS_ASSERT(IsA(expr, ScalarArrayOpExpr)); const ScalarArrayOpExpr *scalar_array_op_expr = (ScalarArrayOpExpr *) expr; // process arguments of op expr GPOS_ASSERT(2 == gpdb::ListLength(scalar_array_op_expr->args)); Expr *left_expr = (Expr *) gpdb::ListNth(scalar_array_op_expr->args, 0); CDXLNode *left_node = TranslateScalarToDXL(left_expr, var_colid_mapping); Expr *right_expr = (Expr *) gpdb::ListNth(scalar_array_op_expr->args, 1); // If the argument array is an array Const, try to transform it to an // ArrayExpr, to allow ORCA to optimize it better. (ORCA knows how to // extract elements of an ArrayExpr, but doesn't currently know how // to do it from an array-typed Const.) if (IsA(right_expr, Const)) { right_expr = gpdb::TransformArrayConstToArrayExpr((Const *) right_expr); } CDXLNode *right_node = TranslateScalarToDXL(right_expr, var_colid_mapping); GPOS_ASSERT(nullptr != left_node); GPOS_ASSERT(nullptr != right_node); // get operator name CMDIdGPDB *mdid_op = GPOS_NEW(m_mp) CMDIdGPDB(IMDId::EmdidGeneral, scalar_array_op_expr->opno); const IMDScalarOp *md_scalar_op = m_md_accessor->RetrieveScOp(mdid_op); mdid_op->Release(); const CWStringConst *op_name = md_scalar_op->Mdname().GetMDName(); GPOS_ASSERT(nullptr != op_name); EdxlArrayCompType type = Edxlarraycomptypeany; if (!scalar_array_op_expr->useOr) { type = Edxlarraycomptypeall; } CDXLScalarArrayComp *dxlop = GPOS_NEW(m_mp) CDXLScalarArrayComp( m_mp, GPOS_NEW(m_mp) CMDIdGPDB(IMDId::EmdidGeneral, scalar_array_op_expr->opno), GPOS_NEW(m_mp) CWStringConst(m_mp, op_name->GetBuffer()), type); // create the DXL node holding the scalar opexpr CDXLNode *dxlnode = GPOS_NEW(m_mp) CDXLNode(m_mp, dxlop); // add children in the right order dxlnode->AddChild(left_node); dxlnode->AddChild(right_node); return dxlnode; } //--------------------------------------------------------------------------- // @function: // CTranslatorScalarToDXL::TranslateConstToDXL // // @doc: // Create a DXL node for a scalar const value from a GPDB Const //--------------------------------------------------------------------------- CDXLNode * CTranslatorScalarToDXL::TranslateConstToDXL( const Expr *expr, const CMappingVarColId * // var_colid_mapping ) { GPOS_ASSERT(IsA(expr, Const)); const Const *constant = (Const *) expr; CDXLNode *dxlnode = GPOS_NEW(m_mp) CDXLNode(m_mp, GPOS_NEW(m_mp) CDXLScalarConstValue( m_mp, TranslateConstToDXL(constant))); return dxlnode; } //--------------------------------------------------------------------------- // @function: // CTranslatorScalarToDXL::TranslateConstToDXL // // @doc: // Create a DXL datum from a GPDB Const //--------------------------------------------------------------------------- CDXLDatum * CTranslatorScalarToDXL::TranslateConstToDXL(CMemoryPool *mp, CMDAccessor *mda, const Const *constant) { CMDIdGPDB *mdid = GPOS_NEW(mp) CMDIdGPDB(IMDId::EmdidGeneral, constant->consttype); const IMDType *md_type = mda->RetrieveType(mdid); mdid->Release(); // translate gpdb datum into a DXL datum CDXLDatum *datum_dxl = CTranslatorScalarToDXL::TranslateDatumToDXL( mp, md_type, constant->consttypmod, constant->constisnull, constant->constlen, constant->constvalue); return datum_dxl; } //--------------------------------------------------------------------------- // @function: // CTranslatorScalarToDXL::TranslateConstToDXL // // @doc: // Create a DXL datum from a GPDB Const //--------------------------------------------------------------------------- CDXLDatum * CTranslatorScalarToDXL::TranslateConstToDXL(const Const *constant) const { return TranslateConstToDXL(m_mp, m_md_accessor, constant); } //--------------------------------------------------------------------------- // @function: // CTranslatorScalarToDXL::TranslateBoolExprToDXL // // @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::TranslateBoolExprToDXL( const Expr *expr, const CMappingVarColId *var_colid_mapping) { GPOS_ASSERT(IsA(expr, BoolExpr)); const BoolExpr *bool_expr = (BoolExpr *) expr; GPOS_ASSERT(0 < gpdb::ListLength(bool_expr->args)); EdxlBoolExprType type = EdxlbooltypeFromGPDBBoolType(bool_expr->boolop); GPOS_ASSERT(EdxlBoolExprTypeSentinel != type); // create the DXL node holding the scalar boolean operator CDXLNode *dxlnode = GPOS_NEW(m_mp) CDXLNode(m_mp, GPOS_NEW(m_mp) CDXLScalarBoolExpr(m_mp, type)); ULONG count = gpdb::ListLength(bool_expr->args); if ((NOT_EXPR != bool_expr->boolop) && (2 > count)) { GPOS_RAISE( gpdxl::ExmaDXL, gpdxl::ExmiQuery2DXLUnsupportedFeature, GPOS_WSZ_LIT( "Boolean Expression (OR / AND): Incorrect Number of Children ")); } else if ((NOT_EXPR == bool_expr->boolop) && (1 != count)) { GPOS_RAISE( gpdxl::ExmaDXL, gpdxl::ExmiQuery2DXLUnsupportedFeature, GPOS_WSZ_LIT( "Boolean Expression (NOT): Incorrect Number of Children ")); } TranslateScalarChildren(dxlnode, bool_expr->args, var_colid_mapping); return dxlnode; } //--------------------------------------------------------------------------- // @function: // CTranslatorScalarToDXL::TranslateBooleanTestToDXL // // @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::TranslateBooleanTestToDXL( const Expr *expr, const CMappingVarColId *var_colid_mapping) { GPOS_ASSERT(IsA(expr, BooleanTest)); const BooleanTest *boolean_test = (BooleanTest *) expr; GPOS_ASSERT(nullptr != boolean_test->arg); static ULONG mapping[][2] = { {IS_TRUE, EdxlbooleantestIsTrue}, {IS_NOT_TRUE, EdxlbooleantestIsNotTrue}, {IS_FALSE, EdxlbooleantestIsFalse}, {IS_NOT_FALSE, EdxlbooleantestIsNotFalse}, {IS_UNKNOWN, EdxlbooleantestIsUnknown}, {IS_NOT_UNKNOWN, EdxlbooleantestIsNotUnknown}, }; EdxlBooleanTestType type = EdxlbooleantestSentinel; const ULONG arity = GPOS_ARRAY_SIZE(mapping); for (ULONG ul = 0; ul < arity; ul++) { ULONG *elem = mapping[ul]; if ((ULONG) boolean_test->booltesttype == elem[0]) { type = (EdxlBooleanTestType) elem[1]; break; } } GPOS_ASSERT(EdxlbooleantestSentinel != type && "Invalid boolean test type"); // create the DXL node holding the scalar boolean test operator CDXLNode *dxlnode = GPOS_NEW(m_mp) CDXLNode(m_mp, GPOS_NEW(m_mp) CDXLScalarBooleanTest(m_mp, type)); CDXLNode *dxlnode_arg = TranslateScalarToDXL(boolean_test->arg, var_colid_mapping); GPOS_ASSERT(nullptr != dxlnode_arg); dxlnode->AddChild(dxlnode_arg); return dxlnode; } //--------------------------------------------------------------------------- // @function: // CTranslatorScalarToDXL::TranslateNullTestToDXL // // @doc: // Create a DXL node for a scalar nulltest expression from a GPDB OpExpr //--------------------------------------------------------------------------- CDXLNode * CTranslatorScalarToDXL::TranslateNullTestToDXL( const Expr *expr, const CMappingVarColId *var_colid_mapping) { GPOS_ASSERT(IsA(expr, NullTest)); const NullTest *null_test = (NullTest *) expr; GPOS_ASSERT(nullptr != null_test->arg); CDXLNode *child_node = TranslateScalarToDXL(null_test->arg, var_colid_mapping); GPOS_ASSERT(nullptr != child_node); GPOS_ASSERT(IS_NULL == null_test->nulltesttype || IS_NOT_NULL == null_test->nulltesttype); BOOL is_null = false; if (IS_NULL == null_test->nulltesttype) { is_null = true; } // create the DXL node holding the scalar NullTest operator CDXLNode *dxlnode = GPOS_NEW(m_mp) CDXLNode(m_mp, GPOS_NEW(m_mp) CDXLScalarNullTest(m_mp, is_null)); dxlnode->AddChild(child_node); return dxlnode; } //--------------------------------------------------------------------------- // @function: // CTranslatorScalarToDXL::TranslateCoalesceExprToDXL // // @doc: // Create a DXL node for a coalesce function from a GPDB OpExpr //--------------------------------------------------------------------------- CDXLNode * CTranslatorScalarToDXL::TranslateCoalesceExprToDXL( const Expr *expr, const CMappingVarColId *var_colid_mapping) { GPOS_ASSERT(IsA(expr, CoalesceExpr)); CoalesceExpr *coalesce_expr = (CoalesceExpr *) expr; GPOS_ASSERT(nullptr != coalesce_expr->args); CDXLScalarCoalesce *dxlop = GPOS_NEW(m_mp) CDXLScalarCoalesce( m_mp, GPOS_NEW(m_mp) CMDIdGPDB(IMDId::EmdidGeneral, coalesce_expr->coalescetype)); CDXLNode *dxlnode = GPOS_NEW(m_mp) CDXLNode(m_mp, dxlop); TranslateScalarChildren(dxlnode, coalesce_expr->args, var_colid_mapping); return dxlnode; } //--------------------------------------------------------------------------- // @function: // CTranslatorScalarToDXL::TranslateMinMaxExprToDXL // // @doc: // Create a DXL node for a min/max operator from a GPDB OpExpr //--------------------------------------------------------------------------- CDXLNode * CTranslatorScalarToDXL::TranslateMinMaxExprToDXL( const Expr *expr, const CMappingVarColId *var_colid_mapping) { GPOS_ASSERT(IsA(expr, MinMaxExpr)); MinMaxExpr *min_max_expr = (MinMaxExpr *) expr; GPOS_ASSERT(nullptr != min_max_expr->args); CDXLScalarMinMax::EdxlMinMaxType min_max_type = CDXLScalarMinMax::EmmtSentinel; if (IS_GREATEST == min_max_expr->op) { min_max_type = CDXLScalarMinMax::EmmtMax; } else { GPOS_ASSERT(IS_LEAST == min_max_expr->op); min_max_type = CDXLScalarMinMax::EmmtMin; } CDXLScalarMinMax *dxlop = GPOS_NEW(m_mp) CDXLScalarMinMax( m_mp, GPOS_NEW(m_mp) CMDIdGPDB(IMDId::EmdidGeneral, min_max_expr->minmaxtype), min_max_type); CDXLNode *dxlnode = GPOS_NEW(m_mp) CDXLNode(m_mp, dxlop); TranslateScalarChildren(dxlnode, min_max_expr->args, var_colid_mapping); return dxlnode; } //--------------------------------------------------------------------------- // @function: // CTranslatorScalarToDXL::TranslateScalarChildren // // @doc: // Translate list elements and add them as children of the DXL node //--------------------------------------------------------------------------- void CTranslatorScalarToDXL::TranslateScalarChildren( CDXLNode *dxlnode, List *list, const CMappingVarColId *var_colid_mapping) { ListCell *lc = nullptr; ForEach(lc, list) { Expr *child_expr = (Expr *) lfirst(lc); CDXLNode *child_node = TranslateScalarToDXL(child_expr, var_colid_mapping); GPOS_ASSERT(nullptr != child_node); dxlnode->AddChild(child_node); } } //--------------------------------------------------------------------------- // @function: // CTranslatorScalarToDXL::TranslateCaseExprToDXL // // @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::TranslateCaseExprToDXL( const Expr *expr, const CMappingVarColId *var_colid_mapping) { GPOS_ASSERT(IsA(expr, CaseExpr)); const CaseExpr *case_expr = (CaseExpr *) expr; if (nullptr == case_expr->args) { GPOS_RAISE(gpdxl::ExmaDXL, gpdxl::ExmiQuery2DXLUnsupportedFeature, GPOS_WSZ_LIT("Case statement with no arguments")); return nullptr; } if (nullptr == case_expr->arg) { return CreateScalarIfStmtFromCaseExpr(case_expr, var_colid_mapping); } return CreateScalarSwitchFromCaseExpr(case_expr, var_colid_mapping); } //--------------------------------------------------------------------------- // @function: // CTranslatorScalarToDXL::CreateScalarSwitchFromCaseExpr // // @doc: // Create a DXL Switch node from a GPDB CaseExpr. // //--------------------------------------------------------------------------- CDXLNode * CTranslatorScalarToDXL::CreateScalarSwitchFromCaseExpr( const CaseExpr *case_expr, const CMappingVarColId *var_colid_mapping) { GPOS_ASSERT(nullptr != case_expr->arg); CDXLScalarSwitch *dxlop = GPOS_NEW(m_mp) CDXLScalarSwitch( m_mp, GPOS_NEW(m_mp) CMDIdGPDB(IMDId::EmdidGeneral, case_expr->casetype)); CDXLNode *switch_node = GPOS_NEW(m_mp) CDXLNode(m_mp, dxlop); // translate the switch expression CDXLNode *dxlnode_arg = TranslateScalarToDXL(case_expr->arg, var_colid_mapping); switch_node->AddChild(dxlnode_arg); // translate the cases ListCell *lc = nullptr; ForEach(lc, case_expr->args) { CaseWhen *expr = (CaseWhen *) lfirst(lc); CDXLScalarSwitchCase *swtich_case = GPOS_NEW(m_mp) CDXLScalarSwitchCase(m_mp); CDXLNode *switch_case_node = GPOS_NEW(m_mp) CDXLNode(m_mp, swtich_case); CDXLNode *cmp_expr_node = TranslateScalarToDXL(expr->expr, var_colid_mapping); GPOS_ASSERT(nullptr != cmp_expr_node); CDXLNode *result_node = TranslateScalarToDXL(expr->result, var_colid_mapping); GPOS_ASSERT(nullptr != result_node); switch_case_node->AddChild(cmp_expr_node); switch_case_node->AddChild(result_node); // add current case to switch node switch_node->AddChild(switch_case_node); } // translate the "else" clause if (nullptr != case_expr->defresult) { CDXLNode *default_result_node = TranslateScalarToDXL(case_expr->defresult, var_colid_mapping); GPOS_ASSERT(nullptr != default_result_node); switch_node->AddChild(default_result_node); } return switch_node; } //--------------------------------------------------------------------------- // @function: // CTranslatorScalarToDXL::TranslateCaseTestExprToDXL // // @doc: // Create a DXL node for a case test from a GPDB Expr //--------------------------------------------------------------------------- CDXLNode * CTranslatorScalarToDXL::TranslateCaseTestExprToDXL( const Expr *expr, const CMappingVarColId * //var_colid_mapping ) { GPOS_ASSERT(IsA(expr, CaseTestExpr)); const CaseTestExpr *case_test_expr = (CaseTestExpr *) expr; CDXLScalarCaseTest *dxlop = GPOS_NEW(m_mp) CDXLScalarCaseTest( m_mp, GPOS_NEW(m_mp) CMDIdGPDB(IMDId::EmdidGeneral, case_test_expr->typeId)); return GPOS_NEW(m_mp) CDXLNode(m_mp, dxlop); } //--------------------------------------------------------------------------- // @function: // CTranslatorScalarToDXL::CreateScalarIfStmtFromCaseExpr // // @doc: // Create a DXL If node from a GPDB CaseExpr //--------------------------------------------------------------------------- CDXLNode * CTranslatorScalarToDXL::CreateScalarIfStmtFromCaseExpr( const CaseExpr *case_expr, const CMappingVarColId *var_colid_mapping) { GPOS_ASSERT(nullptr == case_expr->arg); const ULONG when_clause_count = gpdb::ListLength(case_expr->args); CDXLNode *root_if_tree_node = nullptr; CDXLNode *cur_node = nullptr; for (ULONG ul = 0; ul < when_clause_count; ul++) { CDXLScalarIfStmt *if_stmt_new_dxl = GPOS_NEW(m_mp) CDXLScalarIfStmt( m_mp, GPOS_NEW(m_mp) CMDIdGPDB(IMDId::EmdidGeneral, case_expr->casetype)); CDXLNode *if_stmt_new_node = GPOS_NEW(m_mp) CDXLNode(m_mp, if_stmt_new_dxl); CaseWhen *expr = (CaseWhen *) gpdb::ListNth(case_expr->args, ul); GPOS_ASSERT(IsA(expr, CaseWhen)); CDXLNode *cond_node = TranslateScalarToDXL(expr->expr, var_colid_mapping); CDXLNode *result_node = TranslateScalarToDXL(expr->result, var_colid_mapping); GPOS_ASSERT(nullptr != cond_node); GPOS_ASSERT(nullptr != result_node); if_stmt_new_node->AddChild(cond_node); if_stmt_new_node->AddChild(result_node); if (nullptr == root_if_tree_node) { root_if_tree_node = if_stmt_new_node; } else { cur_node->AddChild(if_stmt_new_node); } cur_node = if_stmt_new_node; } if (nullptr != case_expr->defresult) { CDXLNode *default_result_node = TranslateScalarToDXL(case_expr->defresult, var_colid_mapping); GPOS_ASSERT(nullptr != default_result_node); cur_node->AddChild(default_result_node); } return root_if_tree_node; } //--------------------------------------------------------------------------- // @function: // CTranslatorScalarToDXL::TranslateRelabelTypeToDXL // // @doc: // Create a DXL node for a scalar RelabelType expression from a GPDB RelabelType //--------------------------------------------------------------------------- CDXLNode * CTranslatorScalarToDXL::TranslateRelabelTypeToDXL( const Expr *expr, const CMappingVarColId *var_colid_mapping) { GPOS_ASSERT(IsA(expr, RelabelType)); const RelabelType *relabel_type = (RelabelType *) expr; GPOS_ASSERT(nullptr != relabel_type->arg); CDXLNode *child_node = TranslateScalarToDXL(relabel_type->arg, var_colid_mapping); GPOS_ASSERT(nullptr != child_node); // create the DXL node holding the scalar boolean operator CDXLNode *dxlnode = GPOS_NEW(m_mp) CDXLNode( m_mp, GPOS_NEW(m_mp) CDXLScalarCast( m_mp, GPOS_NEW(m_mp) CMDIdGPDB(IMDId::EmdidGeneral, relabel_type->resulttype), GPOS_NEW(m_mp) CMDIdGPDB(IMDId::EmdidGeneral, 0) // casting function oid )); dxlnode->AddChild(child_node); return dxlnode; } //--------------------------------------------------------------------------- // @function: // CTranslatorScalarToDXL::TranslateCoerceToDomainToDXL // // @doc: // Create a DXL node for a scalar coerce expression from a // GPDB coerce expression //--------------------------------------------------------------------------- CDXLNode * CTranslatorScalarToDXL::TranslateCoerceToDomainToDXL( const Expr *expr, const CMappingVarColId *var_colid_mapping) { GPOS_ASSERT(IsA(expr, CoerceToDomain)); const CoerceToDomain *coerce = (CoerceToDomain *) expr; GPOS_ASSERT(nullptr != coerce->arg); CDXLNode *child_node = TranslateScalarToDXL(coerce->arg, var_colid_mapping); GPOS_ASSERT(nullptr != child_node); // create the DXL node holding the scalar boolean operator CDXLNode *dxlnode = GPOS_NEW(m_mp) CDXLNode( m_mp, GPOS_NEW(m_mp) CDXLScalarCoerceToDomain( m_mp, GPOS_NEW(m_mp) CMDIdGPDB(IMDId::EmdidGeneral, coerce->resulttype), coerce->resulttypmod, (EdxlCoercionForm) coerce->coercionformat, coerce->location)); dxlnode->AddChild(child_node); return dxlnode; } //--------------------------------------------------------------------------- // @function: // CTranslatorScalarToDXL::TranslateCoerceViaIOToDXL // // @doc: // Create a DXL node for a scalar coerce expression from a // GPDB coerce expression //--------------------------------------------------------------------------- CDXLNode * CTranslatorScalarToDXL::TranslateCoerceViaIOToDXL( const Expr *expr, const CMappingVarColId *var_colid_mapping) { GPOS_ASSERT(IsA(expr, CoerceViaIO)); const CoerceViaIO *coerce = (CoerceViaIO *) expr; GPOS_ASSERT(nullptr != coerce->arg); CDXLNode *child_node = TranslateScalarToDXL(coerce->arg, var_colid_mapping); GPOS_ASSERT(nullptr != child_node); // create the DXL node holding the scalar boolean operator CDXLNode *dxlnode = GPOS_NEW(m_mp) CDXLNode( m_mp, GPOS_NEW(m_mp) CDXLScalarCoerceViaIO( m_mp, GPOS_NEW(m_mp) CMDIdGPDB(IMDId::EmdidGeneral, coerce->resulttype), -1, (EdxlCoercionForm) coerce->coerceformat, coerce->location)); dxlnode->AddChild(child_node); return dxlnode; } //--------------------------------------------------------------------------- // @function: // CTranslatorScalarToDXL::TranslateArrayCoerceExprToDXL // @doc: // Create a DXL node for a scalar array coerce expression from a // GPDB Array Coerce expression //--------------------------------------------------------------------------- CDXLNode * CTranslatorScalarToDXL::TranslateArrayCoerceExprToDXL( const Expr *expr, const CMappingVarColId *var_colid_mapping) { GPOS_ASSERT(IsA(expr, ArrayCoerceExpr)); const ArrayCoerceExpr *array_coerce_expr = (ArrayCoerceExpr *) expr; GPOS_ASSERT(nullptr != array_coerce_expr->arg); CDXLNode *child_node = TranslateScalarToDXL(array_coerce_expr->arg, var_colid_mapping); CDXLNode *elemexpr_node = TranslateScalarToDXL(array_coerce_expr->elemexpr, var_colid_mapping); GPOS_ASSERT(nullptr != child_node); GPOS_ASSERT(nullptr != elemexpr_node); CDXLNode *dxlnode = GPOS_NEW(m_mp) CDXLNode( m_mp, GPOS_NEW(m_mp) CDXLScalarArrayCoerceExpr( m_mp, GPOS_NEW(m_mp) CMDIdGPDB(IMDId::EmdidGeneral, array_coerce_expr->resulttype), array_coerce_expr->resulttypmod, (EdxlCoercionForm) array_coerce_expr->coerceformat, array_coerce_expr->location)); dxlnode->AddChild(child_node); dxlnode->AddChild(elemexpr_node); return dxlnode; } //--------------------------------------------------------------------------- // @function: // CTranslatorScalarToDXL::TranslateFieldSelectToDXL // // @doc: // Create a DXL node for a scalar FieldSelect from a GPDB FieldSelect //--------------------------------------------------------------------------- CDXLNode * CTranslatorScalarToDXL::TranslateFieldSelectToDXL( const Expr *expr, const CMappingVarColId *var_colid_mapping) { GPOS_ASSERT(IsA(expr, FieldSelect)); const FieldSelect *fieldselect = (FieldSelect *) expr; GPOS_ASSERT(nullptr != fieldselect->arg); CDXLNode *child_node = TranslateScalarToDXL(fieldselect->arg, var_colid_mapping); GPOS_ASSERT(nullptr != child_node); // create the DXL node holding the scalar boolean operator CDXLNode *dxlnode = GPOS_NEW(m_mp) CDXLNode( m_mp, GPOS_NEW(m_mp) CDXLScalarFieldSelect( m_mp, GPOS_NEW(m_mp) CMDIdGPDB(IMDId::EmdidGeneral, fieldselect->resulttype), GPOS_NEW(m_mp) CMDIdGPDB(IMDId::EmdidGeneral, fieldselect->resultcollid), fieldselect->resulttypmod, fieldselect->fieldnum)); dxlnode->AddChild(child_node); return dxlnode; } //--------------------------------------------------------------------------- // @function: // CTranslatorScalarToDXL::TranslateFuncExprToDXL // // @doc: // Create a DXL node for a scalar funcexpr from a GPDB FuncExpr //--------------------------------------------------------------------------- CDXLNode * CTranslatorScalarToDXL::TranslateFuncExprToDXL( const Expr *expr, const CMappingVarColId *var_colid_mapping) { GPOS_ASSERT(IsA(expr, FuncExpr)); const FuncExpr *func_expr = (FuncExpr *) expr; int32 type_modifier = gpdb::ExprTypeMod((Node *) expr); CMDIdGPDB *mdid_func = GPOS_NEW(m_mp) CMDIdGPDB(IMDId::EmdidGeneral, func_expr->funcid); // create the DXL node holding the scalar funcexpr. CDXLNode *dxlnode = GPOS_NEW(m_mp) CDXLNode( m_mp, GPOS_NEW(m_mp) CDXLScalarFuncExpr( m_mp, mdid_func, GPOS_NEW(m_mp) CMDIdGPDB(IMDId::EmdidGeneral, func_expr->funcresulttype), type_modifier, func_expr->funcretset, static_cast(func_expr->funcformat), func_expr->funcvariadic)); const IMDFunction *md_func = m_md_accessor->RetrieveFunc(mdid_func); if (IMDFunction::EfsVolatile == md_func->GetFuncStability()) { ListCell *lc = nullptr; ForEach(lc, func_expr->args) { Node *arg_node = (Node *) lfirst(lc); if (CTranslatorUtils::HasSubquery(arg_node)) { GPOS_RAISE( gpdxl::ExmaDXL, gpdxl::ExmiQuery2DXLUnsupportedFeature, GPOS_WSZ_LIT( "Volatile functions with subqueries in arguments")); } } } TranslateScalarChildren(dxlnode, func_expr->args, var_colid_mapping); return dxlnode; } //--------------------------------------------------------------------------- // @function: // CTranslatorScalarToDXL::TranslateAggrefToDXL // // @doc: // Create a DXL node for a scalar aggref from a GPDB FuncExpr //--------------------------------------------------------------------------- CDXLNode * CTranslatorScalarToDXL::TranslateAggrefToDXL( const Expr *expr, const CMappingVarColId *var_colid_mapping) { GPOS_ASSERT(IsA(expr, Aggref)); const Aggref *aggref = (Aggref *) expr; BOOL is_distinct; BOOL is_agg_star; if (aggref->aggorder != NIL && GPOS_FTRACE(EopttraceDisableOrderedAgg)) { GPOS_RAISE( gpdxl::ExmaDXL, gpdxl::ExmiQuery2DXLUnsupportedFeature, GPOS_WSZ_LIT( "Ordered aggregates disabled. Enable by setting optimizer_enable_orderedagg=on")); } is_distinct = aggref->aggdistinct; is_agg_star = aggref->aggstar; /* * We shouldn't see any partial aggregates in the parse tree, they're produced * by the planner. */ GPOS_ASSERT(aggref->aggsplit == AGGSPLIT_SIMPLE); EdxlAggrefStage agg_stage = EdxlaggstageNormal; CMDIdGPDB *agg_mdid = GPOS_NEW(m_mp) CMDIdGPDB(IMDId::EmdidGeneral, aggref->aggfnoid); if (0 != aggref->agglevelsup) { // TODO: 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")); } // ORCA doesn't support the FILTER clause yet. if (aggref->aggfilter) { GPOS_RAISE(gpdxl::ExmaDXL, gpdxl::ExmiQuery2DXLUnsupportedFeature, GPOS_WSZ_LIT("Aggregate functions with FILTER")); } IMDId *mdid_return_type = CScalarAggFunc::PmdidLookupReturnType( agg_mdid, (EdxlaggstageNormal == agg_stage), m_md_accessor); IMDId *resolved_ret_type = nullptr; if (m_md_accessor->RetrieveType(mdid_return_type)->IsAmbiguous()) { // if return type given by MD cache is ambiguous, use type provided by aggref node resolved_ret_type = GPOS_NEW(m_mp) CMDIdGPDB(IMDId::EmdidGeneral, aggref->aggtype); } // translate argtypes ULongPtrArray *aggargtypes_values = GPOS_NEW(m_mp) ULongPtrArray(m_mp); ListCell *lc; ForEach(lc, aggref->aggargtypes) { ULONG *poid = GPOS_NEW(m_mp) ULONG(lfirst_oid(lc)); aggargtypes_values->Append(poid); } CDXLScalarAggref *aggref_scalar = GPOS_NEW(m_mp) CDXLScalarAggref( m_mp, agg_mdid, resolved_ret_type, is_distinct, agg_stage, CTranslatorUtils::GetAggKind(aggref->aggkind), aggargtypes_values, is_agg_star); // create the DXL node holding the scalar aggref CDXLNode *dxlnode = GPOS_NEW(m_mp) CDXLNode(m_mp, aggref_scalar); // translate args // // 'indexes' stores the position of the TargetEntry which is referenced by // a SortGroupClause. std::vector indexes(gpdb::ListLength(aggref->args) + 1, -1); CDXLScalarValuesList *args_values = GPOS_NEW(m_mp) CDXLScalarValuesList(m_mp); CDXLNode *args_value_list_dxlnode = GPOS_NEW(m_mp) CDXLNode(m_mp, args_values); int i = 0; ForEachWithCount(lc, aggref->args, i) { TargetEntry *tle = (TargetEntry *) lfirst(lc); CDXLNode *child_node = TranslateScalarToDXL(tle->expr, var_colid_mapping); GPOS_ASSERT(nullptr != child_node); args_value_list_dxlnode->AddChild(child_node); if (tle->ressortgroupref != 0) { // If tleSortGroupRef is non-zero then it means a SotGroupClause // references this TargetEntry. We record that by mapping the // ressortgroupref identifier to the corresponding index position // of the TargetEntry. indexes[tle->ressortgroupref] = i; } } dxlnode->AddChild(args_value_list_dxlnode); // translate direct args CDXLScalarValuesList *dargs_values = GPOS_NEW(m_mp) CDXLScalarValuesList(m_mp); CDXLNode *dargs_value_list_dxlnode = GPOS_NEW(m_mp) CDXLNode(m_mp, dargs_values); ForEach(lc, aggref->aggdirectargs) { Expr *expr = (Expr *) lfirst(lc); CDXLNode *child_node = TranslateScalarToDXL(expr, var_colid_mapping); GPOS_ASSERT(nullptr != child_node); dargs_value_list_dxlnode->AddChild(child_node); } dxlnode->AddChild(dargs_value_list_dxlnode); // translate sort group clause CDXLScalarValuesList *sgc_values = GPOS_NEW(m_mp) CDXLScalarValuesList(m_mp); CDXLNode *sgc_value_list_dxlnode = GPOS_NEW(m_mp) CDXLNode(m_mp, sgc_values); ForEach(lc, aggref->aggorder) { Expr *expr = (Expr *) gpdb::CopyObject(lfirst(lc)); // Set SortGroupClause->tleSortGroupRef to corresponding index into // targetlist. This avoids needing a separate structure to store this // mapping. ((SortGroupClause *) expr)->tleSortGroupRef = indexes[((SortGroupClause *) expr)->tleSortGroupRef]; CDXLNode *child_node = TranslateScalarToDXL(expr, var_colid_mapping); GPOS_ASSERT(nullptr != child_node); sgc_value_list_dxlnode->AddChild(child_node); } dxlnode->AddChild(sgc_value_list_dxlnode); // translate distinct CDXLScalarValuesList *aggdistinct_values = GPOS_NEW(m_mp) CDXLScalarValuesList(m_mp); CDXLNode *aggdistinct_value_list_dxlnode = GPOS_NEW(m_mp) CDXLNode(m_mp, aggdistinct_values); ForEach(lc, aggref->aggdistinct) { Expr *expr = (Expr *) gpdb::CopyObject(lfirst(lc)); // Set SortGroupClause->tleSortGroupRef to corresponding index into // targetlist. This avoids needing a separate structure to store this // mapping. ((SortGroupClause *) expr)->tleSortGroupRef = indexes[((SortGroupClause *) expr)->tleSortGroupRef]; CDXLNode *child_node = TranslateScalarToDXL(expr, var_colid_mapping); GPOS_ASSERT(nullptr != child_node); aggdistinct_value_list_dxlnode->AddChild(child_node); } dxlnode->AddChild(aggdistinct_value_list_dxlnode); return dxlnode; } //--------------------------------------------------------------------------- // @function: // CTranslatorScalarToDXL::TranslateWindowFrameToDXL // // @doc: // Create a DXL window frame from a GPDB WindowFrame //--------------------------------------------------------------------------- CDXLWindowFrame * CTranslatorScalarToDXL::TranslateWindowFrameToDXL( int frame_options, const Node *start_offset, const Node *end_offset, Oid start_in_range_func, Oid end_in_range_func, Oid in_range_coll, bool in_range_asc, bool in_range_nulls_first, const CMappingVarColId *var_colid_mapping, CDXLNode *new_scalar_proj_list) { EdxlFrameSpec frame_spec; if ((frame_options & FRAMEOPTION_ROWS) != 0) { frame_spec = EdxlfsRow; } else if ((frame_options & FRAMEOPTION_RANGE) != 0) { frame_spec = EdxlfsRange; } else if ((frame_options & FRAMEOPTION_GROUPS) != 0) { frame_spec = EdxlfsGroups; } else { GPOS_RAISE(gpdxl::ExmaDXL, gpdxl::ExmiQuery2DXLUnsupportedFeature, GPOS_WSZ_LIT("window frame option")); } EdxlFrameBoundary leading_boundary; if ((frame_options & FRAMEOPTION_START_UNBOUNDED_PRECEDING) != 0) { leading_boundary = EdxlfbUnboundedPreceding; } else if ((frame_options & FRAMEOPTION_START_OFFSET_PRECEDING) != 0) { leading_boundary = EdxlfbBoundedPreceding; } else if ((frame_options & FRAMEOPTION_START_CURRENT_ROW) != 0) { leading_boundary = EdxlfbCurrentRow; } else if ((frame_options & FRAMEOPTION_START_OFFSET_FOLLOWING) != 0) { leading_boundary = EdxlfbBoundedFollowing; } else if ((frame_options & FRAMEOPTION_START_UNBOUNDED_FOLLOWING) != 0) { leading_boundary = EdxlfbUnboundedFollowing; } else { GPOS_RAISE(gpdxl::ExmaDXL, gpdxl::ExmiQuery2DXLUnsupportedFeature, GPOS_WSZ_LIT("Unrecognized window frame option")); } EdxlFrameBoundary trailing_boundary; if ((frame_options & FRAMEOPTION_END_UNBOUNDED_PRECEDING) != 0) { trailing_boundary = EdxlfbUnboundedPreceding; } else if ((frame_options & FRAMEOPTION_END_OFFSET_PRECEDING) != 0) { trailing_boundary = EdxlfbBoundedPreceding; } else if ((frame_options & FRAMEOPTION_END_CURRENT_ROW) != 0) { trailing_boundary = EdxlfbCurrentRow; } else if ((frame_options & FRAMEOPTION_END_OFFSET_FOLLOWING) != 0) { trailing_boundary = EdxlfbBoundedFollowing; } else if ((frame_options & FRAMEOPTION_END_UNBOUNDED_FOLLOWING) != 0) { trailing_boundary = EdxlfbUnboundedFollowing; } else { GPOS_RAISE(gpdxl::ExmaDXL, gpdxl::ExmiQuery2DXLUnsupportedFeature, GPOS_WSZ_LIT("Unrecognized window frame option")); } // We don't support non-default EXCLUDE [CURRENT ROW | GROUP | TIES | // NO OTHERS] options. EdxlFrameExclusionStrategy strategy = EdxlfesNulls; if ((frame_options & FRAMEOPTION_EXCLUDE_CURRENT_ROW) != 0) { strategy = EdxlfesCurrentRow; } else if ((frame_options & FRAMEOPTION_EXCLUDE_GROUP) != 0) { strategy = EdxlfesGroup; } else if ((frame_options & FRAMEOPTION_EXCLUDE_TIES) != 0) { strategy = EdxlfesTies; } CDXLNode *lead_edge = GPOS_NEW(m_mp) CDXLNode(m_mp, GPOS_NEW(m_mp) CDXLScalarWindowFrameEdge( m_mp, true /* fLeading */, leading_boundary)); CDXLNode *trail_edge = GPOS_NEW(m_mp) CDXLNode(m_mp, GPOS_NEW(m_mp) CDXLScalarWindowFrameEdge( m_mp, false /* fLeading */, trailing_boundary)); // Subqueries in window frame bounds cannot be handled by ORCA: the // SubLink would end up as a Var(OUTER_VAR) in the plan, but WindowAgg's // calculate_frame_offsets evaluates offsets with ecxt_outertuple=NULL. // Fall back to the standard planner which converts them to InitPlans. struct SContainsSubLink { static bool Walk(Node *node, void *) { if (node == nullptr) return false; if (IsA(node, SubLink)) return true; return gpdb::WalkExpressionTree(node, SContainsSubLink::Walk, nullptr); } }; if ((start_offset != nullptr && SContainsSubLink::Walk(const_cast(start_offset), nullptr)) || (end_offset != nullptr && SContainsSubLink::Walk(const_cast(end_offset), nullptr))) { GPOS_RAISE(gpdxl::ExmaDXL, gpdxl::ExmiQuery2DXLUnsupportedFeature, GPOS_WSZ_LIT("Subquery in window frame bound")); } // translate the lead and trail value if (nullptr != start_offset) { lead_edge->AddChild(TranslateWindowFrameEdgeToDXL( start_offset, var_colid_mapping, new_scalar_proj_list)); } if (nullptr != end_offset) { trail_edge->AddChild(TranslateWindowFrameEdgeToDXL( end_offset, var_colid_mapping, new_scalar_proj_list)); } CDXLWindowFrame *window_frame_dxl = GPOS_NEW(m_mp) CDXLWindowFrame( frame_spec, strategy, lead_edge, trail_edge, start_in_range_func, end_in_range_func, in_range_coll, in_range_asc, in_range_nulls_first); return window_frame_dxl; } //--------------------------------------------------------------------------- // @function: // CTranslatorScalarToDXL::TranslateWindowFrameEdgeToDXL // // @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::TranslateWindowFrameEdgeToDXL( const Node *node, const CMappingVarColId *var_colid_mapping, CDXLNode *new_scalar_proj_list) { CDXLNode *val_node = TranslateScalarToDXL((Expr *) node, var_colid_mapping); if (!m_context) { GPOS_RAISE(gpdxl::ExmaDXL, gpdxl::ExmiQuery2DXLUnsupportedFeature, GPOS_WSZ_LIT("Window Frame in a stand-alone expression")); } if (!IsA(node, Var) && !IsA(node, Const)) { GPOS_ASSERT(nullptr != new_scalar_proj_list); CWStringConst unnamed_col(GPOS_WSZ_LIT("?column?")); CMDName *alias_mdname = GPOS_NEW(m_mp) CMDName(m_mp, &unnamed_col); ULONG project_element_id = m_context->m_colid_counter->next_id(); // construct a projection element CDXLNode *project_element_node = GPOS_NEW(m_mp) CDXLNode(m_mp, GPOS_NEW(m_mp) CDXLScalarProjElem( m_mp, project_element_id, alias_mdname)); project_element_node->AddChild(val_node); // add it to the computed columns project list new_scalar_proj_list->AddChild(project_element_node); // construct a new scalar ident CDXLScalarIdent *scalar_ident = GPOS_NEW(m_mp) CDXLScalarIdent( m_mp, GPOS_NEW(m_mp) CDXLColRef( GPOS_NEW(m_mp) CMDName(m_mp, &unnamed_col), project_element_id, GPOS_NEW(m_mp) CMDIdGPDB(IMDId::EmdidGeneral, gpdb::ExprType(const_cast(node))), gpdb::ExprTypeMod(const_cast(node)))); val_node = GPOS_NEW(m_mp) CDXLNode(m_mp, scalar_ident); } return val_node; } //--------------------------------------------------------------------------- // @function: // CTranslatorScalarToDXL::TranslateWindowFuncToDXL // // @doc: // Create a DXL node for a scalar window ref from a GPDB WindowFunc // //--------------------------------------------------------------------------- CDXLNode * CTranslatorScalarToDXL::TranslateWindowFuncToDXL( const Expr *expr, const CMappingVarColId *var_colid_mapping) { GPOS_ASSERT(IsA(expr, WindowFunc)); const WindowFunc *window_func = (WindowFunc *) expr; // ORCA doesn't support the FILTER clause yet. if (window_func->aggfilter) { GPOS_RAISE(gpdxl::ExmaDXL, gpdxl::ExmiQuery2DXLUnsupportedFeature, GPOS_WSZ_LIT("Aggregate functions with FILTER")); } if (!m_context) { GPOS_RAISE(gpdxl::ExmaDXL, gpdxl::ExmiQuery2DXLUnsupportedFeature, GPOS_WSZ_LIT("Window function in a stand-alone expression")); } ULONG win_spec_pos = (ULONG) window_func->winref - 1; /* * ORCA's ScalarWindowRef object doesn't have fields for the 'winstar' * and 'winagg', so we lose that information in the translation. * Fortunately, the executor currently doesn't need those fields to * be set correctly. */ /* windistinct removed from WindowFunc in PG18 — pass false */ CDXLScalarWindowRef *winref_dxlop = GPOS_NEW(m_mp) CDXLScalarWindowRef( m_mp, GPOS_NEW(m_mp) CMDIdGPDB(IMDId::EmdidGeneral, window_func->winfnoid), GPOS_NEW(m_mp) CMDIdGPDB(IMDId::EmdidGeneral, window_func->wintype), false /*windistinct*/, window_func->winstar, window_func->winagg, EdxlwinstageImmediate, win_spec_pos); // create the DXL node holding the scalar aggref CDXLNode *dxlnode = GPOS_NEW(m_mp) CDXLNode(m_mp, winref_dxlop); TranslateScalarChildren(dxlnode, window_func->args, var_colid_mapping); return dxlnode; } //--------------------------------------------------------------------------- // @function: // CTranslatorScalarToDXL::CreateScalarCondFromQual // // @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::CreateScalarCondFromQual( List *quals, const CMappingVarColId *var_colid_mapping) { if (nullptr == quals || 0 == gpdb::ListLength(quals)) { return nullptr; } if (1 == gpdb::ListLength(quals)) { Expr *expr = (Expr *) gpdb::ListNth(quals, 0); return TranslateScalarToDXL(expr, var_colid_mapping); } 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 *dxlnode = GPOS_NEW(m_mp) CDXLNode(m_mp, GPOS_NEW(m_mp) CDXLScalarBoolExpr(m_mp, Edxland)); TranslateScalarChildren(dxlnode, quals, var_colid_mapping); return dxlnode; } } //--------------------------------------------------------------------------- // @function: // CTranslatorScalarToDXL::CreateFilterFromQual // // @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::CreateFilterFromQual( List *quals, const CMappingVarColId *var_colid_mapping, Edxlopid filter_type) { CDXLScalarFilter *dxlop = nullptr; switch (filter_type) { case EdxlopScalarFilter: dxlop = GPOS_NEW(m_mp) CDXLScalarFilter(m_mp); break; case EdxlopScalarJoinFilter: dxlop = GPOS_NEW(m_mp) CDXLScalarJoinFilter(m_mp); break; case EdxlopScalarOneTimeFilter: dxlop = GPOS_NEW(m_mp) CDXLScalarOneTimeFilter(m_mp); break; default: GPOS_ASSERT(!"Unrecognized filter type"); } CDXLNode *filter_dxlnode = GPOS_NEW(m_mp) CDXLNode(m_mp, dxlop); CDXLNode *cond_node = CreateScalarCondFromQual(quals, var_colid_mapping); if (nullptr != cond_node) { filter_dxlnode->AddChild(cond_node); } return filter_dxlnode; } //--------------------------------------------------------------------------- // @function: // CTranslatorScalarToDXL::TranslateSubLinkToDXL // // @doc: // Create a DXL node from a GPDB sublink node. // //--------------------------------------------------------------------------- CDXLNode * CTranslatorScalarToDXL::TranslateSubLinkToDXL( const Expr *expr, const CMappingVarColId *var_colid_mapping) { const SubLink *sublink = (SubLink *) expr; switch (sublink->subLinkType) { case EXPR_SUBLINK: return CreateScalarSubqueryFromSublink(sublink, var_colid_mapping); case ALL_SUBLINK: case ANY_SUBLINK: return CreateQuantifiedSubqueryFromSublink(sublink, var_colid_mapping); case EXISTS_SUBLINK: return CreateExistSubqueryFromSublink(sublink, var_colid_mapping); default: { GPOS_RAISE(gpdxl::ExmaDXL, gpdxl::ExmiQuery2DXLUnsupportedFeature, GPOS_WSZ_LIT("Non-Scalar Subquery")); return nullptr; } } } //--------------------------------------------------------------------------- // @function: // CTranslatorScalarToDXL::CreateQuantifiedSubqueryFromSublink // // @doc: // Create ANY / ALL quantified sub query from a GPDB sublink node //--------------------------------------------------------------------------- CDXLNode * CTranslatorScalarToDXL::CreateQuantifiedSubqueryFromSublink( const SubLink *sublink, const CMappingVarColId *var_colid_mapping) { CAutoP query_to_dxl_translator; query_to_dxl_translator = CreateSubqueryTranslator( (Query *) sublink->subselect, var_colid_mapping); CDXLNode *inner_dxlnode = query_to_dxl_translator->TranslateSelectQueryToDXL(); CDXLNodeArray *query_output_dxlnode_array = query_to_dxl_translator->GetQueryOutputCols(); CDXLNodeArray *cte_dxlnode_array = query_to_dxl_translator->GetCTEs(); CUtils::AddRefAppend(m_cte_producers, cte_dxlnode_array); if (1 != query_output_dxlnode_array->Size()) { GPOS_RAISE(gpdxl::ExmaDXL, gpdxl::ExmiQuery2DXLUnsupportedFeature, GPOS_WSZ_LIT("Non-Scalar Subquery")); } CDXLNode *dxl_sc_ident = (*query_output_dxlnode_array)[0]; GPOS_ASSERT(nullptr != dxl_sc_ident); // get dxl scalar identifier CDXLScalarIdent *scalar_ident = dynamic_cast(dxl_sc_ident->GetOperator()); // get the dxl column reference const CDXLColRef *dxl_colref = scalar_ident->GetDXLColRef(); const ULONG colid = dxl_colref->Id(); // get the test expression GPOS_ASSERT(IsA(sublink->testexpr, OpExpr)); OpExpr *op_expr = (OpExpr *) sublink->testexpr; IMDId *mdid = GPOS_NEW(m_mp) CMDIdGPDB(IMDId::EmdidGeneral, op_expr->opno); // get operator name const CWStringConst *str = GetDXLArrayCmpType(mdid); // translate left hand side of the expression GPOS_ASSERT(nullptr != op_expr->args); Expr *LHS_expr = (Expr *) gpdb::ListNth(op_expr->args, 0); CDXLNode *outer_dxlnode = TranslateScalarToDXL(LHS_expr, var_colid_mapping); CDXLNode *dxlnode = nullptr; CDXLScalar *subquery = nullptr; GPOS_ASSERT(ALL_SUBLINK == sublink->subLinkType || ANY_SUBLINK == sublink->subLinkType); if (ALL_SUBLINK == sublink->subLinkType) { subquery = GPOS_NEW(m_mp) CDXLScalarSubqueryAll( m_mp, mdid, GPOS_NEW(m_mp) CMDName(m_mp, str), colid); } else { subquery = GPOS_NEW(m_mp) CDXLScalarSubqueryAny( m_mp, mdid, GPOS_NEW(m_mp) CMDName(m_mp, str), colid); } dxlnode = GPOS_NEW(m_mp) CDXLNode(m_mp, subquery); dxlnode->AddChild(outer_dxlnode); dxlnode->AddChild(inner_dxlnode); #ifdef GPOS_DEBUG dxlnode->GetOperator()->AssertValid(dxlnode, false /* fValidateChildren */); #endif return dxlnode; } //--------------------------------------------------------------------------- // @function: // CTranslatorScalarToDXL::CreateScalarSubqueryFromSublink // // @doc: // Create a scalar subquery from a GPDB sublink node //--------------------------------------------------------------------------- CDXLNode * CTranslatorScalarToDXL::CreateScalarSubqueryFromSublink( const SubLink *sublink, const CMappingVarColId *var_colid_mapping) { Query *subselect = (Query *) sublink->subselect; CAutoP query_to_dxl_translator; query_to_dxl_translator = CreateSubqueryTranslator(subselect, var_colid_mapping); CDXLNode *subquery_dxlnode = query_to_dxl_translator->TranslateSelectQueryToDXL(); CDXLNodeArray *query_output_dxlnode_array = query_to_dxl_translator->GetQueryOutputCols(); GPOS_ASSERT(1 == query_output_dxlnode_array->Size()); CDXLNodeArray *cte_dxlnode_array = query_to_dxl_translator->GetCTEs(); CUtils::AddRefAppend(m_cte_producers, cte_dxlnode_array); // get dxl scalar identifier CDXLNode *dxl_sc_ident = (*query_output_dxlnode_array)[0]; GPOS_ASSERT(nullptr != dxl_sc_ident); CDXLScalarIdent *scalar_ident = CDXLScalarIdent::Cast(dxl_sc_ident->GetOperator()); // get the dxl column reference const CDXLColRef *dxl_colref = scalar_ident->GetDXLColRef(); const ULONG colid = dxl_colref->Id(); CDXLNode *dxlnode = GPOS_NEW(m_mp) CDXLNode(m_mp, GPOS_NEW(m_mp) CDXLScalarSubquery(m_mp, colid)); dxlnode->AddChild(subquery_dxlnode); return dxlnode; } //--------------------------------------------------------------------------- // @function: // CTranslatorScalarToDXL::TranslateArrayExprToDXL // // @doc: // Translate array // //--------------------------------------------------------------------------- CDXLNode * CTranslatorScalarToDXL::TranslateArrayExprToDXL( const Expr *expr, const CMappingVarColId *var_colid_mapping) { GPOS_ASSERT(IsA(expr, ArrayExpr)); const ArrayExpr *parrayexpr = (ArrayExpr *) expr; CDXLScalarArray *dxlop = GPOS_NEW(m_mp) CDXLScalarArray( m_mp, GPOS_NEW(m_mp) CMDIdGPDB(IMDId::EmdidGeneral, parrayexpr->element_typeid), GPOS_NEW(m_mp) CMDIdGPDB(IMDId::EmdidGeneral, parrayexpr->array_typeid), parrayexpr->multidims); CDXLNode *dxlnode = GPOS_NEW(m_mp) CDXLNode(m_mp, dxlop); TranslateScalarChildren(dxlnode, parrayexpr->elements, var_colid_mapping); return dxlnode; } //--------------------------------------------------------------------------- // @function: // CTranslatorScalarToDXL::TranslateArrayRefToDXL // // @doc: // Translate arrayref // //--------------------------------------------------------------------------- CDXLNode * CTranslatorScalarToDXL::TranslateArrayRefToDXL( const Expr *expr, const CMappingVarColId *var_colid_mapping) { GPOS_ASSERT(IsA(expr, SubscriptingRef)); const SubscriptingRef *parrayref = (SubscriptingRef *) expr; Oid restype; INT type_modifier = parrayref->reftypmod; /* slice and/or store operations yield the array type */ if (parrayref->reflowerindexpr || parrayref->refassgnexpr) { restype = parrayref->refcontainertype; } else { restype = parrayref->refelemtype; } CDXLScalarArrayRef *dxlop = GPOS_NEW(m_mp) CDXLScalarArrayRef( m_mp, GPOS_NEW(m_mp) CMDIdGPDB(IMDId::EmdidGeneral, parrayref->refelemtype), type_modifier, GPOS_NEW(m_mp) CMDIdGPDB(IMDId::EmdidGeneral, parrayref->refcontainertype), GPOS_NEW(m_mp) CMDIdGPDB(IMDId::EmdidGeneral, restype)); CDXLNode *dxlnode = GPOS_NEW(m_mp) CDXLNode(m_mp, dxlop); // GPDB_96_MERGE_FIXME: Since upstream commit 9246af6799, the List can contain NULLs, // to indicate omitted array boundaries. Need to add support for them, but until then, // bail out. ListCell *lc; ForEach(lc, parrayref->reflowerindexpr) { Expr *child_expr = (Expr *) lfirst(lc); if (child_expr == nullptr) { GPOS_RAISE(gpdxl::ExmaDXL, gpdxl::ExmiQuery2DXLUnsupportedFeature, GPOS_WSZ_LIT("Omitted array bound")); } } ForEach(lc, parrayref->refupperindexpr) { Expr *child_expr = (Expr *) lfirst(lc); if (child_expr == nullptr) { GPOS_RAISE(gpdxl::ExmaDXL, gpdxl::ExmiQuery2DXLUnsupportedFeature, GPOS_WSZ_LIT("Omitted array bound")); } } // add children AddArrayIndexList(dxlnode, parrayref->reflowerindexpr, CDXLScalarArrayRefIndexList::EilbLower, var_colid_mapping); AddArrayIndexList(dxlnode, parrayref->refupperindexpr, CDXLScalarArrayRefIndexList::EilbUpper, var_colid_mapping); dxlnode->AddChild( TranslateScalarToDXL(parrayref->refexpr, var_colid_mapping)); if (nullptr != parrayref->refassgnexpr) { dxlnode->AddChild( TranslateScalarToDXL(parrayref->refassgnexpr, var_colid_mapping)); } return dxlnode; } CDXLNode * CTranslatorScalarToDXL::TranslateSortGroupClauseToDXL( const Expr *expr, const CMappingVarColId * /*var_colid_mapping*/) { GPOS_ASSERT(IsA(expr, SortGroupClause)); const SortGroupClause *sgc = (SortGroupClause *) expr; CDXLScalarSortGroupClause *sort_group_clause = GPOS_NEW(m_mp) CDXLScalarSortGroupClause(m_mp, sgc->tleSortGroupRef, sgc->eqop, sgc->sortop, sgc->nulls_first, sgc->hashable); // create the DXL node holding the scalar ident operator CDXLNode *dxlnode = GPOS_NEW(m_mp) CDXLNode(m_mp, sort_group_clause); return dxlnode; } //--------------------------------------------------------------------------- // @function: // CTranslatorScalarToDXL::AddArrayIndexList // // @doc: // Add an indexlist to the given DXL arrayref node // //--------------------------------------------------------------------------- void CTranslatorScalarToDXL::AddArrayIndexList( CDXLNode *dxlnode, List *list, CDXLScalarArrayRefIndexList::EIndexListBound index_list_bound, const CMappingVarColId *var_colid_mapping) { GPOS_ASSERT(nullptr != dxlnode); GPOS_ASSERT(EdxlopScalarArrayRef == dxlnode->GetOperator()->GetDXLOperator()); GPOS_ASSERT(CDXLScalarArrayRefIndexList::EilbSentinel > index_list_bound); CDXLNode *index_list_dxlnode = GPOS_NEW(m_mp) CDXLNode(m_mp, GPOS_NEW(m_mp) CDXLScalarArrayRefIndexList(m_mp, index_list_bound)); TranslateScalarChildren(index_list_dxlnode, list, var_colid_mapping); dxlnode->AddChild(index_list_dxlnode); } //--------------------------------------------------------------------------- // @function: // CTranslatorScalarToDXL::GetDXLArrayCmpType // // @doc: // Get the operator name // //--------------------------------------------------------------------------- const CWStringConst * CTranslatorScalarToDXL::GetDXLArrayCmpType(IMDId *mdid) const { // get operator name const IMDScalarOp *md_scalar_op = m_md_accessor->RetrieveScOp(mdid); const CWStringConst *str = md_scalar_op->Mdname().GetMDName(); return str; } //--------------------------------------------------------------------------- // @function: // CTranslatorScalarToDXL::CreateExistSubqueryFromSublink // // @doc: // Create a DXL EXISTS subquery node from the respective GPDB // sublink node //--------------------------------------------------------------------------- CDXLNode * CTranslatorScalarToDXL::CreateExistSubqueryFromSublink( const SubLink *sublink, const CMappingVarColId *var_colid_mapping) { GPOS_ASSERT(nullptr != sublink); CAutoP query_to_dxl_translator; query_to_dxl_translator = CreateSubqueryTranslator( (Query *) sublink->subselect, var_colid_mapping); CDXLNode *root_dxlnode = query_to_dxl_translator->TranslateSelectQueryToDXL(); CDXLNodeArray *cte_dxlnode_array = query_to_dxl_translator->GetCTEs(); CUtils::AddRefAppend(m_cte_producers, cte_dxlnode_array); CDXLNode *dxlnode = GPOS_NEW(m_mp) CDXLNode(m_mp, GPOS_NEW(m_mp) CDXLScalarSubqueryExists(m_mp)); dxlnode->AddChild(root_dxlnode); return dxlnode; } //--------------------------------------------------------------------------- // @function: // CTranslatorScalarToDXL::GetDatum // // @doc: // Create CDXLDatum from GPDB datum //--------------------------------------------------------------------------- CDXLDatum * CTranslatorScalarToDXL::TranslateDatumToDXL(CMemoryPool *mp, const IMDType *md_type, INT type_modifier, BOOL is_null, ULONG len, Datum datum) { switch (md_type->GetDatumType()) { default: { // generate a datum of generic type return TranslateGenericDatumToDXL(mp, md_type, type_modifier, is_null, len, datum); } case IMDType::EtiInt2: { return CTranslatorScalarToDXL::TranslateInt2DatumToDXL( mp, md_type, is_null, len, datum); } case IMDType::EtiInt4: { return CTranslatorScalarToDXL::TranslateInt4DatumToDXL( mp, md_type, is_null, len, datum); } case IMDType::EtiInt8: { return CTranslatorScalarToDXL::TranslateInt8DatumToDXL( mp, md_type, is_null, len, datum); } case IMDType::EtiBool: { return CTranslatorScalarToDXL::TranslateBoolDatumToDXL( mp, md_type, is_null, len, datum); } case IMDType::EtiOid: { return CTranslatorScalarToDXL::TranslateOidDatumToDXL( mp, md_type, is_null, len, datum); } } } //--------------------------------------------------------------------------- // @function: // CTranslatorScalarToDXL::TranslateGenericDatumToDXL // // @doc: // Translate a datum of generic type //--------------------------------------------------------------------------- CDXLDatum * CTranslatorScalarToDXL::TranslateGenericDatumToDXL(CMemoryPool *mp, const IMDType *md_type, INT type_modifier, BOOL is_null, ULONG len, Datum datum) { CMDIdGPDB *mdid_old = CMDIdGPDB::CastMdid(md_type->MDId()); CMDIdGPDB *mdid = GPOS_NEW(mp) CMDIdGPDB(*mdid_old); BYTE *bytes = ExtractByteArrayFromDatum(mp, md_type, is_null, len, datum); ULONG length = 0; if (!is_null) { length = (ULONG) gpdb::DatumSize(datum, md_type->IsPassedByValue(), len); } CDouble double_value(0); if (CMDTypeGenericGPDB::HasByte2DoubleMapping(mdid)) { double_value = ExtractDoubleValueFromDatum(mdid, is_null, bytes, datum); } LINT lint_value = 0; if (CMDTypeGenericGPDB::HasByte2IntMapping(md_type)) { IMDId *base_mdid = GPOS_NEW(mp) CMDIdGPDB(IMDId::EmdidGeneral, gpdb::GetBaseType(mdid->Oid())); // base_mdid is used for text related domain types lint_value = ExtractLintValueFromDatum(md_type, is_null, bytes, length, base_mdid); base_mdid->Release(); } return CMDTypeGenericGPDB::CreateDXLDatumVal( mp, mdid, md_type, type_modifier, is_null, bytes, length, lint_value, double_value); } //--------------------------------------------------------------------------- // @function: // CTranslatorScalarToDXL::TranslateBoolDatumToDXL // // @doc: // Translate a datum of type bool //--------------------------------------------------------------------------- CDXLDatum * CTranslatorScalarToDXL::TranslateBoolDatumToDXL(CMemoryPool *mp, const IMDType *md_type, BOOL is_null, ULONG, //len, Datum datum) { GPOS_ASSERT(md_type->IsPassedByValue()); CMDIdGPDB *mdid_old = CMDIdGPDB::CastMdid(md_type->MDId()); CMDIdGPDB *mdid = GPOS_NEW(mp) CMDIdGPDB(*mdid_old); return GPOS_NEW(mp) CDXLDatumBool(mp, mdid, is_null, gpdb::BoolFromDatum(datum)); } //--------------------------------------------------------------------------- // @function: // CTranslatorScalarToDXL::TranslateOidDatumToDXL // // @doc: // Translate a datum of type oid //--------------------------------------------------------------------------- CDXLDatum * CTranslatorScalarToDXL::TranslateOidDatumToDXL(CMemoryPool *mp, const IMDType *md_type, BOOL is_null, ULONG, //len, Datum datum) { GPOS_ASSERT(md_type->IsPassedByValue()); CMDIdGPDB *mdid_old = CMDIdGPDB::CastMdid(md_type->MDId()); CMDIdGPDB *mdid = GPOS_NEW(mp) CMDIdGPDB(*mdid_old); return GPOS_NEW(mp) CDXLDatumOid(mp, mdid, is_null, gpdb::OidFromDatum(datum)); } //--------------------------------------------------------------------------- // @function: // CTranslatorScalarToDXL::TranslateInt2DatumToDXL // // @doc: // Translate a datum of type int2 //--------------------------------------------------------------------------- CDXLDatum * CTranslatorScalarToDXL::TranslateInt2DatumToDXL(CMemoryPool *mp, const IMDType *md_type, BOOL is_null, ULONG, //len, Datum datum) { GPOS_ASSERT(md_type->IsPassedByValue()); CMDIdGPDB *mdid_old = CMDIdGPDB::CastMdid(md_type->MDId()); CMDIdGPDB *mdid = GPOS_NEW(mp) CMDIdGPDB(*mdid_old); return GPOS_NEW(mp) CDXLDatumInt2(mp, mdid, is_null, gpdb::Int16FromDatum(datum)); } //--------------------------------------------------------------------------- // @function: // CTranslatorScalarToDXL::TranslateInt4DatumToDXL // // @doc: // Translate a datum of type int4 //--------------------------------------------------------------------------- CDXLDatum * CTranslatorScalarToDXL::TranslateInt4DatumToDXL(CMemoryPool *mp, const IMDType *md_type, BOOL is_null, ULONG, //len, Datum datum) { GPOS_ASSERT(md_type->IsPassedByValue()); CMDIdGPDB *mdid_old = CMDIdGPDB::CastMdid(md_type->MDId()); CMDIdGPDB *mdid = GPOS_NEW(mp) CMDIdGPDB(*mdid_old); return GPOS_NEW(mp) CDXLDatumInt4(mp, mdid, is_null, gpdb::Int32FromDatum(datum)); } //--------------------------------------------------------------------------- // @function: // CTranslatorScalarToDXL::TranslateInt8DatumToDXL // // @doc: // Translate a datum of type int8 //--------------------------------------------------------------------------- CDXLDatum * CTranslatorScalarToDXL::TranslateInt8DatumToDXL(CMemoryPool *mp, const IMDType *md_type, BOOL is_null, ULONG, //len, Datum datum) { GPOS_ASSERT(md_type->IsPassedByValue()); CMDIdGPDB *mdid_old = CMDIdGPDB::CastMdid(md_type->MDId()); CMDIdGPDB *mdid = GPOS_NEW(mp) CMDIdGPDB(*mdid_old); return GPOS_NEW(mp) CDXLDatumInt8(mp, mdid, is_null, gpdb::Int64FromDatum(datum)); } //--------------------------------------------------------------------------- // @function: // CTranslatorScalarToDXL::ExtractDoubleValueFromDatum // // @doc: // Extract the double value of the datum //--------------------------------------------------------------------------- CDouble CTranslatorScalarToDXL::ExtractDoubleValueFromDatum(IMDId *mdid, BOOL is_null, BYTE *bytes, Datum datum) { GPOS_ASSERT(CMDTypeGenericGPDB::HasByte2DoubleMapping(mdid)); double d = 0; if (is_null) { return CDouble(d); } if (mdid->Equals(&CMDIdGPDB::m_mdid_numeric)) { Numeric num = (Numeric)(bytes); if (gpdb::NumericIsNan(num)) { // in GPDB NaN is considered the largest numeric number. return CDouble(GPOS_FP_ABS_MAX); } d = gpdb::NumericToDoubleNoOverflow(num); } else if (mdid->Equals(&CMDIdGPDB::m_mdid_float4)) { float4 f = gpdb::Float4FromDatum(datum); if (isnan(f)) { d = GPOS_FP_ABS_MAX; } else { d = (double) f; } } else if (mdid->Equals(&CMDIdGPDB::m_mdid_float8)) { d = gpdb::Float8FromDatum(datum); if (isnan(d)) { d = GPOS_FP_ABS_MAX; } } else if (CMDTypeGenericGPDB::IsTimeRelatedType(mdid)) { d = gpdb::ConvertTimeValueToScalar(datum, CMDIdGPDB::CastMdid(mdid)->Oid()); } else if (CMDTypeGenericGPDB::IsNetworkRelatedType(mdid)) { d = gpdb::ConvertNetworkToScalar(datum, CMDIdGPDB::CastMdid(mdid)->Oid()); } return CDouble(d); } //--------------------------------------------------------------------------- // @function: // CTranslatorScalarToDXL::ExtractByteArrayFromDatum // // @doc: // Extract the byte array value of the datum. The result is NULL if datum is NULL //--------------------------------------------------------------------------- BYTE * CTranslatorScalarToDXL::ExtractByteArrayFromDatum(CMemoryPool *mp, const IMDType *md_type, BOOL is_null, ULONG len, Datum datum) { ULONG length = 0; BYTE *bytes = nullptr; if (is_null) { return bytes; } length = (ULONG) gpdb::DatumSize(datum, md_type->IsPassedByValue(), len); GPOS_ASSERT(length > 0); bytes = GPOS_NEW_ARRAY(mp, BYTE, length); if (md_type->IsPassedByValue()) { GPOS_ASSERT(length <= ULONG(sizeof(Datum))); clib::Memcpy(bytes, &datum, length); } else { clib::Memcpy(bytes, gpdb::PointerFromDatum(datum), length); } return bytes; } //--------------------------------------------------------------------------- // @function: // CTranslatorScalarToDXL::ExtractLintValueFromDatum // // @doc: // Extract the long int value of a datum //--------------------------------------------------------------------------- LINT CTranslatorScalarToDXL::ExtractLintValueFromDatum(const IMDType *md_type, BOOL is_null, BYTE *bytes, ULONG length, IMDId *base_mdid) { IMDId *mdid = md_type->MDId(); GPOS_ASSERT(CMDTypeGenericGPDB::HasByte2IntMapping(md_type)); LINT lint_value = 0; if (is_null) { return lint_value; } if (mdid->Equals(&CMDIdGPDB::m_mdid_cash) || mdid->Equals(&CMDIdGPDB::m_mdid_date)) { // cash is a pass-by-ref type Datum datumConstVal = (Datum) 0; clib::Memcpy(&datumConstVal, bytes, length); // Date is internally represented as an int32 lint_value = (LINT)(gpdb::Int32FromDatum(datumConstVal)); } else { // use hash value ULONG hash = 0; if (is_null) { hash = gpos::HashValue(&hash); } else { if (mdid->Equals(&CMDIdGPDB::m_mdid_uuid)) { hash = gpdb::UUIDHash((Datum) bytes); } else if (mdid->Equals(&CMDIdGPDB::m_mdid_bpchar) || (base_mdid->IsValid() && base_mdid->Equals(&CMDIdGPDB::m_mdid_bpchar))) { hash = gpdb::HashBpChar((Datum) bytes); } else if (mdid->Equals(&CMDIdGPDB::m_mdid_char) || (base_mdid->IsValid() && base_mdid->Equals(&CMDIdGPDB::m_mdid_char))) { hash = gpdb::HashChar((Datum) bytes); } else if (mdid->Equals(&CMDIdGPDB::m_mdid_name) || (base_mdid->IsValid() && base_mdid->Equals(&CMDIdGPDB::m_mdid_name))) { hash = gpdb::HashName((Datum) bytes); } else { hash = gpdb::HashText((Datum) bytes); } } lint_value = (LINT) hash; } return lint_value; } //--------------------------------------------------------------------------- // @function: // CTranslatorScalarToDXL::TranslateDatumToDXL // // @doc: // Create IDatum from GPDB datum //--------------------------------------------------------------------------- IDatum * CTranslatorScalarToDXL::CreateIDatumFromGpdbDatum(CMemoryPool *mp, const IMDType *md_type, BOOL is_null, Datum gpdb_datum) { ULONG length = md_type->Length(); if (!md_type->IsPassedByValue() && !is_null) { INT len = dynamic_cast(md_type)->GetGPDBLength(); length = (ULONG) gpdb::DatumSize(gpdb_datum, md_type->IsPassedByValue(), len); } GPOS_ASSERT(is_null || length > 0); CDXLDatum *datum_dxl = CTranslatorScalarToDXL::TranslateDatumToDXL( mp, md_type, gpmd::default_type_modifier, is_null, length, gpdb_datum); IDatum *datum = md_type->GetDatumForDXLDatum(mp, datum_dxl); datum_dxl->Release(); return datum; } // EOF