greenplumn CXformUtils 源码

  • 2022-08-18
  • 浏览 (229)

greenplumn CXformUtils 代码

文件路径:/src/backend/gporca/libgpopt/include/gpopt/xforms/CXformUtils.h

//---------------------------------------------------------------------------
//	Greenplum Database
//	Copyright 2012 EMC Corp.
//
//	@filename:
//		CXformUtils.h
//
//	@doc:
//		Utility functions for xforms
//---------------------------------------------------------------------------
#ifndef GPOPT_CXformUtils_H
#define GPOPT_CXformUtils_H

#include "gpos/base.h"

#include "gpopt/base/CCastUtils.h"
#include "gpopt/base/CColRef.h"
#include "gpopt/base/COptCtxt.h"
#include "gpopt/base/CUtils.h"
#include "gpopt/operators/CLogicalDML.h"
#include "gpopt/operators/CLogicalDynamicIndexGet.h"
#include "gpopt/operators/CLogicalIndexGet.h"
#include "gpopt/operators/CLogicalJoin.h"
#include "gpopt/operators/CPhysicalJoin.h"
#include "gpopt/operators/CPredicateUtils.h"
#include "gpopt/xforms/CXform.h"
#include "naucrates/md/IMDIndex.h"
#include "naucrates/md/IMDScalarOp.h"

namespace gpopt
{
using namespace gpos;

// forward declarations
class CGroupExpression;
class CColRefSet;
class CExpression;
class CLogical;
class CLogicalDynamicGet;
class CPartConstraint;
class CTableDescriptor;

// map of expression to array of expressions
using ExprToExprArrayMap =
	CHashMap<CExpression, CExpressionArray, CExpression::HashValue,
			 CUtils::Equals, CleanupRelease<CExpression>,
			 CleanupRelease<CExpressionArray>>;

// iterator of map of expression to array of expressions
using ExprToExprArrayMapIter =
	CHashMapIter<CExpression, CExpressionArray, CExpression::HashValue,
				 CUtils::Equals, CleanupRelease<CExpression>,
				 CleanupRelease<CExpressionArray>>;

// array of array of expressions
using CExpressionArrays = CDynamicPtrArray<CExpressionArray, CleanupRelease>;

//---------------------------------------------------------------------------
//	@class:
//		CXformUtils
//
//	@doc:
//		Utility functions for xforms
//
//---------------------------------------------------------------------------
class CXformUtils
{
private:
	// enum marking the index column types
	enum EIndexCols
	{
		EicKey,
		EicIncluded
	};

	// create a logical assert for the not nullable columns of the given table
	// on top of the given child expression
	static CExpression *PexprAssertNotNull(CMemoryPool *mp,
										   CExpression *pexprChild,
										   CTableDescriptor *ptabdesc,
										   CColRefArray *colref_array);

	// create a logical assert for the check constraints on the given table
	static CExpression *PexprAssertCheckConstraints(CMemoryPool *mp,
													CExpression *pexprChild,
													CTableDescriptor *ptabdesc,
													CColRefArray *colref_array);

	// helper for extracting foreign key
	static CColRefSet *PcrsFKey(CMemoryPool *mp, CExpressionArray *pdrgpexpr,
								CColRefSet *prcsOutput, CColRefSet *pcrsKey);

	// return the set of columns from the given array of columns which appear
	// in the index included / key columns
	static CColRefSet *PcrsIndexColumns(CMemoryPool *mp,
										CColRefArray *colref_array,
										const IMDIndex *pmdindex,
										const IMDRelation *pmdrel,
										EIndexCols eic);

	// return the ordered array of columns from the given array of columns which appear
	// in the index included / key columns
	static CColRefArray *PdrgpcrIndexColumns(CMemoryPool *mp,
											 CColRefArray *colref_array,
											 const IMDIndex *pmdindex,
											 const IMDRelation *pmdrel,
											 EIndexCols eic);

	// lookup join keys in scalar child group
	static void LookupJoinKeys(CMemoryPool *mp, CExpression *pexpr,
							   CExpressionArray **ppdrgpexprOuter,
							   CExpressionArray **ppdrgpexprInner,
							   IMdIdArray **join_opfamilies);

	// cache join keys on scalar child group
	static void CacheJoinKeys(CExpression *pexpr,
							  CExpressionArray *pdrgpexprOuter,
							  CExpressionArray *pdrgpexprInner,
							  IMdIdArray *join_opfamilies);

	// helper to extract equality from a given expression
	static BOOL FExtractEquality(
		CExpression *pexpr,
		CExpression **
			ppexprEquality,	 // output: extracted equality expression, set to NULL if extraction failed
		CExpression **
			ppexprOther	 // output: sibling of equality expression, set to NULL if extraction failed
	);

	// check if given xform id is in the given array of xforms
	static BOOL FXformInArray(CXform::EXformId exfid,
							  const CXform::EXformId rgXforms[],
							  ULONG ulXforms);

#ifdef GPOS_DEBUG
	// check whether the given join type is swapable
	static BOOL FSwapableJoinType(COperator::EOperatorId op_id);
#endif	// GPOS_DEBUG

	// helper function for adding hash join alternative
	template <class T>
	static void AddHashOrMergeJoinAlternative(CMemoryPool *mp,
											  CExpression *pexprJoin,
											  CExpressionArray *pdrgpexprOuter,
											  CExpressionArray *pdrgpexprInner,
											  IMdIdArray *join_opfamilies,
											  CXformResult *pxfres);

	// helper for transforming SubqueryAll into aggregate subquery
	static void SubqueryAllToAgg(
		CMemoryPool *mp, CExpression *pexprSubquery,
		CExpression *
			*ppexprNewSubquery,	 // output argument for new scalar subquery
		CExpression *
			*ppexprNewScalar  // output argument for new scalar expression
	);

	// helper for transforming SubqueryAny into aggregate subquery
	static void SubqueryAnyToAgg(
		CMemoryPool *mp, CExpression *pexprSubquery,
		CExpression *
			*ppexprNewSubquery,	 // output argument for new scalar subquery
		CExpression *
			*ppexprNewScalar  // output argument for new scalar expression
	);

	// create the Gb operator to be pushed below a join
	static CLogicalGbAgg *PopGbAggPushableBelowJoin(CMemoryPool *mp,
													CLogicalGbAgg *popGbAggOld,
													CColRefSet *prcsOutput,
													CColRefSet *pcrsGrpCols);

	// check if the preconditions for pushing down Group by through join are satisfied
	static BOOL FCanPushGbAggBelowJoin(CColRefSet *pcrsGrpCols,
									   CColRefSet *pcrsJoinOuterChildOutput,
									   CColRefSet *pcrsJoinScalarUsedFromOuter,
									   CColRefSet *pcrsGrpByOutput,
									   CColRefSet *pcrsGrpByUsed,
									   CColRefSet *pcrsFKey);

	// construct an expression representing a new access path using the given functors for
	// operator constructors and rewritten access path
	static CExpression *PexprBuildBtreeIndexPlan(
		CMemoryPool *mp, CMDAccessor *md_accessor, CExpression *pexprGet,
		ULONG ulOriginOpId, CExpressionArray *pdrgpexprConds,
		CColRefSet *pcrsReqd, CColRefSet *pcrsScalarExpr,
		CColRefSet *outer_refs, const IMDIndex *pmdindex,
		const IMDRelation *pmdrel);

	// create a dynamic operator for a btree index plan
	static CLogical *
	PopDynamicBtreeIndexOpConstructor(CMemoryPool *mp, const IMDIndex *pmdindex,
									  CTableDescriptor *ptabdesc,
									  ULONG ulOriginOpId, CName *pname,
									  ULONG ulPartIndex,
									  CColRefArray *pdrgpcrOutput,
									  CColRef2dArray *pdrgpdrgpcrPart,
									  IMdIdArray *partition_mdids)
	{
		return GPOS_NEW(mp) CLogicalDynamicIndexGet(
			mp, pmdindex, ptabdesc, ulOriginOpId, pname, ulPartIndex,
			pdrgpcrOutput, pdrgpdrgpcrPart, partition_mdids);
	}

	//	create a static operator for a btree index plan
	static CLogical *
	PopStaticBtreeIndexOpConstructor(CMemoryPool *mp, const IMDIndex *pmdindex,
									 CTableDescriptor *ptabdesc,
									 ULONG ulOriginOpId, CName *pname,
									 CColRefArray *pdrgpcrOutput)
	{
		return GPOS_NEW(mp) CLogicalIndexGet(
			mp, pmdindex, ptabdesc, ulOriginOpId, pname, pdrgpcrOutput);
	}

	//	produce an expression representing a new btree index path
	static CExpression *
	PexprRewrittenBtreeIndexPath(CMemoryPool *mp, CExpression *pexprIndexCond,
								 CExpression *pexprResidualCond,
								 const IMDIndex *,	  // pmdindex
								 CTableDescriptor *,  // ptabdesc
								 COperator *popLogical)
	{
		// create the expression containing the logical index get operator
		return CUtils::PexprSafeSelect(
			mp, GPOS_NEW(mp) CExpression(mp, popLogical, pexprIndexCond),
			pexprResidualCond);
	}

	// construct a bitmap index path expression for the given predicate
	// out of the children of the given expression
	static CExpression *PexprBitmapLookupWithPredicateBreakDown(
		CMemoryPool *mp, CMDAccessor *md_accessor,
		CExpression *pexprOriginalPred, CExpression *pexprPred,
		CTableDescriptor *ptabdesc, const IMDRelation *pmdrel,
		CColRefArray *pdrgpcrOutput, CColRefSet *outer_refs,
		CColRefSet *pcrsReqd, CExpression **ppexprRecheck,
		CExpression **ppexprResidual);

	// compute the residual predicate for a bitmap table scan
	static void ComputeBitmapTableScanResidualPredicate(
		CMemoryPool *mp, BOOL fConjunction, CExpression *pexprOriginalPred,
		CExpression **ppexprResidual, CExpressionArray *pdrgpexprResidualNew);

	// construct a bitmap index path expression for the given predicate coming
	// from a condition without outer references
	static CExpression *PexprBitmapSelectBestIndex(
		CMemoryPool *mp, CMDAccessor *md_accessor, CExpression *pexprPred,
		CTableDescriptor *ptabdesc, const IMDRelation *pmdrel,
		CColRefArray *pdrgpcrOutput, CColRefSet *pcrsReqd,
		CColRefSet *pcrsOuterRefs, CExpression **ppexprRecheck,
		CExpression **ppexprResidual, BOOL alsoConsiderBTreeIndexes);

	// iterate over given hash map and return array of arrays of project elements sorted by the column id of the first entries
	static CExpressionArrays *PdrgpdrgpexprSortedPrjElemsArray(
		CMemoryPool *mp, ExprToExprArrayMap *phmexprdrgpexpr);

	// comparator used in sorting arrays of project elements based on the column id of the first entry
	static INT ICmpPrjElemsArr(const void *pvFst, const void *pvSnd);

public:
	CXformUtils(const CXformUtils &) = delete;

	// helper function for implementation xforms on binary operators
	// with predicates (e.g. joins)
	template <class T>
	static void TransformImplementBinaryOp(CXformContext *pxfctxt,
										   CXformResult *pxfres,
										   CExpression *pexpr);

	// helper function for implementation of hash joins
	template <class T>
	static void ImplementHashJoin(CXformContext *pxfctxt, CXformResult *pxfres,
								  CExpression *pexpr);

	// helper function for implementation of merge joins
	template <class T>
	static void ImplementMergeJoin(CXformContext *pxfctxt, CXformResult *pxfres,
								   CExpression *pexpr);

	// helper function for implementation of nested loops joins
	template <class T>
	static void ImplementNLJoin(CXformContext *pxfctxt, CXformResult *pxfres,
								CExpression *pexpr);

	// helper for removing IsNotFalse join predicate for GPDB anti-semi hash join
	static BOOL FProcessGPDBAntiSemiHashJoin(CMemoryPool *mp,
											 CExpression *pexpr,
											 CExpression **ppexprResult);

	// check the applicability of logical join to physical join xform
	static CXform::EXformPromise ExfpLogicalJoin2PhysicalJoin(
		CExpressionHandle &exprhdl);

	// check the applicability of semi join to cross product
	static CXform::EXformPromise ExfpSemiJoin2CrossProduct(
		CExpressionHandle &exprhdl);

	// check the applicability of N-ary join expansion
	static CXform::EXformPromise ExfpExpandJoinOrder(CExpressionHandle &exprhdl,
													 const CXform *xform);

	// extract foreign key
	static CColRefSet *PcrsFKey(CMemoryPool *mp, CExpression *pexprOuter,
								CExpression *pexprInner,
								CExpression *pexprScalar);

	// compute a swap of the two given joins
	static CExpression *PexprSwapJoins(CMemoryPool *mp,
									   CExpression *pexprTopJoin,
									   CExpression *pexprBottomJoin);

	// push a Gb, optionally with a having clause below the child join
	static CExpression *PexprPushGbBelowJoin(CMemoryPool *mp,
											 CExpression *pexpr);

	// check if the the array of aligned input columns are of the same type
	static BOOL FSameDatatype(CColRef2dArray *pdrgpdrgpcrInput);

	// helper function to separate subquery predicates in a top Select node
	static CExpression *PexprSeparateSubqueryPreds(CMemoryPool *mp,
												   CExpression *pexpr);

	// helper for creating inverse predicate for unnesting subquery ALL
	static CExpression *PexprInversePred(CMemoryPool *mp,
										 CExpression *pexprSubquery);

	// helper for creating a null indicator expression
	static CExpression *PexprNullIndicator(CMemoryPool *mp, CExpression *pexpr);

	// helper for creating a logical DML on top of a project
	static CExpression *PexprLogicalDMLOverProject(
		CMemoryPool *mp, CExpression *pexprChild,
		CLogicalDML::EDMLOperator edmlop, CTableDescriptor *ptabdesc,
		CColRefArray *colref_array, CColRef *pcrCtid, CColRef *pcrSegmentId);

	// check whether there are any BEFORE or AFTER triggers on the
	// given table that match the given DML operation
	static BOOL FTriggersExist(CLogicalDML::EDMLOperator edmlop,
							   CTableDescriptor *ptabdesc, BOOL fBefore);

	// does the given trigger type match the given logical DML type
	static BOOL FTriggerApplies(CLogicalDML::EDMLOperator edmlop,
								const IMDTrigger *pmdtrigger);

	// construct a trigger expression on top of the given expression
	static CExpression *PexprRowTrigger(CMemoryPool *mp,
										CExpression *pexprChild,
										CLogicalDML::EDMLOperator edmlop,
										IMDId *rel_mdid, BOOL fBefore,
										CColRefArray *colref_array);

	// construct a trigger expression on top of the given expression
	static CExpression *PexprRowTrigger(CMemoryPool *mp,
										CExpression *pexprChild,
										CLogicalDML::EDMLOperator edmlop,
										IMDId *rel_mdid, BOOL fBefore,
										CColRefArray *pdrgpcrOld,
										CColRefArray *pdrgpcrNew);

	// construct a logical partition selector for the given table descriptor on top
	// of the given child expression. The partition selection filters use columns
	// from the given column array
	static CExpression *PexprLogicalPartitionSelector(
		CMemoryPool *mp, CTableDescriptor *ptabdesc, CColRefArray *colref_array,
		CExpression *pexprChild);

	// return partition filter expressions given a table
	// descriptor and the given column references
	static CExpressionArray *PdrgpexprPartEqFilters(
		CMemoryPool *mp, CTableDescriptor *ptabdesc,
		CColRefArray *pdrgpcrSource);

	// helper for creating Agg expression equivalent to quantified subquery
	static void QuantifiedToAgg(CMemoryPool *mp, CExpression *pexprSubquery,
								CExpression **ppexprNewSubquery,
								CExpression **ppexprNewScalar);

	// helper for creating Agg expression equivalent to existential subquery
	static void ExistentialToAgg(CMemoryPool *mp, CExpression *pexprSubquery,
								 CExpression **ppexprNewSubquery,
								 CExpression **ppexprNewScalar);

	// create a logical assert for the check constraints on the given table
	static CExpression *PexprAssertConstraints(CMemoryPool *mp,
											   CExpression *pexprChild,
											   CTableDescriptor *ptabdesc,
											   CColRefArray *colref_array);

	// return true if stats derivation is needed for this xform
	static BOOL FDeriveStatsBeforeXform(CXform *pxform);

	// return true if xform is a subquery decorrelation xform
	static BOOL FSubqueryDecorrelation(CXform *pxform);

	// return true if xform is a subquery unnesting xform
	static BOOL FSubqueryUnnesting(CXform *pxform);

	// return true if xform should be applied to the next binding
	static BOOL FApplyToNextBinding(CXform *pxform,
									CExpression *pexprLastBinding);

	// return a formatted error message for the given exception
	static CWStringConst *PstrErrorMessage(CMemoryPool *mp, ULONG major,
										   ULONG minor, ...);

	// return the array of key columns from the given array of columns which appear
	// in the index key columns
	static CColRefArray *PdrgpcrIndexKeys(CMemoryPool *mp,
										  CColRefArray *colref_array,
										  const IMDIndex *pmdindex,
										  const IMDRelation *pmdrel);

	// return the set of key columns from the given array of columns which appear
	// in the index key columns
	static CColRefSet *PcrsIndexKeys(CMemoryPool *mp,
									 CColRefArray *colref_array,
									 const IMDIndex *pmdindex,
									 const IMDRelation *pmdrel);

	// return the set of key columns from the given array of columns which appear
	// in the index included columns
	static CColRefSet *PcrsIndexIncludedCols(CMemoryPool *mp,
											 CColRefArray *colref_array,
											 const IMDIndex *pmdindex,
											 const IMDRelation *pmdrel);

	// check if an index is applicable given the required, output and scalar
	// expression columns
	static BOOL FIndexApplicable(
		CMemoryPool *mp, const IMDIndex *pmdindex, const IMDRelation *pmdrel,
		CColRefArray *pdrgpcrOutput, CColRefSet *pcrsReqd,
		CColRefSet *pcrsScalar, IMDIndex::EmdindexType emdindtype,
		IMDIndex::EmdindexType altindtype = IMDIndex::EmdindSentinel);

	// check whether a CTE should be inlined
	static BOOL FInlinableCTE(ULONG ulCTEId);

	// return the column reference of the n-th project element
	static CColRef *PcrProjectElement(CExpression *pexpr,
									  ULONG ulIdxProjElement);

	// create an expression with "row_number" window function
	static CExpression *PexprRowNumber(CMemoryPool *mp);

	// create a logical sequence project with a "row_number" window function
	static CExpression *PexprWindowWithRowNumber(CMemoryPool *mp,
												 CExpression *pexprWindowChild,
												 CColRefArray *pdrgpcrInput);

	// generate a logical Assert expression that errors out when more than one row is generated
	static CExpression *PexprAssertOneRow(CMemoryPool *mp,
										  CExpression *pexprChild);

	// helper for adding CTE producer to global CTE info structure
	static CExpression *PexprAddCTEProducer(CMemoryPool *mp, ULONG ulCTEId,
											CColRefArray *colref_array,
											CExpression *pexpr);

	// does transformation generate an Apply expression
	static BOOL
	FGenerateApply(CXform::EXformId exfid)
	{
		return CXform::ExfSelect2Apply == exfid ||
			   CXform::ExfProject2Apply == exfid ||
			   CXform::ExfGbAgg2Apply == exfid ||
			   CXform::ExfSubqJoin2Apply == exfid ||
			   CXform::ExfSubqNAryJoin2Apply == exfid ||
			   CXform::ExfSequenceProject2Apply == exfid;
	}

	// helper for creating IndexGet/DynamicIndexGet expression
	static CExpression *
	PexprLogicalIndexGet(CMemoryPool *mp, CMDAccessor *md_accessor,
						 CExpression *pexprGet, ULONG ulOriginOpId,
						 CExpressionArray *pdrgpexprConds, CColRefSet *pcrsReqd,
						 CColRefSet *pcrsScalarExpr, CColRefSet *outer_refs,
						 const IMDIndex *pmdindex, const IMDRelation *pmdrel)
	{
		return PexprBuildBtreeIndexPlan(
			mp, md_accessor, pexprGet, ulOriginOpId, pdrgpexprConds, pcrsReqd,
			pcrsScalarExpr, outer_refs, pmdindex, pmdrel);
	}

	// helper for creating bitmap bool op expressions
	static CExpression *PexprScalarBitmapBoolOp(
		CMemoryPool *mp, CMDAccessor *md_accessor,
		CExpression *pexprOriginalPred, CExpressionArray *pdrgpexpr,
		CTableDescriptor *ptabdesc, const IMDRelation *pmdrel,
		CColRefArray *pdrgpcrOutput, CColRefSet *outer_refs,
		CColRefSet *pcrsReqd, BOOL fConjunction, CExpression **ppexprRecheck,
		CExpression **ppexprResidual, BOOL isAPartialPredicate);

	// construct a bitmap bool op given the left and right bitmap access
	// path expressions
	static CExpression *PexprBitmapBoolOp(CMemoryPool *mp,
										  IMDId *pmdidBitmapType,
										  CExpression *pexprLeft,
										  CExpression *pexprRight,
										  BOOL fConjunction);

	// given an array of predicate expressions, construct a bitmap access path
	// expression for each predicate and accumulate it in the pdrgpexprBitmap array
	static void CreateBitmapIndexProbeOps(
		CMemoryPool *mp, CMDAccessor *md_accessor,
		CExpression *pexprOriginalPred, CExpressionArray *pdrgpexprPreds,
		CTableDescriptor *ptabdesc, const IMDRelation *pmdrel,
		CColRefArray *pdrgpcrOutput, CColRefSet *outer_refs,
		CColRefSet *pcrsReqd, BOOL fConjunction,
		CExpressionArray *pdrgpexprBitmap, CExpressionArray *pdrgpexprRecheck,
		CExpressionArray *pdrgpexprResidual, BOOL isAPartialPredicate);

	static void CreateBitmapIndexProbesWithOrWithoutPredBreakdown(
		CMemoryPool *mp, CMDAccessor *md_accessor,
		CExpression *pexprOriginalPred, CExpression *pexprPred,
		CTableDescriptor *ptabdesc, const IMDRelation *pmdrel,
		CColRefArray *pdrgpcrOutput, CColRefSet *outer_refs,
		CColRefSet *pcrsReqd, CExpression **pexprBitmapResult,
		CExpression **pexprRecheckResult,
		CExpressionArray *pdrgpexprResidualResult, BOOL isAPartialPredicate);

	// check if expression has any scalar node with ambiguous return type
	static BOOL FHasAmbiguousType(CExpression *pexpr, CMDAccessor *md_accessor);

	// construct a Bitmap(Dynamic)TableGet over BitmapBoolOp for the given
	// logical operator if bitmap indexes exist
	static CExpression *PexprBitmapTableGet(CMemoryPool *mp, CLogical *popGet,
											ULONG ulOriginOpId,
											CTableDescriptor *ptabdesc,
											CExpression *pexprScalar,
											CColRefSet *outer_refs,
											CColRefSet *pcrsReqd);

	// transform a Select over a (dynamic) table get into a bitmap table scan
	// over bitmap bool op
	static CExpression *PexprSelect2BitmapBoolOp(CMemoryPool *mp,
												 CExpression *pexpr);

	// remap the expression from the old columns to the new ones
	static CExpression *PexprRemapColumns(CMemoryPool *mp,
										  CExpression *pexprScalar,
										  CColRefArray *pdrgpcrA,
										  CColRefArray *pdrgpcrRemappedA,
										  CColRefArray *pdrgpcrB,
										  CColRefArray *pdrgpcrRemappedB);

	// create a new CTE consumer for the given CTE id
	static CExpression *PexprCTEConsumer(CMemoryPool *mp, ULONG ulCTEId,
										 CColRefArray *pdrgpcrConsumer);

	// return a new array containing the columns from the given column array 'colref_array'
	// at the positions indicated by the given ULONG array 'pdrgpulIndexesOfRefs'
	// e.g., colref_array = {col1, col2, col3}, pdrgpulIndexesOfRefs = {2, 1}
	// the result will be {col3, col2}
	static CColRefArray *PdrgpcrReorderedSubsequence(
		CMemoryPool *mp, CColRefArray *colref_array,
		ULongPtrArray *pdrgpulIndexesOfRefs);

	// check if given xform is an Agg splitting xform
	static BOOL FSplitAggXform(CXform::EXformId exfid);

	// check if given xform is an Agg CXformSplitDQA
	static BOOL FAggGenBySplitDQAXform(CExpression *pexprAgg);

	// check if given expression is a multi-stage Agg based on origin xform
	static BOOL FMultiStageAgg(CExpression *pexprAgg);

	static BOOL FLocalAggCreatedByEagerAggXform(CExpression *pexprAgg);

	// check if expression handle is attached to a Join with a predicate that uses columns from only one child
	static BOOL FJoinPredOnSingleChild(CMemoryPool *mp,
									   CExpressionHandle &exprhdl);

	// add a redundant SELECT node on top of Dynamic (Bitmap) IndexGet to be able to use index
	// predicate in partition elimination
	static CExpression *PexprRedundantSelectForDynamicIndex(CMemoryPool *mp,
															CExpression *pexpr);

	// convert an Agg window function into regular Agg
	static CExpression *PexprWinFuncAgg2ScalarAgg(CMemoryPool *mp,
												  CExpression *pexprWinFunc);

	// create a map from the argument of each Distinct Agg to the array of project elements that define Distinct Aggs on the same argument
	static void MapPrjElemsWithDistinctAggs(
		CMemoryPool *mp, CExpression *pexprPrjList,
		ExprToExprArrayMap **pphmexprdrgpexpr, ULONG *pulDifferentDQAs);

	// convert GbAgg with distinct aggregates to a join
	static CExpression *PexprGbAggOnCTEConsumer2Join(CMemoryPool *mp,
													 CExpression *pexprGbAgg);

	// combine the individual bitmap access paths to form a bitmap bool op expression
	static void JoinBitmapIndexProbes(CMemoryPool *pmp,
									  CExpressionArray *pdrgpexprBitmapOld,
									  CExpressionArray *pdrgpexprRecheckOld,
									  BOOL fConjunction,
									  CExpression **ppexprBitmap,
									  CExpression **ppexprRecheck);

	static CExpression *AddALinearStackOfUnaryExpressions(
		CMemoryPool *mp, CExpression *lowerPartOfExpr, CExpression *topOfStack,
		CExpression *exclusiveBottomOfStack);

};	// class CXformUtils


//---------------------------------------------------------------------------
//	@function:
//		CXformUtils::TransformImplementBinaryOp
//
//	@doc:
//		Helper function for implementation xforms on binary operators
//		with predicates (e.g. joins)
//
//---------------------------------------------------------------------------
template <class T>
void
CXformUtils::TransformImplementBinaryOp(CXformContext *pxfctxt,
										CXformResult *pxfres,
										CExpression *pexpr)
{
	GPOS_ASSERT(nullptr != pxfctxt);
	GPOS_ASSERT(nullptr != pexpr);

	CMemoryPool *mp = pxfctxt->Pmp();

	// extract components
	CExpression *pexprLeft = (*pexpr)[0];
	CExpression *pexprRight = (*pexpr)[1];
	CExpression *pexprScalar = (*pexpr)[2];

	// addref all children
	pexprLeft->AddRef();
	pexprRight->AddRef();
	pexprScalar->AddRef();

	// assemble physical operator
	CExpression *pexprBinary = GPOS_NEW(mp)
		CExpression(mp, GPOS_NEW(mp) T(mp), pexprLeft, pexprRight, pexprScalar);

#ifdef GPOS_DEBUG
	COperator::EOperatorId op_id = pexprBinary->Pop()->Eopid();
#endif	// GPOS_DEBUG
	GPOS_ASSERT(COperator::EopPhysicalInnerNLJoin == op_id ||
				COperator::EopPhysicalLeftOuterNLJoin == op_id ||
				COperator::EopPhysicalLeftSemiNLJoin == op_id ||
				COperator::EopPhysicalLeftAntiSemiNLJoin == op_id ||
				COperator::EopPhysicalLeftAntiSemiNLJoinNotIn == op_id);

	// add alternative to results
	pxfres->Add(pexprBinary);
}

template <class T>
void
CXformUtils::AddHashOrMergeJoinAlternative(CMemoryPool *mp,
										   CExpression *pexprJoin,
										   CExpressionArray *pdrgpexprOuter,
										   CExpressionArray *pdrgpexprInner,
										   IMdIdArray *opfamilies,
										   CXformResult *pxfres)
{
	GPOS_ASSERT(CUtils::FLogicalJoin(pexprJoin->Pop()));
	GPOS_ASSERT(3 == pexprJoin->Arity());
	GPOS_ASSERT(nullptr != pdrgpexprOuter);
	GPOS_ASSERT(nullptr != pdrgpexprInner);
	GPOS_ASSERT(nullptr != pxfres);

	for (ULONG ul = 0; ul < 3; ul++)
	{
		(*pexprJoin)[ul]->AddRef();
	}
	CLogicalJoin *popLogicalJoin = CLogicalJoin::PopConvert(pexprJoin->Pop());
	T *op = GPOS_NEW(mp) T(mp, pdrgpexprOuter, pdrgpexprInner, opfamilies,
						   popLogicalJoin->OriginXform());
	CExpression *pexprResult = GPOS_NEW(mp)
		CExpression(mp, op, (*pexprJoin)[0], (*pexprJoin)[1], (*pexprJoin)[2]);
	pxfres->Add(pexprResult);
}


//---------------------------------------------------------------------------
//	@function:
//		CXformUtils::ImplementHashJoin
//
//	@doc:
//		Helper function for implementation of hash joins
//
//---------------------------------------------------------------------------
template <class T>
void
CXformUtils::ImplementHashJoin(CXformContext *pxfctxt, CXformResult *pxfres,
							   CExpression *pexpr)
{
	GPOS_ASSERT(nullptr != pxfctxt);

	// if there are outer references, then we cannot build a hash join
	if (CUtils::HasOuterRefs(pexpr))
	{
		return;
	}

	CMemoryPool *mp = pxfctxt->Pmp();
	CExpressionArray *pdrgpexprOuter = nullptr;
	CExpressionArray *pdrgpexprInner = nullptr;
	IMdIdArray *join_opfamilies = nullptr;

	// check if we have already computed hash join keys for the scalar child
	LookupJoinKeys(mp, pexpr, &pdrgpexprOuter, &pdrgpexprInner,
				   &join_opfamilies);
	if (nullptr != pdrgpexprOuter)
	{
		GPOS_ASSERT(nullptr != pdrgpexprInner);
		if (0 == pdrgpexprOuter->Size())
		{
			GPOS_ASSERT(0 == pdrgpexprInner->Size());

			// we failed before to find hash join keys for scalar child,
			// no reason to try to do the same again
			pdrgpexprOuter->Release();
			pdrgpexprInner->Release();
			CRefCount::SafeRelease(join_opfamilies);
		}
		else
		{
			// we have computed hash join keys on scalar child before, reuse them
			AddHashOrMergeJoinAlternative<T>(mp, pexpr, pdrgpexprOuter,
											 pdrgpexprInner, join_opfamilies,
											 pxfres);
		}

		return;
	}

	CExpression *pexprOuter = (*pexpr)[0];
	CExpression *pexprInner = (*pexpr)[1];
	CExpression *pexprScalar = (*pexpr)[2];

	// split the predicate into arrays of conjuncts based on if they are
	// output from inner or outer child
	pdrgpexprOuter = GPOS_NEW(mp) CExpressionArray(mp);
	pdrgpexprInner = GPOS_NEW(mp) CExpressionArray(mp);

	if (GPOS_FTRACE(EopttraceConsiderOpfamiliesForDistribution))
	{
		join_opfamilies = GPOS_NEW(mp) IMdIdArray(mp);
	}

	CExpressionArray *pdrgpexpr =
		CCastUtils::PdrgpexprCastEquality(mp, pexprScalar);
	ULONG ulPreds = pdrgpexpr->Size();
	for (ULONG ul = 0; ul < ulPreds; ul++)
	{
		CExpression *pexprPred = (*pdrgpexpr)[ul];
		if (CPhysicalJoin::FHashJoinCompatible(pexprPred, pexprOuter,
											   pexprInner))
		{
			CExpression *pexprPredInner;
			CExpression *pexprPredOuter;
			IMDId *mdid_scop;
			CPhysicalJoin::AlignJoinKeyOuterInner(pexprPred, pexprOuter,
												  pexprInner, &pexprPredOuter,
												  &pexprPredInner, &mdid_scop);

			pexprPredInner->AddRef();
			pexprPredOuter->AddRef();
			pdrgpexprOuter->Append(pexprPredOuter);
			pdrgpexprInner->Append(pexprPredInner);

			if (GPOS_FTRACE(EopttraceConsiderOpfamiliesForDistribution))
			{
				CMDAccessor *mda = COptCtxt::PoctxtFromTLS()->Pmda();
				IMDId *hash_opfamily =
					mda->RetrieveScOp(mdid_scop)->HashOpfamilyMdid();
				GPOS_ASSERT(nullptr != hash_opfamily &&
							hash_opfamily->IsValid());
				hash_opfamily->AddRef();
				join_opfamilies->Append(hash_opfamily);
			}
		}
	}
	GPOS_ASSERT(pdrgpexprInner->Size() == pdrgpexprOuter->Size());
	GPOS_ASSERT_IMP(GPOS_FTRACE(EopttraceConsiderOpfamiliesForDistribution),
					pdrgpexprInner->Size() == join_opfamilies->Size());

	// construct new HashJoin expression using explicit casting, if needed
	pexpr->Pop()->AddRef();
	pexprOuter->AddRef();
	pexprInner->AddRef();
	CExpression *pexprResult = GPOS_NEW(mp)
		CExpression(mp, pexpr->Pop(), pexprOuter, pexprInner,
					CPredicateUtils::PexprConjunction(mp, pdrgpexpr));

	// cache hash join keys on scalar child group
	CacheJoinKeys(pexprResult, pdrgpexprOuter, pdrgpexprInner, join_opfamilies);

	// Add an alternative only if we found at least one hash-joinable predicate
	if (0 != pdrgpexprOuter->Size())
	{
		AddHashOrMergeJoinAlternative<T>(mp, pexprResult, pdrgpexprOuter,
										 pdrgpexprInner, join_opfamilies,
										 pxfres);
	}
	else
	{
		// clean up
		pdrgpexprOuter->Release();
		pdrgpexprInner->Release();
		CRefCount::SafeRelease(join_opfamilies);
	}

	pexprResult->Release();
}

template <class T>
void
CXformUtils::ImplementMergeJoin(CXformContext *pxfctxt, CXformResult *pxfres,
								CExpression *pexpr)
{
	GPOS_ASSERT(nullptr != pxfctxt);

	// if there are outer references, then we cannot build a merge join
	if (CUtils::HasOuterRefs(pexpr))
	{
		return;
	}

	CMemoryPool *mp = pxfctxt->Pmp();
	CExpressionArray *pdrgpexprOuter = nullptr;
	CExpressionArray *pdrgpexprInner = nullptr;
	IMdIdArray *join_opfamilies = nullptr;

	// check if we have already computed join keys for the scalar child
	LookupJoinKeys(mp, pexpr, &pdrgpexprOuter, &pdrgpexprInner,
				   &join_opfamilies);
	if (nullptr != pdrgpexprOuter)
	{
		GPOS_ASSERT(nullptr != pdrgpexprInner);
		if (0 == pdrgpexprOuter->Size())
		{
			GPOS_ASSERT(0 == pdrgpexprInner->Size());

			// we failed before to find join keys for scalar child,
			// no reason to try to do the same again
			pdrgpexprOuter->Release();
			pdrgpexprInner->Release();
			CRefCount::SafeRelease(join_opfamilies);
		}
		else
		{
			// we have computed join keys on scalar child before, reuse them
			AddHashOrMergeJoinAlternative<T>(mp, pexpr, pdrgpexprOuter,
											 pdrgpexprInner, join_opfamilies,
											 pxfres);
		}

		return;
	}

	CExpression *pexprOuter = (*pexpr)[0];
	CExpression *pexprInner = (*pexpr)[1];
	CExpression *pexprScalar = (*pexpr)[2];

	// split the predicate into arrays of conjuncts based on if they are
	// output from inner or outer child
	pdrgpexprOuter = GPOS_NEW(mp) CExpressionArray(mp);
	pdrgpexprInner = GPOS_NEW(mp) CExpressionArray(mp);

	if (GPOS_FTRACE(EopttraceConsiderOpfamiliesForDistribution))
	{
		join_opfamilies = GPOS_NEW(mp) IMdIdArray(mp);
	}

	CExpressionArray *pdrgpexpr =
		CPredicateUtils::PdrgpexprConjuncts(mp, pexprScalar);
	ULONG ulPreds = pdrgpexpr->Size();
	for (ULONG ul = 0; ul < ulPreds; ul++)
	{
		CExpression *pexprPred = (*pdrgpexpr)[ul];
		if (CPhysicalJoin::FMergeJoinCompatible(pexprPred, pexprOuter,
												pexprInner))
		{
			CExpression *pexprPredInner;
			CExpression *pexprPredOuter;
			IMDId *mdid_scop;
			CPhysicalJoin::AlignJoinKeyOuterInner(pexprPred, pexprOuter,
												  pexprInner, &pexprPredOuter,
												  &pexprPredInner, &mdid_scop);

			pexprPredInner->AddRef();
			pexprPredOuter->AddRef();
			pdrgpexprOuter->Append(pexprPredOuter);
			pdrgpexprInner->Append(pexprPredInner);

			if (GPOS_FTRACE(EopttraceConsiderOpfamiliesForDistribution))
			{
				CMDAccessor *mda = COptCtxt::PoctxtFromTLS()->Pmda();
				IMDId *hash_opfamily =
					mda->RetrieveScOp(mdid_scop)->HashOpfamilyMdid();
				GPOS_ASSERT(nullptr != hash_opfamily &&
							hash_opfamily->IsValid());
				hash_opfamily->AddRef();
				join_opfamilies->Append(hash_opfamily);
			}
		}
		else
		{
			// In case of FULL merge joins, all the merge clauses must be merge
			// compatible or we cannot create a merge join.
			pdrgpexpr->Release();
			pdrgpexprOuter->Release();
			pdrgpexprInner->Release();
			CRefCount::SafeRelease(join_opfamilies);
			return;
		}
	}
	GPOS_ASSERT(pdrgpexprInner->Size() == pdrgpexprOuter->Size());
	GPOS_ASSERT_IMP(GPOS_FTRACE(EopttraceConsiderOpfamiliesForDistribution),
					pdrgpexprInner->Size() == join_opfamilies->Size());

	// construct new MergeJoin expression using explicit casting, if needed
	pexpr->Pop()->AddRef();
	pexprOuter->AddRef();
	pexprInner->AddRef();
	CExpression *pexprResult = GPOS_NEW(mp)
		CExpression(mp, pexpr->Pop(), pexprOuter, pexprInner,
					CPredicateUtils::PexprConjunction(mp, pdrgpexpr));

	// cache hash join keys on scalar child group
	CacheJoinKeys(pexprResult, pdrgpexprOuter, pdrgpexprInner, join_opfamilies);

	// Add an alternative only if we found at least one merge-joinable predicate
	if (0 != pdrgpexprOuter->Size())
	{
		AddHashOrMergeJoinAlternative<T>(mp, pexprResult, pdrgpexprOuter,
										 pdrgpexprInner, join_opfamilies,
										 pxfres);
	}
	else
	{
		// clean up
		pdrgpexprOuter->Release();
		pdrgpexprInner->Release();
	}
	CRefCount::SafeRelease(join_opfamilies);

	pexprResult->Release();
}

//---------------------------------------------------------------------------
//	@function:
//		CXformUtils::ImplementNLJoin
//
//	@doc:
//		Helper function for implementation of nested loops joins
//
//---------------------------------------------------------------------------
template <class T>
void
CXformUtils::ImplementNLJoin(CXformContext *pxfctxt, CXformResult *pxfres,
							 CExpression *pexpr)
{
	GPOS_ASSERT(nullptr != pxfctxt);

	CMemoryPool *mp = pxfctxt->Pmp();

	CColRefArray *pdrgpcrOuter = GPOS_NEW(mp) CColRefArray(mp);
	CColRefArray *pdrgpcrInner = GPOS_NEW(mp) CColRefArray(mp);

	TransformImplementBinaryOp<T>(pxfctxt, pxfres, pexpr);

	// clean up
	pdrgpcrOuter->Release();
	pdrgpcrInner->Release();
}
}  // namespace gpopt

#endif	// !GPOPT_CXformUtils_H

// EOF

相关信息

greenplumn 源码目录

相关文章

greenplumn CDecorrelator 源码

greenplumn CJoinOrder 源码

greenplumn CJoinOrderDP 源码

greenplumn CJoinOrderDPv2 源码

greenplumn CJoinOrderGreedy 源码

greenplumn CJoinOrderMinCard 源码

greenplumn CSubqueryHandler 源码

greenplumn CXform 源码

greenplumn CXformAntiSemiJoinAntiSemiJoinNotInSwap 源码

greenplumn CXformAntiSemiJoinAntiSemiJoinSwap 源码

0  赞