| #ifndef NormWA_H |
| #define NormWA_H |
| /* -*-C++-*- |
| ************************************************************************* |
| * |
| * File: NormWA.h |
| * Description: The workarea used by the normalizer |
| * Created: December 7, 1994 |
| * Language: C++ |
| * |
| * |
| // @@@ 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 @@@ |
| * |
| * |
| ************************************************************************* |
| */ |
| |
| #include "BaseTypes.h" |
| #include "Collections.h" |
| #include "VEGTable.h" |
| #include "ValueDesc.h" |
| // ---------------------------------------------------------------------- |
| // contents of this file |
| // ---------------------------------------------------------------------- |
| class NormWA; |
| class SqoWA; |
| |
| // ---------------------------------------------------------------------- |
| // Forward declarations |
| // ---------------------------------------------------------------------- |
| class VEGReference; |
| class CmpContext; |
| |
| // *********************************************************************** |
| // SqoWA |
| // |
| // The work area for the Semantic Query Optimizer phase. |
| // |
| // For now to keep track of things we have to undo if we hit |
| // conditions where we cannot proceed with the SQO and have to restore |
| // the relExpr tree to its original form. |
| // *********************************************************************** |
| |
| enum SqoChangedItemExprEnum { SQO_REPLACED, SQO_NEWCHILD, SQO_NEWOPTYPE }; |
| enum SqoChangedRelExprEnum { SQO_REASSIGNED_VREGION }; |
| |
| class SqoChangedItemExprs: public NABasicObject |
| { |
| public: |
| |
| // Constructor |
| SqoChangedItemExprs(ValueId changedId, SqoChangedItemExprEnum what, |
| ItemExpr *old , Int32 changedChild, Lng32 subqId) : |
| changedVid_(changedId), |
| whatChanged_(what), |
| oldItemExpr_(old), |
| changedChild_(changedChild), |
| subqId_(subqId) |
| {} |
| |
| SqoChangedItemExprs(ValueId changedId, SqoChangedItemExprEnum what, |
| ItemExpr *old, const OperatorTypeEnum oldOpType, |
| Lng32 subqId) : |
| changedVid_(changedId), |
| whatChanged_(what), |
| oldItemExpr_(old), |
| changedChild_(0), |
| oldOperatorType_(oldOpType), |
| subqId_(subqId) |
| {} |
| |
| SqoChangedItemExprs(ValueId changedId, SqoChangedItemExprEnum what, |
| ItemExpr *old, Lng32 subqId ) : |
| changedVid_(changedId), |
| whatChanged_(what), |
| oldItemExpr_(old), |
| changedChild_(0), |
| subqId_(subqId) |
| {} |
| |
| // Destructor |
| ~SqoChangedItemExprs() {} |
| |
| NABoolean undoChanges(NormWA & normWARef, Lng32 subqId); |
| |
| private: |
| Lng32 subqId_; |
| ValueId changedVid_; |
| SqoChangedItemExprEnum whatChanged_; |
| ItemExpr *oldItemExpr_; |
| Lng32 changedChild_; |
| OperatorTypeEnum oldOperatorType_; |
| }; // class SqoChangedItemExprs |
| |
| |
| class SqoChangedRelExprs: public NABasicObject |
| { |
| public: |
| |
| // Constructor |
| SqoChangedRelExprs(RegionId vegRegion, SqoChangedRelExprEnum what, |
| RelExpr *changedExpr, RelExpr *origExpr, |
| Lng32 origChildId, Lng32 changedChildId, Lng32 subqId) |
| : vregion_(vegRegion), whatChanged_(what), |
| changedRelExpr_(changedExpr), originalRelExpr_(origExpr), |
| origChildId_(origChildId), changedChildId_(changedChildId), |
| subqId_(subqId) |
| {} |
| |
| // Destructor |
| ~SqoChangedRelExprs() {} |
| |
| NABoolean undoChanges(NormWA & normWARef, Lng32 subqId); |
| |
| private: |
| Lng32 subqId_; |
| SqoChangedRelExprEnum whatChanged_; |
| RelExpr *changedRelExpr_; |
| RelExpr *originalRelExpr_; |
| Lng32 changedChildId_; |
| Lng32 origChildId_; |
| RegionId vregion_; |
| }; // class SqoChangedRelExprs |
| |
| class SqoWA: public NABasicObject |
| { |
| public: |
| // Constructors |
| SqoWA() |
| : changedItemExprs_(CmpCommon::statementHeap()), |
| changedRelExprs_(CmpCommon::statementHeap()), |
| subqId_(0) |
| {} |
| |
| SqoWA(const SqoWA & other) |
| : changedItemExprs_(other.changedItemExprs_), |
| changedRelExprs_(other.changedRelExprs_), |
| subqId_(other.subqId_) |
| {} |
| |
| // Destructor |
| ~SqoWA() {} |
| |
| void incrementSubQId() { subqId_ ++; } |
| Lng32 getSubQId() { return subqId_; } |
| |
| void insertChangedItemExpr(ValueId changedId, SqoChangedItemExprEnum whatChanged, ItemExpr *origExpr ) |
| { |
| changedItemExprs_.insert( new (CmpCommon::statementHeap()) |
| SqoChangedItemExprs(changedId, |
| whatChanged, |
| origExpr, subqId_ )); |
| } |
| |
| void insertChangedItemExpr(ValueId changedId, SqoChangedItemExprEnum whatChanged, ItemExpr *origExpr, Int32 changedChild ) |
| { |
| changedItemExprs_.insert( new (CmpCommon::statementHeap()) |
| SqoChangedItemExprs(changedId, |
| whatChanged, |
| origExpr, |
| changedChild, subqId_ )); |
| } |
| |
| void insertChangedItemExpr(ValueId changedId, SqoChangedItemExprEnum whatChanged, ItemExpr *origExpr, OperatorTypeEnum origOp ) |
| { |
| changedItemExprs_.insert( new (CmpCommon::statementHeap()) |
| SqoChangedItemExprs(changedId, |
| whatChanged, |
| origExpr, |
| origOp, subqId_ )); |
| } |
| void insertChangedRelExpr(RelExpr *originalRel, RelExpr *changedRel, SqoChangedRelExprEnum whatChanged, RegionId vregionId, Int32 origRegionChild, Int32 newRegionChild) |
| { |
| changedRelExprs_.insert( new (CmpCommon::statementHeap()) |
| SqoChangedRelExprs(vregionId, whatChanged, |
| changedRel, originalRel, |
| origRegionChild, |
| newRegionChild, subqId_)); |
| } |
| |
| void undoChanges(NormWA & normWARef ); |
| |
| private: |
| Lng32 subqId_; |
| // We need a list of ItemExprs that we have changed |
| LIST(SqoChangedItemExprs *) changedItemExprs_; |
| |
| |
| // We need to remember a list of RelExprs that we have changed |
| // For now the only thing we change for RelExprs are the ownership |
| // of VEGRegions, thus we have to remember the original owner and |
| // the RegionId. |
| LIST(SqoChangedRelExprs *) changedRelExprs_; |
| |
| |
| }; // class SqoWA |
| |
| |
| |
| // *********************************************************************** |
| // |
| // Region |
| // |
| // A ValueId Equality Group (VEG) contains the ValueIds of all |
| // expressions that are related by an "=" relationship. This means, |
| // that each expression that belongs to a certain VEG will produce |
| // the same value as any other expression that belongs to the same |
| // VEG. Aggregeting operation, such as, summation, averaging or |
| // even an outer join impose certain restrictions on how VEGs are |
| // formed. For example, consider the query tree |
| // |
| // IJ-> T1.c = T3.c |
| // / \ |
| // T1 IJ -> T2.c = T3.c |
| // / \ |
| // T2 T3 |
| // |
| // The predicate T1.c = T3.c causes the columns T1.c and T3.c to |
| // belong to a VEG, VEG1. The predicate T2.c = T3.c defines another |
| // VEG, VEG2. Since each inner join transmits values without any |
| // aggregation, it is clear that since T1.c = T3.c and T2.c = T3.c |
| // T1.c must also be equal to T2.c. Hence VEG1 and VEG2 can be |
| // into a single VEG. Now consider the query tree, |
| // |
| // R1 |
| // .......................... |
| // LJ.-> T1.c = T3.c R2 |
| // / . \ ...................... |
| // T1 . LJ. -> T2.c = T3.c R3 |
| // . / .\ |
| // . T2 : T3 |
| // : :....................... |
| // :.............................. |
| // |
| // For the sake of disucssion, the query tree is partitioned into |
| // three zones or regions, called Regions R1, R2 and R3. Each Region |
| // defines a scope within which a certain equality relationship is |
| // valid. Thus the relationship T1.c = T3.c is valid only within R2 |
| // while the relationship T2.c = T3.c is valid only within R3. The |
| // effect of such a partionining is seen in the manner in which VEGs |
| // are formed. The predicate T1.c = T3.c causes the columns T1.c and |
| // T3.c to belong to a VEG, VEG1. Similarly, the predicate T2.c = T3.c |
| // causes the columns T2.c and T3.c to belong to another VEG, VEG2. |
| // VEG1 and VEG2 cannot be combined because T3.c values that flow |
| // from R3 into R2 can suffer null augmentation and hence change. |
| // |
| // The normalizer creates a new Region for |
| // a) the right subtree of a left outer join |
| // b) the left subtree of a right outer join and |
| // c) each of the left and right subtrees of a full outer join |
| // |
| // *********************************************************************** |
| |
| // *********************************************************************** |
| // NormWA |
| // |
| // The work area for the Transform/Normalize/Rewrite phase. |
| // |
| // *********************************************************************** |
| class NormWA : public NABasicObject |
| { |
| public: |
| // -------------------------------------------------------------------- |
| // Constructor functions |
| // -------------------------------------------------------------------- |
| |
| NormWA(CmpContext* cmpContext) |
| : currentCmpContext_(cmpContext), subqUnderExprTreeCount_(0), |
| walkingAnExprTreeCount_(0), complexScalarExprCount_(0), |
| nullCount_(0), notCount_(0), orCount_(0), inConstraintsCount_(0), |
| inBlockedUnionCount_(0) //++Triggers - |
| // QSTUFF |
| ,inEmbeddedUpdateOrDelete_(FALSE) |
| // QSTUFF |
| ,inEmbeddedInsert_(FALSE) |
| ,inBeforeTrigger_(FALSE) |
| ,inJoinPredicate_(FALSE) |
| ,mergeUpdDelCount_(0) |
| ,leftJoinConversionCount_(0) |
| ,correlatedSubqCount_(0) |
| ,inSelectListCount_(0) |
| ,inHavingClause_(FALSE) |
| ,inValueIdProxy_(FALSE) |
| ,inGenericUpdateAssign_(FALSE) |
| ,inMergeUpdWhere_(FALSE) |
| ,inMVQueryRewrite_(FALSE) |
| ,containsJoinsToBeEliminated_(FALSE) |
| ,containsSemiJoinsToBeTransformed_(FALSE) |
| ,extraHubVertex_(NULL) |
| ,leftJoinChildVEGRegion_(NULL) |
| ,containsGroupBysToBeEliminated_(FALSE) |
| ,checkForExtraHubTables_(FALSE) |
| ,compilingMVDescriptor_(FALSE) |
| ,requiresRecursivePushdown_(FALSE) |
| ,readList_(CmpCommon::statementHeap()) |
| ,writeList_(CmpCommon::statementHeap()) |
| ,origSeqFunction_(CmpCommon::statementHeap()) |
| ,equiTransformedExpr_(CmpCommon::statementHeap()) |
| ,commonSubExprCount_(0) |
| { |
| vegTable_ = new (wHeap()) VEGTable; |
| sqoWARef_ = new (CmpCommon::statementHeap()) SqoWA; |
| } |
| |
| |
| NormWA(const NormWA & other) |
| : currentCmpContext_(other.currentCmpContext_), |
| walkingAnExprTreeCount_(other.walkingAnExprTreeCount_), |
| subqUnderExprTreeCount_(other.subqUnderExprTreeCount_), |
| complexScalarExprCount_(other.complexScalarExprCount_), |
| nullCount_(other.nullCount_), |
| notCount_(other.notCount_), |
| orCount_(other.orCount_), |
| inConstraintsCount_(other.inConstraintsCount_), |
| inBlockedUnionCount_(other.inBlockedUnionCount_), //++ Triggers - |
| vegTable_(other.vegTable_) |
| // QSTUFF |
| ,inEmbeddedUpdateOrDelete_(other.inEmbeddedUpdateOrDelete_) |
| // QSTUFF |
| ,inEmbeddedInsert_(other.inEmbeddedInsert_) |
| ,inBeforeTrigger_(other.inBeforeTrigger_) |
| ,inJoinPredicate_(other.inJoinPredicate_) |
| ,mergeUpdDelCount_(other.mergeUpdDelCount_) |
| ,leftJoinConversionCount_(other.leftJoinConversionCount_) |
| ,correlatedSubqCount_(other.correlatedSubqCount_) |
| ,inSelectListCount_(other.inSelectListCount_) |
| ,inHavingClause_(other.inHavingClause_) |
| ,inValueIdProxy_(other.inValueIdProxy_) |
| ,inGenericUpdateAssign_(other.inGenericUpdateAssign_) |
| ,inMergeUpdWhere_(other.inMergeUpdWhere_) |
| ,inMVQueryRewrite_(other.inMVQueryRewrite_) |
| ,containsJoinsToBeEliminated_(other.containsJoinsToBeEliminated_) |
| ,containsSemiJoinsToBeTransformed_(other.containsSemiJoinsToBeTransformed_) |
| ,extraHubVertex_(other.extraHubVertex_) |
| ,sqoWARef_(other.sqoWARef_) |
| ,leftJoinChildVEGRegion_(other.leftJoinChildVEGRegion_) |
| ,containsGroupBysToBeEliminated_(other.containsGroupBysToBeEliminated_) |
| ,checkForExtraHubTables_(FALSE) |
| ,compilingMVDescriptor_(FALSE) |
| ,requiresRecursivePushdown_(other.requiresRecursivePushdown_) |
| ,readList_(other.readList_, STMTHEAP) |
| ,writeList_(other.writeList_, STMTHEAP) |
| ,origSeqFunction_(other.origSeqFunction_, STMTHEAP) |
| ,equiTransformedExpr_(other.equiTransformedExpr_, STMTHEAP) |
| ,commonSubExprCount_(0) |
| {} |
| |
| // -------------------------------------------------------------------- |
| // Destructor functions |
| // -------------------------------------------------------------------- |
| ~NormWA(){} |
| |
| // -------------------------------------------------------------------- |
| // Initialize a NormWA free of all state information. |
| // This method is called at the root of each (sub)query tree. |
| // -------------------------------------------------------------------- |
| void clearStateInformation() |
| { walkingAnExprTreeCount_ = |
| complexScalarExprCount_ = |
| nullCount_ = notCount_ = orCount_ = inConstraintsCount_ = 0; |
| inValueIdProxy_ = FALSE; // not a recursive flag. |
| } |
| |
| // -------------------------------------------------------------------- |
| // Region |
| // -------------------------------------------------------------------- |
| void allocateAndSetVEGRegion(const VEGRegionTypeEnum tev, |
| ExprNode * const ownerExprPtr, |
| Lng32 subtreeId = 0) |
| { |
| vegTable_->allocateAndSetVEGRegion(tev,ownerExprPtr,subtreeId); |
| } |
| |
| void locateAndSetVEGRegion(ExprNode * const ownerExprPtr, |
| Lng32 subtreeId = 0) |
| { vegTable_->locateAndSetVEGRegion(ownerExprPtr, subtreeId); } |
| |
| void restoreOriginalVEGRegion() { vegTable_->restoreOriginalRegion(); } |
| void reassignVEGRegion(ExprNode * ownerExprPtr, |
| Lng32 ownerSubtreeId, |
| ExprNode * newOwnerExprPtr, |
| Lng32 newOwnerSubtreeId = 0) |
| { |
| vegTable_->reassignVEGRegion(ownerExprPtr, |
| ownerSubtreeId, newOwnerExprPtr, newOwnerSubtreeId); |
| } |
| |
| // -------------------------------------------------------------------- |
| // Add a ValueId Equality Group (VEG) for each "=" predicate. |
| // -------------------------------------------------------------------- |
| void addVEG(const ValueId & expr1Id, const ValueId & expr2Id) |
| { vegTable_->addVEG(expr1Id, expr2Id); } |
| |
| void addVEG(const ValueIdSet & setOfValues) |
| { vegTable_->addVEG(setOfValues); } |
| |
| void deleteVEGMember(const ValueId &vId) |
| { vegTable_->deleteVEGMember(vId); } |
| |
| // ++Trigger -, from later version |
| void addVEGInOuterRegion(const ValueId & expr1Id, const ValueId & expr2Id) |
| { vegTable_->addVEGInOuterRegion(expr1Id, expr2Id); } |
| |
| // -------------------------------------------------------------------- |
| // Accessor method for retrieving a VEG, given the ValueId of a |
| // potential member. |
| // -------------------------------------------------------------------- |
| ItemExpr * getVEGReference(const ValueId & exprId) const |
| { return vegTable_->getVEGReference(exprId,leftJoinChildVEGRegion_); } |
| |
| // -------------------------------------------------------------------- |
| // The following method locates the Region where the owner ExprNode |
| // produces the given value and marks it as "To Be Merged". |
| // -------------------------------------------------------------------- |
| VEGRegion * locateVEGRegionAndMarkToBeMerged(const ValueId & exprId) const |
| { return vegTable_->locateVEGRegionAndMarkToBeMerged(exprId); } |
| |
| // -------------------------------------------------------------------- |
| // Do the same as above. But also look at the contents of the |
| // ToBeMerged Regions to see if we could merge some more regions as |
| // well because contents of the region might contain null_instantiated |
| // columns in some other regions. |
| // -------------------------------------------------------------------- |
| void locateVEGRegionAndMarkToBeMergedRecursively(const ValueId & exprId); |
| |
| // -------------------------------------------------------------------- |
| // The following method locates the Region of which the given ExprNode |
| // is the owner and returns TRUE if it is merged; FALSE otherwise. |
| // -------------------------------------------------------------------- |
| NABoolean locateVEGRegionAndCheckIfMerged(ExprNode * const ownerExpr) const |
| { return vegTable_->locateVEGRegionAndCheckIfMerged(ownerExpr); } |
| |
| NABoolean locateVEGRegionAndCheckIfMerged |
| (ExprNode * const ownerExpr, Lng32 subtreeId) const |
| { return vegTable_->locateVEGRegionAndCheckIfMerged(ownerExpr, subtreeId); } |
| |
| |
| // -------------------------------------------------------------------- |
| // Post processing of the VEGTable after it is built. |
| // -------------------------------------------------------------------- |
| void processVEGRegions() { vegTable_->processVEGRegions(); } |
| |
| //----------------------------------------------------------------------- |
| //A method to locate the VEG region given an ExprNode |
| //----------------------------------------------------------------------- |
| VEGRegion* locateVEGRegion(ExprNode *ownerENptr) |
| { return vegTable_->locateVEGRegion(ownerENptr);} |
| |
| //----------------------------------------------------------------------- |
| //A method to locate the VEG region given an ExprNode and subtreeId |
| //----------------------------------------------------------------------- |
| VEGRegion* locateVEGRegion(ExprNode *ownerENptr, Lng32 subtreeId) |
| { return vegTable_->locateVEGRegion(ownerENptr, subtreeId);} |
| |
| |
| // -------------------------------------------------------------------- |
| // A method for performing transitive closure of "=" predicates. |
| // -------------------------------------------------------------------- |
| ItemExpr * performTC(const ValueId & vegMember) const |
| { return vegTable_->performTC(vegMember); } |
| |
| // -------------------------------------------------------------------- |
| // The Normalizer sets the "walking an expression tree" flag when |
| // processing one of the following expressions: |
| // 1) An IF-THEN-ELSE (SQL CASE statement). |
| // 2) An aggregate function. |
| // 3) A predicate tree that is root in an OR. |
| // 4) A predicate tree that is root in a NOT. |
| // 5) A predicate tree that is root in an IS NULL/IS UNKNOWN. |
| // The method that sets it is also expected to restore it to its |
| // original state. |
| // -------------------------------------------------------------------- |
| void setWalkingAnExprTreeFlag() { walkingAnExprTreeCount_++; } |
| void restoreWalkingAnExprTreeFlag() { walkingAnExprTreeCount_--; } |
| NABoolean walkingAnExprTree() const { return walkingAnExprTreeCount_ > 0; } |
| Lng32 getWalkingAnExprTreeCount() { return walkingAnExprTreeCount_; } |
| |
| // --------------------------------------------------------------------- |
| // Needs to remember this subquery is under an expr, so that when we go |
| // back to transform the new Join and its subtree introduced, we won't |
| // incorrectly use the selection predicates in the subquery to convert |
| // left join into inner join. |
| // --------------------------------------------------------------------- |
| void setSubqUnderExprTreeFlag() { subqUnderExprTreeCount_++; } |
| void restoreSubqUnderExprTreeFlag() { subqUnderExprTreeCount_--; } |
| NABoolean subqUnderExprTree() const { return subqUnderExprTreeCount_ > 0; } |
| |
| // -------------------------------------------------------------------- |
| // The Normalizer sets the complex scalar expression flag while |
| // processing one of the following expressions: |
| // 1) An IF-THEN-ELSE (SQL CASE statement). |
| // 2) A user defined function. |
| // The method that sets it is also expected to restore it to its |
| // original state. |
| // -------------------------------------------------------------------- |
| void setComplexScalarExprFlag(); |
| void restoreComplexScalarExprFlag(); |
| NABoolean inAComplexScalarExpr() const { return complexScalarExprCount_ > 0; } |
| |
| // -------------------------------------------------------------------- |
| // The Normalizer NULL flag is usually set when an IS NULL or an |
| // IS UNKNOWN is encountered in the transformed tree. The method |
| // that sets it is also expected to restore it to its original state. |
| // This is because normalization is performed recursively and an |
| // IS NULL or an IS UNKNOWN may be encountered while processing |
| // the operand of another ISNULL or IS UNKNOWN. |
| // The subquery transformation uses this information. |
| // -------------------------------------------------------------------- |
| void setNullFlag(); |
| void restoreNullFlag(); |
| NABoolean isChildOfAnIsNull() const { return nullCount_ > 0; } |
| |
| // -------------------------------------------------------------------- |
| // The Normalizer NOT flag is usually set when a NOT is encountered |
| // in the transformed tree. The method that sets it is also expected |
| // to restore it to its original state. This is because normalization |
| // is performed recursively and a NOT may be encountered while |
| // processing the operand of another NOT. |
| // The subquery transformation uses this information. |
| // -------------------------------------------------------------------- |
| void setNotFlag(); |
| void restoreNotFlag(); |
| NABoolean isChildOfANot() const { return notCount_ > 0; } |
| |
| // -------------------------------------------------------------------- |
| // The Normalizer OR flag is usually set when an OR is encountered |
| // in the transformed tree. The method that sets it is also expected |
| // to restore it to its original state. This is because normalization |
| // is performed recursively and an OR may be encountered while |
| // processing the subtree rooted in another OR. |
| // The subquery transformation uses this information. |
| // -------------------------------------------------------------------- |
| void setOrFlag(); |
| void restoreOrFlag(); |
| NABoolean haveAnOrAncestor() const { return orCount_ > 0; } |
| |
| // -------------------------------------------------------------------- |
| // Check constraints are relied upon to enforce things, so we cannot |
| // rely on them and do certain transforms (eliminate/strength-reduce) |
| // when we are transforming constraints -- that would be circulus in probando. |
| // -------------------------------------------------------------------- |
| void setInConstraintsFlag() { inConstraintsCount_++; } |
| void restoreInConstraintsFlag() { inConstraintsCount_--; } |
| NABoolean inConstraints() const { return inConstraintsCount_ > 0; } |
| |
| // -------------------------------------------------------------------- |
| // |
| // If a recursive/cascaded triggers backbone has a connection to the |
| // triggering generic update the connection is using @old and @new |
| // columns from the triggering generic update. |
| // We found out that equality relation between each two levels of cascaded |
| // triggers might cause the creation of a huge VEGREF that the optimizer |
| // can't handle in a reasonable time. |
| // To prevent this problem will block the creation of VEGs on equal predicates |
| // involving a @old/ @new columns on high cascade levels. |
| // Cascade levels are counted by inBlockedUnionCount_, since every cascaded |
| // trigger backbone top node is a BlockedUnion |
| // |
| // -------------------------------------------------------------------- |
| void setInBlockedUnionCount() { inBlockedUnionCount_++; } |
| void restoreInBlockedUnionCount() {inBlockedUnionCount_--; } |
| Lng32 getInBlockedUnionCount() { return inBlockedUnionCount_; } |
| |
| // retrieve the current CmpContext |
| CmpContext* currentCmpContext() const { return currentCmpContext_; } |
| |
| // retrieve the wHeap |
| CollHeap* wHeap(); |
| |
| //QSTUFF |
| // these lists contain the names of tables read and updates |
| // respectively to check whether there is a potential read/write |
| // conflict |
| LIST(NAString) &getWriteList() { return writeList_; } |
| LIST(NAString) &getReadList() { return readList_; } |
| |
| NABoolean isInEmbeddedUpdateOrDelete() { return inEmbeddedUpdateOrDelete_; } |
| void setInEmbeddedUpdateOrDelete(NABoolean i) { inEmbeddedUpdateOrDelete_ = i;} |
| //QSTUFF |
| |
| // Support for embedded inserts from VALUES |
| NABoolean isInEmbeddedInsert() { return inEmbeddedInsert_; } |
| void setInEmbeddedInsert (NABoolean i) { inEmbeddedInsert_ = i;} |
| |
| NABoolean isInBeforeTrigger() { return inBeforeTrigger_; } |
| void setInBeforeTrigger(NABoolean i) { inBeforeTrigger_ = i;} |
| |
| NABoolean isInJoinPredicate() { return inJoinPredicate_; } |
| void setInJoinPredicate(NABoolean i) { inJoinPredicate_ = i;} |
| |
| long getMergeUpdDelCount() { return mergeUpdDelCount_; } |
| void setMergeUpdDelCount(long val) {mergeUpdDelCount_ = val;} |
| void incrementMergeUpdDelCount() { mergeUpdDelCount_++; } |
| |
| NABoolean requiresLeftTSJLinearization() |
| { return leftJoinConversionCount_ > 1; } |
| |
| void incrementLeftJoinConversionCount() { leftJoinConversionCount_++; } |
| void decrementLeftJoinConversionCount() { leftJoinConversionCount_--; } |
| Lng32 getLeftJoinConversionCount() { return leftJoinConversionCount_; } |
| void setLeftJoinConversionCount(Lng32 val) {leftJoinConversionCount_ = val;} |
| |
| NABoolean requiresSemanticQueryOptimization() |
| { return ((correlatedSubqCount_ > 0) || |
| containsJoinsToBeEliminated_ || |
| checkForExtraHubTables_ || |
| containsGroupBysToBeEliminated_ || |
| containsSemiJoinsToBeTransformed_ || |
| commonSubExprCount_ > 0); } |
| |
| void incrementCorrelatedSubqCount() { correlatedSubqCount_++; } |
| void decrementCorrelatedSubqCount() {correlatedSubqCount_--; } |
| Lng32 getCorrelatedSubqCount() { return correlatedSubqCount_; } |
| void setCorrelatedSubqCount(Lng32 val) {correlatedSubqCount_ = val;} |
| |
| NABoolean requiresRecursivePushdown() |
| { return requiresRecursivePushdown_;} |
| void setRequiresRecursivePushdown(NABoolean val) |
| {requiresRecursivePushdown_ = val;} |
| |
| NABoolean containsJoinsToBeEliminated() |
| { return containsJoinsToBeEliminated_;} |
| void setContainsJoinsToBeEliminated(NABoolean val) |
| {containsJoinsToBeEliminated_ = val;} |
| |
| NABoolean checkForExtraHubTables() |
| { return checkForExtraHubTables_;} |
| void setCheckForExtraHubTables(NABoolean val) |
| {checkForExtraHubTables_ = val;} |
| |
| NABoolean containsGroupBysToBeEliminated() |
| { return containsGroupBysToBeEliminated_;} |
| void setContainsGroupBysToBeEliminated(NABoolean val) |
| {containsGroupBysToBeEliminated_ = val;} |
| |
| NABoolean containsSemiJoinsToBeTransformed() |
| { return containsSemiJoinsToBeTransformed_;} |
| void setContainsSemiJoinsToBeTransformed(NABoolean val) |
| {containsSemiJoinsToBeTransformed_ = val;} |
| RelExpr* getExtraHubVertex() { return extraHubVertex_;} |
| void setExtraHubVertex(RelExpr* ptr) |
| {extraHubVertex_ = ptr;} |
| |
| Int32 getCommonSubExprRefCount() { return commonSubExprCount_; } |
| void incrementCommonSubExprRefCount() { commonSubExprCount_++; } |
| |
| // Return a reference to the Semantic Query WA |
| SqoWA * getSqoWA() { return sqoWARef_;} |
| |
| |
| // -------------------------------------------------------------------- |
| // counter to record if we are currently transforming expressions in a select |
| // list (i.e. compExpr). This is used for subquery unesting. A subquery in a |
| // select list does not reject null values since there is no predicate |
| // outside the subquery and the result if the subquery is produced as is. |
| // If the subquery produces a null value that must be retained. Therefore |
| // subqureries in a select list are equivalent to other predicates that do |
| // not reject null values (for e.g. IS NOT NULL, count(*) = 0, ...) |
| // -------------------------------------------------------------------- |
| void setInSelectList() { inSelectListCount_++; } |
| void restoreInSelectList() { inSelectListCount_--; } |
| NABoolean inSelectList() const { return inSelectListCount_ > 0; } |
| |
| // -------------------------------------------------------------------- |
| // flag to record if we are currently transforming expressions in a HAVING |
| // clause (i.e. selection pred of GroupByAgg). This is used for subquery |
| // unesting. A subquery in a HAVING clause currently cannot be unnested. |
| // -------------------------------------------------------------------- |
| void setInHavingClause(NABoolean val ) { inHavingClause_ = val; } |
| NABoolean inHavingClause() const { return inHavingClause_; } |
| |
| // -------------------------------------------------------------------- |
| // flag to record if we are currently transforming a ValueIdProxy |
| // The assumption is that the we have already split out the different |
| // outputs of MVFs or Subqueries of degree > 1. Thus we want the transform |
| // to only return a descrete value, not a list. |
| // This is used for flattening ITM_ITEM_LISTS of subqueries with degree > 1 |
| // and MVFs |
| // -------------------------------------------------------------------- |
| void setInValueIdProxy(NABoolean val ) { inValueIdProxy_ = val; } |
| NABoolean inValueIdProxy() const { return inValueIdProxy_; } |
| |
| // -------------------------------------------------------------------- |
| // flag to record if we are currently transforming expressions |
| // associated with a assign expression of a GenericUpdate node |
| // Examples are newRecExpr, insert expresion for mergeThis is used for subquery unesting. |
| // A subquery in an INSERT/UPDATE/DELETE needs a left join to be unnested. |
| // -------------------------------------------------------------------- |
| void setInGenericUpdateAssign(NABoolean val) {inGenericUpdateAssign_ = val;} |
| NABoolean inGenericUpdateAssign() const {return inGenericUpdateAssign_;} |
| |
| // flag to record if we are currently transforming expressions in |
| // a Merge ... Update ... Where predicate. |
| void setInMergeUpdWhere(NABoolean val) {inMergeUpdWhere_ = val;} |
| NABoolean inMergeUpdWhere() const {return inMergeUpdWhere_;} |
| |
| // Use this to avoid rangespec transformation in the Normalizer if called by |
| // MVQR for a node in rewritten query (since it will already have been done). |
| void setInMVQueryRewrite(NABoolean val) { inMVQueryRewrite_ = val; } |
| NABoolean inMVQueryRewrite() const { return inMVQueryRewrite_; } |
| |
| //---------------------------------------------------------------------- |
| // |
| void setAllSeqFunctions(ValueIdSet v) { allSeqFunctions_ = v;} |
| ValueIdSet getAllSeqFunctions() const { return allSeqFunctions_; } |
| void resetAllSeqFunctions () { allSeqFunctions_.clear(); } |
| void addSeqFunction( ValueId v) { allSeqFunctions_ += v ; } |
| ValueId getEquivalentItmSequenceFunction(ValueId newSeqId); |
| void optimizeSeqFunctions( ItemExpr * ie, ItemExpr * pie, Int32 idx ); |
| |
| |
| void resetSeqFunctionsCache(){ |
| origSeqFunction_.clear(); |
| equiTransformedExpr_.clear(); |
| } |
| |
| void insertIntoSeqFunctionsCache (ItemExpr * orig, ValueId transformed) { |
| origSeqFunction_.insert( orig); |
| equiTransformedExpr_.insert( transformed ); |
| CMPASSERT (origSeqFunction_.entries() == equiTransformedExpr_.entries()); |
| } |
| |
| NABoolean retrieveFromSeqFunctionsCache(CollIndex index, ValueId &transformed) { |
| if (index <0 || index > origSeqFunction_.entries()-1) { |
| return FALSE; |
| } |
| //orig = origSeqFunction_[index]; |
| transformed = equiTransformedExpr_[index]; |
| return TRUE; |
| } |
| |
| CollIndex SeqFunctionsCacheEntries(){ |
| CMPASSERT (origSeqFunction_.entries() == equiTransformedExpr_.entries()); |
| return origSeqFunction_.entries(); |
| } |
| |
| NABoolean findEquivalentInSeqFunctionsCache( ItemExpr * newItem , ValueId &cacheEquivTransSeqId); |
| |
| VEGTable * getVEGTable() {return vegTable_ ;} |
| |
| const RelExpr * getCurrentOwnerExpr() ; |
| |
| void saveLeftJoinChildVEGRegion(ExprNode * const ownerExprPtr, |
| Lng32 subtreeId = 0) |
| {leftJoinChildVEGRegion_ = |
| vegTable_->locateVEGRegion(ownerExprPtr, subtreeId); } |
| |
| void resetLeftJoinChildVEGRegion() {leftJoinChildVEGRegion_ = NULL; } |
| |
| void setCompilingMVDescriptor(NABoolean b) { compilingMVDescriptor_ = b; } |
| |
| NABoolean compilingMVDescriptor() { return compilingMVDescriptor_; } |
| |
| private: |
| |
| // -------------------------------------------------------------------- |
| // Counters that keep track of whether an expression is the child of |
| // an ISNULL, IS UNKNOWN or a NOT. |
| // Whenever a new counter is added, update the following methods: |
| // 1) default constructor |
| // 2) copy constructor |
| // 3) clearStateInformation() |
| // -------------------------------------------------------------------- |
| Lng32 walkingAnExprTreeCount_; |
| Lng32 subqUnderExprTreeCount_; |
| |
| Lng32 complexScalarExprCount_; |
| |
| Lng32 nullCount_; |
| |
| Lng32 notCount_; |
| |
| Lng32 orCount_; |
| |
| Lng32 inConstraintsCount_; |
| |
| // ++Triggers - |
| Lng32 inBlockedUnionCount_; |
| |
| // QSTUFF |
| |
| // this flag is set to prevent a constant equalitity predicate, e.g. |
| // x = 10, to become veggyfied when normalizing an expression containing |
| // an embedded delete or update. This prevents the predicate from being |
| // lost when not pushing it down to leave operators due to the veg relation |
| |
| NABoolean inEmbeddedUpdateOrDelete_; |
| |
| // this flag is set to prevent a constant equalitity predicate, e.g. |
| // x = 10, to become veggyfied when normalizing an expression containing |
| // an embedded insert from VALUES. This prevents the predicate from being |
| // lost when not pushing it down to leave operators due to the veg relation |
| |
| NABoolean inEmbeddedInsert_; |
| |
| // this flag is set to prevent some transformations for binary logic |
| // that does not take before triggers into account |
| |
| NABoolean inBeforeTrigger_; |
| |
| // this flag is set so that ItemExpr trees are not modified during calls |
| // to ItemExpr::normalizeNode, when normalizing (i.e. rewriting) the join |
| // predicate. All modifications will be done on a copy of the original |
| // itemexpr. This is necessary since the same valueid may be used in |
| // others parts of the query tree that are in different veg regions. |
| // and any veg rewite that is correct in one region may not be in other |
| // regions. |
| |
| NABoolean inJoinPredicate_ ; |
| |
| // counter to record the number of mergeupdate/delete in query |
| long mergeUpdDelCount_; |
| |
| // counter to record the number of correlated subqueries where we need to |
| // transform the TSJ into a Left Join. During transform |
| // this counter is incremented for each subquery that matches criteria for |
| // subquery unnesting. The criteria is that we have a correlated Subquery |
| // (TSJ->GB->Filter), and the GroupBy contains nonNullRejecting predicates |
| // (like count() etc) |
| Lng32 leftJoinConversionCount_ ; |
| |
| // counter to record the number of correlated subqueries. During transform |
| // this counter is incremented for each subquery that matches criteria for |
| // subquery unnesting. Then during normalize the counter will be decremented |
| // for each qualifying subquery that is not correlated. The during the SQO phase |
| // we undertake a tree walk only if there is at least one correlated subquery. |
| Lng32 correlatedSubqCount_ ; |
| |
| // counter to record if we are currently transforming expressions in a select |
| // list (i.e. compExpr). This is used for subquery unesting. A subquery in a |
| // select list does not reject null values since there is no predicate outside |
| // the subquery and the result if the subquery is produced as is. If the |
| // subquery produces a null value that must be reatined. Therefor |
| // subqureries in a select list are equivalent to other predicates that |
| // do not reject null values (like IS NOT NULL, count(*) = 0, ...) |
| |
| Lng32 inSelectListCount_ ; |
| |
| NABoolean inHavingClause_ ; |
| |
| NABoolean inValueIdProxy_ ; |
| |
| NABoolean inGenericUpdateAssign_ ; |
| |
| NABoolean inMergeUpdWhere_ ; |
| |
| NABoolean inMVQueryRewrite_ ; |
| |
| NABoolean containsJoinsToBeEliminated_ ; |
| |
| NABoolean checkForExtraHubTables_; |
| |
| NABoolean containsGroupBysToBeEliminated_; |
| |
| NABoolean containsSemiJoinsToBeTransformed_ ; |
| |
| RelExpr * extraHubVertex_; |
| |
| Int32 commonSubExprCount_; |
| |
| // Pointer to Semantic Query Optimization WA. Used for error recovery |
| SqoWA * sqoWARef_; |
| |
| // this variable are used to check whether the same table is both |
| // updated and read |
| LIST(NAString) readList_; |
| LIST(NAString) writeList_; |
| // QSTUFF |
| |
| // -------------------------------------------------------------------- |
| // A VEGTable instance is allocted in the NormWA |
| // Once could either call it a vegTable_ because it is a table of |
| // VEG's or a salad_ because it is a collection of VEG's. The name |
| // salad_ is more appropriate because the vegTable_ is not a table |
| // but a list. |
| // -------------------------------------------------------------------- |
| VEGTable * vegTable_; |
| |
| // place to hold the current CmpContext |
| CmpContext* currentCmpContext_; |
| |
| ValueIdSet allSeqFunctions_; |
| |
| LIST(ItemExpr *) origSeqFunction_; |
| LIST(ValueId) equiTransformedExpr_; |
| |
| VEGRegion *leftJoinChildVEGRegion_; |
| |
| NABoolean compilingMVDescriptor_; |
| |
| NABoolean requiresRecursivePushdown_; |
| |
| }; // class NormWA |
| |
| |
| #endif /* NormWA_H */ |