blob: 2f462d7977ff7fe643e5bf265589af4fc9ac4ba4 [file] [log] [blame]
/**********************************************************************
// @@@ START COPYRIGHT @@@
//
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
//
// @@@ END COPYRIGHT @@@
**********************************************************************/
#ifndef RELSET_H
#define RELSET_H
/* -*-C++-*-
******************************************************************************
*
* File: RelSet.h
* Description: Relational set operations (both physical and logical operators)
* Created: 4/28/94
* Language: C++
*
*
*
*
******************************************************************************
*/
#include "ObjectNames.h"
#include "RelExpr.h"
#include "Rel3GL.h"
// -----------------------------------------------------------------------
// contents of this file
// -----------------------------------------------------------------------
class Union;
class Intersect;
class Except;
// The following are physical operators
class MergeUnion;
// -----------------------------------------------------------------------
// forward references
// -----------------------------------------------------------------------
class LogicalProperty;
class BindWA;
class Generator;
class AssignmentStArea;
// -----------------------------------------------------------------------
// Intersect Operator
// -----------------------------------------------------------------------
class Intersect : public RelExpr
{
public:
// constructor
Intersect(RelExpr *leftChild,
RelExpr *rightChild);
// virtual destructor
virtual ~Intersect();
// get the degree of this node (it is a binary op).
virtual Int32 getArity() const;
const NAString getText() const;
virtual RelExpr * copyTopNode(RelExpr *derivedNode = NULL, CollHeap* outHeap = 0);
// a virtual function for performing name binding within the query tree
virtual RelExpr * bindNode(BindWA *bindWAPtr);
};
// Except Operator
// -----------------------------------------------------------------------
class Except: public RelExpr
{
public:
// constructor
Except(RelExpr *leftChild,
RelExpr *rightChild);
// virtual destructor
virtual ~Except();
// get the degree of this node (it is a binary op).
virtual Int32 getArity() const;
const NAString getText() const;
virtual RelExpr * copyTopNode(RelExpr *derivedNode = NULL, CollHeap* outHeap = 0);
// a virtual function for performing name binding within the query tree
virtual RelExpr * bindNode(BindWA *bindWAPtr);
};
// -----------------------------------------------------------------------
// Union Operator:
//
// What we call "Union" here is what is called "UNION ALL" in SQL. To
// achieve a true union a la Codd, a duplicate elimination (see class
// GroupByAgg) is needed above the union node.
// -----------------------------------------------------------------------
class UnionMap : public NABasicObject
{
friend class Union;
friend class MergeUnion;
// The union map is a data struture that is shared by a number
// of Union nodes that need to do the same mappings of values
// from parent expressions to children expressions.
// It is intended to be accessible only from Union methods.
private:
// Constructor
UnionMap() : count_(1)
{}
// copy ctor
UnionMap (const UnionMap & rhs) :
colMapTable_(rhs.colMapTable_),
leftColMap_ (rhs.leftColMap_),
rightColMap_(rhs.rightColMap_),
count_(rhs.count_)
{}
// normalize all the expressions in the maps that are contributed
// by the child, whose index is childIndex, in the map.
void normalizeSpecificChild(NormWA & normWARef, Lng32 childIndex);
// The map table contains a list of item expressions, where each item
// expression is a ValueIdUnion that points to two Value Ids from the
// left and right child. This list implements a mapping table indicating
// how the columns of the left child and right child map the result
// columns.
ValueIdList colMapTable_;
// two value id maps that contain the identical information as in
// colMapTable_, for easier mapping
ValueIdMap leftColMap_;
ValueIdMap rightColMap_;
// Reference Count
Lng32 count_;
};
class AssignmentStHostVars;
class Union : public RelExpr
{
public:
// constructor
Union(RelExpr *leftChild,
RelExpr *rightChild,
UnionMap *colMapTable = NULL,
ItemExpr *condExpr = NULL,
OperatorTypeEnum otype = REL_UNION,
CollHeap *outHeap = CmpCommon::statementHeap(),
NABoolean sysGenerated = FALSE,
NABoolean mayBeCacheable = TRUE
);
// copy ctor
Union (const Union &) ; // not written
// virtual destructor
virtual ~Union();
// get the degree of this node (it is a binary op).
virtual Int32 getArity() const;
// a virtual function for performing name binding within the query tree
virtual RelExpr * bindNode(BindWA *bindWAPtr);
// accessor functions
// Provide a short-lived read-write access to the contents ofthe colMapTable_
inline ValueIdList & colMapTable() { return unionMap_->colMapTable_; }
inline const ValueIdList & colMapTable() const { return unionMap_->colMapTable_; }
inline ValueIdMap & getLeftMap() { return unionMap_->leftColMap_; }
inline ValueIdMap & getLeftMap() const { return unionMap_->leftColMap_; }
inline ValueIdMap & getRightMap() { return unionMap_->rightColMap_; }
inline ValueIdMap & getRightMap() const { return unionMap_->rightColMap_; }
ValueIdMap & getMap(Lng32 i)
{
CMPASSERT(i == 0 OR i == 1);
if (i == 0) return unionMap_->leftColMap_;
else return unionMap_->rightColMap_;
}
inline UnionMap * getUnionMap() { return unionMap_; }
void addValueIdUnion(ValueId vidUnion, CollHeap* heap);
// This method rewrites unionExpr in terms of the values produced
// produced by the left and the right children and returns
// them in the sets exprForLeftChild and exprForRightChild
// respectively.
void rewriteUnionExpr(const ValueIdSet & unionExpr,
ValueIdSet & exprForLeftChild,
ValueIdSet & exprForRightChild) const;
// Each operator supports a (virtual) method for transforming its
// scalar expressions to a canonical form
virtual void transformNode(NormWA & normWARef,
ExprGroupId & locationOfPointerToMe);
// a method used during subquery transformation for pulling up predicates
// towards the root of the transformed subquery tree
virtual void pullUpPreds();
// a method used for recomputing the outer references (external dataflow
// input values) that are still referenced by each operator in the
// subquery tree after the predicate pull up is complete.
virtual void recomputeOuterReferences();
// Each operator supports a (virtual) method for rewriting its
// value expressions.
virtual void rewriteNode(NormWA & normWARef);
// Each operator supports a (virtual) method for performing
// predicate pushdown and computing a "minimal" set of
// characteristic input and characteristic output values.
virtual RelExpr * normalizeNode(NormWA & normWARef);
virtual RelExpr * semanticQueryOptimizeNode(NormWA & normWARef);
// Method to push down predicates from a Union node into the
// children
virtual
void pushdownCoveredExpr(const ValueIdSet & outputExprOnOperator,
const ValueIdSet & newExternalInputs,
ValueIdSet& predOnOperator,
const ValueIdSet * nonPredExprOnOperator = NULL,
Lng32 childId = (-MAX_REL_ARITY) );
// The set of values that I can potentially produce as output.
virtual void getPotentialOutputValues(ValueIdSet & vs) const;
// methods for common subexpressions
virtual NABoolean prepareTreeForCSESharing(
const ValueIdSet &outputsToAdd,
const ValueIdSet &predicatesToRemove,
const ValueIdSet &commonPredicatesToAdd,
const ValueIdSet &inputsToRemove,
ValueIdSet &valuesForVEGRewrite,
ValueIdSet &keyColumns,
CSEInfo *info);
// ---------------------------------------------------------------------
// Function for testing the eligibility of this
// Union to form a plan using the given required physical properties.
// This method is called by UnionRule::topMatch().
// ---------------------------------------------------------------------
NABoolean rppAreCompatibleWithOperator
(const ReqdPhysicalProperty* const rppForUnion) const;
// ---------------------------------------------------------------------
// Union::createPartitioningRequirement()
// It is not declared as a const method because it can supply the
// ValueIdMap, colMapTable(), for copying and rewriting the
// partitioning requirement.
// ---------------------------------------------------------------------
PartitioningRequirement* createPartitioningRequirement
(const ReqdPhysicalProperty* const rppForUnion,
Lng32 currentChildIndex);
virtual HashValue topHash();
virtual NABoolean duplicateMatch(const RelExpr & other) const;
virtual RelExpr * copyTopNode(RelExpr *derivedNode = NULL,
CollHeap* outHeap = CmpCommon::statementHeap());
// method to do code generation
virtual short codeGen(Generator*);
// synthesize logical properties
virtual void synthLogProp(NormWA * normWAPtr = NULL);
virtual void synthEstLogProp(const EstLogPropSharedPtr& inputEstLogProp);
virtual void addLocalExpr(LIST(ExprNode *) &xlist,
LIST(NAString) &llist) const;
// get a printable string that identifies the operator
const NAString getText() const;
// adds information about this node to the Explain tree
ExplainTuple *addSpecificExplainInfo(ExplainTupleMaster *explainTuple,
ComTdb * tdb,
Generator *generator);
// merge of R1.5 to R2, renumbered
enum UnionFlags {
UNION_NONE = 0x000,
UNION_ORDERED = 0x001,
UNION_COND_UNARY = 0x002,
UNION_COND_EMPTY_IFELSE = 0x004, // set when ELSE part IF statement
// is missing or empty
UNION_FOR_IF = 0x008,
UNION_DISTINCT = 0x010, // Ansi SQL default, opp. of "UNION ALL"
UNION_COND_EMPTY_IFTHEN = 0x020, // set when we see
// IF (expression) THEN
// BEGIN END ;
// ELSE
// some sql statement/sqlstatements
// END IF ;
UNION_BLOCKED = 0x040 // UNION_BLOCKED was added for trigger project
};
void setSerialUnion() {isSerialUnion_ = TRUE;}
NABoolean getSerialUnion() const {return isSerialUnion_;}
void setOrderedUnion() {flags_ |= UNION_ORDERED;}
NABoolean getOrderedUnion() const {return (flags_ & UNION_ORDERED) != 0;}
void setCondUnary() {flags_ |= UNION_COND_UNARY;}
NABoolean getCondUnary() const {return (flags_ & UNION_COND_UNARY) != 0;}
void setCondEmptyIfElse() {flags_ |= UNION_COND_EMPTY_IFELSE;}
NABoolean getCondEmptyIfElse() const {return (flags_ &UNION_COND_EMPTY_IFELSE) != 0;}
void setUnionForIF() {flags_ |= UNION_FOR_IF;}
NABoolean getUnionForIF() const {return (flags_ & UNION_FOR_IF) != 0; }
void setDistinctUnion() {flags_ |= UNION_DISTINCT;}
NABoolean getDistinctUnion() const {return (flags_ & UNION_DISTINCT) != 0;}
void setCondEmptyIfThen() {flags_ |= UNION_COND_EMPTY_IFTHEN;}
NABoolean getCondEmptyIfThen() const {return (flags_ & UNION_COND_EMPTY_IFTHEN) != 0;}
void setUnionFlags(ULng32 f) {flags_ = f;}
ULng32 getUnionFlags() const {return flags_;}
// UNION_BLOCKED was added for trigger project
inline void setBlockedUnion(){flags_ = UNION_BLOCKED;}
inline Int32 getBlockedUnion(){return flags_ == UNION_BLOCKED;}
// controlFlags were added for trigger project
// setNoOutput can be applied to OrderUnion or BlockedUnion
void setNoOutputs();
inline Int32 hasNoOutputs(){return controlFlags_ & NO_OUTPUTS;}
// inNotAtomicStmt is applied for unary unions to raise an error during execution
// if an after trigger is enabled and we are executing a notAtomicStatement.
void setInNotAtomicStatement() {controlFlags_ |= IN_NOT_ATOMIC_STMT;}
NABoolean getInNotAtomicStatement() const {return (controlFlags_ & IN_NOT_ATOMIC_STMT) != 0;}
// a blocked union is temporary if it is used to inline
// a after row trigger (statement MVs too). This union will be
// removed during optimization.
void setIsTemporary() {controlFlags_ |= IS_TEMPORARY;}
NABoolean getIsTemporary() const {return (controlFlags_ & IS_TEMPORARY) != 0;}
inline void setControlFlags(Int32 flg){controlFlags_ = flg;}
inline Int32 getControlFlags() const {return controlFlags_;}
void addCondExprTree(ItemExpr *condExpr);
ItemExpr *getCondExprTree();
ItemExpr *removeCondExprTree();
ValueIdList &condExpr() {return condExpr_;}
const ValueIdList &condExpr() const {return condExpr_;}
ValueIdList getCondExpr() {return condExpr_;}
void setCondExpr(ValueIdList condExpr) {condExpr_ = condExpr;}
// support methods for the Triggered Action Exception
void addTrigExceptExprTree(ItemExpr *trigExceptExpr);
ItemExpr *getTrigExceptExprTree();
ItemExpr *removeTrigExceptExprTree();
ValueIdList &trigExceptExpr() {return trigExceptExpr_;}
const ValueIdList &trigExceptExpr() const {return trigExceptExpr_;}
ValueIdList getTrigExceptExpr() {return trigExceptExpr_;}
void setTrigExceptExpr(ValueIdList trigExceptExpr)
{trigExceptExpr_ = trigExceptExpr;}
// These functions are to support functionality of compound statements.
// Please see documentation of data members below.
Union * getPreviousIF() { return previousIF_; }
void setPreviousIF(Union * node) { previousIF_ = node; }
AssignmentStHostVars *&leftList() { return leftList_; }
AssignmentStHostVars *&rightList() { return rightList_; }
short &currentChild() { return currentChild_; }
AssignmentStHostVars *getCurrentList(BindWA *bindWA);
// When we are in a CompoundStatement and we have IF statements in it,
// we must create a RETDesc for this Union node (which is
// actually an IF node). In this function, we create a list of
// ValueIdUnion nodes. We figure out which valueids
// of the left child must be matched with those of the right child
// (for instance, if SET :a appears in both children) and which must
// be matched with previously existing valueids (for instance, if
// SET :a = ... only appears in one branch, then the ValueIdUnion associated
// with that SET statement must reference the value id of :a that existed before
// this IF statement).
RETDesc * createReturnTable(AssignmentStArea *assignArea, BindWA *bindWA);
//Used only for conditional union. Copies the leftlist and rightlist this conditional
//union to the leftlist of the conditional union node pointed to by the previousIF argument,
//if the calling conditional union is in the left subtree of the previousIF conditional union.
//If the calling conditional union is in the right subtree of the previousIF conditional union
//then we copy to the rightlist of the previousIF conditional union.
void copyLeftRightListsToPreviousIF(Union * previousIF, BindWA * bindWA);
// MV ++
// MV refresh optimization refer to MVRefreshBuilder.cpp
// MultiTxnMavBuilder::buildUnionBetweenRangeAndIudBlocks()
// THIS OPTIMIZATION IS FOR MV REFRESH ONLY AND IS BASED ON THE KNOWLEDGE THAT RANGES RECORDS
// IN THE RANGE LOG DO NOT OVERLAPPED
void addAlternateRightChildOrderExprTree(ItemExpr *alternateRightChildOrderExprTree);
ItemExpr *removeAlternateRightChildOrderExprTree();
inline ValueIdList &alternateRightChildOrderExpr() {return alternateRightChildOrderExpr_;}
inline const ValueIdList &alternateRightChildOrderExpr() const {return alternateRightChildOrderExpr_;}
inline ValueIdList getAlternateRightChildOrderExpr() {return alternateRightChildOrderExpr_;}
inline void setAlternateRightChildOrderExpr(ValueIdList alternateRightChildOrderExpr)
{
alternateRightChildOrderExpr_ = alternateRightChildOrderExpr;
}
// MV --
// added for trigger project, to activate after trigger transformation
virtual RelExpr * fixupTriggers(NABoolean & treeModified);
// check for & warn against UNIONs that have inconsistent access/lock modes
void checkAccessLockModes();
// append an ascii-version of Union into cachewa.qryText_
void generateCacheKey(CacheWA &cwa) const;
private:
// controlFlags were added for trigger project
enum controlFlags { NO_OUTPUTS = 0x0001,
IN_NOT_ATOMIC_STMT = 0x0002,
IS_TEMPORARY = 0x0004};
// ---------------------------------------------------------------------
// Union::createPartitioningRequirement()
// It is not declared as a const method because it can supply the
// ValueIdMap, equiJoinExpressions_, for copying and rewriting the
// partitioning function to match. The rewrite requires a read-write
// access to the ValueIdMap (interfaces supported by class ValueIdMap).
// ---------------------------------------------------------------------
PartitioningFunction* createPartitioningRequirement
(const ReqdPhysicalProperty* const rppForUnion,
const PartitioningFunction* const partFuncToMatch,
Lng32 currentChildIndex,
Lng32 currentPlanNumber);
// MV --
// A debugging method for dumping the columns in the RETDesc of both
// children when they do not match.
void dumpChildrensRETDescs(const RETDesc& leftTable,
const RETDesc& rightTable);
// Conditional union expression.
ItemExpr *condExprTree_;
ValueIdList condExpr_;
// expression used by triggeres to implement the ANSI
// triggered action exception.
ItemExpr *trigExceptExprTree_;
ValueIdList trigExceptExpr_;
// MV ++
ItemExpr *alternateRightChildOrderExprTree_;
ValueIdList alternateRightChildOrderExpr_;
// MV --
// The union map is shared by a number of Union nodes that were
// transformed from one another
UnionMap *unionMap_;
// see unionFlags
ULng32 flags_;
// We keep a list of all variables that appear on the left side of a SET
// statement and that appear below this Union node. Please see compound
// statements documentation. In this way, we can keep track of SET statements
// that appear within IF statements
LIST(HostVar *) variablesSet_;
// We keep a pointer to the closest Union node that is an ancestor of this
// one. This is to support functionality for compound statements, in particular
// for SET statements within IF statements.
Union *previousIF_;
// These lists contain all the variables that have been SET in the left and
// right childs, respectively
AssignmentStHostVars * leftList_;
AssignmentStHostVars * rightList_;
// Child we are currently visiting
short currentChild_;
//++ Triggers -
// see controlFlags
Int32 controlFlags_;
// true iff this Union is system-generated (ie, is not user-specified)
NABoolean isSystemGenerated_;
NABoolean isSerialUnion_;
};
// -----------------------------------------------------------------------
// physical Union node
// -----------------------------------------------------------------------
class MergeUnion : public Union
{
public:
// constructor
MergeUnion(RelExpr *leftChild,
RelExpr *rightChild,
UnionMap *unionMap = NULL,
OperatorTypeEnum otype = REL_MERGE_UNION,
CollHeap *oHeap = CmpCommon::statementHeap())
: Union(leftChild, rightChild, unionMap, NULL, otype, oHeap),
mergeExpr_(NULL) {}
// copy ctor
MergeUnion (const MergeUnion &) ; // not written
// virtual destructor
virtual ~MergeUnion();
virtual NABoolean isLogical () const;
virtual NABoolean isPhysical() const;
virtual HashValue topHash();
virtual NABoolean duplicateMatch(const RelExpr & other) const;
virtual RelExpr * copyTopNode(RelExpr *derivedNode = NULL,
CollHeap* outHeap = CmpCommon::statementHeap());
// Cascades-related functions
virtual CostMethod* costMethod() const;
virtual Context* createContextForAChild(Context* myContext,
PlanWorkSpace* pws,
Lng32& childIndex);
virtual NABoolean findOptimalSolution(Context* myContext,
PlanWorkSpace* pws);
virtual PhysicalProperty *synthPhysicalProperty(const Context *context,
const Lng32 planNumber,
PlanWorkSpace *pws);
// Helper function for plan generation.
Context* createChildContext(Context* context, PlanWorkSpace* pws,
Lng32 childIndex);
// handling sort order and merge expression
inline const ValueIdList &getSortOrder() { return sortOrder_; }
void setSortOrder(const ValueIdList &newSortOrder);
inline ItemExpr *getMergeExpr() const { return mergeExpr_; }
// method to do code generation
virtual RelExpr * preCodeGen(Generator * generator,
const ValueIdSet & externalInputs,
ValueIdSet &pulledNewInputs);
virtual short codeGen(Generator*);
// -----------------------------------------------------
// generate CONTROL QUERY SHAPE fragment for this node.
// -----------------------------------------------------
virtual short generateShape(CollHeap * space, char * buf, NAString * shapeStr = NULL);
// add all the expressions that are local to this
// node to an existing list of expressions (used by GUI tool)
virtual void addLocalExpr(LIST(ExprNode *) &xlist,
LIST(NAString) &llist) const;
// Given an input synthesized child sort key, a required arrangement,
// and a input required sort order (if any), generate a new sort key
// that has all the expressions in the required sort key and required
// arrangement, and only those expressions, in an order that matches
// the child sort key. Return this new sort key, which can then be used
// as a sort key requirement for the other child of the union or as the
// synthesized union sort key after being mapped.
void synthUnionSortKeyFromChild (const ValueIdList &childSortKey,
const ValueIdSet &reqArrangement,
ValueIdList &unionSortKey) const;
// -----------------------------------------------------------------------
// Performs mapping on the partitioning function, from the union to the
// designated child.
// -----------------------------------------------------------------------
virtual PartitioningFunction* mapPartitioningFunction(
const PartitioningFunction* partFunc,
NABoolean rewriteForChild0) ;
// -----------------------------------------------------------------------
// This help function tries to make the Union sort key the same
// length as the arrangement requirement of Union cols. The key
// can be shorter when some of the Union columns are duplicated.
//
// -----------------------------------------------------------------------
NABoolean finalizeUnionSortKey(const ValueIdList& knownSortKey, // IN
Lng32 knownSide, // IN
const ValueIdSet& arrCols, // IN
ValueIdList& unionSortKey); // IN&OUT
private:
// the sorting order of the union result (if any), expressed in terms
// of the union's outputs
ValueIdList sortOrder_;
// The merge expression is a boolean expression telling which of the
// children to read next (TRUE means read the left child, FALSE means
// read the right child). It is used to merge two sorted child streams
// into a sorted output stream if the expression is (left value <= right).
ItemExpr *mergeExpr_;
// a private method to build the merge expression from the sort order
void buildMergeExpr();
};
#endif /* RELSET_H */