/**********************************************************************
// @@@ 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 RELEXPR_H
#define RELEXPR_H
/* -*-C++-*-
******************************************************************************
*
* File:         RelExpr.h
* Description:  Relational expression base class
* Created:      4/28/94
* Language:     C++
* Status:       $State: Exp $
*
*
*
*
******************************************************************************
*/

#include "ObjectNames.h"
#include "CmpContext.h"
#include "CmpStatement.h"
#include "RETDesc.h"
#include "ValueDesc.h"
#include "Rule.h"
#include "ExprNode.h"
#include "ComTransInfo.h"
#include "mdam.h"
#include "DefaultConstants.h"
#include "Inlining.h"
#include "NADefaults.h"
#include "OptUtilIncludes.h"
#include "ExplainTupleMaster.h"

// -----------------------------------------------------------------------
// contents of this file
// -----------------------------------------------------------------------
class ExprGroupId;
class RelExpr;
class RelExprList;
class CutOp;
class SubtreeOp;
class WildCardOp;
class ScanForceWildCard;
class UDFForceWildCard;
class RequiredResources;

// -----------------------------------------------------------------------
// forward references
// -----------------------------------------------------------------------
class BindWA;
class CacheWA;
class CascadesPlan;
class Context;
class ContextList;
class Cost;
class CostLimit;
class CostMethod;
class EstLogProp;
class Generator;
class ComTdb;
class ExplainTuple;
class GroupAttibutes;
class Guidance;
class NormWA;
class PhysicalProperty;
class InputPhysicalProperty;
class ReqdPhysicalProperty;
class PlanWorkSpace;
class PartitioningRequirement;
class FileScan;
class Scan;
class SubTreeAccessSet;
class SearchKey;
class ScanKey;
class MVInfoForDDL;
class PlanPriority;
class Hint;
class TableMappingUDF;
class RelSequence;
class CSEInfo;


////////////////////
class CANodeIdSet;
class QueryAnalysis;
class GroupAnalysis;
////////////////////

// used in heuristics to limit VSBB and SIDETREE inserts only if number rows
// being inserted is larger than this constant. Used in ImplRule.cpp and 
// GenPreCode.cpp
const Lng32 MIN_ROWS_FOR_VSBB = 100;

// used to defined input partitioning type of a TMUDF table input (its child)
enum TMUDFInputPartReq 
{
  ANY_PARTITIONING, 
  SPECIFIED_PARTITIONING, 
  REPLICATE_PARTITIONING, 
  NO_PARTITIONING 
};

// -----------------------------------------------------------------------
// An ExprGroupId object is a pointer to a logical or a physical RelExpr
// object or to a Cascades group. It is used to point to the child
// nodes (subtrees) of an ExprNode object. Different modes of addressing
// are available, depending on whether the tree is a standalone object
// outside of Cascades, a materialized binding in Cascades, or a memoized
// expression (a member of the CascadesMemo structure).
// -----------------------------------------------------------------------
class ExprGroupId : public NABasicObject
{
public:

  // state of the object
  enum GroupIdMode
  {
    STANDALONE,
    BINDING,
    MEMOIZED
  };

  // constructors

  ExprGroupId();
  ExprGroupId(const ExprGroupId & other);
  ExprGroupId(RelExpr *node);
  ExprGroupId(CascadesGroupId groupId);

  // assignment operators
  ExprGroupId & operator = (const ExprGroupId & other);
  ExprGroupId & operator = (RelExpr * other);
  ExprGroupId & operator = (CascadesGroupId other);

  // compare an ExprGroupId with another ExprGroupId or a RelExpr *
  NABoolean operator == (const ExprGroupId &other) const;
  NABoolean operator != (const ExprGroupId &other) const
                                        { return NOT operator == (other); }
  NABoolean operator == (const RelExpr *other) const;
  NABoolean operator != (const RelExpr *other) const
                                        { return NOT operator == (other); }

  // dereferencing operator, this class works like a pointer
  inline RelExpr * operator ->() const;         // defined below class Rexpr

  // same as a "normal" method
  inline RelExpr * getPtr() const;              // defined below class RelExpr

  // cast into a RelExpr *
  inline operator RelExpr *() const;            // defined below class RelExpr

  // return a group number instead of a pointer
  CascadesGroupId getGroupId() const;

  // return the mode of the pointer
  GroupIdMode getMode() const           { return groupIdMode_; }

  // change a binding back to mode MEMOIZED
  void releaseBinding();
  void convertBindingToStandalone(); // use after optimization

  // The Group Attributes contains certain attributes that are
  // characteristics for a relational operator.
  void setGroupAttr(GroupAttributes *gaPtr);
  GroupAttributes *getGroupAttr() const;

  // shortcut to get the estimated output log props out of the group
  // given the corresponding input estimated logical property.
  // NOTE:  If the OLP has not yet been synthesized, this method
  //        will synthesize the OLP on demand.
  //        (This means that no const version of this function is
  //         possible)
  EstLogPropSharedPtr outputLogProp(const EstLogPropSharedPtr& inputLogProp);

  // A shortcut to get the bound expression (if it exists) ...
  // or the first logical expression in the Cascades Group.
  RelExpr * getLogExpr() const;

  RelExpr * getFirstLogExpr() const;

private:

  enum GroupIdMode groupIdMode_;
  RelExpr * node_;              // used for all modes but MEMOIZED
  CascadesGroupId groupId_;     // used for the MEMOIZED and BINDING mode

}; // class ExprGroupId

// -----------------------------------------------------------------------
// A generic relational expression node. This class is a base class for
// any relational operator in the system. Every relational operator has
// a selection predicate associated with it. This base class also
// maintains all the data members describing the output row of a
// relational operator and its outer references.
// -----------------------------------------------------------------------

class RelExpr : public ExprNode
{

public:

  // ---------------------------------------------------------------------
  // default constructor
  // ---------------------------------------------------------------------
  RelExpr(OperatorTypeEnum otype,
          RelExpr  *leftChild = NULL,
          RelExpr  *rightChild = NULL,
          CollHeap *outHeap = CmpCommon::statementHeap());

  // operator== required for use in templates
  NABoolean operator==(const RelExpr &other) const
  {
    if(&other == this)
      return TRUE;
    else
      return FALSE;
  }

  // ---------------------------------------------------------------------
  // virtual destructor
  // ---------------------------------------------------------------------
  virtual ~RelExpr();

  virtual Int32 getArity() const;

  NABoolean isAnyJoin() const;

  virtual const NAString getText() const {return NAString("RelExpr"); }

  // are RelExpr's kids cacheable after this phase?
  NABoolean cacheableKids(CacheWA& cwa);

  // is this entire expression cacheable after this phase?
  virtual NABoolean isCacheableExpr(CacheWA& cwa);

  // is this single ExprNode cacheable after this phase?
  NABoolean isCacheableNode(CmpPhase phase) const;

  // mark this ExprNode as cacheable for this and later phases
  void setCacheableNode(CmpPhase phase);

  // append an ascii-version of RelExpr into cachewa.qryText_
  virtual void generateCacheKey(CacheWA& cachewa) const;

  // change literals of a cacheable query into ConstantParameters
  virtual RelExpr* normalizeForCache(CacheWA& cachewa, BindWA& bindWA);

  // helper function on CQS Tree
  virtual RelExpr *generateMatchingExpr(CANodeIdSet &,
                                        CANodeIdSet &,
                                        RelExpr *);

  // helper function on Normalized tree (CQS project)
  virtual RelExpr * generateLogicalExpr (CANodeIdSet &,
                                        CANodeIdSet &);

  Hint *getHint() const { return hint_; }

  void  setHint(Hint *h) { hint_ = h; }

  static const CorrName invalid;
 virtual inline const CorrName& getTableName()const { return invalid;}



 protected:
  // append an ascii-version of RelExpr node into cachewa.qryText_
  void generateCacheKeyNode(CacheWA& cwa) const;

  // append an ascii-version of RelExpr's kids into cachewa.qryText_
  void generateCacheKeyForKids(CacheWA& cachewa) const;

  // change literals in cacheable query's kids into ConstantParameters
  void normalizeKidsForCache(CacheWA& cachewa, BindWA& bindWA);

  // How much memory do we expect this operator's executor to be able to use 
  // per ESP/master fragment ?
  Lng32 getExeMemoryAvailable(NABoolean inMaster) const;

  // compute the memory quota 
  double computeMemoryQuota(NABoolean inMaster,
                            NABoolean perNode,
                            double BMOsMemoryLimit,
                            UInt16 totalNumBMOs,
                            double totalBMOsMemoryUsage,
                            UInt16 numBMOsPerFragment,
                            double BMOMemoryUsage,
                            Lng32  numStreams,
                            double &memQuotaRatio
                           );

 
 public:
  // ---------------------------------------------------------------------
  // perform a safe type cast (return NULL ptr for illegal casts)
  // ---------------------------------------------------------------------
  virtual RelExpr *castToRelExpr();
  const RelExpr * castToRelExpr() const;

  // This method clears all logical expressions uptill the leaf node
  // for multi-join. The methid should be called only before optimization phases
  // Reason for that is (1)it is very expensive to synthLogProp and should be avoided
  // (2) we are resetting number of joined tables, which should not be done once it is
  // set during optimization phases

  void clearLogExprForSynthDuringAnalysis();

  virtual NABoolean  isAControlStatement()    const { return FALSE; }
  virtual StaticOnly isAStaticOnlyStatement() const { return NOT_STATIC_ONLY; }

  NABoolean isParHeuristic4Feasible(Context* myContext,
                           const ReqdPhysicalProperty* rppForMe);

  // safe casting to derived classes
  virtual TableMappingUDF *castToTableMappingUDF();

  // ---------------------------------------------------------------------
  // method required for traversing an ExprNode tree
  // access a child of an ExprNode
  // ---------------------------------------------------------------------
  virtual ExprNode * getChild(Lng32 index);

  // Method for replacing a particular child
  virtual void setChild(Lng32 index, ExprNode *);

  // ---------------------------------------------------------------------
  // Delete this node without deleting its subtree.
  // ---------------------------------------------------------------------
  void deleteInstance();

  // ---------------------------------------------------------------------
  // methods for traversing the tree
  // ---------------------------------------------------------------------

  // operator [] is used to access the children of a tree
  virtual ExprGroupId & operator[] (Lng32 index)
    {
      CMPASSERT(index >= 0 AND index < MAX_REL_ARITY);
      return child_[index];
    }

  virtual const ExprGroupId & operator[] (Lng32 index) const
    {
      CMPASSERT(index >= 0 AND index < MAX_REL_ARITY);
      return child_[index];
    }

  // for cases where a named method is more convenient than operator []
  inline ExprGroupId & child(Lng32 index)
                                             { return operator[](index); }
  // const version of the above
  inline const ExprGroupId & child(Lng32 index) const
                                             { return operator[](index); }

  // ---------------------------------------------------------------------
  // manipulate the selection predicate of the node
  // (read and set the entire predicate, add and remove
  // predicates that are ANDed together).
  // Predicates that are passed through this interface change
  // ownership, meaning that the new "owner" is responsible
  // for deallocation. No copies are made by these methods.
  // ---------------------------------------------------------------------

  // add a new selection predicate (new pred = child pred AND existing pred)
  void addSelPredTree(ItemExpr *selpred);

  // remove the selection predicate tree from this node and return its pointer
  ItemExpr * removeSelPredTree();

  // non-destructive read of the selection predicates
  ItemExpr * selPredTree() const                        { return selection_; }
  const ItemExpr * getSelPredTree() const               { return selection_; }

  // return a (short-lived) read/write reference to the selection predicates
  ValueIdSet & selectionPred() { CMPASSERT(NOT isCutOp()); return predicates_; }

  // return a constant reference to the selection predicates
  const ValueIdSet & getSelectionPred() const           { return predicates_; }
  const ValueIdSet & getSelectionPredicates() const     { return predicates_; }

  void setSelectionPredicates(const ValueIdSet& p)      { predicates_ = p; }

  //++MV
  // Used by inlining mechanism for adding optimizer constraints
  void addUniqueColumnsTree(ItemExpr *uniqueColumnsTree);
  ItemExpr * removeUniqueColumnsTree();

  inline ValueIdSet& getUniqueColumns()			{ return uniqueColumns_; }
  inline void setUniqueColumns(const ValueIdSet& uniqueColumns)
  {
    uniqueColumns_ = uniqueColumns;
  }

  CardConstraint * getCardConstraint() const { return cardConstraint_; }
  void addCardConstraint(Cardinality lowerBound, Cardinality upperBound)
  {
    cardConstraint_ = new(CmpCommon::statementHeap())
			 CardConstraint(lowerBound,upperBound);
  }
  //--MV


  // ---------------------------------------------------------------------
  // The Group Attributes contains certain attributes that are
  // characteristics for this relational operator, namely,
  // 1) the values that it requires as external inputs, which are
  //    outer references such as a column from an outer scope,
  //    a host variable, a dynamic parameter or a constant.
  // 2) the values that it produces as output.
  // 3) the logical properties such as constraints, statistics, etc.
  // ---------------------------------------------------------------------
  void setGroupAttr(GroupAttributes *gaPtr);
  inline GroupAttributes *getGroupAttr() const      { return groupAttr_; }
  virtual NABoolean reconcileGroupAttr(GroupAttributes *newGroupAttr);

  // *********************************************************************
  // Common interfaces for processing DML statements.
  // Each interface implements one phase of query processing.
  // *********************************************************************
  enum AtomicityType
  {UNSPECIFIED_ = 0, ATOMIC_ = 1, NOT_ATOMIC_ = 2};

  // Rowsets processing does some transformations after parsing but before
  // binding. For example, it transforms a query Q that has an input rowset
  // array A into a TSJ that feeds each element of A into the query Q. The argument
  // inputArrayMaxsize is used to set the length of input arrays for ODBC
  // insert queries.
  virtual RelExpr *xformRowsetsInTree(BindWA& wa,
					const ULng32 inputArrayMaxsize = 0,
					const AtomicityType atomicity = UNSPECIFIED_);

  // --------------------------------------------------------------------
  // The name binding and semantics checking phase is implemented
  // by the virtual function bindNode().
  // --------------------------------------------------------------------
  virtual RelExpr * bindNode(BindWA *bindWAPtr);

  // --------------------------------------------------------------------
  // Unconditional query transformations such as the transformation of
  // a subquery to a semijoin are implemented by the virtual function
  // transformNode(). The aim of such transformations is to bring the
  // query tree to a canonical form. transformNode() also ensures
  // that the "required" (or characteristic) input values are "minimal"
  // and the "required" (or characteristic) outputs values are
  // "maximal" for each operator.
  //
  // transformNode() is an overloaded name, which is used for a set
  // of methods that implement the transformation phase of query
  // normalization.
  //
  // We use the term query tree for a tree of relational operators,
  // each of which can contain none or more scalar expression trees.
  // The transformations performed by transformNode() brings scalar
  // expressions into a canonical form. The effect of most such
  // transformations is local to the scalar expression tree.
  // However, the transformation of a subquery requires a semijoin
  // to be performed between the relational operator that contains
  // the subquery and the query tree for the subquery. The effect
  // of such a subquery transformation is therefore visible not
  // only in the scalar expression tree but also in the relational
  // expression tree.
  //
  // Originally, transformNode() was a virtual method on ExprNode.
  // The relational as well as scalar expressions are derived from
  // ExprNode and used to provide proprietary implementations for it.
  // However, relational and scalar expressions have different
  // processing requirements during the transformation phase. Hence,
  // each of them now support a virtual transformNode() method that
  // differ in their interfaces.
  //
  // Parameters:
  //
  // NormWA & normWARef
  //    IN : a pointer to the normalizer work area
  //
  // ExprGroupId & locationOfPointerToMe
  //    IN : a reference to the location that contains a pointer to
  //         the RelExpr that is currently being processed.
  //
  // --------------------------------------------------------------------
  virtual void transformNode(NormWA & normWARef,
                             ExprGroupId & locationOfPointerToMe);

  // --------------------------------------------------------------------
  // rewriteNode() is the virtual function that computes
  // the transitive closure for "=" predicates and rewrites value
  // expressions.
  // --------------------------------------------------------------------
  virtual void rewriteNode(NormWA & normWARef);

  // QSTUFF

  // --------------------------------------------------------------------
  // This routine checks whether a table is both read and updated
  // --------------------------------------------------------------------
  enum rwErrorStatus
    {
      RWERROR,
      RWOKAY
    };

  virtual rwErrorStatus checkReadWriteConflicts(NormWA & normWARef);

  // QSTUFF

  // --------------------------------------------------------------------
  // normalizeNode() performs predicate pushdown and also ensures
  // that the characteristic input as well as characteristic output
  // values are both "minimal".
  // --------------------------------------------------------------------
  virtual RelExpr * normalizeNode(NormWA & normWARef);

  // --------------------------------------------------------------------
  // getEssentialOutputsFromChildren() is a helper method used by the
  // classifyChildOutputs() method. This method will have a set containing
  // all Essential Outputs out a node's direct children in essOutputs,
  // upon completion.
  // --------------------------------------------------------------------
  void getEssentialOutputsFromChildren(ValueIdSet & essOutputs);

  // --------------------------------------------------------------------
  // fixEssentialCharacteristicOutputs() is a used during the bottom-up of
  // normalizeNode(). This method collects the essential outputs of the
  // children nodes and if any nonessential outputs of the cureent node
  // overlap with those essential outputs, then the overlapping nonessential
  // outputs are set to be essential too. In other words this method implements
  // the rule that states if an output is essential in my child, it is
  // essential for me too (if the valueid is part of my output).
  // --------------------------------------------------------------------
  void fixEssentialCharacteristicOutputs();

  // --------------------------------------------------------------------
  // semanticQueryOptimizeNode() performs sematic query optimization
  // In Neo R2.2 this includes only subquery unnesting
  // semantic query optimization is defined as a sematics preserving
  // tranformation on a query tree that uses the logical constraints
  // computed for the query.
  // --------------------------------------------------------------------
  virtual RelExpr * semanticQueryOptimizeNode(NormWA & normWARef);

  // used during SemanticQueryOptimize to remove filter nodes introduced
  // in previous phases, if the subquery is not going to be unnested.
  // The objective is to push predicates as far down as possible so that
  // cardinality can be estimated correctly for all nodes during Analyzer
  // phase
  void eliminateFilterChild();

  // used duirng SQO, to check if the child or grandchild of current
  // node is a filter. Two acceptable patterns are (a) child(0) is filter
  // child(0) is groupby an child(0)->child(0) is filter
  NABoolean hasFilterChild();

  // used during SQO phase to make the left sub tree of the join
  // being unnested produce the extra outputs that is necessary to
  // group by a set of unique columns of of the left sub tree
  NABoolean getMoreOutputsIfPossible(ValueIdSet& outputsNeeded) ;

  // calls pushDownCoveredExpr recursively. Used at the end of the
  // SQO phase to get outputs at every node to be minimal
  void recursivePushDownCoveredExpr(NormWA * normWAPtr, 
                                    NABoolean doSynthLogProp = TRUE) ;

  // synthesizes (in Scan's implemenation), matches (in Join's implementation)
  // and flows CompRefOpt constraints up the query tree.
  virtual void processCompRefOptConstraints(NormWA * normWAPtr) ;

  // Used during SQO to prepare the child tree of a CommonSubExprRef
  // for sharing between multiple consumers. This basically undoes
  // some of the normalizations, like eliminating unneeded outputs
  // and pushing predicates down. This is a recursive tree walk
  // method, most nodes don't override this one.
  // Returns TRUE for success, FALSE if it was unable to prepare
  // (diags will be set).
  // Tree remains unchanged if testRun is TRUE.
  virtual NABoolean prepareTreeForCSESharing(
       const ValueIdSet &outputsToAdd,
       const ValueIdSet &predicatesToRemove,
       const ValueIdSet &commonPredicatesToAdd,
       const ValueIdSet &inputsToRemove,
       ValueIdSet &valuesForVEGRewrite,
       ValueIdSet &keyColumns,
       CSEInfo *info);

  // A virtual method called on every node from prepareTreeForCSESharing(),
  // use this to do the actual work of removing predicates other than
  // selection predicates, and to indicate that the node supports this
  // method (the default implementation returns FALSE).
  //
  // This method needs to
  // - make sure no changes are done to the node when testRun is TRUE
  // - add any required new outputs to the char. outputs, unless they
  //   are produced by a child
  // - make sure no local expression reference any of the inputs to
  //   be removed
  // - indicate in its return value whether it was successful doing so
  //
  // This method doesn't need to take care of the following, since the
  // caller of this method already does it:
  // - removing predicates from selectionPred()
  // - adding new common predicates to selectionPred(), unless
  //   they are covered by the children's group attributes
  // - adding required outputs that are produced by children
  // - removing char. inputs that are requested to be removed
  virtual NABoolean prepareMeForCSESharing(
       const ValueIdSet &outputsToAdd,
       const ValueIdSet &predicatesToRemove,
       const ValueIdSet &commonPredicatesToAdd,
       const ValueIdSet &inputsToRemove,
       ValueIdSet &valuesForVEGRewrite,
       ValueIdSet &keyColumns,
       CSEInfo *info);

  // --------------------------------------------------------------------
  // Create a query execution plan.
  // --------------------------------------------------------------------
  virtual RelExpr * optimizeNode();

  // --------------------------------------------------------------------
  // Perform local query rewrites such as for the creation and
  // population of intermediate tables, for accessing partitioned
  // data. Rewrite the value expressions after minimizing the dataflow
  // using the transitive closure of equality predicates.
  // --------------------------------------------------------------------
  virtual RelExpr * preCodeGen(Generator * generator,
                               const ValueIdSet & externalInputs,
                               ValueIdSet &pulledNewInputs);

  // --------------------------------------------------------------------
  // Perform DoP reduction. Called during preCodeGen().
  // --------------------------------------------------------------------
  virtual void prepareDopReduction(Generator*);
  virtual void doDopReduction();
  virtual void doDopReductionWithinFragment(Lng32 newDoP);

  // --------------------------------------------------------------------
  // Generate executor task definition blocks (ComTdb's).
  // --------------------------------------------------------------------
  virtual short codeGen(Generator *);

  // -----------------------------------------------------
  // generate CONTROL QUERY SHAPE fragment for this node.
  // -----------------------------------------------------
  virtual short generateShape(CollHeap * space, char * buf, NAString * shapeStr = NULL);

  // *********************************************************************
  // Helper functions and methods used by the binder.
  // *********************************************************************

  void bindChildren(BindWA *bindWAPtr);

  RelExpr *bindSelf(BindWA *bindWAPtr);

  void setRETDesc(RETDesc *retdesc) { RETDesc_ = retdesc; }
  RETDesc *getRETDesc() const;
  CollIndex getDegree() const
  {
    RETDesc *rd = getRETDesc();
    return rd ? rd->getDegree() : (CollIndex)0;
  }

  Scan *getScanNode(NABoolean assertExactlyOneScanNode = TRUE) const;
  Scan *getLeftmostScanNode() const;
  Scan *getAnyScanNode() const;
  Join *getLeftJoinChild() const;
  RelSequence *getOlapChild() const;
  void getAllTableDescs(TableDescList &tableDescs);

  TableDesc *findFirstTableDescAndValueIdMap(RelExpr *currentNode,
                                             ValueIdMap &valueIdMap);


  // QSTUFF
  // we must pushdown the outputs of a genericupdate root to its
  // descendants to ensure that only those required output values are
  // tested against indexes when selecting an index for a stream scan
  // followed by an embedded update. Since we may allow for unions and
  // for inner updates we just follow the isEmbeddedUpdate() thread once
  // we reach a generic update root.

  void pushDownGenericUpdateRootOutputs(const ValueIdSet &outputs);

  // in order to bind constraints for views with the check option we
  // have to locate the respective view scan scope. In case of a simple
  // view the scope is associated with the leaf scan node; in case of
  // stacked views the scope is associated with the rename node inserted
  // by view expansion.

  RelExpr *getViewScanNode(NABoolean isTopLevelUpdateInView = FALSE) const;
  // QSTUFF

  // a virtual function to get addressability to the list of output values
  virtual ItemExpr * selectList();    // in the external form

  // Triggers --
  // get/set the InliningInfo object.
  inline       InliningInfo& getInliningInfo()       { return inliningInfo_; }
  inline const InliningInfo& getInliningInfo() const { return inliningInfo_; }
  inline void setInliningInfo(InliningInfo *info) { inliningInfo_ = *info; }

  // Access set handling methods
  inline SubTreeAccessSet *getAccessSet0()     { return accessSet0_;}
  inline SubTreeAccessSet *getAccessSet1()     { return accessSet1_;}
  inline void setAccessSet0(SubTreeAccessSet *as) { accessSet0_ = as; }
  inline void setAccessSet1(SubTreeAccessSet *as) { accessSet1_ = as; }

  virtual SubTreeAccessSet *calcAccessSets(CollHeap *heap);

  // MV --
  virtual NABoolean isIncrementalMV() { return FALSE; }
  virtual void collectMVInformation(MVInfoForDDL *mvInfo,
				    NABoolean isNormalized);

  // determine whether an IUD operation has been seen
  virtual NABoolean seenIUD() { return seenIUD_; }
  virtual void setSeenIUD() { seenIUD_ = TRUE; }

  // *********************************************************************
  // Helper functions and methods used by the normalizer.
  // *********************************************************************

  // procedure to do the common processing of the select predicate
  void transformSelectPred(NormWA & normWARef,
                           ExprGroupId & locationOfPointerToMe);

  // ---------------------------------------------------------------------
  // Inputs and Ouptuts.
  //
  // Each relational operator in the dataflow tree can receive some
  // external dataflow inputs such as constant values or values in
  // host variables or dynamic parameters, for evaluating some scalar
  // expression. Each operator can also produce one or more output
  // values that are either "raw" values from columns or values that
  // result from the evaluation of an expression.
  //
  // An operator can receive more values as inputs than it requires
  // for its own expressions because it passes them down to its
  // children. It is also capable of producing a large number of
  // values as outputs: potentially all those values that its children
  // can produce as well as those that do not require any new external
  // children. For example, if the children can produce values a, b,
  // then the operator is capable of producing a, b, a + b and so on.
  //
  // The Group Attributes that are associated with each relational
  // operator contain its Charcateristic Input and Outputs. The
  // following methods are used for priming the Group Attributes
  // with an set of values that provide the basis for computing
  // the Characteristic Input and Outputs.
  // --------------------------------------------------------------------
  void primeGroupAttributes();
  void allocateAndPrimeGroupAttributes(); // used after a rule-based transformation
  virtual void primeGroupAnalysis();

  // --------------------------------------------------------------------
  // A method that provides the set of values that can potentially be
  // produced as output by this operator. These are values over and
  // above those that are prodcued as Characteristic Outputs.
  // --------------------------------------------------------------------
  virtual void getPotentialOutputValues(ValueIdSet & vs) const;

  virtual void getPotentialOutputValuesAsVEGs(ValueIdSet& outputs) const;

  // ---------------------------------------------------------------------
  // pullUpPreds()
  //
  // This method is used during subquery transformation.
  // It moves predicates from transformed children of the node to the
  // appropriate place in the node.
  // If a child loses some predicates then recomputeOuterReferences()
  // must be called on it.
  //
  // ---------------------------------------------------------------------
  virtual void pullUpPreds();

  // ---------------------------------------------------------------------
  // recomputeOuterReferences()
  //
  // This method is used by the normalizer 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();

  // --------------------------------------------------------------------
  // pushdownCoveredExpr()
  //
  // In order to compute the Group Attributes for a relational operator
  // an analysis of all the scalar expressions associated with it is
  // performed. The purpose of this analysis is to identify the sources
  // of the values that each expression requires. As a result of this
  // analysis values are categorized as external dataflow inputs or
  // those that can be produced completely by a certain child of the
  // relational operator.
  //
  // This method is invoked on each relational operator. It causes
  // a) the pushdown of predicates and
  // b) the recomputation of the Group Attributes of each child.
  //    The recomputation is required either because the child is
  //    assigned new predicates or is expected to compute some of
  //    expressions that are required by its parent.
  // c) Classification of outputs into essential and non-essential outputs
  //
  // Parameters:
  //
  // const ValueIdSet &  outputExprOnOperator
  //    IN:  a read-only reference to the outputs of a node. This will
  //         be used to classify the child outputs into essential &
  //         non-essential outputs. Ideally this argument is not needed
  //         as a relExpr is capable of finding out what its outputs are.
  //         This argument is being kept so that many callers do not
  //         have to change.
  //
  // ValueIdSet & newExternalInputs
  //    IN : a reference to a set of new external inputs (ValueIds)
  //         that are provided by this operator for evaluating the
  //         the above expressions.
  //
  // ValueIdSet & predOnOperator
  //    IN : the set of predicates existing on the operator
  //    OUT: a subset of the original predicates. Some of the
  //         predicate factors may have been pushed down to
  //         the operator's children.
  //
  // ValueIdSet &  nonPredNonOutputExprOnOperator
  //    IN:  A pointer to a set of expressions that are
  //         associated with this operator. Typically, they do not
  //         include the selection predicates. For example this will
  //         include the group and aggregate expr of a GroupBy, any
  //         order requirement on a Root node
  //
  // short  childId
  //    IN : This is an optional parameter.
  //         If supplied, it is a zero-based index for a specific child
  //         on which the predicate pushdown should be attempted.
  //         If not supplied, or a null pointer is supplied, then
  //         the pushdown is attempted on all the children.
  //
  // ---------------------------------------------------------------------
  virtual void pushdownCoveredExpr(
                                   const ValueIdSet & outputExprOnOperator,
                                   const ValueIdSet & newExternalInputs,
                                   ValueIdSet& predOnOperator,
				   const ValueIdSet *
				      nonPredNonOutputExprOnOperator = NULL,
                                   Lng32 childId = (-MAX_REL_ARITY));


  // -----------------------------------------------------------------------
  // RelExpr::computeValuesReqdForPredicates()
  // This function obtains the values required to evaluate the predicates
  // contained in setOfExpr (first argument). The
  // computed list of values is returned in the second argument
  // -----------------------------------------------------------------------
  static void computeValuesReqdForPredicates(const ValueIdSet& setOfExpr,
				      ValueIdSet& reqdValues,
                                             NABoolean addInstNull = FALSE);

  // -----------------------------------------------------------------------
  // RelExpr::computeValuesReqdForOutput()
  // This function obtains the values required to evaluate the predicates
  // contained in setOfExpr (first argument). The
  // computed list of values is returned in the third argument.
  // -----------------------------------------------------------------------
  static void computeValuesReqdForOutput(const ValueIdSet& setOfExpr,
                                         const ValueIdSet& newExternalInputs,
                                         ValueIdSet& outputsOnOperator);

  // -----------------------------------------------------------------------
  // RelExpr::preventPushDownPartReq()
  // This function returns TRUE if both children have plans, are small and
  // not partitioned. Looking through all group's plans could be expensive,
  // especially at the end of the compilation process when we have lots of
  // plans in the memo. The idea of heuristic4, implemented here, is to check
  // just the first plan's partitioning properties for the child's group.
  // Under SYSTEM option we try to create parallel plan first. So if this
  // first plan happend to be non-parallel because we couldn't create a
  // parallel one we don't want to try parallelism again.
  // SO, if this is the only child and the child is small and non-partitioned
  // then the function returns TRUE preventing creation of parallel plan. If
  // the child is partitioned the function will return FALSE allowing creation
  // of parallel plan for the child's group. If the current expression has two
  // children they should be both "small" and have their first plans non-
  // parallel and succeeded in the current pass to prevent attempt to create
  // another parallel plan.

  NABoolean preventPushDownPartReq
                                    (const ReqdPhysicalProperty* rppForMe,
                                     const EstLogPropSharedPtr& inLogProp     ); 
  // *********************************************************************
  // Helper functions and methods used by the optimizer.
  // *********************************************************************

  // synthesize logical properties
  virtual void synthLogProp(NormWA * normWAPtr = NULL);

  // finish the synthesis of logical properties by setting various cardinality
  // related attributes
  virtual void finishSynthEstLogProp();

  // synthesize estimated logical properties given a specific set of
  // input log. properties
  virtual void synthEstLogProp(const EstLogPropSharedPtr& inputLP);

  // synthesize estimated logical properties for unary and leaf ops
  EstLogPropSharedPtr synthEstLogPropForUnaryLeafOp
              (const EstLogPropSharedPtr& inputEstLogProp,
               const ColStatDescList & childStats,
               CostScalar initialRowcount = 1,
               CostScalar *childMaxCardEst = NULL) const;

  // call the optimizer with requirements
  RelExpr * optimize(NABoolean               exception = FALSE,
	                 Guidance*               guidance = NULL,
                     ReqdPhysicalProperty  * rpp = NULL,
                     CostLimit*              costLimit = NULL);

  RelExpr * optimize2();

  RelExpr * checkAndReorderTree();

  void clearAllEstLogProp();

  // clear logical properties of me and mine children
  void clearAllLogProp();

  virtual RelExpr * reorderTree(NABoolean & treeModified,
	  NABoolean doReorderJoin);

  // added for trigger project, to activate after trigger transformation
  virtual RelExpr * fixupTriggers(NABoolean & treeModified);

  // ---------------------------------------------------------------------
  // comparison, hash, and copy methods
  // ---------------------------------------------------------------------

  virtual SimpleHashValue hash(); // from ExprNode
  virtual HashValue topHash();
  HashValue treeHash();
  virtual NABoolean patternMatch(const RelExpr & other) const;
  virtual NABoolean duplicateMatch(const RelExpr & other) const;

  // "virtual copy constructor", provides a generic method to duplicate
  // the top node of an expression tree or an entire tree.
  virtual RelExpr * copyTopNode(RelExpr *derivedNode = NULL,
                                CollHeap* outHeap = NULL);
  RelExpr * copyTree(CollHeap* heap = NULL);
  RelExpr * copyRelExprTree(CollHeap* outHeap = NULL);
  const RelExpr * getOriginalExpr(NABoolean transitive = TRUE) const;
  RelExpr * getOriginalExpr(NABoolean transitive = TRUE);

  // --------------------------------------------------------------------
  // Methods used internally by Cascades
  // --------------------------------------------------------------------

  virtual NABoolean  isLogical() const;
  virtual NABoolean  isPhysical() const;

  // these functions must not be redefined, except for Cut, Subtree,
  // or Wildcard nodes
  virtual NABoolean isCutOp() const;
  virtual NABoolean isSubtreeOp() const;
  virtual NABoolean isWildcard() const;

  // get/set the Cascades internal data of a RelExpr
  // NOTE: these methods are not really intended for general use!!!
  inline CascadesGroupId getGroupId() const             { return groupId_; }
  inline void setGroupId(CascadesGroupId g)                { groupId_ = g; }

  inline RelExpr * getNextInGroup()                   { return groupNext_; }
  inline void setNextInGroup(RelExpr * v)                { groupNext_ = v; }
  inline RelExpr * getNextInBucket()                 { return bucketNext_; }
  inline void setNextInBucket(RelExpr * v)              { bucketNext_ = v; }

  inline const RuleSubset &getContextInsensRules() const { return contextInsensRules_; }
  inline RuleSubset &contextInsensRules()          { return contextInsensRules_; }
  inline const RulesPerContextList &getContextSensRules() const { return contextSensRules_; }
  inline RulesPerContextList &contextSensRules() { return contextSensRules_; }

  // ---------------------------------------------------------------------
  // methods needed by Cascades iff an operator is logical
  // ---------------------------------------------------------------------

  // determine how many promising moves to pursue in exploration
  virtual Int32 computeExploreExprCutoff(RuleWithPromise promisingMoves [],
                                       Int32 numberOfMoves,
                                       RelExpr* pattern,
                                       Guidance* myGuidance);

  // determine how many promising moves to pursue in optimization
  virtual Int32 computeOptimizeExprCutoff(RuleWithPromise promisingMoves [],
                                        Int32 numberOfMoves,
                                        Guidance* myGuidance,
                                        Context* myContext);

  // ---------------------------------------------------------------------
  // Methods needed by Cascades iff an operator is physical
  // ---------------------------------------------------------------------

  // ---------------------------------------------------------------------
  // A virtual function to permit the allocation of an operator-specific
  // work space that is used during plan generation.
  // ---------------------------------------------------------------------
  virtual PlanWorkSpace* allocateWorkSpace() const;

  // ---------------------------------------------------------------------
  // Obtain a pointer to a CostMethod object that provides access
  // to the cost estimation functions for nodes of this type.
  // ---------------------------------------------------------------------
  virtual CostMethod* costMethod() const;

  // ---------------------------------------------------------------------
  // The main driver for plan generation.
  // Generate a context for optimizing a child of this operator,
  // given the optimization context and an operator-specific
  // work space that is used during plan generation.
  // The (implementation) rule and the guidance that was used
  // for creating this instance of the operator are also supplied.
  // They are used for creating a new guidance that is used for
  // optimizing the child.
  // ---------------------------------------------------------------------
  virtual Context* createPlan(Context* myContext,
                              PlanWorkSpace* pws,
                              Rule* rule,
                              Guidance* myGuidance,
                              Guidance* & childGuidance);

  // ---------------------------------------------------------------------
  // Create a Context for a specific child and store it in the
  // PlanWorkSpace.
  // This method is called from within the implementation
  // of createPlan().
  // ---------------------------------------------------------------------
  virtual Context* createContextForAChild(Context* myContext,
                     PlanWorkSpace* pws,
                     Lng32& childIndex);

  // ---------------------------------------------------------------------
  // Create a Context for a specific child, given a sortkey and
  // arranged columns.
  // This method should be called from within the implementation
  // of createContextForAChild() for operators that require the dataflow
  // produced by their child to be sorted.
  // ---------------------------------------------------------------------
  Context * generateContext(Context* myContext,
                            PlanWorkSpace* pws,
                            Lng32 childIndex,
                            const ValueIdSet* const arrangedCols,
                            const ValueIdList* const sortKey,
                            PartitioningRequirement* partReq);

  // ---------------------------------------------------------------------
  // A virtual function for computing the cost limit to be imposed
  // on the child that is about to be optimized.
  // ---------------------------------------------------------------------
  virtual CostLimit* computeCostLimit(const Context* myContext,
                                            PlanWorkSpace* pws);

  // ---------------------------------------------------------------------
  // A virtual function that determines if the current plan is
  // compatible with any forced plan constraints and is viable.
  // ---------------------------------------------------------------------
  virtual NABoolean currentPlanIsAcceptable(Lng32 planNo,
            const ReqdPhysicalProperty* const rppForMe) const;

  // ---------------------------------------------------------------------
  // A virtual function for associating one of the Contexts
  // that was created for each child of this operator
  // with the Context for this operator.
  // ---------------------------------------------------------------------
  virtual NABoolean findOptimalSolution(Context* myContext,
                                        PlanWorkSpace* pws);

  // ---------------------------------------------------------------------
  // calculate physical properties from child's phys properties
  // (assuming the children are already optimized and have physical properties)
  // (used in the implementation of createPlan)
  // ---------------------------------------------------------------------
  virtual PhysicalProperty* synthPhysicalProperty(const Context* myContext,
                                                  const Lng32     planNumber,
                                                  PlanWorkSpace  *pws);

  // ---------------------------------------------------------------------
  // A helper method for synthesizing the physical properties for the leaf
  // operators scan, cursor insert, cursor update, and cursor delete.
  // ---------------------------------------------------------------------
  PhysicalProperty* synthDP2PhysicalProperty(
                              const Context*     myContext,
                              const ValueIdList& sortOrder,
                              const IndexDesc*   indexDesc,
                              const SearchKey*   partSearchKey);

  // ---------------------------------------------------------------------
  // create or share an optimization goal for a child group
  // ---------------------------------------------------------------------
  Context* shareContext(Lng32 childIndex,
                        const ReqdPhysicalProperty* const reqdPhys,
                        const InputPhysicalProperty* const inputPhys,
                        CostLimit* costLimit,
                        Context* parentContext,
                        const EstLogPropSharedPtr& inputLogProp,
                        RelExpr *explicitlyRequiredShape = NULL) const;

  // ---------------------------------------------------------------------
  // release a binding that was created by means other than using a
  // BINDING object (e.g. a binding created by Context::bindSolutionTree()
  // ---------------------------------------------------------------------
  void releaseBindingTree(NABoolean memoIsMoribund = FALSE);

  // ---------------------------------------------------------------------
  // A virtual function that decides if ESP parallelism is allowed
  // by the settings in the defaults table, or if the number of
  // ESPs is being forced.
  // ---------------------------------------------------------------------
  virtual DefaultToken getParallelControlSettings (
            const ReqdPhysicalProperty* const rppForMe, /*IN*/
            Lng32& numOfESPs, /*OUT*/
            float& allowedDeviation, /*OUT*/
            NABoolean& numOfESPsForced /*OUT*/) const;

  // ---------------------------------------------------------------------
  // A virtual function that decides if ESP parallelism is worth it
  // for the operator.
  // ---------------------------------------------------------------------
  virtual NABoolean okToAttemptESPParallelism (
            const Context* myContext, /*IN*/
            PlanWorkSpace* pws, /*IN*/
            Lng32& numOfESPs, /*OUT*/
            float& allowedDeviation, /*OUT*/
            NABoolean& numOfESPsForced /*OUT*/) ;

  // ---------------------------------------------------------------------
  // Checks the required physical properties to see if they require
  // something that only an enforcer (i.e. sort or exchange) can provide.
  // This method is called by all implementations of the
  // method topMatch() except the enforcer rule implementations.
  // ---------------------------------------------------------------------
  NABoolean rppRequiresEnforcer
              (const ReqdPhysicalProperty* const rppForMe) const;

  // ---------------------------------------------------------------------
  // Compares the pivs of this node to those of its children.
  // If they are different, they are made the same.
  // ---------------------------------------------------------------------
  virtual void replacePivs();

  // ---------------------------------------------------------------------
  // Performs mapping on the partitioning function, from this
  // operator to the designated child, if the operator has/requires mapping.
  // Note that this default implementation does no mapping.
  // ---------------------------------------------------------------------
  virtual PartitioningFunction* mapPartitioningFunction(
                          const PartitioningFunction* partFunc,
                          NABoolean rewriteForChild0) ;

  virtual void addPartKeyPredsToSelectionPreds(
                          const ValueIdSet& partKeyPreds,
                          const ValueIdSet& pivs)
  {}

  // *********************************************************************
  // Helper functions and methods during the pre code generation phase.
  // *********************************************************************

  // ---------------------------------------------------------------------
  // get... methods for the code generator.
  // ---------------------------------------------------------------------
  void getOutputValuesOfMyChildren(ValueIdSet & vs) const;
  virtual void getInputValuesFromParentAndChildren(ValueIdSet & vs) const;
  void getInputAndPotentialOutputValues(ValueIdSet& vs) const;

  ULng32 getDefault(DefaultConstants);

  // cleanup after the generator phase
  virtual void cleanupAfterCompilation();

  // ---------------------------------------------------------------------
  // This method is used to propagate to all Sort nodes in the query
  // if the top N sorted rows are needed. Called when the user
  // has specified [first <N>] in their select statement. The actual
  // value of <N> is sent to the operator at runtime via a GET_N request.
  // See executor queue structure for details about GET_N request.
  // The value of 'val' is used to set or reset this in the Sort node.
  // ---------------------------------------------------------------------
  virtual void needSortedNRows(NABoolean val);

  // ---------------------------------------------------------------------
  // Methods for retrieving information from the best plan.
  // NOTE: The following set of methods should be used ONLY AFTER
  //       optimization is complete, at which point physical property,
  //       cost, and estimated # rows are transferred from the optimal plan.
  // ---------------------------------------------------------------------

  inline const PhysicalProperty* getPhysicalProperty() const
                                                      { return physProp_; }
  inline void setPhysicalProperty (const PhysicalProperty* physProp)
                                                  { physProp_ = physProp; }

  inline const Cost * getOperatorCost() const
  { return operatorCost_; }

  inline void setOperatorCost (const Cost * cost)
  { operatorCost_ = cost; }

  inline const Cost * getRollUpCost() const
  { return rollUpCost_; }

  inline void setRollUpCost (const Cost * cost)
  { rollUpCost_ = cost; }

  inline const CostScalar getEstRowsUsed() const { return estRowsUsed_; }
  inline void setEstRowsUsed(CostScalar r)          { estRowsUsed_ = r; }

  inline const CostScalar getInputCardinality() const { return inputCardinality_; }
  inline void setInputCardinality(CostScalar r)          { inputCardinality_ = r; }

  inline const CostScalar getMaxCardEst() const { return maxCardEst_; }
  inline void setMaxCardEst(CostScalar r)       { maxCardEst_ = r; }

  static short bmoGrowthPercent(CostScalar e, CostScalar m);
  // ---------------------------------------------------------------------
  // for debugging
  // ---------------------------------------------------------------------

  // add all the expressions that are local to this
  // node to an existing list of expressions
  virtual void addLocalExpr(LIST(ExprNode *) &xlist,
                            LIST(NAString) &llist) const;

  void addExplainPredicates(ExplainTupleMaster * explainTuple,
				       Generator * generator);

  ExplainTuple *addExplainInfo(ComTdb *tdb,
                                         ExplainTuple *leftChild,
                                         ExplainTuple *rightChild,
                                         Generator *generator);

  virtual ExplainTuple *addSpecificExplainInfo(ExplainTupleMaster *explainTuple,
					      ComTdb * tdb,
					      Generator *generator);


  virtual void print(FILE * f = stdout,
                     const char * prefix = "",
                     const char * suffix = "") const;

  virtual void unparse(NAString &result,
                       PhaseEnum phase = DEFAULT_PHASE,
                       UnparseFormatEnum form = USER_FORMAT,
		       TableDesc * tabId = NULL) const;


  // -- Triggers
  // Count the number of nodes in the tree.
  Int32 nodeCount() const;

  // Determine whether a node of the given type exists in the tree.
  NABoolean containsNode(OperatorTypeEnum nodeType);

  // ---------------------------------------------------------------------
  // isBigMemoryOperator() returns TRUE for operators which intend to use
  // an amount of memory per cpu that is greater than the limit. It is
  // used during costing. The context is needed because we need the number of
  // CPU the operator can execute on to estimate its memory needs on each
  // CPU, and we also need the input logical properties to estimate the
  // size of the table the operator is handling. Both of them are stored
  // in the Context object. We also need to know the plan number,
  // since different plans for the same operator may consume different
  // quantities of memory. For example, a Type-2 parallel hash join vs.
  // a Type-1 parallel hash join.
  // ---------------------------------------------------------------------
  virtual NABoolean isBigMemoryOperator(const PlanWorkSpace* pws,
                                        const Lng32 planNumber);

  virtual CostScalar getEstimatedRunTimeMemoryUsage(Generator *generator, NABoolean perNode, Lng32 *numStreams = NULL) {return 0;}
  virtual double getEstimatedRunTimeMemoryUsage(Generator *generator, ComTdb * tdb) {return 0;}

  inline NABoolean isinBlockStmt() const
                          { return isinBlockStmt_; }
  inline NABoolean isinBlockStmt()
                          { return isinBlockStmt_; }
  inline void setBlockStmt(NABoolean cs)
                          { isinBlockStmt_ = cs; }

  // set the isinBlockStmt_ flag to x for the entire tree rooted
  // at this RelExpr.
  void setBlockStmtRecursively(NABoolean x);

  double calculateNoOfLogPlans(Lng32& numOfMergedExprs);

  double calculateSubTreeComplexity(NABoolean& antiSemiJoinQuery);

  // calculate a query's MJ complexity,
  // shoud be called after MJ rewrite
  double calculateQueryMJComplexity(double &n,double &n2,double &n3,double &n4);

  void makeListBySize(LIST(CostScalar) & orderedList,
                        NABoolean  recompute);

  void setFirstNRows(Int64 firstNRows) 		{ firstNRows_ = firstNRows; }
  Int64 getFirstNRows() 			{ return firstNRows_; }

  virtual PlanPriority computeOperatorPriority
    (const Context* context,
     PlanWorkSpace *pws=NULL,
     Lng32 planNumber=0);

  NABoolean oltOpt() { return oltOptInfo_.oltAnyOpt(); };
  NABoolean oltOptLean() { return oltOptInfo_.oltEidLeanOpt(); };

  OltOptInfo &oltOptInfo() { return oltOptInfo_; };

  // get TableDesc from the expression. It could be directly
  // attached to the expression, as in Scan, or could be a
  // part of GroupAnalysis, as in cut-opp. For expressions
  // which do not have a tableDesc attached to them, like Join
  // it would be NULL
  TableDesc* getTableDescForExpr();

  NABoolean treeContainsEspExchange();

///////////////////////////////////////////////////////////

  virtual NABoolean pilotAnalysis(QueryAnalysis* qa);
  virtual void jbbAnalysis(QueryAnalysis* qa);
  virtual void jbbJoinDependencyAnalysis(ValueIdSet & predsWithDependencies);
  virtual void predAnalysis(QueryAnalysis* qa);
  virtual RelExpr* convertToMultiJoinSubtree(QueryAnalysis* qa);
  virtual EstLogPropSharedPtr setJBBInput(EstLogPropSharedPtr & inLP = (*GLOBAL_EMPTY_INPUT_LOGPROP));
  virtual RelExpr* expandMultiJoinSubtree();
  GroupAnalysis* getGroupAnalysis();

///////////////////////////////////////////////////////////

  // do some analysis on the initial plan
  // this is called at the end of the analysis phase
  virtual void analyzeInitialPlan();

  virtual void computeRequiredResources(RequiredResources & reqResources,
                                       EstLogPropSharedPtr & inLP = (*GLOBAL_EMPTY_INPUT_LOGPROP));

  virtual void computeMyRequiredResources(RequiredResources & reqResources,
                                      EstLogPropSharedPtr & inLP);

  // Accessor for the rowsetIterator flag.
  NABoolean isRowsetIterator() const { return rowsetIterator_; }
  // Mutator for the rowsetIterator flag.
  void setRowsetIterator(NABoolean rowsetIterator)
    { rowsetIterator_ = rowsetIterator;  }

   // Accessor for the tolerateNonFatalError flag.
  AtomicityType getTolerateNonFatalError() const { return tolerateNonFatalError_; }
  // Mutator for the tolerateNonFatalError flag.
  void setTolerateNonFatalError(AtomicityType tolerateNonFatalError)
    { tolerateNonFatalError_ = tolerateNonFatalError;  }

  // method used by generator to detrmine if rowsAffected needs to be set in PA.
  // The base class implementaion returns FALSE. FirstN and GenericUpdate are the only
  // classes that return true currently.
  virtual NABoolean computeRowsAffected() const
    {return FALSE;} ;

  inline NABoolean markedForElimination() const
  { return markedForElimination_; }
  inline void setMarkedForElimination(NABoolean b)
  { markedForElimination_ = b; }

  inline NABoolean isExtraHub() const
  { return isExtraHub_; }
  inline void setIsExtraHub(NABoolean b)
  { isExtraHub_ = b; }

  // methods to set, get and update substitute potential
  void setPotential(Int32 potential) { potential_ = potential; };
  Int32 getPotential() const { return potential_;};
  Int32 updatePotential(Int32 potential)
  {
    if ((potential != -1) &&
        (potential_ == -1))
    {
      potential_ = potential;
    }

    return potential_;
  };

  void setExpandShortRows(NABoolean val)
  { (val ? (flags_ |= EXPAND_SHORT_ROWS) : (flags_ &= ~EXPAND_SHORT_ROWS)); }

  NABoolean expandShortRows()
  {  return ((flags_ & EXPAND_SHORT_ROWS) != 0); }

  // For compressed internal format.
  // At codegen some nodes will switch from compressed internal format to
  // the exploded format when they are directly beneath the root node.
  void setParentIsRoot(NABoolean val)
  { (val ? (flags_ |= PARENT_IS_ROOT) : (flags_ &= ~PARENT_IS_ROOT)); }

  NABoolean isParentRoot()
  {  return ((flags_ & PARENT_IS_ROOT) != 0); }

  virtual int getCifBMOWeight()
  {
    return 1;
  }

  NABoolean dopReduced() const { return dopReduced_; };
  void setDopReduced(NABoolean x) { dopReduced_ = x; };

  void adjustTopPartFunc(Lng32 newDop);

protected:

  void synthPropForBindChecks();

private:

  enum Flags {
    EXPAND_SHORT_ROWS  = 0x00000001     // expand short rows when added columns
   ,PARENT_IS_ROOT     = 0x00000002     // compressed internal format
  };

  // every relational expression node has the ability to perform
  // a selection on its result and to project some of its output
  // columns (or expressions on its output columns).

  ItemExpr             * selection_;   // generated by the parser
  ValueIdSet           predicates_;    // predicates represented as a set

  // A descriptor for the table derived from the RelExpr.
  RETDesc              * RETDesc_;

  // During the bind and normalization phase, each relational
  // operator has a private set of Group Attributes. Within
  // Cascades, once the operator is memoized, it shares the
  // Group Attributes for the Cascades Group.
  GroupAttributes      * groupAttr_;

  // Cascades-specific part of a relational expression
  CascadesGroupId        groupId_;     // pointer back to eq. class

  RelExpr              * groupNext_;   // list within group
  RelExpr              * bucketNext_;  // list within hash bucket
  RuleSubset           contextInsensRules_;  // context insensitive rules tried
                                             // on this expression

  RulesPerContextList  contextSensRules_; // context sensitive rules tried
                                          // per context

  // The children of an expression (its operands). Only a fixed number of
  // children can be stored here (could use a virtual operator[] to
  // overcome this, if it ever becomes necessary).
  ExprGroupId          child_[MAX_REL_ARITY];

  // The following fields are applicable only after optimization is complete.
  // After the optimal plan is selected, the following properties are transferred
  // from the CascadesPlan structure to the following placeholders for the
  // purposes of code generation.

  const PhysicalProperty * physProp_;  // physical properties for the optimal plan

  // ---------------------------------------------------------------------
  // The operator cost is the cost for this operator independent
  // of its children.
  // ---------------------------------------------------------------------
  const Cost             * operatorCost_;      // operator cost for the optimal plan

  // ---------------------------------------------------------------------
  // The roll-up cost is the cost of the sub-plan rooted at
  // this operator (operator cost of this operator combined with
  // the operator's children cost)
  // ---------------------------------------------------------------------
  const Cost             * rollUpCost_;      // roll up cost for the optimal plan
  CostScalar              estRowsUsed_; // est. # rows produced from this plan per probe
  CostScalar		  inputCardinality_;  // est. # of probes
                                             // (cardinality of input logical prop.) for this plan
  CostScalar          maxCardEst_; // maximum cardinality estimate

  // Triggers --
  // Information for Triggers, RI and IM.
  InliningInfo inliningInfo_;

  //++MV
  // Used by inlining mechanism for adding optimizer constraints
  ItemExpr *uniqueColumnsTree_;
  ValueIdSet uniqueColumns_;

  CardConstraint *cardConstraint_;

  //--MV

  SubTreeAccessSet *accessSet0_;
  SubTreeAccessSet *accessSet1_;

  // An object counter for debugging purpose only
  static THREAD_P ObjectCounter *counter_;

  NABoolean isinBlockStmt_;  // is this operator inside a compound statement?

  // if set to -1, return all rows.
  // Otherwise, return firstNRows_ at runtime.
  Int64 firstNRows_;

  UInt32 flags_;

  // various olt type optimizations. See OptUtilIncludes.h.
  // Set during preCodeGen phase.
  OltOptInfo oltOptInfo_;

  // Should this node be enabled for counting rowset rownumber counting?
  // Currently only UnPack, TupleFlow and NestedJoin nodes will have this attribute
  // set to TRUE for rowset IUD statements
  NABoolean rowsetIterator_;

  // Should this node continue execution after a Nonfatal error has been seen?
  // Currently only UnPack & Insert & NestedJoin  have this attribute set to NOT_ATOMIC for NOT ATOMIC
  // rowset insert statements. Root, PA & TupleFlow also have a similar flag set
  // in their TDBs during codegen.
  AtomicityType tolerateNonFatalError_;

  // optimizer hint
  Hint *hint_;

  // if TRUE, this join can be eliminated because
  // (a) it is guaranteed to match one and only one row
  // (b) no outputs from the inner child are used beyond this join
  // The marking is done during Join::synthLogProp() and the actual
  // removal during Join::SemanticQueryOptimization()
  NABoolean markedForElimination_ ;

  // if TRUE, this join can be placed at the top of the join chain because
  // (a) it is guaranteed to match one and only one row
  // (therefore does not increase/decrease dataflow)
  // (b) no outputs from the inner child are used beyond this join,
  // excepts as outputs of the root node (part of select list)
  // The marking is done during Join::synthLogProp() and the actual
  // reordering is done during Join::leftLinearizeTree()

  NABoolean isExtraHub_;

  // potential of the substitute
  Int32 potential_;

  // Used to help determine whether hash join 
  // optimizations may be turned on
  // This flag is set to true when an Insert/Update/Delete has been
  // seen
  NABoolean seenIUD_; 

  // the following data members were added solely for the cascades display gui
  // so we can trace each relexpr to its creator and source
  // begin relexpr tracking info
  Lng32  parentTaskId_; // {parentTaskId_,stride_} of the CascadesTask 
  short stride_;       // that created this RelExpr

  CascadesGroupId sourceGroupId_; // GroupId of creator task of this relexpr
  Int32 birthId_; // TaskCount when this relexpr was created

  ULng32 memoExprId_; // MemoExprId of this relexpr
  ULng32 sourceMemoExprId_; // MemoExprId of the source of this relexpr

  double costLimit_; // CostLimit of task's context that created this relexpr
  // end relexpr tracking info

  ExpTupleDesc::TupleDataFormat cachedTupleFormat_;
  NABoolean cachedResizeCIFRecord_;
  NABoolean cachedDefrag_;

  // Record the status whether my dop has been reduced. That is, whether
  // the partfunc pointed by my spp has a dop reduction.
  NABoolean dopReduced_;

  // if we copy an expression with copyTopNode() then
  // remember the original here, e.g. to find VEG regions
  RelExpr *originalExpr_;

  NAString operKey_;

public:

  // begin: accessors & mutators for relexpr tracking info
  Lng32 getParentTaskId() { return parentTaskId_; }
  short getSubTaskId() { return stride_; }
  Int32 getBirthId() { return birthId_; }

  const NAString getCascadesTraceInfoStr();
  void setCascadesTraceInfo(RelExpr *src);
  // end: accessors & mutators for relexpr tracking info
  enum CifUseOptions
  {
    CIF_ON,
    CIF_OFF,
    CIF_SYSTEM
  };


  void cacheTupleFormatAndResizeFlag(ExpTupleDesc::TupleDataFormat tf, NABoolean r, NABoolean d)
  {
    cachedTupleFormat_ = tf;
    cachedResizeCIFRecord_ = r;
    cachedDefrag_ = d;
  }

  ExpTupleDesc::TupleDataFormat getCachedTupleFormat()
  {
    return cachedTupleFormat_;
  }

  NABoolean getCachedResizeCIFRecord()
  {
    return cachedResizeCIFRecord_;
  }

  NABoolean getCachedDefrag()
  {
    return cachedDefrag_;
  }

  CostScalar getChild0Cardinality(const Context*);

  NAString *getKey();
}; // class RelExpr

// -----------------------------------------------------------------------
// List of RelExprs.
// -----------------------------------------------------------------------
class RelExprList : public LIST (RelExpr *)
{
  public:

  RelExprList(CollHeap* h) : LIST (RelExpr *)(h) {}

  // copy ctor
  RelExprList (const RelExprList & rlist, CollHeap * h=0) :
    LIST (RelExpr *)(rlist, h) {}

  // ---------------------------------------------------------------------
  // Insert RelExpr into list order by estimated rowcount (of the logical
  // properties).
  // ---------------------------------------------------------------------
  void insertOrderByRowcount (RelExpr * expr);

  NABoolean operator== (const RelExprList &other) const;
  NABoolean operator!= (const RelExprList &other) const;

}; // RelExprList

// -----------------------------------------------------------------------
// Leaf Operator (for use in rule patterns and substitutes only).
// A leaf operator in a pattern matches any logical expression. When
// firing the rule, the binding presented to the rule contains the
// leaf operator as its leaf.
// -----------------------------------------------------------------------
class CutOp : public RelExpr
{

public:

  CutOp (Int32 index,
                CollHeap *oHeap = CmpCommon::statementHeap()) :
    RelExpr(REL_CUT_OP, NULL, NULL, oHeap)
  { index_ = index; expr_ = NULL; }

  virtual ~CutOp();

  virtual void print(FILE * f = stdout,
                     const char * prefix = "",
                     const char * suffix = "") const;
  virtual Int32 getArity () const;
  virtual NABoolean isCutOp () const;
  virtual RelExpr * copyTopNode(RelExpr *,
                                CollHeap* outHeap = 0);
  inline Int32 getIndex()                                 { return index_; }
  void setGroupIdAndAttr(CascadesGroupId groupId);
  inline RelExpr * getExpr() const                       { return expr_; }
  void setExpr(RelExpr *e);

  virtual void synthLogProp(NormWA * normWAPtr = NULL);

  virtual const NAString getText() const;

private:

  Int32 index_;           // in rules, used to distinguish multiple children
  RelExpr *expr_;       // only for bindings fixed to a particular expression

}; // CutOp

// -----------------------------------------------------------------------
// Tree operator (for use in rule patterns and substitutes only).
// A tree operator in a pattern matches any logical expression. When
// firing the rule, the binding is materialized beyond the tree operator
// all the way down to leaf nodes. Depending on whether the "all"
// data member is set to TRUE, all possible bindings for the tree node are
// or just one (randomly selected) binding is presented to the rule.
// Rules using a tree node must redefine their nextSubstitute() method
// since the generic method can not handle tree nodes.
// -----------------------------------------------------------------------
class SubtreeOp : public RelExpr
{

public:

  inline SubtreeOp (NABoolean all) : RelExpr(REL_TREE_OP) {all_ = all;}
  virtual ~SubtreeOp();
  virtual Int32 getArity() const;
  virtual NABoolean isSubtreeOp() const;
  virtual const NAString getText() const;
  virtual RelExpr * copyTopNode(RelExpr *,
                                CollHeap* outHeap = 0);
  inline NABoolean all_bindings() const { return all_; }

private:

  NABoolean       all_;            // find all bindings?

}; // SubtreeOp

// -----------------------------------------------------------------------
// A wildcard node can appear in rule patterns and rule substitutes.
// When used in a substitute, the designator of a wildcard must match
// a designator in the pattern. The wildcard is then replaced with
// the child node that matched the corresponding wildcard in the pattern.
// -----------------------------------------------------------------------
class WildCardOp: public RelExpr
{

public:

  WildCardOp(OperatorType otype,
                    Int32 designator = 0,
                    RelExpr  *child0 = NULL,
                    RelExpr  *child1 = NULL,
                    CollHeap *outHeap = CmpCommon::statementHeap())
    : RelExpr(otype,child0,child1,outHeap)
  { designator_ = designator; corrNode_ = NULL; }

  virtual ~WildCardOp();

  virtual Int32 getArity() const;

  inline Int32 getDesignator()                       { return designator_; }
  virtual NABoolean isWildcard() const;
  virtual RelExpr * copyTopNode(RelExpr *derivedNode = NULL,
                                CollHeap* outHeap = 0);

  inline void setCorrespondingNode(RelExpr *corr)    { corrNode_ = corr; }
  inline RelExpr * getCorrespondingNode()            { return corrNode_; }

  virtual const NAString getText() const;

private:

  Int32      designator_;
  RelExpr  *corrNode_;

}; // WildCardOp

// -----------------------------------------------------------------------
// A special form of a wildcard op, used to force scans on specific
// tables and indexes
// -----------------------------------------------------------------------

class ScanForceWildCard : public WildCardOp
{
  // to be used with operator type REL_FORCE_ANY_SCAN

public:

  enum scanOptionEnum
    {
      UNDEFINED,
      INDEX_SYSTEM,
      MDAM_SYSTEM,
      MDAM_FORCED,
      MDAM_OFF,
      MDAM_COLUMNS_REST_BY_SYSTEM,
      MDAM_COLUMNS_NO_MORE,
      MDAM_COLUMNS_ALL,
      COLUMN_SYSTEM,
      COLUMN_SPARSE,
      COLUMN_DENSE,
      DIRECTION_SYSTEM,
      DIRECTION_FORWARD,
      DIRECTION_REVERSED
    };

  // either use any scan on the table with a given exposed name
  // or only use an index scan on the specified index
  ScanForceWildCard(CollHeap *outHeap = CmpCommon::statementHeap());
  ScanForceWildCard(const NAString& exposedName,
                    CollHeap *outHeap = CmpCommon::statementHeap());
  ScanForceWildCard(const NAString& exposedName,
                    const NAString& indexName,
                    CollHeap *outHeap = CmpCommon::statementHeap());

  virtual ~ScanForceWildCard();

  virtual void initializeScanOptions();
  virtual const NAString getText() const;
  virtual RelExpr * copyTopNode(RelExpr *derivedNode = NULL,
                                CollHeap* outHeap = 0);

  virtual NABoolean setScanOptions(ScanForceWildCard::scanOptionEnum option);
  virtual NABoolean setIndexName(const NAString& value);
  virtual NABoolean setColumnOptions(CollIndex numColumns,
                                     ScanForceWildCard::scanOptionEnum* columnAlgos,
                                     ScanForceWildCard::scanOptionEnum mdamColumnsStatus);
  virtual NABoolean setColumnOptions(CollIndex numColumns,
                                     ScanForceWildCard::scanOptionEnum mdamColumnsStatus);
  virtual NABoolean mergeScanOptions(const ScanForceWildCard& other);
  virtual void prepare();

  virtual NABoolean doesThisCoflictMasterSwitch() const;
  inline const NAString& getExposedName() const    { return exposedName_; }
  inline const NAString& getIndexName() const      { return indexName_; }
  inline CollIndex getNumMdamColumns() const       { return numMdamColumns_;}
  inline scanOptionEnum getIndexStatus() const     { return indexStatus_;}
  inline scanOptionEnum getDirection() const       { return direction_;}
  inline scanOptionEnum getMdamStatus() const      { return mdamStatus_;}
  inline scanOptionEnum getMdamColumnsStatus() const
    { return mdamColumnsStatus_;}
  scanOptionEnum getEnumAlgorithmForColumn(CollIndex column) const;

  void setNumberOfBlocksToReadPerAccess(const Lng32& blocks)
  {
    DCMPASSERT(blocks > -1);
    numberOfBlocksToReadPerAccess_ = blocks;
  }

  // If this returns -1 it indicates that we are not forcing blocks per access...
  Lng32 getNumberOfBlocksToReadPerAccess() const
  {
    return numberOfBlocksToReadPerAccess_;
  }

  // helper function on CQS Tree
  virtual RelExpr *generateMatchingExpr(CANodeIdSet &,
                                       CANodeIdSet &,
                                       RelExpr *);
private:

  NAString exposedName_;
  NAString indexName_;
  scanOptionEnum indexStatus_;  // UNDEFINED or INDEX_SYSTEM
  scanOptionEnum mdamStatus_;   // MDAM_OFF, _FORCED, _SYSTEM, or UNDEFINED
  scanOptionEnum direction_;    // .._FORWARD, _REVERSE, _SYSTEM, or UNDEFINED
  scanOptionEnum mdamColumnsStatus_; // .._REST_BY_SYSTEM, _NO_MORE, _ALL
  CollIndex numMdamColumns_;
  scanOptionEnum* enumAlgorithms_;   // array of enumeration algorithms
                                     // for each column
  // To force the FileScan member of the same name
  Lng32 numberOfBlocksToReadPerAccess_;

};

// -----------------------------------------------------------------------
// A special form of a wildcard op, used to force joins and parallel join
// plan2 (any plan, plan1 or plan2, number of ESPs used)
// -----------------------------------------------------------------------

class JoinForceWildCard : public WildCardOp
{
  // to be used with operator types REL_FORCE_JOIN, REL_FORCE_NESTED_JOIN,
  // REL_FORCE_MERGE_JOIN, REL_FORCE_HASH_JOIN

public:

  enum forcedPlanEnum { ANY_PLAN,         // don't care which plan
                        FORCED_PLAN0,     // plan # 0
                        FORCED_PLAN1,     // plan # 1
                        FORCED_PLAN2,     // plan # 2
                        FORCED_PLAN3,     // plan # 3
                        FORCED_TYPE1,     // join matching partitions
                        FORCED_TYPE2,
                        FORCED_INDEXJOIN };   // replicate one child

  // either use any scan on the table with a given exposed name
  // or only use an index scan on the specified index
  JoinForceWildCard(OperatorTypeEnum type,
                    RelExpr *child0,
                    RelExpr *child1,
                    forcedPlanEnum plan = ANY_PLAN,
                    Int32 numOfEsps = 0,
                    CollHeap *outHeap = CmpCommon::statementHeap());

  virtual ~JoinForceWildCard();

  virtual RelExpr * copyTopNode(RelExpr *derivedNode = NULL,
                                CollHeap* outHeap = 0);

  inline forcedPlanEnum getPlan() const                  { return plan_; }
  inline Int32 getNumOfEsps() const                   { return numOfEsps_; }

  virtual const NAString getText() const;

  // helper function on CQS Tree
  virtual RelExpr *generateMatchingExpr(CANodeIdSet &,
                                       CANodeIdSet &,
                                       RelExpr *);

private:

  forcedPlanEnum plan_; // ANY_PLAN means don't force the plan type
  Int32 numOfEsps_;       // 0 means don't force number of ESPs

};

// -----------------------------------------------------------------------
// A special form of a wildcard op, used to force specific Exchange
// nodes (3 forms are distinguished, ESP exchange, PA node and PAPA node).
// -----------------------------------------------------------------------

class ExchangeForceWildCard : public WildCardOp
{
  // to be used with operator type REL_FORCE_EXCHANGE

public:

  enum forcedExchEnum
  {
    ANY_EXCH,              // don't care which exchange
    FORCED_PA,             // single PA node
    FORCED_PAPA,           // PAPA on top of PA node
    FORCED_ESP_EXCHANGE    // split/send nodes with ESPs
  };

  enum forcedLogPartEnum
  {
    ANY_LOGPART,           // don't care which form of logical partitioning
    FORCED_GROUP,          // PA partition grouping
    FORCED_SPLIT,          // subpartitioning or partition slicing
    FORCED_REPART          // PA grouped repartitioning
  };

  // either use any scan on the table with a given exposed name
  // or only use an index scan on the specified index
  ExchangeForceWildCard(RelExpr *child0,
                        forcedExchEnum which = ANY_EXCH,
                        forcedLogPartEnum whatLogPart = ANY_LOGPART,
                        Lng32 numBottomEsps = -1,
                        CollHeap *outHeap = CmpCommon::statementHeap());

  virtual ~ExchangeForceWildCard();

  virtual RelExpr * copyTopNode(RelExpr *derivedNode = NULL,
                                CollHeap* outHeap = 0);

  inline forcedExchEnum getWhich() const                { return which_; }
  inline forcedLogPartEnum getWhichLogPart() const { return whatLogPart_;}
  inline Lng32 getHowMany() const                      { return howMany_; }

  virtual const NAString getText() const;

  // helper function on CQS Tree
  virtual RelExpr *generateMatchingExpr(CANodeIdSet &,
                                       CANodeIdSet &,
                                       RelExpr *);

private:

  forcedExchEnum    which_;       // which of the flavors of Exchange we want

  forcedLogPartEnum whatLogPart_; // which flavor of logical partitioning

  Lng32              howMany_;     // how many exchanges on the bottom

}; // ExchangeForceWildCard

// -----------------------------------------------------------------------
// A special form of a wildcard op, used to force the use of UDFs via CQS.
// -----------------------------------------------------------------------

class UDFForceWildCard : public WildCardOp
{
  // to be used with operator type REL_FORCE_ANY_SCLAR_UDF.
public:

  // Constructor used when parsing ISOLATED_SCALAR_UDF in controlDB.cpp.
  // op used is REL_FORCE_ANY_SCALAR_UDF.
  UDFForceWildCard(OperatorTypeEnum op, 
                   CollHeap *outHeap = CmpCommon::statementHeap());
  // Instantiated when parsing 'SCALAR_UDF' or 'UDF_ACTION' followed by name.
  // Uses 'FORCE_ANY_SCALAR_UDF' as operator.
  UDFForceWildCard(const NAString& functionName,
                   const NAString& actionName,
                   CollHeap *outHeap = CmpCommon::statementHeap());

  virtual ~UDFForceWildCard();

  virtual const NAString getText() const;
  virtual RelExpr * copyTopNode(RelExpr *derivedNode = NULL,
                                CollHeap* outHeap = 0);

  virtual NABoolean mergeUDFOptions(const UDFForceWildCard& other);

  inline const NAString& getFunctionName() const { return functionName_; }
  inline const NAString& getActionName() const   { return actionName_;   }

  // helper function on CQS Tree - this is never called.  Not implemented
  //virtual RelExpr *generateMatchingExpr(CANodeIdSet &,
  //                                      CANodeIdSet &,
  //                                      RelExpr *);
private:

  NAString functionName_;
  NAString actionName_;
}; // UDFForceWildCard


class RequiredResources : public NABasicObject {
public:
  RequiredResources() : memoryResources_(0),
                        cpuResources_(0),
                        dataAccessCost_(0),
                        maxOperMemReq_(0),
                        maxOperCPUReq_(0),
                        maxOperDataAccessCost_(0),
                        maxMaxCardinality_(0){};
  void accumulate(CostScalar memRsrcs, CostScalar cpuRsrcs, CostScalar dataAccessCost, CostScalar maxCard = csZero);
  CostScalar getMemoryResources(){ return memoryResources_; };
  CostScalar getCpuResources(){ return cpuResources_; };
  CostScalar getDataAccessCost() { return dataAccessCost_;}
  CostScalar getMaxOperMemoryResources(){ return maxOperMemReq_; };
  CostScalar getMaxOperCpuReq(){ return maxOperCPUReq_; };
  CostScalar getMaxOperDataAccessCost() { return maxOperDataAccessCost_;}
  CostScalar getMaxMaxCardinality() { return maxMaxCardinality_;}

  void setMemoryResources(CostScalar memRes) { memoryResources_ = memRes; };
  void setCpuResources(CostScalar cpuRes) { cpuResources_ = cpuRes; };
  void setDataAccessCost(CostScalar dataAccessCost) { dataAccessCost_ = dataAccessCost; };

private:
  CostScalar memoryResources_;
  CostScalar cpuResources_;
  CostScalar dataAccessCost_;
  CostScalar maxOperMemReq_;
  CostScalar maxOperCPUReq_;
  CostScalar maxOperDataAccessCost_;
  CostScalar maxMaxCardinality_;
}; // RequiredResources

// *********************************************************************
// The following five enumerated types are specific to plan generation.
// They are housed in this file so that many derived classes of
// RelExpr can use them. Another alternative is to create a separate
// ".h" file for them.
// *********************************************************************

// ---------------------------------------------------------------------
// Location where a plan or a plan fragment should be executed.
//
// EXECUTE_IN_MASTER_AND_ESP
//   Can execute in the master and also can execute in an ESP
// EXECUTE_IN_MASTER_OR_ESP
//   Used for requirements only: require EXECUTE_IN_MASTER_AND_ESP
//   or EXECUTE_IN_MASTER or EXECUTE_IN_ESP
// EXECUTE_IN_MASTER
//   Execute ONLY in the root exector server process that is at
//   thr root of the tree of processes.
// EXECUTE_IN_ESP
//   Execute in an executor server process (ESP) only
// EXECUTE_IN_DP2
//   Execute in a disk server process.
// ---------------------------------------------------------------------
enum PlanExecutionEnum
  {
     EXECUTE_IN_MASTER_AND_ESP,
     EXECUTE_IN_MASTER_OR_ESP,
     EXECUTE_IN_MASTER,
     EXECUTE_IN_ESP,
     EXECUTE_IN_DP2
  };

// ---------------------------------------------------------------------
// Source for the data.
// 1) A persistent table.
// 2) An SQL  temporary table.
// 3) A table that is materialized transiently at the optimizer's behest.
// 4) A virtual table, that is, a table-values stored procedure.
// 5) A tuple provided by the user.
// 6) An ESP where the different data streams are dependent on each
//    other in the sense that if one were to read only from some of
//    them and not from others one could run into a deadlock
//    (this is true for repartitioned data)
// 7) An ESP where the individual data streams can be read independently
//    from each other without causing a deadlock
// ---------------------------------------------------------------------
enum DataSourceEnum
  {
    SOURCE_PERSISTENT_TABLE,
    SOURCE_TEMPORARY_TABLE,
    SOURCE_TRANSIENT_TABLE,
    SOURCE_VIRTUAL_TABLE,
    SOURCE_TUPLE,
    SOURCE_ESP_DEPENDENT,
    SOURCE_ESP_INDEPENDENT
  };

// ---------------------------------------------------------------------
// The next enum is used for both synthesized and required sort
// order types. Only the first four are valid as a synthesized
// sort order type. The meaning of each literal is slightly
// different depending on whether it is being used as a requirement
// or a synthesized value.
// ---------------------------------------------------------------------
// Synthesized Sort Order Type (SOT)
//
// NO_SOT
//   The spp contains no sort order, or we are in DP2 and the
//   sort order type is irrelevant.
// ESP_NO_SORT_SOT
//   The sort order in the spp was generated naturally via a disk
//   process access path. If necessary, a merge of sorted streams
//   or synchronous access will be done to maintain the order.
// ESP_VIA_SORT_SOT
//   The sort order in the spp was generated by a sort operator.
//   If necessary, a merge of sorted streams will be done to
//   maintain the order.
// DP2_SOT
//   The sort order in the spp is only valid in DP2. Synchronous
//   access or a merge of sorted streams will not be done. The
//   sort order is only usable by another operator if it is also
//   in DP2 and the physical partitioning function of it's access
//   path matches exactly the physical partitioning function in
//   this operator's spp.
// ---------------------------------------------------------------------
// ---------------------------------------------------------------------
// Sort Order Type (SOT) Requirement
//
// NO_SOT
//   There is no required sort order or arrangement in the rpp, or we
//   are in DP2 and the sort order type is irrelevant.
// ESP_NO_SORT_SOT
//   A complete executor process order is required, and the child is
//   is not allowed to sort to satisfy the requirement.
// ESP_VIA_SORT_SOT
//   A complete executor process order is required, and the child must
//   utilize sort to satisfy the requirement.
// DP2_SOT
//   The required sort order or arrangement must only be valid in
//   DP2. A complete executor process order is not necessary and does
//   NOT satisfy the requirement. This means a merge of sorted
//   streams or synchronous access cannot be done.
// ESP_SOT
//   A complete executor process order is required. This can be
//   achieved naturally or via a sort.
// DP2_OR_ESP_NO_SORT_SOT
//   A synthesized sort order type of ESP_NO_SORT or DP2 satisfies
//   this sort order type requirement.
// INCOMPATIBLE_SOT
//   Used to signify that two required sort order types are not
//   compatible with each other.
// ---------------------------------------------------------------------
enum SortOrderTypeEnum
{
  NO_SOT,
  ESP_NO_SORT_SOT,
  ESP_VIA_SORT_SOT,
  DP2_SOT,
  ESP_SOT,
  DP2_OR_ESP_NO_SORT_SOT,
  INCOMPATIBLE_SOT
};

// -----------------------------------------------------------------------
// Inlines that couldn't be defined till now due to dependencies
// -----------------------------------------------------------------------
inline RelExpr * ExprGroupId::getPtr() const
{
  // part of fix to genesis case: 10-981030-4975
  if (node_) node_->checkInvalidObject(this);
  // else plan is not valid
  return node_;
}

inline RelExpr * ExprGroupId::operator ->() const       { return getPtr(); }
inline ExprGroupId::operator RelExpr *() const          { return getPtr(); }

#endif /* RELEXPR_H */
