//--------------------------------------------------------------------------- // Greenplum Database // Copyright (C) 2011 EMC Corp. // // @filename: // CSubqueryHandler.h // // @doc: // Helper class for transforming subquery expressions to Apply // expressions //--------------------------------------------------------------------------- #ifndef GPOPT_CSubqueryHandler_H #define GPOPT_CSubqueryHandler_H #include "gpos/base.h" #include "gpopt/operators/CExpression.h" namespace gpopt { using namespace gpos; //--------------------------------------------------------------------------- // @class: // CSubqueryHandler // // @doc: // Helper class for transforming subquery expressions to Apply // expressions // //--------------------------------------------------------------------------- class CSubqueryHandler { public: // context in which subquery appears enum ESubqueryCtxt { EsqctxtValue, // subquery appears in a project list EsqctxtFilter // subquery appears in a comparison predicate }; private: //--------------------------------------------------------------------------- // @struct: // SSubqueryDesc // // @doc: // Structure to maintain subquery descriptor // //--------------------------------------------------------------------------- struct SSubqueryDesc { // subquery can return more than one row BOOL m_returns_set{false}; // subquery has volatile functions BOOL m_fHasVolatileFunctions{false}; // subquery has outer references BOOL m_fHasOuterRefs{false}; // the returned column is an outer reference BOOL m_fReturnedPcrIsOuterRef{false}; // subquery has skip level correlations -- when inner expression refers to columns defined above the immediate outer expression BOOL m_fHasSkipLevelCorrelations{false}; // subquery has a single count(*)/count(Any) agg BOOL m_fHasCountAgg{false}; // column defining count(*)/count(Any) agg, if any CColRef *m_pcrCountAgg{nullptr}; // does subquery project a count expression BOOL m_fProjectCount{false}; // subquery is used in a value context BOOL m_fValueSubquery{false}; // subquery requires correlated execution BOOL m_fCorrelatedExecution{false}; // ctor SSubqueryDesc() = default; // set correlated execution flag void SetCorrelatedExecution(); }; // struct SSubqueryDesc // memory pool CMemoryPool *m_mp; // enforce using correlated apply for unnesting subqueries BOOL m_fEnforceCorrelatedApply; // helper for adding nullness check, only if needed, to the given scalar expression static CExpression *PexprIsNotNull(CMemoryPool *mp, CExpression *pexprOuter, CExpression *pexprLogical, CExpression *pexprScalar); // helper for adding a Project node with a const TRUE on top of the given expression static void AddProjectNode(CMemoryPool *mp, CExpression *pexpr, CExpression **ppexprResult); // helper for creating a groupby node above or below the apply static CExpression *CreateGroupByNode(CMemoryPool *mp, CExpression *pexprChild, CColRefArray *colref_array, BOOL fExistential, CColRef *colref, CExpression *pexprPredicate, CColRef **pcrCount, CColRef **pcrSum); // helper for creating an inner select expression when creating outer apply static CExpression *PexprInnerSelect(CMemoryPool *mp, const CColRef *pcrInner, CExpression *pexprInner, CExpression *pexprPredicate, BOOL *useNotNullableInnerOpt); // helper for creating outer apply expression for scalar subqueries static BOOL FCreateOuterApplyForScalarSubquery( CMemoryPool *mp, CExpression *pexprOuter, CExpression *pexprInner, CExpression *pexprSubquery, BOOL fOuterRefsUnderInner, CExpression **ppexprNewOuter, CExpression **ppexprResidualScalar); // helper for creating grouping columns for outer apply expression static BOOL FCreateGrpCols( CMemoryPool *mp, CExpression *pexprOuter, CExpression *pexprInner, BOOL fExistential, BOOL fOuterRefsUnderInner, CColRefArray **ppdrgpcr, // output: constructed grouping columns BOOL *pfGbOnInner // output: is Gb created on inner expression ); // helper for creating outer apply expression for existential/quantified subqueries static BOOL FCreateOuterApplyForExistOrQuant( CMemoryPool *mp, CExpression *pexprOuter, CExpression *pexprInner, CExpression *pexprSubquery, CExpression *pexprPredicate, BOOL fOuterRefsUnderInner, CExpression **ppexprNewOuter, CExpression **ppexprResidualScalar, BOOL useNotNullableInnerOpt); // helper for creating outer apply expression static BOOL FCreateOuterApply( CMemoryPool *mp, CExpression *pexprOuter, CExpression *pexprInner, CExpression *pexprSubquery, CExpression *pexprPredicate, BOOL fOuterRefsUnderInner, CExpression **ppexprNewOuter, CExpression **ppexprResidualScalar, BOOL useNotNullableInnerOpt); // helper for creating a scalar if expression used when generating an outer apply static CExpression *PexprScalarIf(CMemoryPool *mp, CColRef *pcrBool, CColRef *pcrSum, CColRef *pcrCount, CExpression *pexprSubquery, BOOL useNotNullableInnerOpt); // helper for creating a correlated apply expression for existential subquery static BOOL FCreateCorrelatedApplyForExistentialSubquery( CMemoryPool *mp, CExpression *pexprOuter, CExpression *pexprSubquery, ESubqueryCtxt esqctxt, CExpression **ppexprNewOuter, CExpression **ppexprResidualScalar); // helper for creating a correlated apply expression for quantified subquery static BOOL FCreateCorrelatedApplyForQuantifiedSubquery( CMemoryPool *mp, CExpression *pexprOuter, CExpression *pexprSubquery, ESubqueryCtxt esqctxt, CExpression **ppexprNewOuter, CExpression **ppexprResidualScalar); // helper for creating correlated apply expression static BOOL FCreateCorrelatedApplyForExistOrQuant( CMemoryPool *mp, CExpression *pexprOuter, CExpression *pexprSubquery, ESubqueryCtxt esqctxt, CExpression **ppexprNewOuter, CExpression **ppexprResidualScalar); // create subquery descriptor static SSubqueryDesc *Psd(CMemoryPool *mp, CExpression *pexprSubquery, CExpression *pexprOuter, const CColRef *pcrSubquery, ESubqueryCtxt esqctxt); // detect subqueries with expressions over count aggregate similar to // (SELECT 'abc' || (SELECT count(*) from X)) static BOOL FProjectCountSubquery(CExpression *pexprSubquery, CColRef *ppcrCount); // given an input expression, replace all occurrences of given column with the given scalar expression static CExpression *PexprReplace(CMemoryPool *mp, CExpression *pexpr, CColRef *colref, CExpression *pexprSubquery); // remove a scalar subquery node from scalar tree BOOL FRemoveScalarSubquery(CExpression *pexprOuter, CExpression *pexprSubquery, ESubqueryCtxt esqctxt, CExpression **ppexprNewOuter, CExpression **ppexprResidualScalar); // helper to generate a correlated apply expression when needed static BOOL FGenerateCorrelatedApplyForScalarSubquery( CMemoryPool *mp, CExpression *pexprOuter, CExpression *pexprSubquery, ESubqueryCtxt esqctxt, CSubqueryHandler::SSubqueryDesc *psd, BOOL fEnforceCorrelatedApply, CExpression **ppexprNewOuter, CExpression **ppexprResidualScalar); // internal function for removing a scalar subquery node from scalar tree static BOOL FRemoveScalarSubqueryInternal( CMemoryPool *mp, CExpression *pexprOuter, CExpression *pexprSubquery, ESubqueryCtxt esqctxt, SSubqueryDesc *psd, BOOL fEnforceCorrelatedApply, CExpression **ppexprNewOuter, CExpression **ppexprResidualScalar); // remove a subquery ANY node from scalar tree BOOL FRemoveAnySubquery(CExpression *pexprOuter, CExpression *pexprSubquery, ESubqueryCtxt esqctxt, CExpression **ppexprNewOuter, CExpression **ppexprResidualScalar); // remove a subquery ALL node from scalar tree BOOL FRemoveAllSubquery(CExpression *pexprOuter, CExpression *pexprSubquery, ESubqueryCtxt esqctxt, CExpression **ppexprNewOuter, CExpression **ppexprResidualScalar); // add a limit 1 expression over given expression, // removing any existing limits static CExpression *AddOrReplaceLimitOne(CMemoryPool *mp, CExpression *pexpr); // remove a subquery EXISTS/NOT EXISTS node from scalar tree static BOOL FRemoveExistentialSubquery( CMemoryPool *mp, COperator::EOperatorId op_id, CExpression *pexprOuter, CExpression *pexprSubquery, ESubqueryCtxt esqctxt, CExpression **ppexprNewOuter, CExpression **ppexprResidualScalar); // remove a subquery EXISTS from scalar tree BOOL FRemoveExistsSubquery(CExpression *pexprOuter, CExpression *pexprSubquery, ESubqueryCtxt esqctxt, CExpression **ppexprNewOuter, CExpression **ppexprResidualScalar); // remove a subquery NOT EXISTS from scalar tree BOOL FRemoveNotExistsSubquery(CExpression *pexprOuter, CExpression *pexprSubquery, ESubqueryCtxt esqctxt, CExpression **ppexprNewOuter, CExpression **ppexprResidualScalar); // handle subqueries in scalar tree recursively BOOL FRecursiveHandler(CExpression *pexprOuter, CExpression *pexprScalar, ESubqueryCtxt esqctxt, CExpression **ppexprNewOuter, CExpression **ppexprNewScalar); // handle subqueries on a case-by-case basis BOOL FProcessScalarOperator(CExpression *pexprOuter, CExpression *pexprScalar, ESubqueryCtxt esqctxt, CExpression **ppexprNewOuter, CExpression **ppexprNewScalar); #ifdef GPOS_DEBUG // assert valid values of arguments static void AssertValidArguments(CMemoryPool *mp, CExpression *pexprOuter, CExpression *pexprScalar, CExpression **ppexprNewOuter, CExpression **ppexprResidualScalar); #endif // GPOS_DEBUG public: CSubqueryHandler(const CSubqueryHandler &) = delete; // ctor CSubqueryHandler(CMemoryPool *mp, BOOL fEnforceCorrelatedApply) : m_mp(mp), m_fEnforceCorrelatedApply(fEnforceCorrelatedApply) { } // build an expression for the quantified comparison of the subquery CExpression *PexprSubqueryPred(CExpression *pexprOuter, CExpression *pexprSubquery, CExpression **ppexprResult, CSubqueryHandler::ESubqueryCtxt esqctxt); // main driver BOOL FProcess( CExpression *pexprOuter, // logical child of a SELECT node CExpression *pexprScalar, // scalar child of a SELECT node ESubqueryCtxt esqctxt, // context in which subquery occurs CExpression * *ppexprNewOuter, // an Apply logical expression produced as output CExpression ** ppexprResidualScalar // residual scalar expression produced as output ); }; // class CSubqueryHandler } // namespace gpopt #endif // !GPOPT_CSubqueryHandler_H // EOF