text:
/* -*-C++-*-
******************************************************************************
*
* File:         ValueDesc.C
* Description:  Value Descriptor
*
* Created:      11/16/1994
* Language:     C++
*
*
******************************************************************************
*/

#define   SQLPARSERGLOBALS_FLAGS	// must precede all #include's
#define   SQLPARSERGLOBALS_NADEFAULTS

#include "ValueDesc.h"
#include "Sqlcomp.h"
#include "BindWA.h"
#include "NormWA.h"
#include "GroupAttr.h"
#include "AllItemExpr.h"
#include "RelJoin.h"
#include "CmpStatement.h"
#include "Generator.h"
#include "GenExpGenerator.h"
#include "ExpCriDesc.h"
#include "ExpAtp.h"
#include "exp_dp2_expr.h"
#include "exp_clause_derived.h"
#include "SQLCLIdev.h"
#include "GroupAttr.h"
#include "BindWA.h"
#include "ItemOther.h"
#include "ComDefs.h"
#include "OptimizerSimulator.h"
//////////////////////////////
#include "Analyzer.h"
//////////////////////////////
//
#include "NATable.h"
#include "EncodedKeyValue.h"

#include "SqlParserGlobals.h"		// must be last #include

#define TEXT_DISPLAY_LENGTH 1001

// ***********************************************************************
// A function having an external linkage to allow display() to
// be called on a tree object. This is a workaround for bugs/missing
// functionality in ObjectCenter that cause display() to become
// an undefined symbol.
// ***********************************************************************

void displayMap(const ValueIdMap & map)
{
  map.getTopValues().display();
  map.getBottomValues().display();
}

void displaySet(const ValueIdSet & vs)
{
  vs.display();
}

void displayList(const ValueIdList & vl)
{
  vl.display();
}

void DisplayVid(CollIndex id)		// useful when debugging in MSDEV on NT
{
  ValueId vid(id);
  NAString unp(CmpCommon::statementHeap());
  vid.getItemExpr()->unparse(unp);
  cerr << "[" << id << "]" << unp << endl;
}

// ***********************************************************************
// Methods for class ValueId
// ***********************************************************************

ValueId::ValueId(ValueDesc *vdesc)
{
  ActiveSchemaDB()->insertValueDesc(vdesc);
  id_ = vdesc->getValueId();
}

ValueDesc* ValueId::getValueDesc() const
{
  ValueDesc *vdesc = (ActiveSchemaDB()->getValueDescArray())[id_];
  // The if() is for easier debugging, to break on the assertion.
  if (vdesc == NULL)
    CMPASSERT(vdesc);
  return vdesc;
}

ItemExpr* ValueId::getItemExpr() const
{
  return getValueDesc()->getItemExpr();
}

void ValueId::replaceItemExpr(ItemExpr * iePtr)
{
  iePtr->setValueId(id_);
  getValueDesc()->replaceItemExpr(iePtr);
}

const NAType& ValueId::getType() const
{
  return getValueDesc()->getDomainDesc()->getType();
}

// return TRUE iff i'm a string literal with unknown char set
NABoolean ValueId::inferableCharType()
{
  if (getType().getTypeQualifier() != NA_CHARACTER_TYPE ||
      getItemExpr()->getOperatorType() != ITM_CONSTANT) {
    return FALSE;
  }
  else {
    return ((CharType*)(&getType()))->getCharSet() == CharInfo::UnknownCharSet;
  }
}

// return TRUE iff i'm a char type with known char set
NABoolean ValueId::hasKnownCharSet(const CharType **ctp)
{
  if (getType().getTypeQualifier() != NA_CHARACTER_TYPE) {
    return FALSE;
  }
  else {
    *ctp = (const CharType*)(&getType());
    return ((CharType*)(&getType()))->getCharSet() != CharInfo::UnknownCharSet;
  }
}

void ValueId::changeType(const NAType *type)
{
  getValueDesc()->getDomainDesc()->changeType(type);
}

// ----------------------------------------------------------------------
// returns TRUE if the valueId is a veg_ref referring columns from more
// than one tables
// ----------------------------------------------------------------------

NABoolean ValueId::isInvolvedInJoinAndConst() const
{

  ValueIdSet tempSet(*this);

  if (!tempSet.referencesAConstExpr())
    return FALSE;

  ValueIdSet columns;

  getItemExpr()->findAll( ITM_BASECOLUMN, columns, TRUE, TRUE );

  // Now get all the base tables in this VEG_reference

  // see if this column is being joined to a column of another table
  SET(TableDesc *) * tablesJoined = columns.getAllTables();
  if (tablesJoined->entries() > 1)
    return TRUE;
  else
    return FALSE;
}

////////////////////////////////////////////
ColAnalysis* ValueId::colAnalysis() const
{
  ItemExpr *ie = getItemExpr();
  switch (ie->getOperatorType())
  {
    case ITM_BASECOLUMN:
      return QueryAnalysis::Instance()->getColAnalysis(id_);
    case ITM_INDEXCOLUMN:
      return QueryAnalysis::Instance()->getColAnalysis(((IndexColumn *)ie)->getDefinition());
    default:
      return NULL;
//    if (okIfNotColumn)
//      return NULL;
//    CMPASSERT("ColAnalysis call by non column");
  }
//  return NULL;
}

ColAnalysis*
ValueId::baseColAnalysis(NABoolean *isaConstant, ValueId &vid) const
{
  vid = getBaseColumn(isaConstant);
  if (isaConstant AND *isaConstant)
    return NULL;
  else
    return vid.colAnalysis();
}

// should be inlined
PredAnalysis* ValueId::predAnalysis() const
{
  return QueryAnalysis::Instance()->getPredAnalysis(id_);
}
////////////////////////////////////////////

void ValueId::coerceType(enum NABuiltInTypeEnum desiredQualifier,
                         enum CharInfo::CharSet charSet)
{
  //
  // If the ValueId has already been typed or the desired type is unknown,
  // do nothing.
  //
  const NAType& originalType = getType();
  if (originalType.getTypeQualifier() != NA_UNKNOWN_TYPE ||
      desiredQualifier == NA_UNKNOWN_TYPE)
    return;
  // If charset is unknown then take the default charset
  if(charSet==CharInfo::UnknownCharSet)
    charSet = CharInfo::DefaultCharSet;
  //
  // Create the desired type, retaining the original null attribute,
  // with any UPSHIFT set to FALSE.
  //
  NAType *desiredType = NULL;
  switch (desiredQualifier) {
  case NA_BOOLEAN_TYPE:
    desiredType = new STMTHEAP SQLBoolean();
    break;
  case NA_CHARACTER_TYPE:
    {
#pragma warning (disable : 4244)  // warning elimination
#pragma nowarn(1506)   // warning elimination
      Lng32 len = CmpCommon::getDefaultNumeric(VARCHAR_PARAM_DEFAULT_SIZE);
#pragma warn(1506)  // warning elimination
#pragma warning (default : 4244)  // warning elimination

      desiredType = new STMTHEAP
	SQLVarChar(len, //DEFAULT_CHARACTER_LENGTH,
		   originalType.supportsSQLnull(),
		   FALSE/*isUpShifted*/,
		   FALSE/*isCaseinsensitive*/,
		   charSet,
		   CharInfo::DefaultCollation,
		   CharInfo::COERCIBLE);
    }
    break;
  case NA_NUMERIC_TYPE:
    {
      Int16 DisAmbiguate = 0;
      desiredType = new STMTHEAP
      SQLNumeric(TRUE,   		// signed
                 MAX_NUMERIC_PRECISION,	// precision
                 6,    			// scale
                 DisAmbiguate, // added for 64bit proj.
                 originalType.supportsSQLnull());
    }
    break;
  default:
    ABORT("Internal error in ValueId::coerceType()");
  }

  // Propagate (pushDowntype()) this type to the children of this valueid
  // in case one of the children could not be typed.
  //
  const NAType *newType = getItemExpr()->pushDownType(*desiredType);
  changeType(newType);
}

void ValueId::coerceType(const NAType& desiredType,
                         enum NABuiltInTypeEnum defaultQualifier)
{
  //
  // If the ValueId has already been typed, do nothing.
  //
  const NAType& originalType = getType();
  NABoolean NotaCharType = TRUE;

  NAType *newType = NULL;

  // If the original is of CHARACTER type and the charset field is
  // known, return.
  if ( originalType.getTypeQualifier() == NA_CHARACTER_TYPE )
  {
     if ( ((CharType&)originalType).getCharSet() == CharInfo::ISO88591 &&
          desiredType.getTypeQualifier() == NA_CHARACTER_TYPE &&
          ((CharType&)originalType).getEncodingCharSet() != ((CharType&)desiredType).getEncodingCharSet()) {
         NotaCharType = FALSE;
         newType = originalType.newCopy(STMTHEAP);
         ((CharType*)newType) -> setEncodingCharSet(((CharType&)desiredType).getEncodingCharSet()); // for now ...
         if ( getItemExpr()->getOperatorType() == ITM_CONSTANT ) {
            ((ConstValue*)getItemExpr())->setRebindNeeded(TRUE);
         }
     } else
     // experimenting code end
     if ( ((CharType&)originalType).getCharSet() != CharInfo::UnknownCharSet ) {
       return;
     } else {
         NotaCharType = FALSE;
         if ( getItemExpr()->getOperatorType() == ITM_CONSTANT ) {
            ((ConstValue*)getItemExpr())->setRebindNeeded(TRUE);
         }
     }

     // CharSet is unknown but the desired type is not CHARACTER, assume the
     // charset is ISo88591
     if ( desiredType.getTypeQualifier() != NA_CHARACTER_TYPE ) {
       newType = originalType.newCopy(STMTHEAP);
       ((CharType*)newType) -> setCharSet(CharInfo::ISO88591);
     }

  } else {
     if ( originalType.getTypeQualifier() != NA_UNKNOWN_TYPE )
       return;

     //
     // If the desired type is unknown, set the ValueId's type according to the
     // default qualifier.
     //
     if (desiredType.getTypeQualifier() == NA_UNKNOWN_TYPE) {
        coerceType(defaultQualifier);
        return;
     }
  }

  // Copy the desired type, retaining the original null attribute,
  // but dropping any UPSHIFT attribute.
  //
  if (NotaCharType &&          // We do not want to force a characters storage values to be float
     (desiredType.getFSDatatype() == REC_FLOAT32 ||
      desiredType.getFSDatatype() == REC_FLOAT64 ))
    {
      if (desiredType.getFSDatatype() == REC_FLOAT32)
        newType = new STMTHEAP
          SQLReal(desiredType.supportsSQLnull(),
                  STMTHEAP,
                  desiredType.getPrecision());
      else
        // ieee double, tandem real and tandem double are all
        // cast as IEEE double. Tandem real is cast as ieee double as
        // it won't 'fit' into ieee real.
        newType = new STMTHEAP
          SQLDoublePrecision(desiredType.supportsSQLnull(),
                             STMTHEAP,
                             desiredType.getPrecision());
    }
  else {
     if ( newType == NULL )
       {
         // if param default is OFF, type tinyint as smallint.
         // This is needed until all callers/drivers have full support to
         // handle IO of tinyint datatypes.
	 if ((desiredType.getTypeName() == LiteralTinyInt) &&
             ((CmpCommon::getDefault(TRAF_TINYINT_SUPPORT) == DF_OFF) ||
              (CmpCommon::getDefault(TRAF_TINYINT_INPUT_PARAMS) == DF_OFF)))
	   {
             NABoolean isSigned = ((NumericType&)desiredType).isSigned();
             newType = new (STMTHEAP)
               SQLSmall(isSigned, desiredType.supportsSQLnull());
	   } // TinyInt
	 else if ((desiredType.getFSDatatype() == REC_BIN64_UNSIGNED) &&
                  (CmpCommon::getDefault(TRAF_LARGEINT_UNSIGNED_IO) == DF_OFF))
           {
             NumericType &nTyp = (NumericType &)desiredType;
             if (CmpCommon::getDefault(BIGNUM_IO) == DF_OFF)
               {
		 Int16 DisAmbiguate = 0;
                 newType = new (STMTHEAP)
                   SQLLargeInt(nTyp.getScale(),
                               DisAmbiguate,
                               TRUE,
                               nTyp.supportsSQLnull(),
                               NULL);
               }
             else
               {
                 newType = new (STMTHEAP)
                   SQLBigNum(MAX_HARDWARE_SUPPORTED_UNSIGNED_NUMERIC_PRECISION,
                             nTyp.getScale(),
                             FALSE,
                             FALSE,
                             nTyp.supportsSQLnull(),
                             NULL);
               }
           }
	 else if (DFS2REC::isBigNum(desiredType.getFSDatatype()))
	   {
	     // If bignum IO is not enabled or
	     // if max numeric precision allowed is what is supported in
	     // hardware, do what was previously being done: generate
	     // equivalent SQLNumeric class.
	     // Can't do this inside of closestEquivalentExternalType method
	     // since CmpCommon::getDefault method is not accessible from it.

	     NABoolean bignumIO = FALSE;
	     if (CmpCommon::getDefault(BIGNUM_IO) == DF_ON)
	       bignumIO = TRUE; // explicitely set to ON
	     else if (CmpCommon::getDefault(BIGNUM_IO) == DF_OFF)
	       bignumIO = FALSE; // explicitely set to OFF
	     else if (CmpCommon::getDefault(BIGNUM_IO) == DF_SYSTEM)
	       {
		 if (((SQLBigNum&)desiredType).isARealBigNum())
		   bignumIO = TRUE;
	       }
	     if (CmpCommon::getDefaultNumeric(MAX_NUMERIC_PRECISION_ALLOWED) ==
		   MAX_HARDWARE_SUPPORTED_SIGNED_NUMERIC_PRECISION)
	       bignumIO = FALSE;

	     if (bignumIO)
	       {
		 Lng32 precision =
		   MINOF(desiredType.getPrecision(), (Lng32)
			 CmpCommon::getDefaultNumeric(MAX_NUMERIC_PRECISION_ALLOWED));
		 Lng32 scale     = MINOF(desiredType.getScale(), precision);
		 newType = new (STMTHEAP)
		   SQLBigNum(precision, scale,
			     ((SQLBigNum&)desiredType).isARealBigNum(),
			     ((NumericType&)desiredType).isSigned(),
			     desiredType.supportsSQLnull(),
			     NULL);
	       }
	     else
	       {
		 Lng32 precision = MINOF(desiredType.getPrecision(), MAX_NUMERIC_PRECISION);
		 Lng32 scale     = MINOF(desiredType.getScale(), precision);
		 NABoolean isSigned = ((NumericType&)desiredType).isSigned();
		 if ((precision > MAX_HARDWARE_SUPPORTED_UNSIGNED_NUMERIC_PRECISION) &&
		     (precision <= MAX_NUMERIC_PRECISION))
		   isSigned = TRUE;

		 Int16 DisAmbiguate = 0;
		 newType = new (STMTHEAP)
		   SQLNumeric(isSigned,
			      precision,
			      scale,
			      DisAmbiguate, // added for 64bit proj.
			      desiredType.supportsSQLnull());
	       }

	   } // BigNum
	 else
	   newType = desiredType.closestEquivalentExternalType(STMTHEAP);
       }
  }

  NAType *tempType = originalType.newCopy(STMTHEAP);

  // In rowsets, we preserve the nullability of the type
  if (getItemExpr()->origOpType() == ITM_ROWSETARRAY_SCAN) {
    tempType->setNullable(*newType);
  }

  // If param is being typed from odbc or jdbc, preserve the
  // nullability of the type.
  NABoolean ODBC = (CmpCommon::getDefault(ODBC_PROCESS) == DF_ON);
  NABoolean JDBC = (CmpCommon::getDefault(JDBC_PROCESS) == DF_ON);
  if ((ODBC || JDBC) &&
      //      (CmpCommon::getDefault(GENERATE_LEAN_EXPR) == DF_ON)) {
      ((CmpCommon::getDefaultLong(QUERY_OPTIMIZATION_OPTIONS) & QO_PARAM_NULLABILITY_OPT) != 0)) {
        if ((getItemExpr()->origOpType()) == ITM_DYN_PARAM)
	  tempType->setNullable(*newType);
  }

  newType->setNullable(*tempType);

  if (newType->getTypeQualifier() == NA_CHARACTER_TYPE) {
    CharType *ct = (CharType *)newType;
    ct->setUpshifted(FALSE);
  }

  // Propagate (pushDowntype()) this type to the children of this valueid
  // in case one of the children could not be typed.
  //
  const NAType* synthesizedNewType =
	getItemExpr()->pushDownType(*newType, defaultQualifier);

  changeType(synthesizedNewType);
}

NAColumn*
ValueId::getNAColumn(NABoolean okIfNotColumn) const
{
  ItemExpr *ie = getItemExpr();
  switch (ie->getOperatorType()) {
  case ITM_BASECOLUMN:
    return ((BaseColumn *)ie)->getNAColumn();
  case ITM_INDEXCOLUMN:
    return ((IndexColumn *)ie)->getNAColumn();
  case ITM_UNPACKCOL:
  case ITM_NOTCOVERED:
    return ie->child(0).getValueId().getNAColumn(okIfNotColumn);
  case ITM_INSTANTIATE_NULL:
    return (*ie)[0].getNAColumn(okIfNotColumn);
  default:
    if (okIfNotColumn)
      return NULL;
    CMPASSERT(okIfNotColumn);
  }
  return NULL;  // NT_PORT
}

NABoolean ValueId::isColumnWithNonNullNonCurrentDefault() const{
  NAColumn * nac = NULL;
  ItemExpr *ck = getItemExpr();
  if ( ck == NULL )
     return FALSE;
  switch (ck->getOperatorType()){
  case ITM_BASECOLUMN:
      nac = ((BaseColumn*)ck)->getNAColumn();
      break;
  case ITM_INDEXCOLUMN:
      nac = ((IndexColumn*)ck)->getNAColumn();
      break;
  default:
      break;
  }
  if (nac &&  nac->getDefaultValue() && nac->getDefaultClass()!=COM_NULL_DEFAULT && nac->getDefaultClass()!=COM_CURRENT_DEFAULT)
      return TRUE;
  else
      return FALSE;
}

// Since we *can* have an INSTANTIATE_NULL inside a VEG_REFERENCE, a loop
// was required for the function below.
//
// Genesis case # 10-981118-9063 was the impetus for this change; basically,
// three left joins caused the previous version of this function to have an
// assertion failure.

BaseColumn *
ValueId::castToBaseColumn(NABoolean *isaConstant) const
{
  ItemExpr *ie = getItemExpr();

  // loop until we RETURN from this function or its a NULL expression
  while (ie)
    {
	  ValueId vid = NULL_VALUE_ID;

      switch (ie->getOperatorType())
        {
        case ITM_BASECOLUMN:
          return (BaseColumn *)ie;

        case ITM_INSTANTIATE_NULL:
		case ITM_UNPACKCOL:
		  ie = (*ie)[0] ;
		  break;

        case ITM_VALUEIDUNION:
		  // In case of ValueiId Union, get the child, which should be a
		  // base column.
		  vid = ((ValueIdUnion *)ie)->getSource(0);
		  if (vid == NULL_VALUE_ID)
		  {
			ie = NULL;
			break;
		  }

          ie = vid.getItemExpr();
          break;

		case ITM_ROWSETARRAY_SCAN:
          // $$$ mar: no good way to do this easily, so for now we punt
          // $$$ --> post-FCS, do something better
	  //
	  // $$$ ste: return 80 yards for a touch down.
	  // $$$ ---> score: ste 6, mar 0
          return NULL ;
          // ie = ((ValueIdUnion *)ie)->getSource(0) ;
          break;

        case ITM_VEG_REFERENCE:
          {
            ValueId kid;
            ((VEGReference*)ie)->getVEG()->getAllValues().getFirst(kid);
            ie = kid.getItemExpr();
            break;
          }

		default:
		  if (ie->getArity() > 0)
		  {
			ie = (*ie)[0];
			break;
		  }
		  else
                  {
                       if (isaConstant)
                       {
                         *isaConstant = ie->doesExprEvaluateToConstant
                           (FALSE,TRUE);
                       }
			return NULL;
                  }
        }
    } // end of while
	return NULL;
}

ValueId
ValueId::getBaseColumn(NABoolean *isaConstant) const
{
  BaseColumn *bc = castToBaseColumn(isaConstant);
  return bc==NULL ? NULL_VALUE_ID : bc->getValueId();
}

ValueId ValueId::nullInstantiate(BindWA *bindWAPtr, NABoolean forceCast) const
{
  const NAType &sourceType = getType();

  // For Joins, the Normalizer requires the cast to null-instantiation
  // (InstantiateNull is a subclass of Cast),
  // so Binder here passes forceCast as TRUE.
  if (sourceType.supportsSQLnull())
    if (!forceCast)
      return *this;
//##	// It would be nice not to put an InstNull on top of an InstNull.
//##	// Unfortunately, TEST014 q15 fails when we do so --
//##	// should investigate why and fix that!
//##    else if (getItemExpr()->getOperatorType() == ITM_INSTANTIATE_NULL)
//##      return *this;
  const NAType *resultType = sourceType.synthesizeNullableType(STMTHEAP);
  InstantiateNull *instNull = new (bindWAPtr->wHeap())
				  InstantiateNull(getItemExpr(), resultType);
  instNull->bindNode(bindWAPtr);
  CMPASSERT(NOT bindWAPtr->errStatus());
  return instNull->getValueId();
};

// -----------------------------------------------------------------------
// get the value id's of all ValueIdUnion nodes which exists as sub expr
// of the item expr which has this valueid.
// Used in MergeUnion::preCodeGen() to minimize the set of outputs the
// operator should produce.
// -----------------------------------------------------------------------
void ValueId::getSubExprRootedByVidUnion(ValueIdSet & vs)
{
  ItemExpr* thisItemExpr = getItemExpr();
  if ( thisItemExpr->getOperatorType() == ITM_VALUEIDUNION )
    vs.insert( *this );
  else
    for ( Lng32 i = 0; i < thisItemExpr->getArity(); i++ )
      thisItemExpr->child(i).getValueId().getSubExprRootedByVidUnion( vs );
}

// -----------------------------------------------------------------------
// replace any BaseColumn (of the given column name) in of this value
// expression with the given expression.
// used in Insert::bindNode() to move constraints from the target table
// to the source table.
// ----------------------------------------------------------------------
void ValueId::replaceBaseColWithExpr(const NAString& colName,
				     const ValueId & vid)
{
  ItemExpr* thisItemExpr = getItemExpr();
  for( Lng32 i = 0; i < thisItemExpr->getArity(); i++ )
  {
    ValueId childValueId = thisItemExpr->child(i).getValueId();
    ItemExpr* childItemExpr = childValueId.getItemExpr();

    if( childItemExpr->getOperatorType() == ITM_BASECOLUMN )
    {
      if( ((BaseColumn*)childItemExpr)->getColName() == colName )
        thisItemExpr->setChild( i, vid.getItemExpr() );
    }
    childValueId.replaceBaseColWithExpr( colName, vid );
  }
}

// ---------------------------------------------------
// Method for applying normalizeNode() to a ValueId.
// ---------------------------------------------------
NABoolean ValueId::normalizeNode(NormWA & normWARef)
{
  ItemExpr * nePtr;              // normalized expr.
  NABoolean transformed = FALSE;
  ItemExpr * iePtr = getItemExpr(); // original expr.
  // Transform the Item Expression.
  nePtr = iePtr->getReplacementExpr()->normalizeNode( normWARef );
  // If the original expression was transformed, update the id
  if ( nePtr->castToItemExpr() != iePtr ||
       nePtr->getValueId() != *this)
    {
      transformed = TRUE;
      id_ = nePtr->castToItemExpr()->getValueId();
    }

  return transformed;
}

// ***********************************************************************
// Methods for class ValueIdList
// (normalizer-related methods further below)
// ***********************************************************************

THREAD_P ObjectCounter (*ValueIdList::counter_)(0);

ValueIdList::ValueIdList(const ValueIdSet &vs, CollHeap *h) :
NAList<ValueId>(h, vs.entries())
{
  CollIndex index = 0;
  for (ValueId vid = vs.init(); vs.next(vid); vs.advance(vid))
    insertAt(index++,vid);
  CMPASSERT(index == vs.entries());
  (*counter_).incrementCounter();
}

// Initialization of list assumes array is densely populated or full
ValueIdList::ValueIdList(const ValueIdArray &va, CollHeap *h) :
NAList<ValueId>(h, va.entries())
{
  for (CollIndex i = 0; i < va.entries(); i++)
    if (va.used(i))
      insert(va[i]);
  (*counter_).incrementCounter();
}

void ValueIdList::insertSet(const ValueIdSet &other)
{
  CollIndex index = entries();
  for (ValueId vid = other.init(); other.next(vid); other.advance(vid))
    insertAt(index++,vid);
}

Lng32 ValueIdList::getRowLength() const
{
  Lng32 result = 0;

  for (CollIndex i = 0; i < entries(); i++)
    {
      result += at(i).getType().getTotalSize();
    }

  return result;
}

Lng32 ValueIdList::getRowLengthOfNumericCols() const
{
  Lng32 result = 0;

  for (CollIndex i = 0; i < entries(); i++)
    {
     if (at(i).getType().isNumeric())
      result += at(i).getType().getTotalSize();
    }

  return result;
}

// -----------------------------------------------------------------------
// Calculate the space needed in an sql_buffer for Mdam values.
// These values are: high, low, non-null high, non-null low, and current.
// There are five per key column.  Data in sql_buffer is eight-byte
// alligned.
// -----------------------------------------------------------------------
Lng32 ValueIdList::getMdamSqlBufferSpace() const
{
  Lng32 result = 0;

  for (CollIndex i = 0; i < entries(); i++)
    {
      result += 5 * (ROUND8(at(i).getType().getEncodedKeyLength())
                      + sizeof(tupp_descriptor));
    }

  return result;
}

// -----------------------------------------------------------------------
// prefixCoveredInSet()
// Is a prefix of this list covered in the provided set?  If so,
// return the number of covered elements.  Otherwise, return 0.
// -----------------------------------------------------------------------
Int32 ValueIdList::prefixCoveredInSet (const ValueIdSet& vidSet) const
{
  Int32 i = 0;
  ValueId simpVid;
  ValueId noInverseVid;

  // if the set's empty, clearly it doesn't cover anything!
  if ( vidSet.entries() == 0 ) return 0 ;

  while (i < (Int32)entries())
  {
    // simplify the expression
    // e.g. remove any INVERSE nodes on top,
    // and simplify any bi-arith ops involving constants to their
    // base value.
    simpVid = (*this)[i].getItemExpr()->simplifyOrderExpr()->getValueId();
    // Also compute the value id that results when the only
    // simplification that is done is to remove any INVERSE nodes -
    // i.e. if the valueId is a bi-arith op or is a bi-arith op that
    // is the child of an INVERSE node, it will remain.
    noInverseVid = (*this)[i].getItemExpr()->removeInverseOrder()->getValueId();

    // Stop unless we find the completely simplified or partially
    // simplified version of the expression in the provided set.
    if (NOT (vidSet.contains (simpVid) OR vidSet.contains(noInverseVid)) )
    {
         return i;
    }
    else
      i++;
  }

  return i;
}

// -----------------------------------------------------------------------
// allMembersCoveredInSet()
// Are all members of this list are covered in the provided set?
// If exactMatch is set:
//    If all the members of this list are covered in the provided set AND
//    if they are exact match, return TRUE. Otherwise, return FALSE.
// If exactMatch is not set:
//    If all the members of this list are covered in the provided set,
//    return TRUE. Otherwise, return FALSE.
// -----------------------------------------------------------------------
NABoolean ValueIdList::allMembersCoveredInSet(const ValueIdSet& vidSet,
                                              NABoolean exactMatch) const
{
  // Get the length of the covered prefix
  CollIndex numCovered = prefixCoveredInSet(vidSet);

  // Check if all the members of this list are covered.
  if (numCovered == entries())
  {
    // All members of this list are covered.
    // If they are exact match, return TRUE.
    if (entries() == vidSet.entries())
      return TRUE;
    else
    {
      // The provided set has additional memebers.
      // If exactMatch is set, return FALSE. Otherwise, return TRUE.
      if (exactMatch)
        return FALSE;
      else
        return TRUE;
    }
  }
  // All members of this list are NOT covered, so return FALSE.
  return FALSE;
}

// ---------------------------------------------------------------------
// removeUncoveredSuffix()
// Check whether a prefix of this list is covered by the provided set.
// For the remaining suffix, remove those items from this list.
// ---------------------------------------------------------------------
void ValueIdList::removeUncoveredSuffix (const ValueIdSet& vidSet)
{
  Int32 index = prefixCoveredInSet(vidSet);	// last covered id in this list
  Int32 i = (Int32)entries() - 1;			// index of last key column

  // Remove all entries following the index
  while (i >= index)
    removeAt(i--);
}

// ---------------------------------------------------------------------
// findNJEquiJoinColumns()
// Determine the maximum prefix of this list that is covered
// by either a constant, a parameter/host variable, or an equi-join
// column.  Then return the list that is composed of just the equi-join
// columns. Also returns in an output parameter the columns
// of this list that were not covered.
// Input: child0Outputs, child1Inputs
// Output: uncoveredCols
// Return value: a list representing the equijoin columns found
// ---------------------------------------------------------------------
ValueIdList ValueIdList::findNJEquiJoinCols(
                           const ValueIdSet & child0Outputs,
                           const ValueIdSet & child1Inputs,
                           ValueIdList & uncoveredCols) const
{
  ValueIdList equiJoinCols;
  NABoolean isChild0Output,isChild1Input;
  GroupAttributes emptyGA;
  ValueIdSet dummy;
  CollIndex i = 0;
  CollIndex j = 0;

  // Start off assuming that all columns are not covered
  uncoveredCols = *this;

  while ( i < entries() )
  {
    // simplify the expression
    // e.g. remove any INVERSE nodes on top (i.e. DESC)
    const ValueId & noInverseVid =
      (*this)[i].getItemExpr()->removeInverseOrder()->getValueId();

    // Is the value a constant or produced by child0?
    isChild0Output = emptyGA.covers( noInverseVid, child0Outputs, dummy );
    // Is the value a parameter/host variable or produced by
    // child0 or the parent?
    isChild1Input = child1Inputs.contains( noInverseVid );

    // If the value is produced by child0 and it is also an input
    // value, then it must be an equi-join column.
    if ( isChild0Output AND isChild1Input )
    {
      equiJoinCols.insert( (*this)[i] );
      uncoveredCols.removeAt(j);
      j--;
    }
    // Otherwise, check to see if the value is a constant or a
    // parameter/host variable.
    else if ( isChild0Output OR isChild1Input )
    {
      uncoveredCols.removeAt(j);
      j--;
    }
    // Otherwise, the column is not covered and we must stop now.
    else
    {
      return equiJoinCols;
    }
    // advance loop
    i++;
    j++;
  } // end while more entries in the list

  return equiJoinCols;
} // findNJEquiJoinCols()

// -----------------------------------------------------------------------
// complifyAndCheckPrefixCovered()
// Is a prefix of this list covered in the unsimplified provided set?  If so,
// return the number of covered elements.  Otherwise, if an element
// fails the check, check to see if it is in the simplified version of
// the provided set. If the element is found there, then remove the
// original version from the list and replace it with the unsimplified
// version of that element from the provided set, and keep going.
// Otherwise, return the length of the prefix seen so far. If there
// were no matches, then we will return 0.
// -----------------------------------------------------------------------
Int32 ValueIdList::complifyAndCheckPrefixCovered (const ValueIdSet& vidSet,
                                                  const GroupAttributes *ga)
{
  // if the set's empty, clearly it doesn't cover anything!
  if ( vidSet.entries() == 0 ) return 0 ;

  Int32 i = 0;
  ValueId thisVid;

  // Set up an empty GA so we can test for coverage by the provided set.
  ValueIdSet referencedInputs;
  GroupAttributes emptyGA;
  // The provided set will be the char. outputs that provide coverage
  emptyGA.setCharacteristicOutputs(vidSet);

  while (i < (Int32)entries())
  {
    // Get the current expression
    thisVid = (*this)[i];

    // Stop unless the provided set covers the current value id expression,
    // or unless we are able to do a "complify" operation.
    if (NOT emptyGA.covers(thisVid,
                           vidSet,
                           referencedInputs))
    {
      // Prepare to see if we can do a "complify" operation.
      // First, simplify the expression
      // e.g. remove any INVERSE nodes on top,
      // and simplify any bi-arith ops involving constants to their
      // base value.
      OrderComparison order1,order2;
      const ValueId & simpThisVid =
	(*this)[i].getItemExpr()->simplifyOrderExpr(&order1)->getValueId();
      // compute the simplified version of the provided set
      ValueIdSet simpleVidSet = vidSet.simplifyOrderExpr();

      // The current expression was not covered by the unsimplified version
      // of the provided set. So, see if the simplified version of the current
      // expression is in the simplified version of the provided set.
      //
      // Note that the typical usage of this method is to check if a sort key
      // is covered by the group attributes characteristic outputs. We need
      // to use the simplified version of the current expression because
      // inverse nodes (for DESC orders) will never be in the group attributes,
      // so we must strip them off. Also note that the simplifyOrderExpr
      // method does not yet handle all the simplifications that we would
      // like. For example, it does not simplify CAST expressions.  It also
      // does not simplify expressions involving multiplication, because
      // multiplying a column by a negative number reverses the ordering of
      // the column. This is an example of why we test for strict containment
      // here with only very basic simplifications allowed: since the "complify"
      // expression is actually substituting a different expression into the
      // sort key, we must ensure that the new expression is in fact completely
      // equivalent to the old. In some cases, such as CAST, we could
      // probably be more liberal, but in other cases, such as multiplication,
      // we cannot.
      if (simpleVidSet.contains(simpThisVid))
      {
        // Need to replace the current entry with one that is based on
        // the value id of the unsimplified version in the provided set.

        // Compute the corresponding value id in the provided set
        ValueId newThisVid;
        for (ValueId vid = vidSet.init();
                           vidSet.next(vid);
                           vidSet.advance(vid))
        {
          const ValueId & simpOtherVid =
	    vid.getItemExpr()->simplifyOrderExpr(&order2)->getValueId();
          if (simpOtherVid == simpThisVid)
          {
            newThisVid = vid;
            break;
          }
        }

        if (order1==order2)
        {
          // No inverse function to worry about - just replace the
          // current valid with the one from the provided set.
          (*this)[i] = newThisVid;
        }
        else
        {
          // Need to add an inverse operator on top of the provided
          // set expression.
          ItemExpr *inverseCol;
          inverseCol = new(CmpCommon::statementHeap())
                         InverseOrder(newThisVid.getItemExpr());
          inverseCol->synthTypeAndValueId();
          (*this)[i] = inverseCol->getValueId();
        }
      } // end if the simp. set contains the simp. expresssion
      else if (ga && ga->canEliminateOrderColumnBasedOnEqualsPred(thisVid))
      {
        // if this column is constrained to a single value, then
        // simply remove it from "this"
        removeAt(i--);
      }
      else
        return i;
    }
    i++;
  } // end while

  return i;
} // complifyAndCheckPrefixCovered

// ---------------------------------------------------------------------
// complifyAndRemoveUncoveredSuffix()
// Check whether a prefix of this list is covered by the provided set.
// This might involve replacing some elements of the list with their
// corresponding versions in the provided set.
// For the remaining suffix, remove those items from this list.
// ---------------------------------------------------------------------
void ValueIdList::complifyAndRemoveUncoveredSuffix (const ValueIdSet& vidSet,
                                                    const GroupAttributes *ga)
{
  // last covered id in this list
  Int32 index = complifyAndCheckPrefixCovered(vidSet, ga);
  Int32 i = (Int32)entries() - 1;  // index of last key column

  // Remove all entries following the index
  while (i >= index)
    removeAt(i--);
}

// ---------------------------------------------------------------------
// simplifyOrderExpr()
//
//  Returns a version of the list that has all expressions involving
// columns and constants or columns and inverse nodes simplified to be
// the column only.
// ---------------------------------------------------------------------
ValueIdList ValueIdList::simplifyOrderExpr() const
{
  CollIndex i;
  ValueId svid;
  ValueIdList simpleSortCols;

  for (i = 0; i < entries(); i++)
  {
    svid = (*this)[i].getItemExpr()->simplifyOrderExpr()->getValueId();
    simpleSortCols.insert(svid);
  }

  return simpleSortCols;
}

// ---------------------------------------------------------------------
// removeInverseOrder()
//
//  Returns a version of the list that has all expressions involving
// columns and inverse nodes simplified to be the column only.
// ---------------------------------------------------------------------
ValueIdList ValueIdList::removeInverseOrder() const
{
  CollIndex i;
  ValueId svid;
  ValueIdList noInverseSortCols;

  for (i = 0; i < entries(); i++)
  {
    svid = (*this)[i].getItemExpr()->removeInverseOrder()->getValueId();
    noInverseSortCols.insert(svid);
  }

  return noInverseSortCols;
}

// -----------------------------------------------------------------------
// Method for applying normalizeNode() to a ValueIdList.
// -----------------------------------------------------------------------
NABoolean ValueIdList::normalizeNode(NormWA & normWARef)
{
  ItemExpr * nePtr;              // normalized expr.
  NABoolean transformed = FALSE;

  for ( CollIndex index = 0; index < entries(); index++ )
  {
    ItemExpr * iePtr = at(index).getItemExpr(); // original expr.
    // Transform the Item Expression.
    nePtr = iePtr->getReplacementExpr()->normalizeNode( normWARef );
    // If the original expression was transformed, update the list
    if ( nePtr->castToItemExpr() != iePtr ||
	 nePtr->getValueId() != at(index) )
    {
      transformed = TRUE;
      at(index) = nePtr->castToItemExpr()->getValueId();
    }
  } // loop over expressions list

  return transformed;

} // ValueIdList::normalizeNode()

// -----------------------------------------------------------------------
// Method for rebuilding a predicate tree from a ValueIdList.
// -----------------------------------------------------------------------
ItemExpr * ValueIdList::rebuildExprTree
                           (OperatorTypeEnum op,
                            NABoolean redriveTypeSynthesisFlag,
			    NABoolean createFinalizeResultNode) const
{
  ItemExpr * iePtr;
  ItemExpr * leftPtr = NULL;
  // ---------------------------------------------------------------------
  // Iterate over the predicate factors in the given predicate tree,
  // constructing a left-linear backbone of the specified node type.
  // ---------------------------------------------------------------------
  for (CollIndex ix = 0; ix < entries(); ix++)
    {
      iePtr = at(ix).getItemExpr();
      if (leftPtr)
	switch (op)
	  {
	  case ITM_AND:
	  case ITM_OR:
	    leftPtr = new STMTHEAP BiLogic(op,leftPtr,iePtr);
	    break;

	  case ITM_ITEM_LIST:
	    leftPtr = new STMTHEAP ItemList(leftPtr,iePtr);
	    break;

	  default:
	    ABORT("Can't do backbones with this node type");
	  }
      else
        leftPtr = iePtr;
    } // loop over predTree

  // -----------------------------------------------------------------
  // Create a BoolResult node on top of the ANDed tree, if asked for.
  // Used by generator to finalize results.
  // -----------------------------------------------------------------
  if (leftPtr && createFinalizeResultNode)
    {
      CMPASSERT(op == ITM_AND);
      leftPtr = new STMTHEAP BoolResult(leftPtr);
    }

  // ---------------------------------------------------------------------
  // Synthesize the data type for the operators in the tree and allocate
  // their ValueIds.
  // ---------------------------------------------------------------------
  if (leftPtr)
    leftPtr->synthTypeAndValueId(redriveTypeSynthesisFlag);

  return leftPtr;

} // ValueIdList::rebuildExprTree()

// -----------------------------------------------------------------------
// ValueIdList::replaceVEGExpressions()
//
// This method is used by the code generator for rewriting
// expressions that belong to a ValueIdList. A reference to
// a VEG, i.e., a ValueId Equality Group is replaced with
// an expression that belongs the VEG as well as to the
// set of availableValues that is supplied.
// -----------------------------------------------------------------------
void ValueIdList::replaceVEGExpressions
                     (const ValueIdSet & availableValues,
                      const ValueIdSet & inputValues,
                      NABoolean thisIsAKeyPredicate,
                      VEGRewritePairs * lookup,
                      NABoolean replicateExpression,
                      const ValueIdSet * outputExpr,
                      const ValueIdSet * joinInputAndPotentialOutput,
                      const IndexDesc * iDesc,
                      const GroupAttributes * left_ga,
                      const GroupAttributes * right_ga
)
{
  // ---------------------------------------------------------------------
  // Iterate over the predicate factors in the given predicate tree.
  // ---------------------------------------------------------------------
  NABoolean savedReplicateExpression = replicateExpression ;
  for (CollIndex ix = 0; ix < entries(); ix++)
    {
      // -----------------------------------------------------------------
      // Walk through the item expression tree and replace any
      // VEGPredicates or VEGReferences that are found.
      // -----------------------------------------------------------------
      ValueId exprId = at(ix);
      if (outputExpr && outputExpr->containsTheGivenValue(exprId))
        replicateExpression = FALSE;

      ItemExpr * iePtr = NULL;
      if(CmpCommon::getDefault(RANGESPEC_TRANSFORMATION) == DF_ON &&
         exprId.getItemExpr()->getOperatorType() == ITM_RANGE_SPEC_FUNC)
      {
        iePtr = exprId.getItemExpr()->child(1)->replaceVEGExpressions
                                                   (availableValues,
                                                    inputValues,
                                                    thisIsAKeyPredicate,
                                                    lookup,
                                                    replicateExpression,
                                                    joinInputAndPotentialOutput,
                                                    iDesc,
                                                    left_ga,
                                                    right_ga);
      }
      else
      {

        iePtr = exprId.getItemExpr()->replaceVEGExpressions
                                                 (availableValues,
                                                  inputValues,
                                                  thisIsAKeyPredicate,
                                                  lookup,
                                                  replicateExpression,
                                                  joinInputAndPotentialOutput,
                                                  iDesc,
                                                  left_ga,
                                                  right_ga);
      }

      replicateExpression = savedReplicateExpression;
      if (iePtr) // wild card expansion was successful
	{
	  if (!iePtr->nodeIsBound() || iePtr->isPreCodeGenNATypeChanged())
	    // redrive type synthesis for both self and child nodes
	    iePtr->synthTypeAndValueId(TRUE, TRUE);
	  if (iePtr->getValueId() != exprId)
	    at(ix) = iePtr->getValueId();
	}
      else               // discard element from the list
        {
	  removeAt(ix);
          ix--;
        }

    } // loop over expression list

} // ValueIdList::replaceVEGExpressions()

OrderComparison ValueIdList::satisfiesReqdOrder(const ValueIdList & reqdOrder,
                                                GroupAttributes *ga,
                                                const ValueIdSet *preds) const
{
  NAUnsigned numReqdEntries = reqdOrder.entries();
  OrderComparison allCols = SAME_ORDER; // sort order comparison of all columns together
  OrderComparison oneCol;  // one column compared with its counterpart

  CollIndex thisIx = 0;
  CollIndex reqdIx = 0;

  ValueIdList tempThis(*this);

  // if group attributes are provided, remove any constant expressions,
  // since those should not appear in the requirements and since they
  // are not relevant to the ordering
  if (ga)
    tempThis.removeCoveredExprs(ga->getCharacteristicInputs());

  CollIndex numActEntries = tempThis.entries();

  // we assume that reqdOrder went through a RequirementGenerator
  // and is therefore already optimized (e.g. no duplicate columns)

  // is the actual sort key at least as long as the required one?
  if (numActEntries < numReqdEntries)
     return DIFFERENT_ORDER;

  for (CollIndex reqdIx = 0; reqdIx < numReqdEntries; reqdIx++)
  {
     NABoolean done = FALSE;

     // compare the next required order column with one or more
     // ValueIds in tempThis
     while (!done)
     {
       // make sure we have enough columns in "tempThis"
       if (thisIx >= numActEntries)
         return DIFFERENT_ORDER;

       // compare the next column of tempThis with the required order
       oneCol = reqdOrder[reqdIx].getItemExpr()->sameOrder(
            tempThis[thisIx].getItemExpr());

       done = TRUE;

       // If we didn't find the column, then try to find an equals
       // predicate that equates the column to a constant, so that
       // we can skip over it. This typically happens with computed
       // columns such as salt or division that don't have associated
       // VEGs, which are handled by tempThis.removeCoveredExprs() above.
       if (oneCol == DIFFERENT_ORDER &&
           ga &&
           (numActEntries-thisIx) > (numReqdEntries-reqdIx) && // extra cols in this
           ga->tryToEliminateOrderColumnBasedOnEqualsPred(tempThis[thisIx],
                                                          preds))
       {
         // this is a predicate of the form col = const
         // and col is our current ValueId in tempThis,
         // therefore skip over it and try again
         thisIx++;
         done = FALSE;
       }
     }

     if (reqdIx == 0)
        allCols = oneCol;
     else
        allCols = combineOrderComparisons(allCols,oneCol);

     if (allCols == DIFFERENT_ORDER)
        return allCols;

     thisIx++;
  }
  return allCols;
}

NABoolean ValueIdList::satisfiesReqdArrangement(
     const ValueIdSet &reqdArrangement,
     GroupAttributes * ga,
     const ValueIdSet *preds) const
{
  // ---------------------------------------------------------------------
  // check requirement for arrangement of data (check whether the required
  // arranged columns form a prefix of the sort key or whether the
  // table contains at most one row, in which case it satisfies any
  // required ordering)
  // ---------------------------------------------------------------------
  ValueIdSet arrCols(reqdArrangement);
  NABoolean found = TRUE;
  CollIndex startCol = 0;

  // if group attributes are provided, remove any constant expressions,
  // since those should not appear in the requirements and since they
  // are not relevant to the ordering
  if (ga)
    arrCols.removeCoveredExprs(ga->getCharacteristicInputs());

  // walk along the sort key, as long as all columns in the sort
  // keys are part of the required set of arranged columns

  for (CollIndex i = startCol; i < entries() AND found; i++)
    {
      found = FALSE;

      // try a shortcut first: is the value id a required column?
      if (reqdArrangement.contains((*this)[i]))
	{
	  // yes, the sort key column is one of the columns passed in
	  // through "reqdArrangement", this required arrangement col.
	  // is satisfied
	  found = TRUE;
	  arrCols -= (*this)[i];
	}
      else
	{
	  // do it the long way: is the sort key colum in the same order
	  // as one of the columns that are required for the arrangement?

	  ItemExpr *sortKeyCol = (*this)[i].getItemExpr();

	  for (ValueId x = reqdArrangement.init();
	       reqdArrangement.next(x);
	       reqdArrangement.advance(x))
	    {
	      if (sortKeyCol->sameOrder(x.getItemExpr()) != DIFFERENT_ORDER)
		{
		  // yes, the sort key column has the same order as or the
		  // inverse order of the value x that was passed in
		  // through "reqdArrangement", this required arrangement col.
		  // is satisfied
		  found = TRUE;
		  arrCols -= x;
		}
	    }

          if ((NOT found) && ga)
            {
              // if this column is constrained to a single value,
              // we can skip over it and continue (we set found to
              // true but don't remove anything from arrCols)
              found = ga->tryToEliminateOrderColumnBasedOnEqualsPred(
                   (*this)[i],
                   preds);
            }
	}
    }

  // if there are leftover columns from the required arrangement that
  // haven't been satisfied yet, return FALSE

  return (arrCols.isEmpty());
}

// -----------------------------------------------------------------------
// Method for applying transformNode() to a ValueIdList.
// -----------------------------------------------------------------------
NABoolean ValueIdList::transformNode(NormWA & normWARef,
                                     ExprGroupId & introduceSemiJoinHere,
				     const ValueIdSet & externalInputs)
{
  NABoolean transformed = FALSE;
  RelExpr * saveOrigPtr = introduceSemiJoinHere;

  for (CollIndex index = 0; index < entries(); index++)
    {
      ItemExpr * iePtr = at(index).getItemExpr(); // original expr.
      ExprValueId nePtr(iePtr);                   // normalized expr.
      // Transform the Item Expression.
      iePtr->getReplacementExpr()->transformNode(normWARef, nePtr,
                           introduceSemiJoinHere, externalInputs);
      // If the original expression was transformed, update the list
      if (nePtr != (const ItemExpr *)iePtr)
	{
	  at(index) = nePtr->getValueId();
	}
      // if the original expression contains an ITM_ONE_ROW aggregate as output,
      // replace it with its child (or children)

      if ( iePtr->getReplacementExpr()->getOperatorType() == ITM_ONE_ROW )
      {
        ItemExpr* ReplacedExpr =
            iePtr->getReplacementExpr()->transformOneRowAggregate( normWARef );

	// redrive type synthesis for both self and child nodes
        ReplacedExpr->synthTypeAndValueId( TRUE, TRUE );

        // For now (as of 11/17/98) assume arity of childIE is at most one
        CMPASSERT(ReplacedExpr->child(0)->castToItemExpr()->getArity() <= 1 );

        at(index) = ReplacedExpr->child(0)->castToItemExpr()->getValueId();
      }
    } // loop over expressions list

  // if a subquery was transformed, set transformed flag
  if (introduceSemiJoinHere != (const RelExpr *)saveOrigPtr)
    transformed = TRUE;

  return transformed;

} // ValueIdList::transformNode()

// ------------------------------------------------------------------------
// ValueIdList::removeCoveredExprs()
//
// Removes from the valueid set those expressions that are
// covered by the available values
// ------------------------------------------------------------------------

void ValueIdList::removeCoveredExprs(const ValueIdSet & newExternalInputs)
{
  NABoolean coverFlag;
  ValueIdSet referencedInputs;
  GroupAttributes emptyGA;

  emptyGA.setCharacteristicOutputs(newExternalInputs);
  for (CollIndex ix = 0; ix < entries(); ix++)
    {
      ValueId exprId = at(ix);
      if (exprId.getItemExpr()->getOperatorType() == ITM_VEG_PREDICATE)
        {
          VEG * vegPtr = ((VEGPredicate *)(exprId.getItemExpr()))->getVEG();
          coverFlag = emptyGA.covers(vegPtr->getVEGReference()->getValueId(),
                                     newExternalInputs,
                                     referencedInputs);
        }
      else
        coverFlag = emptyGA.covers(exprId,
                                   newExternalInputs,
                                   referencedInputs);
      if (coverFlag)
        {
	  removeAt(ix);
          ix--;
        }
    } // for
} // ValueIdList::removeCoveredExprs

// ------------------------------------------------------------------------
// ValueIdList::removeUnCoveredExprs()
//
// Removes from the valueid list those expressions that are NOT covered by
// the available values.
//
// When the first uncovered element is found, that and all subsequent list
// elements are removed.
// ------------------------------------------------------------------------

void ValueIdList::removeUnCoveredExprs(const ValueIdSet & newExternalInputs)
{
  NABoolean coverFlag;
  ValueIdSet referencedInputs;
  GroupAttributes emptyGA;

  emptyGA.setCharacteristicOutputs(newExternalInputs);
  for (CollIndex ix = 0; ix < entries(); ix++)
    {
      ValueId exprId = at(ix);
      if (exprId.getItemExpr()->getOperatorType() == ITM_VEG_PREDICATE)
        {
          VEG * vegPtr = ((VEGPredicate *)(exprId.getItemExpr()))->getVEG();
          coverFlag = emptyGA.covers(vegPtr->getVEGReference()->getValueId(),
                                     newExternalInputs,
                                     referencedInputs);
        }
      else
        coverFlag = emptyGA.covers(exprId,
                                   newExternalInputs,
                                   referencedInputs);
      if (!coverFlag)
        {
          CollIndex entriesToRemove = entries()-ix ;
          while (entriesToRemove > 0)
            {
              removeAt (entries()-1) ; // remove the last elt, n times
              entriesToRemove-- ;
            }
        }
    } // for
} // ValueIdList::removeUnCoveredExprs

// ---------------------------------------------------------------------
// removeDuplicateValueIds()
// This method removes duplicate value ids(vid) from the ValueIdList object.
// First get the last vid and walks through the list comparing this last vid
// with the rest of vids. If the previous vid is same as the next one then,
// remove the last one.
// ---------------------------------------------------------------------
void ValueIdList::removeDuplicateValueIds()
{
  CollIndex entry = entries()-1;
  for (CollIndex last = entry; last > 0; last--)
  {
    // Get the last vid from the List.
    // simplify the expression
    // e.g. remove any INVERSE nodes on top (i.e. DESC)
    ValueId  prev =
      (*this)[last].getItemExpr()->removeInverseOrder()->getValueId();
    // walk through the list comparing next vid with the prev vid.
    for (Int32 start = 0; start < (Int32)last; start++)
    {
      // Get the next value id from the List.
      // simplify the expression
      // e.g. remove any INVERSE nodes on top (i.e. DESC)
      ValueId  next =
      (*this)[start].getItemExpr()->removeInverseOrder()->getValueId();
      // If there is a duplicate vid, then remove the last one.
      if (next == prev)
      {
        removeAt(last);
        break;
      }
    } // for start
  } // for last
} // removeDuplicateValueIds()

// ---------------------------------------------------------------------
// substituteValueIds()
// This method replaces the vid with the replacementVid
// ---------------------------------------------------------------------
void ValueIdList::substituteValueIds(const ValueId vid, const ValueId replacementVid)
{
  for (CollIndex i=0; i <  entries(); i++)
  {
    // walk through the list comparing next cvid with vid.
    ValueId  cvid = (*this)[i];

    if (cvid == vid)
    {
       // found one to replace, replace it.
        removeAt(i);
        insertAt(i, replacementVid);
    }
  } // for i
} // substituteValueIds()

// -----------------------------------------------------------------------
// ValueIdList::removeSubqueryOrIsolatedUDFunctionPredicates()
//
// This method walks through the ItemExprs that belong to this set,
// collects the ValueIds of the subqueries or UDFs in the list. It also
// collects any ValueIdProxies associated with the said subquiery or UDF.
// -----------------------------------------------------------------------
void ValueIdList::removeSubqueryOrIsolatedUDFunctionPredicates(ValueIdSet & subqueryExpr)
{

  for (CollIndex ix = 0; ix < entries(); ix++)
    {
      ValueId exprId = at(ix);

      if (exprId.getItemExpr()->containsValueIdProxySibling(subqueryExpr) ||
          exprId.getItemExpr()->containsSubquery() ||
          exprId.getItemExpr()->containsIsolatedUDFunction())

        {
          subqueryExpr.addElement(exprId);
          removeAt(ix);
          ix--;

        }
    }
} // ValueIdList::removeSubqueryOrIsolatedUDFunctionPredicates()

void ValueIdList::unparse(NAString &result,
			  PhaseEnum phase,
			  UnparseFormatEnum form,
			  TableDesc * tabId) const
{
  //result += "(";
  for (CollIndex i = 0; i < entries(); i++)
    {
      if (i > 0) result += ", ";

      if ( form == ERROR_MSG_FORMAT ) // ERROR_MSG_FORMAT : don't print vid's
        {
          at(i).getItemExpr()->unparse(result,phase,EXPLAIN_FORMAT,tabId);
        }
      else
        {
	//never print vid's
       /*   char vidbuf[TEXT_DISPLAY_LENGTH];
          sprintf(vidbuf, "[%u]", (CollIndex)at(i));
          result += vidbuf;
	  */

          at(i).getItemExpr()->unparse(result,phase,form,tabId);
        }
    }
  //result += ")";

} // ValueIdList::unparse

// -----------------------------------------------------------------------
// ValueIdList::replaceOperandsOfInstantiateNull()
// This method is used by the code generator for replacing the
// operands of an ITM_INSTANTIATE_NULL with a value that belongs
// to availableValues.
// -----------------------------------------------------------------------
void ValueIdList::replaceOperandsOfInstantiateNull
                      (const ValueIdSet & availableValues,
                       const ValueIdSet & inputValues)
{
 for (CollIndex j = 0; j < entries(); j++)
    {
      at(j).getItemExpr()->replaceOperandsOfInstantiateNull(availableValues,inputValues);
    }
} // ValueIdList::replaceOperandsOfInstantiateNull()

void ValueIdList::print(FILE* ofd, const char* indent, const char* title,
                        CollHeap *c, char *buf) const
{
#pragma nowarn(1506)   // warning elimination
  BUMP_INDENT(indent);
#pragma warn(1506)  // warning elimination
  Space * space = (Space *)c;
  char mybuf[1000];

  snprintf(mybuf, sizeof(mybuf), "%s%s\n",NEW_INDENT,title);
  PRINTIT(ofd, c, space, buf, mybuf);

  for (CollIndex j = 0; j < entries(); j++)
  {
    Int32 i = (Int32)((CollIndex) (at(j))); // valueid as an integer
    NAString unparsed(CmpCommon::statementHeap());

    if (at(j).getItemExpr())
      at(j).getItemExpr()->unparse(unparsed); // expression as ascii string

    snprintf(mybuf, sizeof(mybuf), "%4d: %s\n",i,(const char *) unparsed);
    PRINTIT(ofd, c, space, buf, mybuf);
  }
} // ValueIdList::print()

void ValueIdList::display() const	// To be called from the debugger
{
  print();
}

// ***********************************************************************
// Methods for class ValueIdSet
// ***********************************************************************

THREAD_P ObjectCounter (*ValueIdSet::counter_)(0);

ValueIdSet::ValueIdSet() :
   ClusteredBitmap(CmpCommon::statementHeap())
{
  (*counter_).incrementCounter();
}

ValueIdSet::ValueIdSet(const ValueIdSet &other) :
   ClusteredBitmap(other, CmpCommon::statementHeap())
{
  (*counter_).incrementCounter();
}

ValueIdSet::ValueIdSet(const ValueId& vid) :
   ClusteredBitmap(CmpCommon::statementHeap())
{
  addElement(vid.id_);
  (*counter_).incrementCounter();
}

ValueIdSet::ValueIdSet(const ValueIdList &other) :
   ClusteredBitmap(CmpCommon::statementHeap())
{
  for (CollIndex i = 0; i < other.entries(); i++)
    {
      *this += other[i];
    }
  (*counter_).incrementCounter();
}

ValueIdSet::ValueIdSet(ValueDescArray *arr) :
  ClusteredBitmap(CmpCommon::statementHeap())
{
  (*counter_).incrementCounter();
}

NABoolean ValueIdSet::operator == (const ValueIdSet & other) const
{
  if (entries() != other.entries()) return FALSE;
  for (ValueId vid = init(); next(vid); advance(vid))
  {
    if (other.contains(vid) == FALSE)
      return FALSE;
  }
  return TRUE;
}

void ValueIdSet::getFirst(ValueId & v) const
{
  v = init();
  if (NOT next(v))
    v = NULL_VALUE_ID;
}
//------------------------------------------------------------------------
// ValueIdSet::convertToBaseids()
// Method that synthesizes a valueIdset that is comprised of the basecolumn
// valueids of this valueidset. So the ids in this set are expected to be
// for Columns.
//------------------------------------------------------------------------
ValueIdSet ValueIdSet::convertToBaseIds() const
{
  ValueIdSet result;
  for(ValueId vid=init(); next(vid); advance(vid))
  {
    // Since we can call this on any ValueIdSet, make sure we actually have
    // an IndexColumn.
    DCMPASSERT(vid.getItemExpr()->getOperatorType() == ITM_INDEXCOLUMN);
    result.insert(((BaseColumn *)(((IndexColumn *)vid.getItemExpr())->
			  getDefinition().getItemExpr()))->getValueId());
  }
  return result;
}

// --------------------------------------------------------------------
// ValueIdSet::getMinOrigUecOfJoiningCols
// Out of all columns in the set, return the one with minimum UEC
// --------------------------------------------------------------------

CostScalar ValueIdSet::getMinOrigUecOfJoiningCols()
{
  BaseColumn * result = NULL;
  CostScalar minUec = COSTSCALAR_MAX;

  for(ValueId vid= init(); next(vid); advance(vid))
  {
    // Find the base column for the input column:

    ItemExpr *inputColumnIEPtr = vid.getItemExpr();

    if (inputColumnIEPtr == NULL)
      continue;

    ValueId baseColumnForInputColumn = NULL_VALUE_ID;
    switch ( inputColumnIEPtr->getOperatorType() )
      {
      case ITM_VEG_REFERENCE:
	{
	  //  The inputColumn is a VEG reference
	  //  Loop through the columns until you find it:
	  ValueIdSet columnSet;

	  inputColumnIEPtr->findAll(ITM_BASECOLUMN, columnSet, TRUE, TRUE);
	  if (!columnSet.isEmpty() )
	    columnSet.getFirst(baseColumnForInputColumn);
	  break;
	}

	case ITM_INSTANTIATE_NULL:
	case ITM_BASECOLUMN:
	  //  The inputColumn is a base column.
	  baseColumnForInputColumn = vid;
	  break;

	case ITM_INDEXCOLUMN:
	  //  Get the base column for the index column:
	  {
	    const BaseColumn *bcIEPtrForIndexColumn =
	      (BaseColumn *) ((IndexColumn *) inputColumnIEPtr)->
	      getDefinition().getItemExpr();

	    baseColumnForInputColumn = bcIEPtrForIndexColumn->getValueId();
	    break;
	  }

	default:
	  // The value id in inputColumns *must* be either an index column or
	  // a base table column; anything else, when we reach here, is an
	  // internal error.
	  break;
	} // switch on type of input column

    if (baseColumnForInputColumn != NULL_VALUE_ID)
      result = (BaseColumn *)(vid.getItemExpr() );

    if (result)
    {
      ColStatDescList & colStatsList = result->getTableDesc()->tableColStats();

      CollIndex index;
      NABoolean found = colStatsList.getColStatDescIndexForColumn( index, baseColumnForInputColumn );

      if (found)
      {
	CostScalar uec = colStatsList[index]->getColStats()->getTotalUec();
	if (uec < minUec)
	{
	  minUec = uec;
	}
      }
    }
  }

  return minUec;
}

NABoolean ValueIdSet::coversFirstN(const ValueIdList &other, Int32 N) const
{
  Int32 i, limit = N <= (Int32)other.entries() ? N : (Int32)other.entries();
  for (i = 0; i < limit; i++) {
    // if other is an indexcolumn, compare against its definition,
    // ie, compare against what column it indexes
    if (other[i].getItemExpr()->getOperatorType() == ITM_INDEXCOLUMN) {
      IndexColumn *ixCol = (IndexColumn*)(other[i].getItemExpr());
      if (!contains(ixCol->getDefinition())) { return FALSE; }
    }
    else if (!contains(other[i])) { return FALSE; }
  }
  return TRUE; // this covers first N elements of other
}

// how many prefix columns of other are found in this predicate?
Int32 ValueIdSet::prefixMatchesOf(const ValueIdList &other) const
{
  Int32 result = 0; // assume no prefix match until proven otherwise
  ValueId vId;

  for (CollIndex i = 0; i <  other.entries(); i++)
    {
      if (referencesTheGivenValue(other[i], vId))
        result++;
      else
	return result; // quit on first prefix mismatch
    }
  // all elements of other are found in this
  return result;
}

NABoolean ValueIdSet::isDensePrefix(const ValueIdList &other) const
{
  ValueIdSet notContainedInThis(*this);
  NABoolean found = TRUE;

  for (CollIndex i = 0; i <  other.entries() AND found; i++)
    {
      if (contains(other[i]))
	notContainedInThis -= other[i];
      else
	found = FALSE;
    }

  // if all value ids of this set are contained in the prefix, return TRUE
  return notContainedInThis.isEmpty();
}

Lng32 ValueIdSet::getRowLength() const
{
  Lng32 result = 0;

  for (ValueId x = init(); next(x); advance(x))
    {
      result += x.getType().getTotalSize();
    }

  return result;
}

Lng32 ValueIdSet::getRowLengthOfNumericCols() const
{
  Lng32 result = 0;

  for (ValueId x = init(); next(x); advance(x))
    {
      if (x.getType().isNumeric())
      	result += x.getType().getTotalSize();
    }

  return result;
}

// ***********************************************************************
// normalizer-related methods for class ValueIdSet
// ***********************************************************************

// -----------------------------------------------------------------------
// ValueIdSet::accumulateReferencedValues()
//
// This method accumulates those values that are members of the
// referencedSet and are referenced either individually or in a
// VEGReference in the referencingSet, if the optional parameters
// allow it. The original contents of this ValueIdSet are augmented.
// -----------------------------------------------------------------------
void ValueIdSet::accumulateReferencedValues(const ValueIdSet & referencedSet,
                                  const ValueIdSet & referencingSet,
                                  NABoolean doNotDigInsideVegRefs,
                                  NABoolean doNotDigInsideInstNulls)
{
  for (ValueId referencedExpr = referencedSet.init();
       referencedSet.next(referencedExpr);
       referencedSet.advance(referencedExpr))
    {
      for (ValueId referencingExpr = referencingSet.init();
	   referencingSet.next(referencingExpr);
	   referencingSet.advance(referencingExpr))
	{
          if (referencingExpr.getItemExpr()
               ->referencesTheGivenValue(
                   referencedExpr,
                   doNotDigInsideVegRefs,
                   doNotDigInsideInstNulls))
	    addElement(referencedExpr);
	} // referencingExpr loop
    } // referencedExpr loop

} // ValueIdSet::accumulateReferencedValues()

// -----------------------------------------------------------------------
// Walk through an ItemExpr tree and gather the ValueIds of those
// expressions that behave as if they are "leaves" for the sake of
// the coverage test, e.g., expressions that have no children, or
// aggregate functions, or instantiate null. These are usually values
// that are produced in one "scope" and referenced above that "scope"
// in the dataflow tree for the query.
// -----------------------------------------------------------------------
void ValueIdSet::getLeafValuesForCoverTest(ValueIdSet & leafValueIds,
                                           const GroupAttributes& coveringGA,
                                           const ValueIdSet & newExternalInputs) const
{
  for (ValueId exprId = init(); next(exprId); advance(exprId) )
    {
      exprId.getItemExpr()->getLeafValuesForCoverTest(leafValueIds, coveringGA,
	newExternalInputs);
    }
} // ValueIdSet::getLeafValuesForCoverTest()

// -----------------------------------------------------------------------
// ValueIdSet::referencesOneValueFromTheSet()
//
// Check whether an expression contained in this ValueIdSet
// references an expression that is a member of the otherSet.
// -----------------------------------------------------------------------
NABoolean ValueIdSet::referencesOneValueFromTheSet
                         (const ValueIdSet & otherSet) const
{
  for (ValueId myExpr = init(); next(myExpr); advance(myExpr))
    {
      for (ValueId otherExpr = otherSet.init();
	   otherSet.next(otherExpr);
	   otherSet.advance(otherExpr))
	{
	  if (myExpr.getItemExpr()->referencesTheGivenValue(otherExpr))
	    return TRUE;
	}
    }
  return FALSE;
} // ValueIdSet::referencesOneValueFromTheSet()

// -----------------------------------------------------------------------
// ValueIdSet::referencesAllValuesFromMe()
//
// Check whether all expressions contained in this ValueIdSet
// references an expression that is a member of the otherSet.
// -----------------------------------------------------------------------
NABoolean ValueIdSet::referencesAllValuesFromMe
		      (const ValueIdSet & otherSet) const
{
   ValueId id;
   for (ValueId myExpr = init(); next(myExpr); advance(myExpr))
    {
      if (NOT(otherSet.referencesTheGivenValue(myExpr, id)))
	return FALSE;
    }
  return TRUE;
} // ValueIdSet::referencesAllValuesFromMe()

// -----------------------------------------------------------------------
// ValueIdSet::referencesTheGivenValue()
//
// Check whether any expression contained in this ValueIdSet
// references the given value.
// -----------------------------------------------------------------------
NABoolean ValueIdSet::referencesTheGivenValue(const ValueId & theValue,
                                    ValueId & exprId,
                                    NABoolean doNotDigInsideVegRefs,
                                    NABoolean doNotDigInsideInstNulls) const
{
  for (ValueId vid = init(); next(vid); advance(vid))
    {
      if (vid.getItemExpr()->referencesTheGivenValue(
                               theValue,
                               doNotDigInsideVegRefs,
                               doNotDigInsideInstNulls))
      {
	exprId = vid;
	return TRUE;
      }
    }
  return FALSE;
} // ValueIdSet::referencesTheGivenValue()

// -----------------------------------------------------------------------
// ValueIdSet::containsTheGivenValue()
//
// Check whether any expression contained in this ValueIdSet
// references the given value.
// -----------------------------------------------------------------------
NABoolean ValueIdSet::containsTheGivenValue( const ValueId & theValue ) const
{
  for ( ValueId vid = init(); next(vid); advance(vid) )
  {
    if ( vid.getItemExpr()->containsTheGivenValue( theValue ) )
    {
      return TRUE;
    }
  }

  return FALSE;
} // ValueIdSet::containsTheGivenValue()

// return true iff set has RandomNum expr
NABoolean ValueIdSet::hasRandom() const
{
  for ( ValueId vid = init(); next(vid); advance(vid) )
  {
    if ( vid.getItemExpr()->getOperatorType() == ITM_RANDOMNUM )
    {
      return TRUE;
    }
  }
  return FALSE;
}

// -----------------------------------------------------------------------
// ValueIdSet::membersCoveredInSet()
//
// Check whether any of the members of this ValueIdSet are contained
// in the provided ValueIdSet.  Return the number of members found.
// -----------------------------------------------------------------------
#pragma nowarn(262)   // warning elimination
Int32 ValueIdSet::membersCoveredInSet (const ValueIdSet& vidSet, NABoolean lookBelowInstantiateNull) const
{
  NABoolean coverFlag = FALSE;
  ItemExpr * memberExpr = NULL;
  ValueId memberValId;

  Int32 membersFound = 0;

  for ( ValueId vid = init(); next(vid); advance(vid) )
  {
    // If any member of this set contains the INVERSE function (for
    // specifying DESC ordering), examine the valueid of the child of
    // the inverse expression for coverage.
    memberExpr = vid.getItemExpr();
    if ((memberExpr->getOperatorType() == ITM_INVERSE) ||
	(lookBelowInstantiateNull && memberExpr->getOperatorType() == ITM_INSTANTIATE_NULL))
      memberValId = ((ItemExpr *)memberExpr->child(0))->getValueId();
    else
      memberValId = vid;

    if ( vidSet.contains( memberValId ) )
      membersFound++;
  }

  return (membersFound);
}
#pragma warn(262)  // warning elimination

//-------------------------------------------------------
//removeCoveredVidSet()
//Input: other set
//output: reduced *this set by other set
//Constraints: will remove the ids as long as
//other set contains a reference or the id itself.
//---------------------------------------------------------
void ValueIdSet::removeCoveredVIdSet(const ValueIdSet & otherSet)
{
  for ( ValueId id = otherSet.init(); otherSet.next(id); otherSet.advance(id) )
  {
    if ( id.getItemExpr()->getOperatorType() == ITM_VEG_REFERENCE )
    {
      const ValueIdSet & insideSet =
	((VEGReference *)(id.getItemExpr()))->getVEG()->getAllValues();
      remove( insideSet );
    }
    else
    {
      remove( id );
    }
  }
}

// -----------------------------------------------------------------------
// ValueIdSet::removeUnReferencedVEGPreds()
//
// Check whether a VEGPred contained in this ValueIdSet references
// references a value that is a member of the otherSet and remove it
// othewise.
// -----------------------------------------------------------------------
void ValueIdSet::removeUnReferencedVEGPreds
                         (const ValueIdSet & otherSet)
{
  for (ValueId myExpr = init(); next(myExpr); advance(myExpr))
    {
      if (myExpr.getItemExpr()->getOperatorType() == ITM_VEG_PREDICATE)
        {
          ValueIdSet predSet;
          predSet += myExpr;
          // If any of the vegMembers is provided by the available values
          // we want to keep the predicate
          if(NOT predSet.referencesOneValueFromTheSet(otherSet))
	    subtractElement(myExpr); // delete original expression from set
        }
    }
} // ValueIdSet::removeUnReferencedVEGPreds()

// -----------------------------------------------------------------------
// ValueIdSet::removeSubqueryOrIsolatedUDFunctionPredicates()
//
// This method walks through the ItemExprs that belong to this set,
// collects the ValueIds of the expressions at their leaves and
// returns them.
// -----------------------------------------------------------------------
void ValueIdSet::removeSubqueryOrIsolatedUDFunctionPredicates(ValueIdSet & subqueryExpr)
{
  for (ValueId exprId = init(); next(exprId); advance(exprId))
    {
      if (exprId.getItemExpr()->containsSubquery() ||
         (exprId.getItemExpr()->containsIsolatedUDFunction()))
        {
          subqueryExpr.addElement(exprId);
	  subtractElement(exprId); // delete original expression from set
        }
    }
} // ValueIdSet::removeSubqueryOrIsolatedUDFunctionPredicates()

// -----------------------------------------------------------------------
// ValueIdSet::transformNode()
//
// Method for applying transformNode() to a ValueIdSet.
// If the ValueIdSet represents a predicate tree, then the caller is
// expected to set movePredicate to TRUE. Whenever movePredicate is
// is set and a subquery is transformed, the transformed predicate
// is moved to the SemiJoin or Join that is introduced by the
// subquery transformation.
// -----------------------------------------------------------------------
NABoolean ValueIdSet::transformNode(NormWA & normWARef,
                                    ExprGroupId & introduceSemiJoinHere,
                                    const ValueIdSet & externalInputs,
				    const NABoolean movePredicates,
				    const NABoolean postJoinPredicates)
{
  // ---------------------------------------------------------------------
  // Save the contents of introduceSemiJoinHere in order to be able to
  // detect whether a subquery transformation was performed while
  // processing one of the elements of this set.
  // ---------------------------------------------------------------------
  RelExpr * saveOrigPtr = introduceSemiJoinHere;
  // ---------------------------------------------------------------------
  // newJoin is allocated for referencing a SemiJoin or a Join that is
  // introduced by a subquery transformation.
  // Set its initial value to be the contents of introduceSemiJoinHere.
  // ---------------------------------------------------------------------
  RelExpr * newJoin = (RelExpr *) introduceSemiJoinHere.getPtr();
  // ---------------------------------------------------------------------
  // newExpr will contain the ValueIds of new expressions that are
  // introduced by the normalizing transformations that are performed
  // during the transformation phase of query normalization.
  // ---------------------------------------------------------------------
  ValueIdSet newExpr;
  // ---------------------------------------------------------------------
  // Iterate over all the values (scalar expressions) in this set.
  // ---------------------------------------------------------------------
  for (ValueId exprId = init(); next(exprId); advance(exprId))
    {
      ItemExpr *iePtr = exprId.getItemExpr();  // original expr.
      ExprValueId nePtr(iePtr);                // normalized expr.
      // -----------------------------------------------------------------
      // Transform the Item Expression.
      // -----------------------------------------------------------------
      iePtr->getReplacementExpr()->transformNode(normWARef, nePtr,
      						 introduceSemiJoinHere,
			   			 externalInputs);
      // -----------------------------------------------------------------
      // If the original expression was transformed ..
      // -----------------------------------------------------------------
      if (nePtr != (const ItemExpr *)iePtr)
	{
	  // -------------------------------------------------------------
	  // Delete the original expression from this set.
	  // -------------------------------------------------------------
	  subtractElement(exprId);
	  // -------------------------------------------------------------
	  // If the original expression was not eliminated by transformation,
          // then if its replacement is an unconditional True, eliminate it now
	  // otherwise, accumulate the replacement in the set newExpr.
	  // -------------------------------------------------------------
	  if (nePtr.getPtr())
	  {
	    if (nePtr.getPtr()->getOperatorType() == ITM_RETURN_TRUE &&
		nePtr.getPtr()->getArity() == 0)
	      nePtr = NULL;
	    else
        {
              // Make sure selectivity hint information is carried over correctly.
              if(iePtr->isSelectivitySetUsingHint())
              {
                nePtr.getPtr()->setSelectivitySetUsingHint();
                nePtr.getPtr()->setSelectivityFactor(iePtr->getSelectivityFactor());
              }

                // See if UDF_SUBQ_IN_AGGS_AND_GBYS is enabled. It is
                // enabled if the default is ON, or if the default is
                // SYSTEM and ALLOW_UDF is ON.
                NABoolean udfSubqInAggGrby_Enabled = FALSE;
                DefaultToken udfSubqTok =
                  CmpCommon::getDefault(UDF_SUBQ_IN_AGGS_AND_GBYS);
                if ((udfSubqTok == DF_ON) ||
                    (udfSubqTok == DF_SYSTEM))
                  udfSubqInAggGrby_Enabled = TRUE;

                if (!udfSubqInAggGrby_Enabled)
                  nePtr->convertToValueIdSet(newExpr);
                else
                  // Since we can have UDFs or Subqueries in the group by
                  // we now can get an ITM_ITEM_LIST back from a transformation
                  // of a MVF or multi-degree subqueries. So we have to
                  // flatten any such itemExpr
                  nePtr->convertToValueIdSet(newExpr, NULL,
                                             ITM_AND, TRUE, TRUE/*flattenlist*/);
        }
       }
      }
      // -----------------------------------------------------------------
      // If a subquery transformation has introduced a new Join ...
      // -----------------------------------------------------------------
      if (introduceSemiJoinHere.getPtr() != newJoin)
        {
	  // -------------------------------------------------------------
	  // Get addressability to the new Join node.
	  // -------------------------------------------------------------
          newJoin = (RelExpr *) introduceSemiJoinHere.getPtr();
	  // -------------------------------------------------------------
          // Note that it is possible to encounter a subquery in each
	  // scalar expression that is processed per iteration of the loop.
          // Hence, introduceSemiJoinHere can contain a different
          // SemiJoin or a Join per iteration of the loop. Therefore, the
	  // movement of predicates must be done inside the loop.
	  // -------------------------------------------------------------
          if (movePredicates)
            {               // this ValueIdSet represents a predicate tree
	      // ---------------------------------------------------------
	      // If the subquery predicate is buried in a complex
	      // expression, such as T1.x = 10 OR EXISTS ( ... ), then
	      // the predicate that replaces the subquery cannot be moved
	      // independently. The entire expression in which it is
	      // contained must be moved. Delete the original expression
	      //  from this set.
	      // ---------------------------------------------------------
              subtractElement(exprId);

              if (nePtr.getPtr())
                {                    // if the subquery was not eliminated
		  // -----------------------------------------------------
                  // Remove the expression that replaces the subquery
                  // predicate (*nePtr) from newExpr because it will be
		  // evaluated as a member of another expression tree.
		  // -----------------------------------------------------
                  newExpr -= nePtr->getValueId();
		  // -----------------------------------------------------
                  // Add it to newJoin (the SemiJoin or Join) node that
                  // was introduced by the subquery transformation.
		  // -----------------------------------------------------
		  ValueIdSet transformedExpr;
		  nePtr->convertToValueIdSet(transformedExpr,
					     NULL, ITM_AND, FALSE);

                  //--------------------------------------------------------
                  // Generator does not know how to transmit
                  // ONE_ROW of columns yet from a child to its parent. So do not
                  // ask for it. One Row check is already performed at the
                  // concerned GroupBy node.
                  //--------------------------------------------------------

                  transformedExpr.replaceOneRowbyList( normWARef );

                  if (newJoin->getOperator().match(REL_ANY_SEMIJOIN))
                    ((Join *)newJoin)->joinPred() += transformedExpr;	  // ON clause
                  else
                    newJoin->selectionPred() += transformedExpr;
		  // -----------------------------------------------------
		  // Compute the additional set of external inputs that
		  // should be supplied to newJoin so that the expression
		  // that replaces the subquery predicate (*nePtr) can
		  // be evaluated.
		  // -----------------------------------------------------
                  ValueIdSet neededValues(externalInputs);
                  ValueIdSet outputValues;
                  newJoin->getPotentialOutputValues(outputValues);
                  neededValues -= outputValues;
		  // -----------------------------------------------------
                  // neededValues contains the external inputs. Remove
                  // all those values from it that are not referenced
		  // by the expression that replaces the subquery
		  // predicate (*nePtr).
		  // -----------------------------------------------------
                  transformedExpr.weedOutUnreferenced(neededValues);
                  newJoin->getGroupAttr()->addCharacteristicInputs(neededValues);
                }                    // if the subquery was not eliminated
            }               // this ValueIdSet represents a predicate tree
          else
            {
	      // ---------------------------------------------------------
              // If we are not moving predicates, newJoin should not be
              // a SemiJoin. This is because a SemiJoin can only be
	      // introduced by the transformation of a subquery predicate.
	      // ---------------------------------------------------------
              CMPASSERT(NOT newJoin->getOperator().match(REL_ANY_SEMIJOIN));
            }
        }                      // if (introduceSemiJoinHere != newJoin)
      // -----------------------------------------------------------------
      // If the given predicates are post-join predicates, i.e., they
      // are evaluated after the join is performed, check whether a
      // left join can be converted to an inner join by the transformed
      // predicate. The check initiates the transformation of a left
      // join to an inner join as a side effect.
      // -----------------------------------------------------------------
      if (postJoinPredicates)
	{
	ValueIdSet outerReferences;
	newJoin->getGroupAttr()->getCharacteristicInputs().
					getOuterReferences(outerReferences);
	if (nePtr != (const ItemExpr *)iePtr)
	  {
	    if (nePtr.getPtr()) // transformation hasn't eliminated it
	      nePtr->predicateEliminatesNullAugmentedRows(normWARef, outerReferences);
	  }
	else
	  iePtr->predicateEliminatesNullAugmentedRows(normWARef, outerReferences);
	}
      // ---------------------------------------------------------------------
      // try conditionally eliminate LJ even for join preds.  The code
      // in the else clause pretty much resembles the code in predicateElim-
      // inateNullAugmentRows(). The only difference is due to the nature of
      // join predicate, we need to check for whether the instantiate null
      // value involved comes from the right before transforming the associated
      // left join into an inner join. The characteristics outputs from the
      // right child is needed to determine this. Ideally, this additional
      // parameter could be passed in predicateEliminateNullAugmentedRows()
      // so that the condition could be determined there. However, for now,
      // I don't have time to recompile a bunch of stuffs after changing a
      // header file. So,... promise to move this code into there after FCS.
      // ---------------------------------------------------------------------
      else
      {
        if (saveOrigPtr)
        {
          const ValueIdSet & outputs = saveOrigPtr->getGroupAttr()->
                                       getCharacteristicOutputs();
          ItemExpr *ie;
          if (nePtr != (const ItemExpr *)iePtr)
          {
            if (nePtr.getPtr()) // transformation hasn't eliminated it
              ie = nePtr.getPtr();
            else
              ie = NULL;
          }
          else ie = iePtr;

          if (ie)
          {
            // emulate predicateEliminatesNullAugmentedRows() in BiRelat
            //

            NABoolean isFOJ = FALSE;
            if (normWARef.getCurrentOwnerExpr())
              isFOJ = (normWARef.getCurrentOwnerExpr()
                        ->getOperatorType() == REL_FULL_JOIN);

            if ( (NOT normWARef.walkingAnExprTree()) AND
                 (NOT isFOJ) AND
                 (ie->getOperatorType() == ITM_EQUAL OR
                  ie->getOperatorType() == ITM_NOT_EQUAL OR
                  ie->getOperatorType() == ITM_LESS OR
                  ie->getOperatorType() == ITM_LESS_EQ OR
                  ie->getOperatorType() == ITM_GREATER OR
                  ie->getOperatorType() == ITM_GREATER_EQ) )
            {
              if (ie->child(0)->getOperatorType() == ITM_INSTANTIATE_NULL)
              {
                InstantiateNull *inst =
                       (InstantiateNull *)(ie->child(0)->castToItemExpr());
                if (NOT inst->NoCheckforLeftToInnerJoin)
                {
                  // Only for values coming from right hand side.
                  //
                  if (outputs.contains(ie->child(0)->getValueId()))
                  {
                    ie->child(0) = ie->child(0)->
                          initiateLeftToInnerJoinTransformation(normWARef);
                  }
                }
              }
              if (ie->child(1)->getOperatorType() == ITM_INSTANTIATE_NULL)
              {
                InstantiateNull *inst =
                       (InstantiateNull *)(ie->child(1)->castToItemExpr());
                if (NOT inst->NoCheckforLeftToInnerJoin)
                {
                  // Only for values coming from right hand side.
                  //
                  if (outputs.contains(ie->child(1)->getValueId()))
                  {
                    ie->child(1) = ie->child(1)->
                          initiateLeftToInnerJoinTransformation(normWARef);
                  }
                }
              }
            } // end of emulation of predicateEliminatesNullAugmentedRows()
          } // if(ie)
        } // endif(saveOrigPtr)
      }   // endif(postJoinPredicates)

    } // loop over given expressions

  addSet(newExpr); // add transformed expressions to the given set

  // Indicate whether a subquery was transformed to the caller.
  return (introduceSemiJoinHere != (const RelExpr *)saveOrigPtr);

} // ValueIdSet::transformNode()

// -----------------------------------------------------------------------
// Method for applying normalizeNode() to a ValueIdSet.
// -----------------------------------------------------------------------
NABoolean ValueIdSet::normalizeNode(NormWA & normWARef)
{
  NABoolean transformed = FALSE;
  ValueIdSet newExpr;
  ItemExpr * nePtr;                      // normalized expr.
  for (ValueId exprId = init(); next(exprId); advance(exprId) )
    {
      ItemExpr *iePtr = exprId.getItemExpr();  // original expr.
      // Transform the Item Expression.
      nePtr = iePtr->getReplacementExpr()->normalizeNode(normWARef);
      // If the original expression was transformed, remember transformed ids
      if ( nePtr != iePtr ||
           nePtr->getValueId() != exprId )
	{
	  transformed = TRUE;

	  // Need to set selectivity correctly when JOIN predicate (t1.a = t2.a) is eliminated:
	  // select * from t1, t2 where t1.a = t2.a <<+ selectivity 10e-3 >> and t1.a = 3;
	  if(iePtr->isSelectivitySetUsingHint() &&
	     nePtr->getOperatorType() == ITM_VEG_PREDICATE )
	  {
	    VEG * predVEG = ((VEGPredicate *)nePtr)->getVEG();
	    const ValueIdSet & VEGGroup = predVEG->getAllValues();
	    ItemExpr *constant = NULL;
	    if(VEGGroup.referencesAConstValue(&constant) ||
	       VEGGroup.referencesAConstExpr(&constant))
	    {
              ValueIdSet cols;
	      nePtr->findAll(ITM_BASECOLUMN, cols, TRUE, TRUE);

	      CollIndex tblCount = cols.getAllTables()->entries();
	      if(tblCount > 0)
	      {
		// The following line is to make sure selectivity pushed down to Scan will result
		// in cumulative selectivity equal to that specifed originally by the user.In the
		// example above, the selectivity pushed down will be pow(sel, 1/2) = sqrt(0.01) = 0.1.
		double selFactor = pow(iePtr->getSelectivityFactor(), ((double)1/tblCount));
		nePtr->setSelectivitySetUsingHint();
		nePtr->setSelectivityFactor(selFactor);
	      }
	    }
	  }
	  subtractElement(exprId); // delete original expression from set
	  // accumulate new expressions in another set
	  if (nePtr)
	    nePtr->convertToValueIdSet(newExpr);
	}
    } // loop over given expressions

  addSet(newExpr); // add transformed expressions to the given set

  return transformed;
} // ValueIdSet::normalizeNode

// -----------------------------------------------------------------------
// lookForVEGReferences()
// Accumulate ValueIds of VEGReferences, if any, in vs.
// -----------------------------------------------------------------------
void ValueIdSet::lookForVEGReferences(ValueIdSet & VEGRefSet) const
{
  for (ValueId vid = init(); next(vid); advance(vid))
    {
      if (vid.getItemExpr()->getOperatorType() == ITM_VEG_REFERENCE)
        VEGRefSet += vid;
    }
} // ValueIdSet::lookForVEGReferences

// *this is a set of (join) equality predicates.
// grcols is a set of group by columns.
// if c is in grcols and c is an opd of an equality predicate then
// add the equality's other opd to grcols.
void ValueIdSet::introduceMissingVEGRefs(ValueIdSet & grcols) const
{
  // iterate over the equality predicates
  for (ValueId vid = init(); next(vid); advance(vid))
    {
      if (vid.getItemExpr()->getOperatorType() == ITM_EQUAL)
        {
          BiRelat *eq = (BiRelat*)vid.getItemExpr();
          ValueId v0, v1;
          if (eq->child(0)->getOperatorType() == ITM_VEG_REFERENCE)
            v0 = eq->child(0)->getValueId();
          if (eq->child(1)->getOperatorType() == ITM_VEG_REFERENCE)
            v1 = eq->child(1)->getValueId();
          // if left child is in grcols then add right child to grcols
          if (grcols.containsTheGivenValue(v0) AND v1 != NULL_VALUE_ID)
            {
              grcols += v1;
            }
          // if right child is in grcols then add left child to grcols
          else if (grcols.containsTheGivenValue(v1) AND v0 != NULL_VALUE_ID)
            {
              grcols += v0;
            }
        }
    }
}

// -----------------------------------------------------------------------
// lookForVEGPredicates()
// Accumulate ValueIds of VEGPredicates, if any, in vs.
// -----------------------------------------------------------------------
void ValueIdSet::lookForVEGPredicates(ValueIdSet & VEGPredSet) const
{
  for (ValueId vid = init(); next(vid); advance(vid))
    {
      if (vid.getItemExpr()->getOperatorType() == ITM_VEG_PREDICATE)
        VEGPredSet += vid;
    }
} // ValueIdSet::lookForVEGPredicates

// return TRUE iff this has no equality predicates at all
// put in joinCols the simple base columns being equijoined
// given "a-1=b and c=d+1", joinCols should get "b,c"
NABoolean ValueIdSet::hasNoEquiPredicates(ValueIdSet& joinCols) const
{
  NABoolean result = TRUE; // until proven otherwise
  if (entries() <= 0)
    return result; // has no predicates at all

  for (ValueId vid = init(); next(vid); advance(vid))
    {
      ItemExpr *expr = vid.getItemExpr();
      switch (expr->getOperatorType())
        {
        case ITM_VEG_PREDICATE:
          // given equi-predicate "a=b", add "a,b" to joinCols
          expr->findAll(ITM_BASECOLUMN, joinCols, TRUE, TRUE);
          result = FALSE; // has at least one equality predicate
          break;
        case ITM_EQUAL:
          // given equi-predicate "a=b+1", add "a" to joinCols
          if (expr->child(0)->getOperatorType() == ITM_VEG_REFERENCE)
            expr->child(0)->findAll(ITM_BASECOLUMN, joinCols, TRUE, TRUE);
          // given equi-predicate "a-1=b", add "b" to joinCols
          if (expr->child(1)->getOperatorType() == ITM_VEG_REFERENCE)
            expr->child(1)->findAll(ITM_BASECOLUMN, joinCols, TRUE, TRUE);
          result = FALSE; // has at least one equality predicate
          break;
        default:
          continue; // keep looking
        }
    }
  return result;
} // ValueIdSet::isAllEquiPredicates

NABoolean ValueIdSet::containsAsEquiLocalPred(ValueId x) const
{
  NABoolean result = FALSE; // until proven otherwise
  if (entries() <= 0)
    return result; // has no predicates at all

  ItemExpr* constExpr = NULL;

  NABoolean found = FALSE;

  for (ValueId vid = init(); next(vid); advance(vid))
    {
      ItemExpr *expr = vid.getItemExpr();
      switch (expr->getOperatorType())
        {
        case ITM_VEG_PREDICATE:
          {
           ValueIdSet vegMembers =
               ((VEGPredicate*)expr)->getVEG()->getAllValues();

           return (vegMembers.contains(x) &&
                   vegMembers.referencesAConstExpr(&constExpr));
          }
          break;

        case ITM_EQUAL:

          // consider equi-predicate "a=1", or "1=a"
          for (CollIndex i=0; i<2; i++ ) {
             if ( expr->child(i)->getOperatorType() == ITM_VEG_REFERENCE )
             {
               ItemExpr* childExpr = expr->child(i);
               found = ((VEGReference*)(childExpr))->getVEG()
                                   ->getAllValues().contains(x);

             } else
                 found = (expr->child(i) == x);

             if (found) {

               CollIndex j = (i==0) ? 1 : 0;
               ValueIdSet vset(expr->child(j));
               if ( vset.entries() == 1 &&
                    vset.referencesAConstExpr(&constExpr) == TRUE )
                  return TRUE;

             }
          }

          break;

        default:
          return FALSE;
        }
    }
  return result;

} // ValueIdSet::containsAsEquiPred()

void ValueIdSet::insertList(const ValueIdList &other)
{
  for (CollIndex i = 0; i < other.entries(); i++)
    insert(other[i]);
}

// -----------------------------------------------------------------------
// isCovered()
// Returns TRUE only if ALL the members of the set are covered.
// -----------------------------------------------------------------------
NABoolean ValueIdSet::isCovered(const ValueIdSet & newExternalInputs,
		                const GroupAttributes & coveringGA,
		                ValueIdSet & referencedInputs,
		                ValueIdSet & coveredSubExpr,
				ValueIdSet & unCoveredExpr) const
{
  NABoolean coverFlag, exprIsCovered = TRUE;

  for (ValueId exprId = init(); next(exprId); advance(exprId))
    {
      // Perform the coverage test for each ItemExpr.
      // This set is covered if EVERY ItemExpr that belongs to it isCovered.
      coverFlag = coveringGA.covers(exprId,
				    newExternalInputs,
				    referencedInputs,
				    &coveredSubExpr,
				    &unCoveredExpr);
      if (coverFlag)
	coveredSubExpr += exprId;
      exprIsCovered &= coverFlag;
    } // for

  return exprIsCovered;

} // ValueIdSet::isCovered()

// ------------------------------------------------------------------------
// ValueIdSet::removeCoveredExprs()
//
// Removes from the valueid set those expressions that are
// covered by the available values
// ------------------------------------------------------------------------

void ValueIdSet::removeCoveredExprs(const ValueIdSet & newExternalInputs,
                                    ValueIdSet* usedInputs)
{
  NABoolean coverFlag;
  ValueIdSet referencedInputs;
  GroupAttributes emptyGA;

  emptyGA.setCharacteristicOutputs(newExternalInputs);
  for (ValueId exprId = init(); next(exprId); advance(exprId))
    {
      if (exprId.getItemExpr()->getOperatorType() == ITM_VEG_PREDICATE)
        {
          VEG * vegPtr = ((VEGPredicate *)(exprId.getItemExpr()))->getVEG();
          coverFlag = emptyGA.covers(vegPtr->getVEGReference()->getValueId(),
                                     newExternalInputs,
                                     referencedInputs);
        }
      else
        coverFlag = emptyGA.covers(exprId,
                                   newExternalInputs,
                                   referencedInputs);
      if (coverFlag) {
	subtractElement(exprId);
        if (usedInputs)
          *usedInputs = referencedInputs ;
      }
    } // for
} // ValueIdSet::removeCoveredExprs

// ------------------------------------------------------------------------
// ValueIdSet::removeUnCoveredExprs()
//
// Removes from the valueid set those expressions that are
// NOT covered by the available values
// ------------------------------------------------------------------------

void ValueIdSet::removeUnCoveredExprs(const ValueIdSet & newExternalInputs)
{
  NABoolean coverFlag;
  ValueIdSet referencedInputs;
  GroupAttributes emptyGA;

  emptyGA.setCharacteristicOutputs(newExternalInputs);
  for (ValueId exprId = init(); next(exprId); advance(exprId))
    {
      if (exprId.getItemExpr()->getOperatorType() == ITM_VEG_PREDICATE)
        {
          VEG * vegPtr = ((VEGPredicate *)(exprId.getItemExpr()))->getVEG();
          coverFlag = emptyGA.covers(vegPtr->getVEGReference()->getValueId(),
                                     newExternalInputs,
                                     referencedInputs);
        }
      else
        coverFlag = emptyGA.covers(exprId,
                                   newExternalInputs,
                                   referencedInputs);
      if (!coverFlag)
	subtractElement(exprId);
    } // for
} // ValueIdSet::removeUnCoveredExprs

// ---------------------------------------------------------------------
// simplifyOrderExpr()
//
//  Returns a version of the set that has all expressions involving
// columns and constants or columns and inverse nodes simplified to be
// the column only.
// ---------------------------------------------------------------------
ValueIdSet ValueIdSet::simplifyOrderExpr() const
{
  ValueIdSet simpleVidSet;
  for (ValueId vid = init();
                     next(vid);
                     advance(vid))
  {
    simpleVidSet +=
      vid.getItemExpr()->simplifyOrderExpr()->getValueId();
  }

  return simpleVidSet;
}

// ---------------------------------------------------------------------
// removeInverseOrder()
//
//  Returns a version of the set that has all expressions involving
// columns and inverse nodes simplified to be the column only.
// ---------------------------------------------------------------------
ValueIdSet ValueIdSet::removeInverseOrder() const
{
  ValueIdSet noInverseVidSet;
  for (ValueId vid = init();
                     next(vid);
                     advance(vid))
  {
    noInverseVidSet +=
      vid.getItemExpr()->removeInverseOrder()->getValueId();
  }

  return noInverseVidSet;
}

// ---------------------------------------------------------------------
// findCommonSubexpressions()
//
// Find common subexpression between "this" and "other". Remove all
// value ids that are not common subexpressions from "this" (so that
// "this" contains the common subexpressions). Optionally, remove
// the common subexpressions from "other" (note that those don't need
// to have the same value ids, just be equivalent).
// ---------------------------------------------------------------------
void ValueIdSet::findCommonSubexpressions(ValueIdSet &other,
					  NABoolean removeCommonExprFromOther)
{
  ValueIdList otherList;
  CollIndex otherNumEntries;
  LIST(HashValue) otherHashValues;
  ValueId vid;
  CollIndex j;
  HashValue hashVal;

  otherList.insertSet(other);
  otherNumEntries = otherList.entries();

  // This is an n**2 (really n * m) algorithm, but for realistic cases
  // it should be good enough. To avoid performance problems, exit
  // this method for very large sets (suggested to use a hash
  // table of the hash values if this ever becomes a problem)
  if (entries() * otherNumEntries > 2000)
    {
      clear();
      return;
    }

  // make hash values for the other set
  for (j=0; j<otherNumEntries; j++)
    {
      otherHashValues.insert(otherList[j].getItemExpr()->treeHash());
    }

  // Go through my set and hash each member. If we find it, do a precise
  // comparison using duplicateMatch. Otherwise, delete the member.
  for (vid=init(); next(vid); advance(vid))
    {
      NABoolean found = FALSE;

      hashVal = vid.getItemExpr()->treeHash();
      for (j=0; j<otherNumEntries; j++)
	{
	  if (otherHashValues[j] == hashVal)
	    if (vid.getItemExpr()->duplicateMatch(
		     *(otherList[j]).getItemExpr()))
	      {
		found = TRUE;
		break;
	      }
	}

      if (found)
	{
	  // found a common subexpression
	  if (removeCommonExprFromOther)
	    other -= otherList[j];
	}
      else
	{
	  // didn't find a common subexpression, remove element from my set
	  *this -= vid;
	}
    }
}

// ---------------------------------------------------------------------
// Build predicate like the originals in the set, that substitues the
// given column reference with a computed column and the corresponding
// computed column expression.
//
// For example:
// predicate is : A = 2
// computed Column is: SQR
// computed Column expr is: POWER(A, 2)
// Then this method will return a ValueIdSet that contains
// a predicate that looks like this:
//    SQR = POWER(VEG(A,2),2)
// ---------------------------------------------------------------------
ValueIdSet ValueIdSet::createMirrorPreds(ValueId &computedCol,
                                         ValueIdSet underlyingCols)
{
  ValueIdSet newComputedPreds;
  ItemExpr *iePtr = computedCol.getItemExpr();

  CMPASSERT( iePtr->getOperatorType() == ITM_BASECOLUMN );

  ItemExpr *compExpr = ((BaseColumn *) iePtr)->getComputedColumnExpr().getItemExpr();
  ItemExpr *prevPred = NULL;

  for (ValueId kpv = init(); next(kpv); advance(kpv))
   {
     ItemExpr *piePtr = kpv.getItemExpr();
     switch (piePtr->getOperatorType())
       {
         case ITM_VEG_PREDICATE:
         case ITM_EQUAL:
         case ITM_LESS:
         case ITM_LESS_EQ:
         case ITM_LESS_OR_LE:
         case ITM_GREATER:
         case ITM_GREATER_EQ:
         case ITM_GREATER_OR_GE:
           {
             ItemExpr * newPred = piePtr->createMirrorPred(iePtr, compExpr, underlyingCols);
             if (newPred != NULL)
               {
                 // look for the following pattern, which is common
                 // when a range of values falls within one division
                 // col1 >= const1 AND col1 <= const1
                 // and transform this into the single predicate col1 = const1
                 if (prevPred)
                   {
                     OperatorTypeEnum prevOp = prevPred->getOperatorType();
                     OperatorTypeEnum newOp = newPred->getOperatorType();
                     NABoolean neg1, neg2;
                     ConstValue *prevConst = prevPred->child(1)->castToConstValue(neg1);
                     ConstValue *newConst = newPred->child(1)->castToConstValue(neg2);

                     if ((prevOp == ITM_GREATER_EQ && newOp  == ITM_LESS_EQ ||
                          newOp  == ITM_GREATER_EQ && prevOp == ITM_LESS_EQ) &&
                         prevPred->child(0) == newPred->child(0) &&
                         prevConst && newConst &&
                         prevConst->duplicateMatch(*newConst) && neg1 == neg2 &&
                         static_cast<BiRelat *>(prevPred)->getSpecialNulls() ==
                         static_cast<BiRelat *>(newPred)->getSpecialNulls())
                       {
                         // make the <= or >= predicate of the pattern into an = predicate
                         BiRelat *newEqualPred = new(CmpCommon::statementHeap())
                           BiRelat(ITM_EQUAL,
                                   newPred->child(0),
                                   newPred->child(1));
                         newEqualPred->setSpecialNulls(
                              static_cast<BiRelat *>(newPred)->getSpecialNulls());
                         newEqualPred->synthTypeAndValueId();

                         newComputedPreds -= prevPred->getValueId();
                         newPred = newEqualPred;
                       }
                   }

                 newComputedPreds += newPred->getValueId();
                 prevPred = newPred;
               }
             break;
           }
         case ITM_ASSIGN:
         default:
            // XXX Don't expect this case to ever happen
           CMPASSERT(0); // LCOV_EXCL_LINE
           break;
       }
   }
   return newComputedPreds;
}

// -----------------------------------------------------------------------
// Method for rebuilding a predicate tree from a ValueIdSet.
// -----------------------------------------------------------------------
ItemExpr * ValueIdSet::rebuildExprTree
                           (OperatorTypeEnum op,
                            NABoolean redriveTypeSynthesisFlag,
			    NABoolean createFinalizeResultNode) const
{
  ValueIdList vidList;
  vidList.insertSet(*this);
  return vidList.rebuildExprTree(op,
				 redriveTypeSynthesisFlag,
				 createFinalizeResultNode);

} // ValueIdSet::rebuildExprTree()

// -----------------------------------------------------------------------
// ValueIdSet::replaceVEGExpressionsAndCopy()
// The wildcard expansion is limited to the VEGReferences that are
// found in this set. There is no attempt to traverse ItemExpr
// trees in order to replace VEGReferences that are not at the
// root.
// -----------------------------------------------------------------------
void ValueIdSet::replaceVEGExpressionsAndCopy
                    (const ValueIdSet & setContainingWildCards)
{
  clear();
  for (ValueId vid = setContainingWildCards.init();
       setContainingWildCards.next(vid);
       setContainingWildCards.advance(vid))
    {
      if (vid.getItemExpr()->getOperatorType() == ITM_VEG_REFERENCE)
        {
          // For an expression that is a VegRef, we invoke
          // VEG::getAndExpandAllValues(). That routine traverses
          // expression tree only for VegReferences at root.
          // (case 10-001201-9972: changed the following to prevent an
          // infinite loop)

          ValueIdSet recurse;

          ((VEGReference *)(vid.getItemExpr()))->
             getVEG()->getAndExpandAllValues(recurse);

	  addSet(recurse);
        }
      else
	addElement(vid);
    }
} // ValueIdSet::replaceVEGExpressionsAndCopy()

// -----------------------------------------------------------------------
// ValueIdSet::getUnReferencedVEGmembers()
//   Called only from preCodeGen. Gets all the VEG members that
//   have not been bound yet.
// -----------------------------------------------------------------------
void ValueIdSet::getUnReferencedVEGmembers
                    (const ValueIdSet & setContainingWildCards)
{
  clear();
  for (ValueId vid = setContainingWildCards.init();
       setContainingWildCards.next(vid);
       setContainingWildCards.advance(vid))
    {
      if (vid.getItemExpr()->getOperatorType() == ITM_VEG_REFERENCE)
        {
          VEGReference * vegRef = ((VEGReference *)(vid.getItemExpr()));

          ValueIdSet unReferencedValues;
          unReferencedValues.replaceVEGExpressionsAndCopy(vegRef->getVEG()->getAllValues());
          unReferencedValues -= vegRef->getVEG()->getReferencedValues();

          addSet(unReferencedValues);
        }
      else
        addElement(vid);
    }
} // ValueIdSet::getUnReferencedVEGmembers()

// -----------------------------------------------------------------------
// ValueIdSet::replaceVEGExpressions()
//
// This method is used by the code generator for rewriting
// expressions that belong to a ValueIdSet. A reference to
// a VEG, i.e., a ValueId Equality Group is replaced with
// an expression that belongs the VEG as well as to the
// set of availableValues that is supplied.
// -----------------------------------------------------------------------
void ValueIdSet::replaceVEGExpressions
                    (const ValueIdSet & availableValues,
                     const ValueIdSet & inputValues,
                     NABoolean thisIsAKeyPredicate,
                     VEGRewritePairs * lookup,
                     NABoolean replicateExpression,
                     const ValueIdSet * outputExpr,
                     const ValueIdSet * joinInputAndPotentialOutput,
                     const IndexDesc * iDesc,
                     const GroupAttributes * left_ga,
                     const GroupAttributes * right_ga)
{
  ValueIdSet newExpr;
  ItemExpr * iePtr;
  NABoolean savedReplicateExpression = replicateExpression ;
  // ---------------------------------------------------------------------
  // Iterate over the predicate factors in the given predicate tree.
  // ---------------------------------------------------------------------
  for (ValueId exprId = init(); next(exprId); advance(exprId))
    {
      if (outputExpr && outputExpr->containsTheGivenValue(exprId))
        replicateExpression = FALSE;
      // -----------------------------------------------------------------
      // Walk through the item expression tree and replace any
      // VEGPredicates or VEGReferences that are found.
      // -----------------------------------------------------------------
      // Modifying for core/TEST029 since copyTopNode() not available for VEG_Reference
      if(CmpCommon::getDefault(RANGESPEC_TRANSFORMATION) == DF_ON &&
	 exprId.getItemExpr()->getOperatorType() == ITM_RANGE_SPEC_FUNC)
      {
	iePtr = exprId.getItemExpr()->child(1)->replaceVEGExpressions(availableValues,
                                                                inputValues,
                                                                thisIsAKeyPredicate,
                                                                lookup,
                                                                replicateExpression,
                                                                joinInputAndPotentialOutput,
                                                                iDesc,
                                                                left_ga,
                                                                right_ga);
      }
      else
      {
	iePtr = exprId.getItemExpr()->replaceVEGExpressions(availableValues,
                                                      inputValues,
                                                      thisIsAKeyPredicate,
                                                      lookup,
                                                      replicateExpression,
                                                      joinInputAndPotentialOutput,
                                                      iDesc,
                                                      left_ga,
                                                      right_ga);
      }

      replicateExpression = savedReplicateExpression;

      if (iePtr)			      // expression was not discarded
	{
	  if(!iePtr->nodeIsBound() || iePtr->isPreCodeGenNATypeChanged())
	    // redrive type synthesis for both self and child nodes
	    iePtr->synthTypeAndValueId(TRUE, TRUE);
          if (iePtr != exprId.getItemExpr())  // a replacement was done
	    {
	      subtractElement(exprId);        // remove existing ValueId
          //insert new expression(s)
          if (iePtr->getOperatorType() == ITM_AND)
              //The replacement of a RangeSpec could be an AND, convert ANDed predicates into additional values in newExpr.
              iePtr->convertToValueIdSet(newExpr, NULL, ITM_AND, FALSE, FALSE);
          else
              newExpr += iePtr->getValueId(); // replace with a new one
	    }
	}
      else // delete the ValueId of the VEGPredicate/VEGReference from the set
	subtractElement(exprId);
    } // loop over predTree

  addSet(newExpr); // add the replacement expressions

} // ValueIdSet::replaceVEGExpressions()

  // --------------------------------------------------------------------
  // ValueIdSet::getVEGesWithMultipleConsts()
  // This method accumulates those VEGes that have more than one constant
  // references in them
  // --------------------------------------------------------------------

  void ValueIdSet::getVEGesWithMultipleConsts(ValueIdSet & keyPredsToBeEvaluated)
  {
     for (ValueId exprId = init(); next(exprId); advance(exprId))
     {
       ItemExpr * vegItemExpr = exprId.getItemExpr();
       if ((vegItemExpr->getOperatorType() == ITM_VEG_PREDICATE)
	 || (vegItemExpr->getOperatorType() == ITM_VEG_REFERENCE))
       {
	 const VEG * predVEG = ((VEGPredicate *)vegItemExpr)->getVEG();
        // Now, get all members of the VEG group
        const ValueIdSet & VEGGroup = predVEG->getAllValues();
        if (VEGGroup.referencesConstExprCount() > 1)
	  keyPredsToBeEvaluated += exprId;
       }

     }
  }

// -----------------------------------------------------------------------
// ValueIdSet::replaceOperandsOfInstantiateNull()
// This method is used by the code generator for replacing the
// operands of an ITM_INSTANTIATE_NULL with a value that belongs
// to availableValues.
// -----------------------------------------------------------------------
void ValueIdSet::replaceOperandsOfInstantiateNull
                      (const ValueIdSet & availableValues,
                       const ValueIdSet & inputValues)
{
  for (ValueId exprId = init(); next(exprId); advance(exprId))
    {
      exprId.getItemExpr()->replaceOperandsOfInstantiateNull
	                      (availableValues,inputValues);
    }
} // ValueIdSet::replaceOperandsOfInstantiateNull()

// -----------------------------------------------------------------------
// weedOutUnreferenced(ValueIdSet & other)
// For each ValueId in other check whether it is referenced anywhere
// within an ItemExpr whose ValueId belongs to this set.
// -----------------------------------------------------------------------
void ValueIdSet::weedOutUnreferenced(ValueIdSet & other)
{
  ValueIdSet unrefSet;
  NABoolean notFound;

  // loop over other
  for ( ValueId otherId = other.init();
	other.next(otherId);
	other.advance(otherId) )
  {
    notFound = TRUE;

    const ValueId & otherId2 =
      otherId.getItemExpr()->getReplacementExpr()->getValueId();

    // loop over this
    for ( ValueId exprId = init(); next(exprId); advance(exprId) )
    {
      if ( exprId.getItemExpr()->referencesTheGivenValue(otherId2) )
      {
	notFound = FALSE;
	break;
      }
    } // iterator on this set
    if ( notFound )         // accumulate the ValueIds that are
      unrefSet += otherId;  // not referenced
  } // iterator on other

  // Delete unreferenced values from other.
  other -= unrefSet;

} // ValueIdSet::weedOutUnreferenced()

void ValueIdSet::weedOutNonEquiPreds()
{
  for (ValueId v = init(); next(v); advance(v))
    {
      if (v.getItemExpr()->getOperatorType() != ITM_VEG_PREDICATE &&
          v.getItemExpr()->getOperatorType() != ITM_EQUAL)
        *this -= v;
    }
}

// -----------------------------------------------------------------------
//  referencesAConstValue
//
//  Does this set references a constant either directly (or indirectly
//  thru a VEGReference)?
// -----------------------------------------------------------------------
NABoolean ValueIdSet::referencesAConstValue(ItemExpr ** constant) const
{
  for (ValueId id = init(); next(id); advance(id))
    {
      const ItemExpr *pred = id.getItemExpr();
      if (pred->getOperatorType() == ITM_CONSTANT)
	{
	  *constant = id.getItemExpr();
	  return TRUE;
	}
      else if (pred->getOperatorType() == ITM_VEG_REFERENCE)
      {
	const VEG * predVEG = ((VEGPredicate *)pred)->getVEG();

	if (predVEG->seenBefore())
	  return FALSE;

	predVEG->markAsSeenBefore();

        // Now, get all members of the VEG group
	ItemExpr *constant2;
        const ValueIdSet & VEGGroup = predVEG->getAllValues();
	if (VEGGroup.referencesAConstValue(&constant2))
	{
	  *constant = constant2;
	  predVEG->markAsNotSeenBefore();
	  return TRUE;
	}
	predVEG->markAsNotSeenBefore();
      }
    }
  return FALSE;
} // ValueIdSet::referencesAConstValue()

// -----------------------------------------------------------------------
//  referenceAConstExpr
//
//  This method is invoked to determine whether any element of the
//  valueidset contains a "constant expression", i.e. a constant,
//  host variable or a parameter.
// -----------------------------------------------------------------------
NABoolean ValueIdSet::referencesAConstExpr(ItemExpr** constExprPtr) const
{
  for (ValueId id = init(); next(id); advance(id))
    {
      const ItemExpr *pred = id.getItemExpr();

      //
	  //check if the item expr is a non-strict constant
	  //a strict constant is somethine like cos(1)
	  //where as cos(?p) can be considered a constant
	  //in the non-strict definition since it remains
      //constant for a given execution of a query
      if (pred->doesExprEvaluateToConstant(FALSE,TRUE))
	{
          if ( constExprPtr )
             *constExprPtr = id.getItemExpr();

	  return TRUE;
	}
      else if (pred->getOperatorType() == ITM_VEG_REFERENCE)
        {
          const VEG * predVEG = ((VEGPredicate *)pred)->getVEG();

	  // To avoid infinite loop for cases where a VEG references itself.
	  // get to each element of the VEG, only if it has not been seen
	  // before
	  if (predVEG->seenBefore() )
	    return FALSE;

	  predVEG->markAsSeenBefore();

	  // Now, get all members of the VEG group
	  const ValueIdSet & VEGGroup = predVEG->getAllValues();
	  if (VEGGroup.referencesAConstExpr(constExprPtr))
	    {
	      predVEG->markAsNotSeenBefore();
	      return TRUE;
	    }
	  predVEG->markAsNotSeenBefore();
        }
    }
  return FALSE;
} // referencesAConstExpr()

NABoolean ValueIdSet::doAllExprsEvaluateToConstant(NABoolean isStrict,
                                                   NABoolean considerVEG) const
{
  for (ValueId id = init(); next(id); advance(id))
    {
      const ItemExpr *pred = id.getItemExpr();
      if (!pred->doesExprEvaluateToConstant(isStrict,considerVEG))
        return FALSE;
    }
    return TRUE ;
} // doAllExprsEvaluateToConstant()

void ValueIdSet::removeConstExprReferences(NABoolean considerExpressions)
{
  for (ValueId id = init(); next(id); advance(id))
  {
    const ItemExpr *expr = id.getItemExpr();

    // we want to consider hostvars and parameters are consts
    NABoolean strict = FALSE;

    // we want to dig inside VEGREFS to see if there is an
    // equality with a constant
    NABoolean considerVEG = TRUE;

    if (expr->doesExprEvaluateToConstant(strict,considerVEG))
	  {
      subtractElement(id);
	  }
    else if (expr->getOperatorType() == ITM_VEG_REFERENCE)
    {
      const VEG * exprVEG = ((VEGReference *)expr)->getVEG();

      // Now, get all members of the VEG group, only if this VEG has not
	    // been seen before. This is to avoid infinite looping for cases
	    // where a VEG references itself
	    if (!exprVEG->seenBefore())
	    {
	      exprVEG->markAsSeenBefore();
        const ValueIdSet & VEGGroup = exprVEG->getAllValues();
        if (VEGGroup.referencesAConstExpr())
	      {
		      subtractElement(id);
	      }
	      exprVEG->markAsNotSeenBefore();
	    }
    }
  }
} // removeConstExprReferences()

// -----------------------------------------------------------------------
//  referenceConstExprCount
//
//  This method is invoked to determine how many elements of the
//  valueidset contains a "constant expression", i.e. a constant,
//  host variable or a parameter.
// -----------------------------------------------------------------------
Int32 ValueIdSet::referencesConstExprCount() const
{
  Int32 count = 0;
  for (ValueId id = init(); next(id); advance(id))
    {
      const ItemExpr *pred = id.getItemExpr();

    //
	//check if the item expr is a non-strict constant
	//a strict constant is somethine like cos(1)
	//where as cos(?p) can be considered a constant
	//in the non-strict definition since it remains
    //constant for a given execution of a query
    if (pred->doesExprEvaluateToConstant(FALSE,TRUE))
	{
	  count = count + 1;
	}
      else if (pred->getOperatorType() == ITM_VEG_REFERENCE)
        {
          const VEG * predVEG = ((VEGPredicate *)pred)->getVEG();
          // Now, get all members of the VEG group, only if this VEG has not
	  // been seen before. This is to avoid infinite looping for cases
	  // where a VEG references itself
	  if (!predVEG->seenBefore())
	  {
	    predVEG->markAsSeenBefore();
	    const ValueIdSet & VEGGroup = predVEG->getAllValues();
	    count = count + VEGGroup.referencesConstExprCount();
	    predVEG->markAsNotSeenBefore();
	  }
        }
    }
  return count;
} // referencesConstExprCount()

// -----------------------------------------------------------------------
// referenceAHostvariableorParam
//
// Checks if the valueidset is a veg predicate and if it contains a
// hostvariable, or param.
// referencesAConstValue() returns TRUE if the VEGGroup contains a constant
// referencesAConstExpr() returns TRUE if the VEGGroup contains a constant
// or a hostvar/dynamic parameter
// Thus, if referencesAConstExpr returns TRUE, but referencesAConstValue
// returns FALSE, then there's a hostvar, not a constant.
// -----------------------------------------------------------------------
// The patch is added to take care of the case when predicate is an equality
// predicate with column or vegref on the left side and CAST of dynamic
// parameter on the right side (TPCC Q7)

NABoolean ValueIdSet::referencesAHostvariableorParam() const
{
  for( ValueId id = init(); next(id); advance(id))
    {
       const ItemExpr * pred = id.getItemExpr();

       if ( pred->getOperatorType() == ITM_VEG_PREDICATE )
         {
           VEG * predVEG = ((VEGPredicate *)pred)->getVEG();

	   // Now, get all members of the VEG group, only if this VEG has not
	   // been seen before. This is to avoid infinite looping for cases
	   // where a VEG references itself
	   if (predVEG->seenBefore())
	    return FALSE;

	   predVEG->markAsSeenBefore();

	   const ValueIdSet & VEGGroup = predVEG->getAllValues();

	   // See if the VEG group contains a constant.
	   // NOTE:  A VEG group should not contain more than 1 constant; but if
	   //        that should happen, referencesAConstValue will return the first
	   //        constant found.

	   ItemExpr *constant = NULL;
	   NABoolean containsConstant  = VEGGroup.referencesAConstValue( &constant );
	   NABoolean containsConstExpr = VEGGroup.referencesAConstExpr();
	   NABoolean containsHostvar   = ( containsConstExpr && !containsConstant );

	   predVEG->markAsNotSeenBefore();
	   if(containsHostvar)
	     return TRUE;
         }

       if ( pred->getOperatorType() == ITM_EQUAL )
         {
           const ItemExpr *leftExpr  = pred->child(0);
           const ItemExpr *rightExpr = pred->child(1);

           const ValueId &leftChildVid  = leftExpr->getValueId();
           const ValueId &rightChildVid = rightExpr->getValueId();

          //check if the item expr is a non-strict constant
          //a strict constant is somethine like cos(1), CAST(1)
          //where as cos(?p), CAST(?p) can be considered a constant
          //in the non-strict definition since it remains
          //constant for a given execution of a query
          if ( leftExpr->doesExprEvaluateToConstant(FALSE) OR
	       rightExpr->doesExprEvaluateToConstant(FALSE) )
	  {
            return TRUE;
          }
       }
    }

  return FALSE;
}

ValueIdSet
ValueIdSet::replaceRangeSpecRefs() const
{
  // If not using rangespec, just return the original set.
  if (CmpCommon::getDefault(RANGESPEC_TRANSFORMATION) != DF_ON)
    return *this;

  ValueIdSet derangedPreds;
  ValueIdSet vs;
  ItemExpr* pred;

  // For each pred, it is a RangespecRef, add its expansion to the new set.
  // Otherwise, just add the pred itself to the new set.
  for (ValueId vid = init(); next(vid); advance(vid))
  {
    pred = vid.getItemExpr();
    if (pred->getOperatorType() == ITM_RANGE_SPEC_FUNC)
    {
      vs.clear();
      (static_cast<RangeSpecRef*>(pred))->getValueIdSetForReconsItemExpr(vs);
      derangedPreds += vs;
    }
    else
      // Add the predicate to the new set.
      derangedPreds += vid;
  }

  return derangedPreds;
}

ValueIdSet
ValueIdSet::removePredsWithHostVars() const
{
  ValueIdSet localPreds;
  localPreds.clear();

  // check if any predicate in this set is a host variable
  for( ValueId id = init(); next(id); advance(id))
  {
    if (id.getItemExpr()->referencesAHostVar())
    {
      // continue to evaluate next pred
      continue;
    }
    // else add the predicate to the new set
    localPreds.insert(id);
  }
  return localPreds;
}

// Return TRUE if any itemExpr is of Bignum type.
NABoolean ValueIdSet::referencesBignumNumericDataType() const
{
  for (ValueId id = init(); next(id); advance(id))
    {
      const ItemExpr *pred = id.getItemExpr();

      if (pred->getOperatorType() == ITM_VEG_REFERENCE)
        {
          const VEG * predVEG = ((VEGReference *)pred)->getVEG();
          // Now, get all members of the VEG group, only if this VEG has not
          // been seen before. This is to avoid infinite looping for cases
          // where a VEG references itself
          if (!predVEG->seenBefore())
          {
            predVEG->markAsSeenBefore();
            const ValueIdSet & VEGGroup = predVEG->getAllValues();
            NABoolean result = VEGGroup.referencesBignumNumericDataType();
            predVEG->markAsNotSeenBefore();
            if ( result == TRUE ) return TRUE;
          }
        }
      else if (pred->getOperatorType() == ITM_VEG_PREDICATE)
        {
          const VEG * predVEG = ((VEGPredicate *)pred)->getVEG();
          // Now, get all members of the VEG group, only if this VEG has not
          // been seen before. This is to avoid infinite looping for cases
          // where a VEG references itself
          if (!predVEG->seenBefore())
          {
            predVEG->markAsSeenBefore();
            const ValueIdSet & VEGGroup = predVEG->getAllValues();
            NABoolean result = VEGGroup.referencesBignumNumericDataType();
            predVEG->markAsNotSeenBefore();
            if ( result == TRUE ) return TRUE;
          }
        }
       else
        {
          const NAType * type = &(pred->getValueId().getType());

          if ( (type->getTypeQualifier() == NA_NUMERIC_TYPE &&
               ((const NumericType *)type)->isBigNum()) )
          {
              return TRUE;
          }

        }
    }
  return FALSE;
}
// ---------------------------------------------------------------------
// Remove any predicate with rolling columns from the
// set of predicates
// ---------------------------------------------------------------------
ValueIdSet
ValueIdSet::removePredsWithRollingCols(TableDesc *tdesc) const
{
  ValueIdSet localPreds;
  localPreds.clear();
  const TableAnalysis * ta = tdesc->getTableAnalysis();

  // it is not a table, so don't bother to call fetchCount
  if (!ta)
    return localPreds;

  // get all user columns of this table
  ValueIdSet usedCols = ta->getUsedCols();

  // traverse thru all predicates
  for( ValueId id = init(); next(id); advance(id))
  {
    // if the predicate is an equality or a range predicate
    // check to see if it is on a date column and if the constant
    // it is being compared to is greater than the value in the
    // histogram
    ItemExpr * pred = id.getItemExpr();
    OperatorTypeEnum op = pred->getOperatorType();

    // if it is not an equality or range pred, insert for evaluation by fetchCount
    if (!((op ==  ITM_VEG_PREDICATE ) ||
        (op ==  ITM_EQUAL) ||
        (op ==  ITM_NOT_EQUAL) ||
        (op ==  ITM_LESS) ||
        (op ==  ITM_LESS_EQ) ||
        (op ==  ITM_GREATER) ||
        (op ==  ITM_GREATER_EQ) ||
        (op == ITM_OR) ||
        (op == ITM_AND)))
    {
      localPreds.insert(id);
      continue;
    }

    // if the type of the predicate is month(col), dayofmonth(col) etc
    // then use fetchCount
    if ( (op != ITM_VEG_PREDICATE) &&
         ((pred->child(0)->getOperatorType() == ITM_EXTRACT_ODBC) ||
         (pred->child(0)->getOperatorType() == ITM_EXTRACT)) )
    {
      localPreds.insert(id);
      continue;
    }

    // get the column from the predicate
    ValueIdSet predCols;
    pred->findAll(ITM_BASECOLUMN, predCols, TRUE, TRUE);

    // from this column set extract columns of this table
    predCols = predCols.intersect(usedCols);
    if (predCols.entries() != 1)
    {
      // if there are more than one column from this table in the
      // predicate, use the predicate for fetchCount
      localPreds.insert(id);
      continue;
    }

    // there is only one column from this table in the predicate
    // check if it is date type
    ValueId colId;
    predCols.getFirst(colId);
    if (colId == NULL_VALUE_ID)
    {
      localPreds.insert(id);
      continue;
    }

    if (colId.getType().getTypeQualifier() != NA_DATETIME_TYPE )
    {
      localPreds.insert(id);
      continue;
    }

    // it is date type, get the constant value from the predicate
    ValueIdSet leafValues;
    pred->findAll(ITM_CONSTANT, leafValues, TRUE, TRUE);

    if(leafValues.entries() == 0)
    {
      // there is no constant in the predicate, insert the predicate for CTS
      localPreds.insert(id);
      continue;
    }

    // get the histogram for the column. If the histogram is fake
    // insert the predicate for evaluation
    ColStatsSharedPtr colStats = tdesc->getTableColStats().getColStatsPtrForColumn(colId);

    if(colStats == NULL)
    {
      // No histograms fetched for the predicate column, it could be a DDL query,
      // continue.
      continue;
    }

    if (colStats->isFakeHistogram())
    {
      // histogram is fake, so no need to comapre the values. Use fetchCount
      localPreds.insert(id);
      continue;
    }

    // for OR and AND, there could be more than one date values
    // go thru each date value, and if even one of them lies outside
    // histogram range, do not use fetchcount on that predicate

    NABoolean insertPred = TRUE;
    for (ValueId cid = leafValues.init();
                       leafValues.next(cid);
                       leafValues.advance(cid))
    {
      // from all the leaf values extract the constant value
      ItemExpr *constant = NULL;
      ValueIdSet cidSet(cid);
      cidSet.referencesAConstValue( &constant );

      // compare the constant value with the min and the max values of the histogram
      NABoolean neg = FALSE;
      ConstValue * cv = NULL;

      if (constant)
        cv = constant->castToConstValue(neg);
      else
        insertPred = FALSE;

      // get the encoded value of the constant if any
      EncodedValue val (UNINIT_ENCODEDVALUE) ;

      if (cv != NULL)
      {
        // get the encoded format for the constant
        val = EncodedValue (cv, neg);

        // valid constant, compare the value with the histogram range
        // if within the range use fetchCount, else use the rolling
        // column adjustment done by the histogram
        if ((val < colStats->getMinValue()) ||
          (val > colStats->getMaxValue()))
        {
          insertPred = FALSE;
          break;
        }
      }
    } // for all leafValues;
    if (insertPred)
    {
      localPreds.insert(id);
    }
  }
  return localPreds;
}

// -----------------------------------------------------------------------
// getColumnsForHistogram
//
// returns columns which are referred in the expressions containing constants,
// constant expressions or host variables
// --------------------------------------------------------------------------

ValueIdSet ValueIdSet::getColumnsForHistogram() const
{
  ValueIdSet result;
  result.clear();

  // traverse through all ValueIds, looking for VEG preds
  for (ValueId id = init(); next(id); advance(id))
  {
    VEG * predVEG = NULL;
    ItemExpr * expr = id.getItemExpr();

    // Presently we are considering only columns in vegPredicates
    // There could be cases where we have a Cast over a column.
    // Example, Cast(col1) = Cast(col2). In this case, the predicate is
    // not transformed into a VEG_PREDICATE, instead it remains as an
    // equality predicate. If we find cases where histograms for these
    // columns are not being picked up during synthEstLogProp. We should
    // revisit this code to add condition for ITM_EQUAL

    if ( expr->getOperatorType() == ITM_VEG_PREDICATE )
      predVEG = ((VEGPredicate *)expr)->getVEG();
    else
      continue ; // it is not a VEG predicate, so continue

    ValueIdSet columns;
    expr->findAll( ITM_BASECOLUMN, columns, TRUE, TRUE );

    // Now get all the base tables in this predicate

    // see if this column is being joined to a column of another table
    SET(TableDesc *) * tablesJoined = columns.getAllTables();
    if (tablesJoined->entries() > 1)
    {
      ValueId vegREF = predVEG->getVEGReference()->getValueId();
      result.insert(vegREF);
    }
  }

  return result;
}

void ValueIdSet::getConstants(ValueIdSet & addConstantsToThisSet, NABoolean includeCacheParams) const
{
  for (ValueId id = init(); next(id); advance(id))
    {
      const ItemExpr *pred = id.getItemExpr();
      if (pred->getOperatorType() == ITM_CONSTANT)
        addConstantsToThisSet += id;
      else
      if (includeCacheParams == TRUE && pred->getOperatorType() == ITM_CACHE_PARAM )
        addConstantsToThisSet += id;
    }
}

void ValueIdSet::getConstantExprs(ValueIdSet & addConstantExprsToThisSet,
				  NABoolean isStrict) const
{
  for (ValueId id = init(); next(id); advance(id))
    {
      ItemExpr *ie = id.getItemExpr();

      //
      //check if the item expr is a non-strict constant
      //a strict constant is somethine like cos(1)
      //where as cos(?p) can be considered a constant
      //in the non-strict definition since it remains
      //constant for a given execution of a query
      // if isStrict we look only for constants and not parameters and hostvars
      // However we still look for constants inside a VEG
      if (ie->doesExprEvaluateToConstant(isStrict,TRUE) OR
          ((ie->previousHostVar() == TRUE) && (NOT isStrict)))
        addConstantExprsToThisSet += id;
    }
}

// -----------------------------------------------------------------------
//  Get Outer References
// -----------------------------------------------------------------------
void ValueIdSet::getOuterReferences(ValueIdSet & OuterRefs) const
{
  NABoolean doNotInsert ;
  for (ValueId id = init(); next(id); advance(id))
    {
      const ItemExpr *pred = id.getItemExpr();
      doNotInsert = FALSE ;
      if (pred->getOperatorType() == ITM_VEG_REFERENCE)

      {
	ItemExpr *constant = NULL;
	const ValueIdSet & VEGGroup =((VEGReference *)pred)->getVEG()->getAllValues();
	if (VEGGroup.referencesAConstExpr(&constant))
	  doNotInsert = TRUE ;
      }
      else if (pred->isAUserSuppliedInput())
	doNotInsert = TRUE ;

      if (NOT doNotInsert)
      {
	  OuterRefs.insert (id);
      }
  }
} // ValueIdSet::getOuterReferences()

// -----------------------------------------------------------------------
// categorizePredicates:
// Group the predicates in the following categories, to be applied
// in the following order:
//
// (1) BiLogic: AND, or OR
// (2) Local Predicates - those that do not contain outer references
//     a) VEG equality predicates
//     b) other non-VEG predicates supported by synthesis (for now,
//        these include class BiRelat predicates, and some UnLogic, only)
// (3) Non-local predicates - those that do contain outer references
//     a) VEG predicates
//     b) other non-VEG class BiRelat and UnLogic predicates
// -----------------------------------------------------------------------

void ValueIdSet::categorizePredicates (const ValueIdSet & outerReferences,
				       ValueIdSet & EqLocalPreds,
				       ValueIdSet & OtherLocalPreds,
				       ValueIdSet & EqNonLocalPreds,
				       ValueIdSet & OtherNonLocalPreds,
				       ValueIdSet & BiLogicPreds,
				       ValueIdSet & DefaultPreds ) const
{

  for (ValueId id = init(); next(id); advance(id))
    {
      const ItemExpr *pred = id.getItemExpr();

      if (pred->synthSupportedOp() && // does the operator support synthesis??
	  ((0 > pred->getSelectivityFactor()) || //++MV does this operator has an assigned selectivity factor
	   ((ItemExpr *)pred)->isSelectivitySetUsingHint())) // Unless selectivity is specified by user
	{
	  OperatorTypeEnum op = pred->getOperatorType();
	  if (op == ITM_VEG_PREDICATE) // Equality (transitive closure) predicate?
	    {
	      if (outerReferences.entries() > 0)
		{
		  if (pred->referencesOneValueFrom(outerReferences))
		    EqNonLocalPreds.insert (id);
		  else
		    EqLocalPreds.insert (id);
		}
	      else
		EqLocalPreds.insert (id);
	    }
	  else if ((op == ITM_LESS) || (op == ITM_LESS_EQ) ||
		   (op == ITM_GREATER) || (op == ITM_GREATER_EQ) ||
		   (op == ITM_EQUAL) || (op == ITM_NOT_EQUAL) ||
		   (op == ITM_IS_NULL) || (op == ITM_IS_NOT_NULL) ||
		   (op == ITM_IS_UNKNOWN) || (op == ITM_IS_NOT_UNKNOWN))
	    {
	      if (outerReferences.entries () > 0)
		{
		  if (pred->referencesOneValueFrom(outerReferences))
		    OtherNonLocalPreds.insert (id);
		  else
		    OtherLocalPreds.insert (id);
		}
	      else
		OtherLocalPreds.insert (id);
	    }
	  else if ((op == ITM_OR) || (op == ITM_AND))
	    {
	      BiLogicPreds.insert (id);
	    }
	  else
    {
	    CCMPASSERT ("Unsupported predicate found");
      continue;
    }

	} // endif (pred->synthSupportedOp())

      else // operator not supported by synthesis

	DefaultPreds.insert (id);

    } // end for loop over setOfPredicates

}    // categorizePredicates

// This method returns TRUE if there are any predicates for which the
// cardinality cannot be accurately estimated by the optimizer
// Conditions are:
// 1. Any predicate with a hos variable or a dynamic parameter
// 2. Any predicate for which the histograms cannot be directly used. These include
//    Case expressions, LIKE predicates, or any other predicate
// 3. For more than one range predicate
// 4. For one range and one or more equality predicate
// 5. Any Bilogic pred
// 6. Equality predicaes
//    a. Any equality on an expression
//    b. Equality on more than one column of the same table. T1.a = T1.b
//    c. More than one equality predicate, and multi col UEC does not exist for that set of columns
//       Also the columns do not constitute unique index

NABoolean
ValueIdSet::predsReqFetchCnt(TableDesc * tdesc)
{
  // categorize all predicates so it is to determine if the
  // predicates are complex or not

  // if there are no predicates, return FALSE
  if (entries() == 0)
    return FALSE;

  // check to see if any of the predicates contain a hostVar or dynamic
  // parameter

  ItemExpr *constant = NULL;
  NABoolean containsConstant  = referencesAConstValue( &constant );
  NABoolean containsConstExpr = referencesAConstExpr();
  NABoolean containsHostvar   = ( containsConstExpr && !containsConstant );

  // if they do, return FALSE, we do not want to call fetchCount with
  // host variables or dynamic parameters
  if (containsHostvar)
    return TRUE;

  ValueIdSet eqLocalPreds, otherLocalPreds, eqNonLocalPreds,
             otherNonLocalPreds, biLogicPreds, defaultPreds;

  // We will not concern ourselves with outer refernces at this time
  ValueIdSet outerRefs;
  outerRefs.clear();

  categorizePredicates (outerRefs, eqLocalPreds,
                        otherLocalPreds, eqNonLocalPreds,
			otherNonLocalPreds, biLogicPreds,
			defaultPreds);

  // Complex predicates are defined as:
  // 1. Predicates for which the optimizer will use default selectivity
  // 2. Bi-logic preds (AND / OR)
  // 3. More than one range predicates
  if ( ((otherLocalPreds.entries() > 0) && (eqLocalPreds.entries() > 0)) ||
       (otherLocalPreds.entries() > 1) ||
       (biLogicPreds.entries() > 0) ||
       (defaultPreds.entries() > 0) ||
       (eqNonLocalPreds.entries() > 0) ||
       (otherNonLocalPreds.entries() > 0))
    return TRUE;

  // for range predicates, use fetchcount:
  // 1. If there is one range predicate but it is on an expression
  // example a+2 > 10
  if (otherLocalPreds.entries() == 1)
  {
    ValueId pred;
    otherLocalPreds.getFirst(pred);
    // if predicate is an expression such as a + 2 > 10
    // use fetchCount
    if (pred.anExpression())
      return TRUE;

    // if predicate involves more than one column from the same
    // table such as a > b use fetchCount
    ValueIdSet colsOfThisTableInPred;

    if (pred.moreThanOneColFromSameTabOrCharDate(tdesc, colsOfThisTableInPred))
      return TRUE;

    // for all other cases return FALSE
    return FALSE;
  }

  if (eqLocalPreds.entries() > 0)
  {
    // check if any predicate is an equality on more
    // than one column, such as a = b where both a and b
    // belong to the same table
    // During this process also collect base columns from
    // all predicate to check for correlation and multi-column
    // stats later
    ValueIdSet cols;
    for(ValueId predId = eqLocalPreds.init();eqLocalPreds.next(predId);eqLocalPreds.advance(predId))
    {
      ValueIdSet colsOfThisTableInPred;
      // There are one or less columns from this table participating
      // in the predicates, so no need to use fetchCount
      if (predId.moreThanOneColFromSameTabOrCharDate(tdesc, colsOfThisTableInPred))
        return TRUE;

      cols.insert(colsOfThisTableInPred);
    }

    // if the columns constitute unique index, no need to use fetchCount
    if (cols.doColumnsConstituteUniqueIndex(tdesc))
      return FALSE;

    // There are more than one columns from this table, see if multi-column
    // stats exists for this set of cols, if not use fetchCount
    const MultiColumnUecList* uecList = tdesc->getTableColStats().getUecList();

    if ( uecList ) {
      CostScalar mcUec = uecList->lookup(cols);
      if (mcUec <= 0)
        return TRUE;
    }
  }
    if (entries() > (ActiveSchemaDB()->getDefaults()).getAsDouble(COMP_INT_43))
      return TRUE;
    else
      return FALSE;
  }

NABoolean
ValueId::anExpression()
{
  ItemExpr * expr = getItemExpr();
  if (!expr)
    return FALSE;

  for (Int32 i=0; i<expr->getArity(); i++)
  {
    // predicate is an expression
    if (expr->child(i)->getArity() >= 1)
      return TRUE;
  }
  return FALSE;
}

NABoolean
ValueId::moreThanOneColFromSameTabOrCharDate(TableDesc * tdesc,
                                     ValueIdSet & colsOfThisTable)
{
  // if the predicate is like a > b such that both a and b
  // belong to same table, then also we want to call fetchCount
  // optimizer will use default selectivity of 33%
  ValueIdSet predCol;
  ValueIdSet predSet(*this);

  predSet.findAllReferencedBaseCols(predCol);

  // if there is only one column in the predicate
  // check for only character columns;
  NABoolean checkForCharCol = FALSE;
  if (predCol.entries() <= 1)
    checkForCharCol = TRUE;

  if (tdesc && tdesc->getTableAnalysis() )
  {
    ValueIdSet usedCols = tdesc->getTableAnalysis()->getUsedCols();
    colsOfThisTable = predCol.intersect(usedCols);
    if (colsOfThisTable.entries() > 1)
      return TRUE;
    if (checkForCharCol || (colsOfThisTable.entries() == 1))
    {
      ValueId colId;
      colsOfThisTable.getFirst(colId);
      if (colId == NULL_VALUE_ID)
        return FALSE;

      // get column type and return TRUE if date time type
      if (colId.getType().getTypeQualifier() == NA_DATETIME_TYPE )
          return TRUE;
      // if the intervals of the histograms had to be merged due
      // to conflicting interval boundaries use
      // fetchCount.
      ColStatsSharedPtr colStats = tdesc->getTableColStats().getColStatsPtrForColumn(colId);
      if (colStats == NULL)
        return FALSE;
      if (colStats->isColWithBndryConflict())
        return TRUE;
    }
  }
  return FALSE;
}

NABoolean ValueId::isDivisioningColumn() const
{
   ItemExpr *ck = getItemExpr();

   if ( ck == NULL )
      return FALSE;

   if (ck->getOperatorType() == ITM_INDEXCOLUMN)
      ck = ((IndexColumn *) ck)->getDefinition().getItemExpr();

   if (ck->getOperatorType() == ITM_BASECOLUMN)
      return (((BaseColumn *) ck)->getNAColumn()->isDivisioningColumn());
   else
      return FALSE;
}

NABoolean ValueId::isSaltColumn() const
{
   ItemExpr *ck = getItemExpr();

   if ( ck == NULL )
      return FALSE;

   if (ck->getOperatorType() == ITM_INDEXCOLUMN)
      ck = ((IndexColumn *) ck)->getDefinition().getItemExpr();

   if (ck->getOperatorType() == ITM_BASECOLUMN)
     return (((BaseColumn *) ck)->getNAColumn()->isSaltColumn());
   else
     return FALSE;
}

// -----------------------------------------------------------------------
// getReferencedPredicates:
// This method goes through the ValueIdSet pointed to by the this pointer.
// All those valueids that are referenced by any member
// of the valueIdSet that is the first argument to this method are inserted
// into the ValueIdSet that is the second argument. This method can be used
// get all the predicates in the selection predicate of a node that contain
// outer references. Method returns TRUE if any predicate is found that
// references a valueid from the first set.
//
// The default behavior of the routine is to skip any expression that
// evaluates to a constant(see ItemExpr::referencesOneValueFrom()). If
// you want those expressions to be searched as well, set searchConstExpr
// to TRUE.
// -----------------------------------------------------------------------

NABoolean ValueIdSet::getReferencedPredicates (const ValueIdSet & outerReferences,
					       ValueIdSet & nonLocalPreds) const
{
  NABoolean found = FALSE;
  if (outerReferences.entries() > 0)
  {
    for (ValueId id = init(); next(id); advance(id))
      {
	const ItemExpr *pred = id.getItemExpr();
	if (pred->referencesOneValueFrom(outerReferences))
	{
	  nonLocalPreds.insert (id);
	  found = TRUE ;
	}
      }
  }
  return found;
}

// ---------------------------------------------------------------------
// ValueIdSet::getAllTables()
// This method will get all tables whose columns are included in the set
// We assume there are all base columns. Hence use all base columns in this
// set.
// ----------------------------------------------------------------------

SET(TableDesc *) * ValueIdSet::getAllTables()
{

  SET(TableDesc *) * tableSet = new STMTHEAP SET(TableDesc *)(STMTHEAP);

  for (ValueId column = init(); next(column); advance(column) )
  {
      const ItemExpr * colExpr = column.getItemExpr() ;
      if (colExpr->getOperatorType() != ITM_BASECOLUMN) continue;

      TableDesc * tableDescForCol = ((BaseColumn *)colExpr)->getTableDesc();

      tableSet->insert(tableDescForCol);
    }
  return tableSet;
}

// ---------------------------------------------------------------------
// ValueIdSet::doColumnsConstituteUniqueIndex(const NATable * table)
// Returns a boolean to indicate if these columns constitute a primary
// key or unique index.
// ---------------------------------------------------------------------
NABoolean ValueIdSet::doColumnsConstituteUniqueIndex(TableDesc * table, NABoolean considerStats)
{
  NABoolean colsConstUniqueIndex = FALSE;

  ValueIdSet primaryKeyColumns = table->getPrimaryKeyColumns();

  if ((primaryKeyColumns.entries() > 0) &&
      (contains(primaryKeyColumns)) )
    colsConstUniqueIndex = TRUE;
  else
  {
    // Complete primary key is not covered by the joining columns. See if
    // if any unique index is covered

    const LIST(IndexDesc *) &uniqueIndexes = table->getUniqueIndexes();
    for (CollIndex i = 0; i < uniqueIndexes.entries(); i++)
    {
      IndexDesc * index = uniqueIndexes[i];
          ValueIdSet indexColumns(index->getIndexKey());
    }
  }

  // if the column set is not unique based on semantics, check to see if it is unique based on
  // its statistics. That is if any column in the set is unique, or has UEC equal to rowcount
  // then we say that the column set is unique
  // Do that only if it is being tested for cardinality estimation.
  if ((colsConstUniqueIndex == FALSE) && considerStats)
  {
    // get the rowcount from the table colstats
    ColStatDescList colStats = table->tableColStats();
    CostScalar rc = colStats[0]->getColStats()->getRowcount();
    for (ValueId vid = init(); next (vid); advance (vid))
    {
      ColStatsSharedPtr cs = colStats.getColStatsPtrForColumn(vid);
      if (cs)
      {
        if (cs->getUecBeforePreds() == rc)
        {
          colsConstUniqueIndex = TRUE;
          break;
        }
      }
    }
  }
  return colsConstUniqueIndex;
}

// -----------------------------------------------------------------------
// containsSubquery()
// determine if any of the vids correspond to a subquery, in this vs.
// -----------------------------------------------------------------------
NABoolean ValueIdSet::containsSubquery() const
{
  for (ValueId vid = init(); next(vid); advance(vid))
    {
      if (vid.getItemExpr()->containsSubquery())
        return TRUE;
    }
  return FALSE;
} // ValueIdSet::containsSubquery

// -----------------------------------------------------------------------
// containsUDF()
// determine if any of the vids correspond to a UDF, in this vs.
// -----------------------------------------------------------------------
ItemExpr *ValueIdSet::containsUDF() const
{
  for (ValueId vid = init(); next(vid); advance(vid))
    {
      if (vid.getItemExpr()->containsUDF())
        return vid.getItemExpr()->containsUDF();
    }
  return 0;
} // ValueIdSet::containsUDF

// -----------------------------------------------------------------------
// containsIsolatedUDFunction()
// determine if any of the vids correspond to an Isolated UDFunction,in this vs.
// -----------------------------------------------------------------------
NABoolean ValueIdSet::containsIsolatedUDFunction() const
{
  for (ValueId vid = init(); next(vid); advance(vid))
    {
      if (vid.getItemExpr()->containsIsolatedUDFunction())
        return TRUE;
    }
  return FALSE;
} // ValueIdSet::containsIsolatedUDFunction

// -----------------------------------------------------------------------
// containsCount()
// determine if any of the vids correspond to a count, in this vs.
// -----------------------------------------------------------------------
NABoolean ValueIdSet::containsCount() const
{
  for (ValueId vid = init(); next(vid); advance(vid))
    {
    if ((vid.getItemExpr()->origOpType() == ITM_COUNT) ||
        (vid.getItemExpr()->origOpType() == ITM_COUNT_STAR__ORIGINALLY))
        return TRUE;
    }
  return FALSE;
} // ValueIdSet::containsCount

// -----------------------------------------------------------------------
// containsOneTrue()
// determine if any of the vids correspond to a oneTrue, in this vs.
// -----------------------------------------------------------------------
NABoolean ValueIdSet::containsOneTrue(ValueId &refOneTrue ) const
{

   for ( ValueId vid = init(); next(vid); advance(vid))
   {
      if (vid.getItemExpr()->isAnAggregate() &&
         (vid.getItemExpr()->getOperatorType() == ITM_ONE_TRUE))
      {
         refOneTrue = vid;
         return TRUE;
      }
   }
   return FALSE;
} // ValueIdSet::containsOneTrue

// -----------------------------------------------------------------------
// containsAnyTrue()
// determine if any of the vids correspond to a anyTrue, in this vs.
// -----------------------------------------------------------------------
NABoolean ValueIdSet::containsAnyTrue(ValueId &refAnyTrue ) const
{

   for ( ValueId vid = init(); next(vid); advance(vid))
   {
      if (vid.getItemExpr()->isAnAggregate() &&
         (vid.getItemExpr()->getOperatorType() == ITM_ANY_TRUE))
      {
         refAnyTrue = vid;
         return TRUE;
      }
   }
   return FALSE;
} // ValueIdSet::containsAnyTrue

// -----------------------------------------------------------------------
// Methods used for debugging and display.
// -----------------------------------------------------------------------
void ValueIdSet::unparse(NAString &result,
			 PhaseEnum phase,
			 UnparseFormatEnum form,
			 TableDesc * tabId) const
{
  NABoolean first = TRUE;
  // MVs --

  NAString connectorText;

  if ((form == MVINFO_FORMAT) || (form == QUERY_FORMAT))
    connectorText = " AND ";
  else
    connectorText = " , ";

  result += "(";
  for (ValueId x = init(); next(x); advance(x))
    {
      if (first)
	first = FALSE;
      else
	result += connectorText;

      if (form == ERROR_MSG_FORMAT) // ERROR_MSG_FORMAT : don't print vid's
        {
          x.getItemExpr()->unparse(result,phase,EXPLAIN_FORMAT,tabId);
        }
      else if ((form == MVINFO_FORMAT) ||
	       (form == QUERY_FORMAT))
        {
	  // MVINFO_FORMAT or QUERY_FORMAT: don't print vid's
          x.getItemExpr()->unparse(result,phase,form,tabId);
        }
      else
        {
          char vidbuf[TEXT_DISPLAY_LENGTH];
          sprintf(vidbuf, "[%u]", (CollIndex)x);
          result += vidbuf;

          x.getItemExpr()->unparse(result,phase,form,tabId);
        }
    }
  result += ")";
} // ValueIdSet::unparse

#pragma nowarn(1506)   // warning elimination
void ValueIdSet::print(FILE* ofd, const char* indent, const char* title,
                       CollHeap *c, char *buf) const
{
  BUMP_INDENT(indent);
  Space * space = (Space *)c;
  char mybuf[1000];

  snprintf(mybuf, sizeof(mybuf), "%s%s\n",NEW_INDENT,title);
  PRINTIT(ofd, c, space, buf, mybuf);

  for (ValueId x = init(); next(x); advance(x))
  {
    Int32 i = (Int32)((CollIndex) x); // valueid as an integer
    NAString unparsed(CmpCommon::statementHeap());

    if (x.getItemExpr())
      x.getItemExpr()->unparse(unparsed); // expression as ascii string

    snprintf(mybuf, sizeof(mybuf),"%4d: %s\n",i,(const char *) unparsed);
    PRINTIT(ofd, c, space, buf, mybuf);
  }
} // ValueIdSet::print()
#pragma warn(1506)  // warning elimination

void ValueIdSet::display() const	// To be called from the debugger
{
  print();
}

#pragma nowarn(1506)   // warning elimination
ex_expr::exp_return_type ValueIdList::evalAtCompileTime
(short addConvNodes, // (IN) : 1 to add conv nodes, 0 otherwise
 ExpTupleDesc::TupleDataFormat tf, // (IN) : tuple format of resulting expr(s)
 char* resultBuffer, // (INOUT): tuple buffer of resulting expr(s)
 ULng32 resultBufferLength, // (IN): length of the result buffer
 Lng32 *length,       // (OUT) : length of 1st result expr
 Lng32 *offset,        // (OUT) : offset of 1st result expr
 ComDiagsArea *diagsArea
) const
{
  // set up binder/generator stuff so expressions could be generated.
  BindWA       bindWA(ActiveSchemaDB(), CmpCommon::context());
  Generator    generator(CmpCommon::context());
  ExpGenerator expGen(&generator);
  generator.appendAtEnd();

  // Do not perform pcode optimizations for expressions being evaluated at
  // compile-time.  This is mainly being done to address a native expressions
  // bug.  However, there is no need to optimize in this case.
  Int16 savedPCodeMode = (Int16) expGen.getPCodeMode();
  expGen.setPCodeMode(savedPCodeMode & ~(ex_expr::PCODE_LLO));

  generator.setBindWA(&bindWA);
  generator.setExpGenerator(&expGen);
  FragmentDir * compFragDir = generator.getFragmentDir();

  // create the fragment (independent code space) for this expression
  CollIndex myFragmentId = compFragDir->pushFragment(FragmentDir::MASTER);

  // space where compile-time expr(s) will be generated
  Space * space = generator.getSpace();

  // allocate a work cri desc to encode expr(s). It has
  // 3 entries: 0, for consts. 1, for temps. 2, for the encoded expr(s).
  ex_cri_desc * workCriDesc = new(space) ex_cri_desc(3, space);
  short keyAtpIndex   = 2;  // where the encoded expr(s) will be built

  ULng32 encodedKeyLen;
  ex_expr * keExpr = 0;
  ValueIdList tempValueIdList;

  // call ExpGenerator::generateContiguousMoveExpr to create an ex_expr
  // to "assign" expr(s) into the resultBuffer
  expGen.generateContiguousMoveExpr
    (*this, addConvNodes, 0, keyAtpIndex, tf, encodedKeyLen, &keExpr,
     NULL, ExpTupleDesc::SHORT_FORMAT, NULL, &tempValueIdList,
     0, NULL, TRUE /*disable const folding*/);

  if(encodedKeyLen > resultBufferLength)
  {
    generator.removeAll();
    return ex_expr::EXPR_ERROR;
  }

  // create a DP2 expression and initialize it with the expr(s)
  ExpDP2Expr * keyEncodeExpr = new(space) ExpDP2Expr(keExpr,
                                                     workCriDesc,
                                                     space);
  keyEncodeExpr->getExpr()->fixup(0,0,0,space,STMTHEAP, FALSE, NULL);

  atp_struct * workAtp = keyEncodeExpr->getWorkAtp();
  workAtp->getTupp(keyAtpIndex).setDataPointer(resultBuffer);

  // set the diagsArea for the caller to get warnings
  if (workAtp->getDiagsArea() != diagsArea)
     workAtp->setDiagsArea(diagsArea);
  // evaluate the expr(s) into resultBuffer
  ex_expr::exp_return_type rc =
    keyEncodeExpr->getExpr()->eval(workAtp, 0, STMTHEAP);

  // constant folding caller (ValueIdList::evaluateTree) wants to get the
  // length, offset of 1st expr because it assumes it has only one element.
  // other callers (CacheData::backpatchConstParams) are not interested in
  // length, offset and these two parameters default to NULL addresses.
  if (rc != ex_expr::EXPR_ERROR && (length || offset)) {
    const ValueId & tempValueId =
      tempValueIdList[0].getItemExpr()->getValueId();
    Attributes *attr = generator.getMapInfo(tempValueId)->getAttr();
    if (length) {
      if (attr->getVCIndicatorLength() > 0) {
        char temp[8];
        str_cpy_all(temp, resultBuffer + attr->getVCLenIndOffset(),
                    attr->getVCIndicatorLength());
        if (attr->getVCIndicatorLength() == sizeof(short))
          *length = *(short *)temp;
        else
          *length = *(Lng32 *)temp;
      }
      else {
        *length = attr->getLength();
      }
    }
    if (offset) *offset = attr->getOffset();
  }

  // Restore pcode mode.
  expGen.setPCodeMode(savedPCodeMode);

  generator.removeAll();
  return rc;

}
#pragma warn(1506)  // warning elimination

// Used by constant folding. Calls the executor evaluator. The parameters are:
// 1.- The root of the expression tree to evaluate. It is assumed that it
// contains constants only.
// 2.- encodedKeyBuffer, which is a pointer to the result.
// 3.- The length of the result
// 4.- The position in which the result starts
short ValueIdList::evaluateTree( const ItemExpr * root,
				 char * encodedKeyBuffer,
                                 ULng32 encodedKeyLength,
				 Lng32 *length,
				 Lng32 *offset,
				 ComDiagsArea *diagsArea)
{
  // Let's start with a list of size 4 rather than resizing continuously (?)
  ValueIdList encodedValueIdList(4);
  encodedValueIdList.insert(root->getValueId());

  if (encodedValueIdList.evalAtCompileTime
      (1, ExpTupleDesc::SQLMX_KEY_FORMAT, encodedKeyBuffer, encodedKeyLength,
       length, offset, diagsArea) == ex_expr::EXPR_ERROR)
    return -1;
  else
    return 0;
}

// This function assumes that the tree rooted at ch contains constants only.
// Parent is the parent of ch and childNumber is the number of ch. The function
// computes the value represented by the subtree rooted at ch and puts
// the new value in the position of ch.	Used by constant folding.
#pragma nowarn(262)   // warning elimination
Lng32 ValueIdList::evaluateConstantTree( const ValueId &parent,
				        const ValueId & ch,
					Int32 childNumber,
					ItemExpr ** outItemExpr,
					ComDiagsArea *diagsArea)
{
  // eval requires CASE to be IF_THEN_ELSE's parent
  if( (ch.getItemExpr()->getOperatorType() == ITM_IF_THEN_ELSE) &&
      (parent.getItemExpr()->getOperatorType() != ITM_CASE) )
      return 0;

  #define RESULT_SIZE 1000
  Lng32 length;
  char value[RESULT_SIZE];

  Lng32 offset;

  if (outItemExpr)
    *outItemExpr = NULL;

  // Compute the value represented by the subtree rooted at ch
  Int32 error = 0;
  error = evaluateTree(ch.getItemExpr(), value, RESULT_SIZE, &length,
		       &offset, diagsArea);
  if(error)
    return error;

  const NAType & type = ch.getType();

  NAString text(CmpCommon::statementHeap());
  ItemExpr *item;

  if ( type.getTypeQualifier() != NA_CHARACTER_TYPE ) {

    Int32 index = 0;

    value[length + offset] = 0;

    // See how many positions the result will take in the display
    // long t = NAType::getDisplayLength(type.getFSDatatype(),
    Lng32 t = type.getDisplayLength(type.getFSDatatype(),
  		    length,
  		    type.getPrecision(),
  		    type.getScale(),
  		    0);

    char *result = new  char[t + 1];
    CMPASSERT( result != NULL );
    memset( result, ' ', t );

    // Get the ASCII representation
    ex_expr::exp_return_type retcode =
      convDoIt(value + offset,
               length,
               (short)type.getFSDatatype(),
               type.getPrecisionOrMaxNumChars(),
               type.getScaleOrCharset(),
               result,
               t,                          // target length
               REC_BYTE_F_ASCII,           // target type
               0,                          // no char limit
               SQLCHARSETCODE_ISO88591,    // ISO 8859-1
               NULL,                       // no vc length
               0,                          // not a varchar
               CmpCommon::statementHeap(), // heap
               0,                          // don't pass a diags area
               CONV_UNKNOWN_LEFTPAD,       // left pad with zeroes
               NULL,                       // no conv error flag
               CONV_ALLOW_INVALID_CODE_VALUE); // non ISO characters are lost,
                                               // see Bugzilla 2938

    // CMPASSERT(retcode == ex_expr::EXPR_OK); //Called by constant folding, no need to panic
    if ( retcode != ex_expr::EXPR_OK )
       return (-1);

    result[t] = 0;

    // Create a new node containing the result
    text = result;

    delete [] result;

    item = new (CmpCommon::statementHeap())
      SystemLiteral((NAType *) &type, value, offset + length, &text);

  } else {

  // for CHARACTER typed result, do not convert to ASCII format, because
  // the result contained in 'value' is in the right format already.
  //
  // Besides, we will have inconsistent result if the conversion did
  // happen for UCS2 'ab':
  //       SystemLiteral.text_ is 'ab' and
  //       type.Unicode=UCS2.
  //
  // The correct representation should be:
  //       stemLiteral.text_ is 'a\0b\0' and
  //       type.Unicode=UCS2.

    const CharType& ctype = (CharType&)type;

    NAString strval(value+offset, length);
    item = new (CmpCommon::statementHeap())
      SystemLiteral(strval, ctype.getCharSet(),ctype.getCollation(),
                            ctype.getCoercibility());
  }

  item->synthTypeAndValueId();

  // Replace the subtree just computed with the node containing the result
  if (childNumber >= 0)
    parent.getItemExpr()->setChild(childNumber,item);

  if (outItemExpr)
    *outItemExpr = item;

  return error;

}
#pragma warn(262)  // warning elimination

////////////////////////////////////////////////////////////////////////////
// Tells us if some sort of algebraic simplification can be done in a tree.
// Used by constant folding. The parameters are:
// 1.- Points to the root of the tree in question
// 2.- Parent of node pointed to by parameter 1
// 3.- The index of one of the childs of parameter 1. If it is a constant,
// then some sort of simplification may be done
// 4.- The index of the node represented by parameter 1
// 5.- Indicates which of the children of the node pointed by parameter 1
//     will not occupy its place after the simplification is done
////////////////////////////////////////////////////////////////////////////
NABoolean ValueIdList::canSimplify(ItemExpr *itemExpr,
				   const ValueId &parent,
				   Int32 i,
				   Int32 childNumber,
				   Int32 &moved)
{
  char value[4];
  Int32 length;
  ItemExpr *item;
  NAString tempStr(CmpCommon::statementHeap());

  if (itemExpr->child(i)->getOperatorType() != ITM_CONSTANT) {
    return FALSE;
  }

  ItemExpr *tempItem1 = itemExpr->child(i);
  ConstValue *c = (ConstValue *) tempItem1;

  short type = c->getType()->getFSDatatype();
  if (!((type >= REC_MIN_NUMERIC && type <= REC_MAX_NUMERIC) ||
	tempItem1->getValueId().getType().getTypeQualifier() == NA_BOOLEAN_TYPE)) {
    return FALSE;
  }

  if ((type >= REC_MIN_NUMERIC && type <= REC_MAX_NUMERIC)&&
    (tempItem1->getValueId().getType().getTypeQualifier() != NA_BOOLEAN_TYPE))
    {
      // must be exact numeric with scale of zero and max
      // precision is less than 10 (so it is a long and atoi can
      // convert that value).
      NumericType *ntyp = (NumericType *) c->getType();
      if ((! ntyp->isExact()) ||
	  (ntyp->getScale() != 0) ||
	  (ntyp->getPrecision() >= 10))
	return FALSE;
    }

  NAString strValue(c->getText(), CmpCommon::statementHeap());
  Int32 val;
  val = atoi(strValue);

  // We simplify the following cases:
  // <expr> AND FALSE => FALSE; FALSE AND <expr> => FALSE
  // <expr> AND TRUE  => expr;  TRUE  AND <expr> => <expr>
  // <expr> OR  TRUE  => TRUE;  <expr> OR TRUE   => TRUE
  // <expr> OR FALSE  => expr;  FALSE  OR <expr> => <expr>
  // NOT FALSE => TRUE
  // NOT TRUE  => FALSE
  // <expr> + 0 => <expr>; 0 + <expr> => <expr>
  // <expr> * 0 => 0; 0 * <expr> => 0
  // <expr> * 1 => <expr>; 1 * <expr> => <expr>
  // <expr> - 0 => <expr>
  // <expr> / 1 => <expr>

  // If we have an OR such that one of its operands is TRUE, replace the operator
  // with TRUE
  if ((itemExpr->getOperatorType() == ITM_OR) &&
      (val == 1)) {
    value[0]  = 1; value[1] = 0; value[2] = 0; value[3] = 0;
    length = 4;
    tempStr = "1";
    item = new (CmpCommon::statementHeap())
      SystemLiteral(itemExpr->synthesizeType(), value, length, &tempStr);

    item->synthTypeAndValueId();
    parent.getItemExpr()->setChild(childNumber,item);

    moved = i;
    return TRUE;
  }

  // We have an OR such that one of its operands is FALSE, then we may replace
  // the OR with its other child
  if ((itemExpr->getOperatorType() == ITM_OR) &&
      (val == 0)) {

    parent.getItemExpr()->setChild(childNumber,itemExpr->getChild(1 - i));
    moved = 1 - i;
    return TRUE;
  }

  // If we have an AND operator such that one of its operands is FALSE, replace
  // the operator with FALSE
  if ((itemExpr->getOperatorType() == ITM_AND) &&
      (val == 0)) {

    value[0]  = 0; value[1] = 0; value[2] = 0; value[3] = 0;
    length = 4;
    tempStr = "0";
    item = new (CmpCommon::statementHeap())
      SystemLiteral(itemExpr->synthesizeType(), value, length, &tempStr);
    item->synthTypeAndValueId();
    parent.getItemExpr()->setChild(childNumber,item);
    moved = i;
    return TRUE;
  }

  // We have an AND operator such that one of its operators is TRUE. We may replace
  // the operator with its other child
  if ((itemExpr->getOperatorType() == ITM_AND) &&
      (val == 1)) {

    parent.getItemExpr()->setChild(childNumber,itemExpr->getChild(1 - i));
    moved = 1 - i;
    return TRUE;
  }

  // We have a NOT operator with TRUE as the child. Replace the operator with
  // a FALSE node
  if ((itemExpr->getOperatorType() == ITM_NOT) &&
      (val == 1)) {

    value[0]  = 0; value[1] = 0; value[2] = 0; value[3] = 0;
    length = 4;
    tempStr = "0";
    item = new (CmpCommon::statementHeap())
      SystemLiteral(itemExpr->synthesizeType(), value, length, &tempStr);
    item->synthTypeAndValueId();
    parent.getItemExpr()->setChild(childNumber,item);
    moved = i;

    return TRUE;
  }

  // We have a NOT operator with FALSE as the child. Replace the operator with
  // a TRUE node
  if ((itemExpr->getOperatorType() == ITM_NOT) &&
      (val == 0)) {

    value[0]  = 1; value[1] = 0; value[2] = 0; value[3] = 0;
    length = 4;
    tempStr = "1";
    item = new (CmpCommon::statementHeap())
      SystemLiteral(itemExpr->synthesizeType(), value, length, &tempStr);
    item->synthTypeAndValueId();
    parent.getItemExpr()->setChild(childNumber,item);
    moved = i;

    return TRUE;
  }

  // We have a + such that one of its operands is 0, then we may replace
  // the + with its other child
  if ((itemExpr->getOperatorType() == ITM_PLUS) &&
      (val == 0)) {

    parent.getItemExpr()->setChild(childNumber,itemExpr->getChild(1 - i));
    moved = 1 - i;
    return TRUE;
  }

  // We have a * operator with 0 as a child. Replace the operator with
  // a 0 node
  if ((itemExpr->getOperatorType() == ITM_TIMES) &&
      (val == 0)) {

    item = new (CmpCommon::statementHeap()) SystemLiteral(0);
    item->synthTypeAndValueId();
    parent.getItemExpr()->setChild(childNumber,item);
    moved = i;

    return TRUE;
  }

  // We have an * operator such that one of its operators is 1. We may replace
  // the operator with its other child
  if ((itemExpr->getOperatorType() == ITM_TIMES) &&
      (val == 1)) {

    parent.getItemExpr()->setChild(childNumber,itemExpr->getChild(1 - i));
    moved = 1 - i;
    return TRUE;
  }

  // We have the case <expr> - 0
  if (itemExpr->getOperatorType() == ITM_MINUS) {

    if (i != 1)
      return FALSE;

    if (val == 0) {
      parent.getItemExpr()->setChild(childNumber,itemExpr->getChild(0));
      moved = 0;
      return TRUE;
    }
  }

  // We have the case <expr> / 1
  if (itemExpr->getOperatorType() == ITM_DIVIDE) {

    if (i != 1)
      return FALSE;

    if (val == 1) {
      parent.getItemExpr()->setChild(childNumber,itemExpr->getChild(0));
      moved = 0;
      return TRUE;
    }
    else {
      // do not change division to multiplication, if this div is
      // to downscale the result and rounding is to be done. Div to
      // round off the value does special processing which cannot be
      // replaced by a multiplication.
      if ((((BiArith*)itemExpr)->getDivToDownscale()) &&
	  (((BiArith*)itemExpr)->getRoundingMode() > 0))
	return FALSE;

      // see if we can replace "<expr> / val" by "<expr> * <newval>"
      // where <newval> is equal to "1 / <val>".
      Int64 temp = val;
      Int64 numerator = 1;
      Lng32 scale = 0;
      while (temp > 0)
	{
	  temp = temp / 10;
	  numerator = numerator * 10;
	  scale++;
	}
      if (numerator == 1)
	return FALSE;

      Int64 div = numerator / val;
      if ( div * val != numerator)
	return FALSE;

      NumericType * ntyp = new (CmpCommon::statementHeap())
	SQLNumeric(4, scale, scale, TRUE, FALSE);
      Lng32 cval = (Lng32)div;
      char cvalStr[20];
      cvalStr[0] = '.';
      str_itoa(cval, &cvalStr[1]);
      NAString nas(cvalStr, CmpCommon::statementHeap());
      item = new (CmpCommon::statementHeap())
	SystemLiteral(ntyp, &cval, 4, &nas);
      item->synthTypeAndValueId();

      BiArith * ba =  new (CmpCommon::statementHeap())
	BiArith(ITM_TIMES, itemExpr->getChild(0)->castToItemExpr(), item);
      ba->synthTypeAndValueId();

      parent.getItemExpr()->setChild(childNumber,ba);

      moved = 0;
      return TRUE;
    }
  }

  return FALSE;
}

// Evaluate all constant subexpressions of the tree whose root is ch; after
// this routine is called, all subtrees that contain constants only will
// be replaced by the corresponding equivalent constant.
// Parent is the parent of ch and childNumber is the number of ch.
//
// RETURN:
//    TRUE, if 'ch' contains all constants
//    FALSE, if 'ch' doesn't contain all constants
//    -1, if error during const expr evaluation
//
//    If evalAllConsts is TRUE and 'ch' contains an all const expr, then that
//    expr is evaluated. If outAllConstsItemExpr is passed in, then on return
//    it contains a ConstValue(SystemLiteral) node representing the result of
//    the const expression.
Int32 ValueIdList::evaluateExpr( const ValueId & parent,
			       const ValueId & ch,
			       Int32 childNumber,
			       NABoolean simplifyExpr,
			       NABoolean evalAllConsts,
			       ItemExpr ** outAllConstsItemExpr,
			       ComDiagsArea *diagsArea)
{
  ItemExpr *itemExpr;

  itemExpr = ch.getItemExpr();
  Int32 nc = itemExpr->getArity();
  Int32 op = itemExpr->getOperatorType();

  if (outAllConstsItemExpr)
    *outAllConstsItemExpr = itemExpr;

  // No aggregate or sequence functions since their arguments are
  // represented as constants when they are not. Ditto for translations.
  // Null-instantiated constants aren't constant either. Should
  // really do a cover test here. Since it handles this issue now
  // and in the future.
  if (itemExpr->isAnAggregate() ||
      itemExpr->isASequenceFunction() ||
      (op == ITM_INSTANTIATE_NULL) ||
      (op == ITM_TRANSLATE) ||
      (op == ITM_ROWSETARRAY_INTO)) {
    return FALSE;
  }

  if (itemExpr->constFoldingDisabled())
    {
      ItemExpr *outExpr = NULL;

      for (Int32 i = 0; i < nc; i++)
	{
	  Int32 rc =
	    evaluateExpr(ch,itemExpr->child(i)->getValueId(),i,
			 simplifyExpr, evalAllConsts, &outExpr,
			 diagsArea);
	  if ((rc < 0) ||
	      (diagsArea && diagsArea->getNumber() > 0))
  	    return -1;
	  else if ((outExpr) &&
		   (evalAllConsts))
	    {
	      itemExpr->child(i) = outExpr;
	    }
	}
      return FALSE;
    }

  // If the tree has no subtrees, we just say if it is a constant or not.
  if (nc == 0) {
    if (itemExpr->getOperatorType() != ITM_CONSTANT) {
      return FALSE;
    }
    else {
      ConstValue *c = (ConstValue *) itemExpr;
      if (c->isNull()) {  // not dealing with NULLs
        return FALSE;
      }

      return TRUE;
    }
  }

  // Assume by now that the tree rooted at ch contains constants only
  Int32 allConstants = TRUE;

  const Int32 constantTreeArrayDim = 2;
  Int32 constantTreeArray[constantTreeArrayDim];
                             //  You probably don't like constants, but
                             // no tree should have more than 2 children.

  Int32 *constantTree = 0;

  if ( nc > constantTreeArrayDim ) {
    constantTree = new (CmpCommon::statementHeap()) Int32[nc];
  } else
    constantTree = constantTreeArray;

  Lng32 i = 0;
  for (; i < nc; i++) {

    // We call this routine recursively; therefore after this call the
    // subtree rooted at child number i will not contain subtrees that
    // contain constants only, since all of them would have been evaluated;
    // We store in an array a boolean value that tells us if this subtree
    // contains constants only, or not
    constantTree[i] = evaluateExpr(ch,itemExpr->child(i)->getValueId(),i,
				   simplifyExpr, FALSE, NULL, diagsArea);
    if (constantTree[i] < 0) {
      Int32 x = constantTree[i];
      if ( nc > constantTreeArrayDim )
	NADELETEBASIC(constantTree, CmpCommon::statementHeap());
      return x;
    }

    // The variable allConstants tells us if the tree rooted at ch consists
    // of constants only so far
    allConstants = (allConstants && constantTree[i]);

  }

  // If we only contain constants, we indicate so and we are done
  if (allConstants) {
    if ( nc > constantTreeArrayDim )
      NADELETEBASIC(constantTree, CmpCommon::statementHeap());

    if (evalAllConsts)
      {
	ValueId dummy;

        Lng32 error = evaluateConstantTree( dummy, itemExpr->getValueId(), -1,
					   outAllConstsItemExpr, diagsArea );
	if (error) // -1
	  return error;
      }

    return TRUE;
  }

  // Otherwise, we limit ourselves to evaluate those subtrees that contain
  // constants only. We indicate that the tree rooted at ch does not only
  // contain constants
  for (i = 0; i < nc; i++) {

    if (constantTree[i]) {

      // Evaluate the tree since we know it only contains constants
      if (itemExpr->child(i)->getArity() != 0) {
        Int32 error = 0;
        error = evaluateConstantTree(ch,itemExpr->child(i)->getValueId(),i,NULL,
				     diagsArea);
        if (error) {
          if ( nc > constantTreeArrayDim )
             NADELETEBASIC(constantTree, CmpCommon::statementHeap());
          return error;
        }
      }

      if (simplifyExpr) {
	Int32 moved;
	// Find out if some sort of simplification can be done; if
	// so, we do it and let know the parent of this subtree
	// whether the result contains all constants or not.
	if (canSimplify(itemExpr, parent, i, childNumber, moved)) {
	  if ( nc > constantTreeArrayDim )
	    NADELETEBASIC(constantTree, CmpCommon::statementHeap());
	  return (moved == i);
	}
      }
    }
  }

  if ( nc > constantTreeArrayDim )
    NADELETEBASIC(constantTree, CmpCommon::statementHeap());

  return FALSE;

}
NABoolean ValueIdList::hasVarChars() const
{
   ValueIdList list = *this;

   for (CollIndex i = 0; i < list.entries(); i++)
   {
     ValueId vid = list[i];

     if (vid.getType().getVarLenHdrSize()>0)
     {
       return TRUE;
     }
   }
   return FALSE;
}

// Simplify subexpressions that contain constants only; for
// example, if the valueIdList looks like x < 3 + 4
// then the list returns as x < 7 and the function result will be FALSE.
// If we see "1=1 and 2=2",
// then the list returns as "1." and the function result will be TRUE.
// If error, the list returned will be empty!
NABoolean ValueIdList::constantFolding()
{
  ItemExpr *tempItem1;
  ConstValue *c;
  Int32 constValue;

  ValueIdList list = *this;
  clear();

  // visit each subtree
  ItemExpr *item = NULL;

  // Tells if the whole expression is TRUE
  NABoolean allTrue = TRUE;

  for (CollIndex i = 0; i < list.entries(); i++)
  {
    const ValueId & vid = list[i];

    // If this constant changes to 1, then we have a TRUE boolean constant as result;
    // if it changes to 0, we have a FALSE value. Otherwise we have any other expression.
    constValue = -1;

    // We create a temporary constant to serve as a dummy tree root
    item = new (CmpCommon::statementHeap()) SystemLiteral();
    item->synthTypeAndValueId();
    item->setChild(0,vid.getItemExpr());

    if ((vid != NULL_VALUE_ID) && (vid.getItemExpr()->getOperatorType() == ITM_OR))
    {
      ValueIdList eqList;
      NABoolean status = vid.getItemExpr()->convertToValueIdList(eqList,NULL, ITM_OR);

      if(!status && eqList.entries() > CmpCommon::getDefaultNumeric(MAX_EXPRS_USED_FOR_CONST_FOLDING))
      {
        // if the number of branches in this OR predicate are more than max_exprs_used_for_constant_folding
        // we will not try to simplify the expression. Add the original expression to the list and continue
        // to evaluate next predicate
        insert(vid);
        // also since we have not done constant folding we don;t know if that expression evaluates to TRUE or not
        // so to be on the safe side we will make allTrue = FALSE
        allTrue = FALSE;
        continue;
      }
    }

    Int32 allConstants;

    // We evaluate the tree rooted at item. If it consists of constants only,
    // evaluateExpr will let us know; otherwise all subtrees that contain only
    // constants will be evaluated
    const ValueId & tempVal = item->getValueId();
    allConstants = evaluateExpr( tempVal, vid, 0 );
    if (allConstants < 0) {
      clear();
      return FALSE;
    }

    // If we only have constants, do the evaluation
    if (allConstants) {

      if (item->child(0)->getArity() > 0) {
        Int32 error = 0;
        const ValueId & tempVal1 = item->getValueId();
        error = evaluateConstantTree( tempVal1, vid, 0, NULL );
        if (error) {
	  clear();
	  return FALSE;
        }
      }

      tempItem1 = item->child(0);
      c = (ConstValue *) tempItem1;

      constValue = atoi(c->getText());

      if (constValue == 0) {			// the FALSE value
	clear();
        insert(item->child(0)->getValueId());
	return FALSE;
      }

      if (constValue != 1) {
        allTrue = FALSE;
      }

    }
    else {
      allTrue = FALSE;
    }

    // Get the simplified tree inserted in resulting list; unless it is a TRUE
    // node.
    if (constValue != 1) {
      insert(item->child(0)->getValueId());
    }

  }

  // If the whole expression evaluates to TRUE, return TRUE
  if (allTrue) {
    clear();
    insert(item->child(0)->getValueId());
  }

  return allTrue;
}

// ---------------------------------------------------------------------
// findCommonElements()
//
// Find common elements between "this" and "other". Remove all
// value ids that are not common elements from "this" (so that
// "this" contains the common subexpressions).
// ---------------------------------------------------------------------
void ValueIdList::findCommonElements(const ValueIdSet &other)
{
  NAList<CollIndex> listCopy(CmpCommon::statementHeap());
  listCopy.clear();
  CollIndex i;

  for (i = 0; i < entries() ; i++)
  {
    // copy the index of the element that is not contained in the "other" set
    // this should be removed later
    if (!other.contains((*this)[i]) )
      listCopy.insert(i);
  }
  // now go and remove all the elements indexed by i. Start from the back of the
  // list. If all elements of this exist in other, then return.

  for (i =  listCopy.entries(); i > 0 ;i--)
    removeAt(listCopy[i-1]);
}

// ---------------------------------------------------------------------
// findCommonElementsFromList()
//
// Find common elements between "this" and "other".
// ---------------------------------------------------------------------
ValueIdList ValueIdList::findCommonElementsFromList(const ValueIdList &other)
{
  ValueIdList listCopy;
  listCopy.clear();
  CollIndex i, j;

  // We use "other' as the main loop, as it is important to maintain the order
  // of the other in "this"
  for (i = 0; i < other.entries() ; i++)
  {
    ValueId currentOtherId = other[i];

    // Find all occurences of "other" in "this"

    for (j = 0; j < entries(); j++)
    {
      // copy the index of the element that is not contained in the "other" set
      // this should be removed later
      if ( (*this)[j] ==  currentOtherId )
	listCopy.insert(currentOtherId);
    }
  }

  return listCopy;
}

// ***********************************************************************
// Methods for class ValueIdMap
// ***********************************************************************

ValueIdMap::ValueIdMap(const ValueIdSet &identity)
{
  for (ValueId x = identity.init();
       identity.next(x);
       identity.advance(x))
    {
      topValues_.insert(x);
      bottomValues_.insert(x);
    }
}

NABoolean ValueIdMap::operator == (const ValueIdMap &other) const
{
  // shortcut: identical lists of value ids
  if (topValues_ == other.topValues_ AND
      bottomValues_ == other.bottomValues_)
    return TRUE;

  return FALSE; // for now
}

void ValueIdMap::remapTopValue(const ValueId &newTopValue,
			       const ValueId &bottomValue)
{
  CollIndex ix = bottomValues_.index(bottomValue);

  if (ix != NULL_COLL_INDEX)
    topValues_[ix] = newTopValue;
  else
    addMapEntry(newTopValue,bottomValue);
}

void ValueIdMap::remapBottomValue(const ValueId &topValue,
			          const ValueId &newBottomValue)
{
  CollIndex ix = topValues_.index(topValue);

  if (ix != NULL_COLL_INDEX)
    bottomValues_[ix] = newBottomValue;
  else
    addMapEntry(topValue,newBottomValue);
}

void ValueIdMap::addMapEntry(const ValueId &newTopValue,
			     const ValueId &newBottomValue)
{
  topValues_.insert(newTopValue);
  bottomValues_.insert(newBottomValue);
}

void ValueIdMap::mapValueIdUp(ValueId &topValue,
			      const ValueId &bottomValue) const
{
  CollIndex ix = bottomValues_.index(bottomValue);

  if (ix != NULL_COLL_INDEX)
    topValue = topValues_[ix];
  else
    topValue = bottomValue;
}

void ValueIdMap::mapValueIdUpWithIndex(ValueId &topValue,
			      const ValueId &bottomValue, CollIndex i) const
{
  CollIndex currEntry = i;
  CollIndex result    = i;
  NABoolean found = FALSE;
  CollIndex bottomEntries = bottomValues_.entries();

  while (currEntry != NULL_COLL_INDEX)
  {
    // get the next used entry of bottomValues_ from the index currEntry_
    // This methos is the const version of usedEntry
    if (bottomValues_.constEntry(currEntry) == bottomValue)
	{
	currEntry = result;
	found = TRUE;
	break;
	}
      else
	{
	  // advance to the next entry
	  result++;
	  currEntry = bottomValues_.getUsage(currEntry);
	}
    }

  if (found)
    topValue = topValues_[currEntry];
  else
    topValue = bottomValue;
}

void ValueIdMap::mapValueIdDown(const ValueId &topValue,
				ValueId &bottomValue) const
{
  CollIndex ix = topValues_.index(topValue);

  if (ix != NULL_COLL_INDEX)
  {
    bottomValue = bottomValues_[ix];
	return;
  }
  //++ Triggers -
  // If a generic update has a trigger,
  // topValues_ might contain VEG_REFERENCEs
  for (ix=0; ix < topValues_.entries() ; ix++)
  {
    ItemExpr *pred = topValues_[ix].getItemExpr();

	if (pred->getOperatorType() == ITM_VEG_REFERENCE)
	{
	  const ValueIdSet & VEGGroup =((VEGReference *)pred)->getVEG()->getAllValues();
	  if (VEGGroup.contains(topValue))
	  {
		bottomValue = bottomValues_[ix];
		return;
	  }
	}
  }
  //-- Triggers -
  bottomValue = topValue;
}

void ValueIdMap::mapValueIdListUp(ValueIdList &topValues,
				  const ValueIdList &bottomValues) const
{
  CMPASSERT(topValues.entries() == 0);

  for (CollIndex i = 0; i < bottomValues.entries(); i++)
    {
      ValueId u;
      mapValueIdUp(u,bottomValues[i]);
      topValues.insert(u);
    }
}

void ValueIdMap::mapValueIdListDown(const ValueIdList &topValues,
				    ValueIdList &bottomValues) const
{
  CMPASSERT(bottomValues.entries() == 0);

  for (CollIndex i = 0; i < topValues.entries(); i++)
    {
      ValueId l;
      mapValueIdDown(topValues[i],l);
      bottomValues.insert(l);
    }
}

void ValueIdMap::mapValueIdSetUp(ValueIdSet &topValues,
				 const ValueIdSet &bottomValues) const
{
  CMPASSERT(topValues.isEmpty());

  for (ValueId l = bottomValues.init();
       bottomValues.next(l); bottomValues.advance(l))
    {
      ValueId u;
      mapValueIdUp(u,l);
      topValues.insert(u);
    }
}

void ValueIdMap::mapValueIdSetDown(const ValueIdSet &topValues,
				   ValueIdSet &bottomValues) const
{
  CMPASSERT(bottomValues.isEmpty());

  for (ValueId u = topValues.init();
       topValues.next(u); topValues.advance(u))
    {
      ValueId l;
      mapValueIdDown(u,l);
      bottomValues.insert(l);
    }
}

void ValueIdMap::rewriteValueIdUp(ValueId &topValue,
				  const ValueId &bottomValue)
{
  topValue = bottomValue.getItemExpr()->mapAndRewrite(*this,FALSE);
}

void ValueIdMap::rewriteValueIdDown(const ValueId &topValue,
				    ValueId &bottomValue)
{
  bottomValue = topValue.getItemExpr()->mapAndRewrite(*this,TRUE);
}

void ValueIdMap::rewriteValueIdUpWithIndex(ValueId &topValue,
				  const ValueId &bottomValue, CollIndex i)
{
  topValue = bottomValue.getItemExpr()->mapAndRewriteWithIndx(*this,i);
}

void ValueIdMap::rewriteValueIdListUp(ValueIdList &topValues,
				      const ValueIdList &bottomValues)
{
  CMPASSERT(topValues.entries() == 0);

  for (CollIndex i = 0; i < bottomValues.entries(); i++)
    {
      ValueId u;
      rewriteValueIdUp(u,bottomValues[i]);
      topValues.insert(u);
    }
}

void ValueIdMap::rewriteValueIdListUpWithIndex(ValueIdList &topValues,
				      const ValueIdList &bottomValues)
{
  CMPASSERT(topValues.entries() == 0);

  for (CollIndex i = 0; i < bottomValues.entries(); i++)
    {
      ValueId u;
      rewriteValueIdUpWithIndex(u,bottomValues[i],i);
      topValues.insert(u);
    }
}

void ValueIdMap::rewriteValueIdListDown(const ValueIdList &topValues,
					ValueIdList &bottomValues)
{
  CMPASSERT(bottomValues.entries() == 0);

  for (CollIndex i = 0; i < topValues.entries(); i++)
    {
      ValueId l;
      rewriteValueIdDown(topValues[i],l);
      bottomValues.insert(l);
    }
}

void ValueIdMap::rewriteValueIdSetUp(ValueIdSet &topValues,
				     const ValueIdSet &bottomValues)
{
  CMPASSERT(topValues.isEmpty());

  for (ValueId l = bottomValues.init();
       bottomValues.next(l); bottomValues.advance(l))
    {
      ValueId u;
      rewriteValueIdUp(u,l);
      topValues.insert(u);
    }
}

void ValueIdMap::rewriteValueIdSetDown(const ValueIdSet &topValues,
				       ValueIdSet &bottomValues)
{
  CMPASSERT(bottomValues.isEmpty());

  for (ValueId u = topValues.init(); topValues.next(u); topValues.advance(u))
    {
      ValueId l;
      rewriteValueIdDown(u,l);
      bottomValues.insert(l);
    }
}

void ValueIdMap::flipSides()
{
  ValueIdList flipList = topValues_;
  topValues_ = bottomValues_;
  bottomValues_ = flipList;
}

NABoolean ValueIdMap::normalizeNode(NormWA & normWARef)
{
  NABoolean t1,t2;

  // Transform both lists
  t1 = topValues_.normalizeNode(normWARef);
  t2 = bottomValues_.normalizeNode(normWARef);

  return (t1 || t2);
}

// Remove unused entries from the Map if they are no longer required
// based on the require values.
//
void ValueIdMap::removeUnusedEntries(const ValueIdSet &requiredValues, NABoolean matchWithTopValues)
{
  if (matchWithTopValues)
  {
    for (CollIndex ix=0; ix < topValues_.entries() ; ix++)
    {
      if(!requiredValues.contains(topValues_[ix]))
      {
	topValues_.removeAt(ix);
	bottomValues_.removeAt(ix);
	ix--;
      }
    }
  }
  else
  {
    for (CollIndex ix=0; ix < bottomValues_.entries() ; ix++)
    {
      if(!requiredValues.contains(bottomValues_[ix]))
      {
	topValues_.removeAt(ix);
	bottomValues_.removeAt(ix);
	ix--;
      }
    }
  }
}

// ***********************************************************************
// Constructor for ValueDesc
//
// Use the ActiveSchemaDB() consistently in ALL methods for ValueDescs
// and ValueIds.
// ***********************************************************************

ValueDesc::ValueDesc(ItemExpr *expr)
         : exprPtr_(expr), domId_(NULL)
{
  ActiveSchemaDB()->insertValueDesc(this);
}

// static ctor
ValueId ValueDesc::create(ItemExpr *expr, const NAType *type, CollHeap *h)
{
  ValueDesc *vdesc = new (h) ValueDesc(expr);
  vdesc->setDomainDesc(new (h) DomainDesc(ActiveSchemaDB(), *type));
  return vdesc->getValueId();
}

// ***********************************************************************
// Methods for class ValueDescArray
// ***********************************************************************
#pragma nowarn(1506)   // warning elimination
void ValueDescArray::print(FILE* ofd, const char* indent, const char* title,
			   NABoolean dontDisplayErrors) const
{
#ifndef NDEBUG
  BUMP_INDENT(indent);
  fprintf(ofd, "%s%s %p (%d entries)\n",
	       NEW_INDENT, title, this, entries());

  for (CollIndex i = 0; i < entries(); i++)
    {
      ValueDesc *vd = at(i);
      if (vd && used(i))
	{
	  Int32 otyp = 0;
          NAString unparsed(CmpCommon::statementHeap());
	  ItemExpr *ie = vd->getItemExpr();
	  if (ie)
	    {
	      CollIndex ivid = (CollIndex)vd->getValueId();
	      if (i != ivid)
		{
		  //fprintf(ofd, "%4d != %d: ERROR\n", i,
		  otyp = -1;
		  char cvid[TEXT_DISPLAY_LENGTH];
		  sprintf(cvid, "ERROR: vid %d", ivid);
		  unparsed = cvid;
		}
	      else
		{
		  otyp = ie->getOperatorType();
		  ie->unparse(unparsed);
		}
	    }
	  if (otyp > 0 || !dontDisplayErrors)
	    fprintf(ofd, "%4d %p %4d: %s\n", i, ie, otyp, unparsed.data());
	}
    }
#endif
} // ValueDescArray::print()
#pragma warn(1506)  // warning elimination

void ValueDescArray::display(NABoolean dontDisplayErrors) const
{
  print(stdout, DEFAULT_INDENT, "ValueDescArray", dontDisplayErrors);
}

/*static*/ void ValueDescArray::Display(NABoolean dontDisplayErrors)
{
  ActiveSchemaDB()->getValueDescArray().print(
    stdout, DEFAULT_INDENT, "Global ValueDescArray", dontDisplayErrors);
}

//--------------------------------------------------------
// Replace aggregates of type ITM_ONE_ROW(I,J,K) with (I,J,K);
// Generator does not know how to transmit
// ONE_ROW of columns from a child to parent. So do not
// ask for it. One Row check would be performed at the
// concerned GroupBy node.
//
// If we have a expression tree where ITM_ONE_ROW node is an
// interior node with arity one, replace it as well.
//--------------------------------------------------------
void ValueIdSet::replaceOneRowbyList( NormWA & normref )
{

  ValueId exprId;
  ValueIdSet replaceSet;
  for (exprId = init(); next(exprId); advance(exprId))
  {
    ItemExpr *thisIE = exprId.getItemExpr();
    if ( (thisIE->getArity() >= 1) &&
         (thisIE->containsOneRowAggregate()) )

    {
      ItemExpr *tfm = NULL;
      tfm = thisIE->transformOneRowAggregate( normref );
      CMPASSERT( tfm );

      exprId.replaceItemExpr(tfm);
      // redrive type synthesis for both self and child nodes
      tfm->synthTypeAndValueId(TRUE, TRUE);

      tfm = tfm->transformMultiValuePredicate(FALSE);
      if (tfm) // transform was needed
      {
        exprId.replaceItemExpr(tfm);
	// redrive type synthesis for both self and child nodes
        tfm->synthTypeAndValueId(TRUE, TRUE);
        tfm->convertToValueIdSet(replaceSet, NULL, ITM_AND, FALSE);
        subtractElement(exprId);
      }
      else
      {
        // this itemexpression tree contains a onerow aggregate node, yet no
        // transformation was done. Remove the aggregate node from the tree so
        // that the relational expression won't ask for a onerow valueid.
        tfm =  thisIE->removeOneRowAggregate( thisIE, normref );
        CMPASSERT( tfm );
        exprId.replaceItemExpr(tfm);
        tfm->convertToValueIdSet(replaceSet, NULL, ITM_AND, FALSE);
        subtractElement(exprId);
      }
    } // if contains oneRow aggregate.

    // Even though some scalar aggregates do not contain the node
    // ITM_ONE_ROW, they implicitly contain them. There is special logic
    // in Subquery::transformNode to identify them. If we are seeing one
    // of those here, they need to be retransformed.

    // Go through the ItemExpression Tree, anchored by the Variable
    // 'ThisIE' and retransform it; case Id: 10-990122-0552

    if ( thisIE->markPathToUnTransformedNode() )

      // Returns TRUE if any node in the whole tree anchored by thisIE
      // contains an untransformed node.
      //
      // Marks the entire path, from this node to the untransformed node, as
      // untransformed.
      //
      // I believe that this modification of what was originally coded
      // handles the case when the item expression tree is deep -- that
      // is, when there is one or more nodes betwen thisIE and the
      // currently untransformed node.  See his comment below:
      //
      // $$$ This fix is temporary as it would only work if the item
      // $$$ expression tree is shallow. Need to do special processing if the
      // $$$ tree is deep.  .... and I have a deadline to keep -  1/29/99

      {
        CMPASSERT( ! thisIE->nodeIsTransformed() );
      }

    // If we don't mark the entire path as untransformed (from the
    // untransformed child to thisIE), when it comes time to transforming
    // thisIE, we won't walk down the tree to the untransformed node.
    // Look at the beginning of all ::transformNode() methods -- the first
    // thing that each one does is check to see if it's already
    // transformed.  If so, returns, without looking at its children.
    // Thus, if there are one or more nodes marked "transformed" between
    // thisIE (marked "UNtransformed") and the untransformed child node,
    // we won't transform that child node when we call
    // thisIE->transformNode().
    //
    // There is a general assumption in all other transformation code: if
    // any node in the tree is transformed, then its children have been
    // transformed already.

  } // for

  addSet(replaceSet);
} // ValueIdSet::replaceOneRowbyList()

// is this list cacheable after this phase?
NABoolean ValueIdList::isCacheableExpr(CacheWA& cwa)
{
  CollIndex ix, limit = entries();
  for (ix = 0; ix < limit; ix++) {
    if (!((*this)[ix].getItemExpr()->isCacheableExpr(cwa))) {
      return FALSE;
    }
  }
  return TRUE;
}

ValueId ValueIdList::extractVEGRefForEquiPredicate(ValueId x) const
{
   ItemExpr* ie = x.getItemExpr();
   switch ( ie->getOperatorType() )
   {
      case ITM_EQUAL:
       {
         for (CollIndex i = 0; i < 2; i++)
          if ( contains(ie->child(i)->getValueId()) )
             return ie->child(i)->getValueId();

          break;
       }

      case ITM_VEG_PREDICATE:
      {
        VEG* veg = ((VEGPredicate*)ie)->getVEG();

        // Simple case first: the veg predicate refers to a VEG
        // that appears in the ValueIdList of this.
        for (CollIndex i = 0; i < entries(); i++)
        {
           ItemExpr* iei = at(i).getItemExpr();

           if (iei->getOperatorType() == ITM_INSTANTIATE_NULL)
              iei=iei->child(0)->castToItemExpr();

           if ( iei->getOperatorType() == ITM_VEG_REFERENCE &&
              ((VEGReference*)iei)->getVEG() == veg )
           {
               return at(i);
           }
       }

       // Next we drill down the VEG predicate to see if there is a
       // VEG reference that appears in ValueIdList of this. We return
       // that VEG reference when the lookup succeeds.
       //
       // The following loop is necessary to deal with a VEG predicate of form
       // D.A = VEGRef(T.A)
       // ValueIdList of this contains {VEGRef(T.A), VEGRef(T.B))
       // The MC join predicate is
       //  T.A = D.A and T.B = D.B
       const ValueIdList vegMembers(veg->getAllValues());

       for (CollIndex i=0; i<vegMembers.entries(); i++) {
          // we will be getting D.A, VegRef(T.A)
          ItemExpr* iei = vegMembers[i].getItemExpr();

          if (iei->getOperatorType() == ITM_INSTANTIATE_NULL)
             iei=iei->child(0)->castToItemExpr();

          if ( iei->getOperatorType() == ITM_VEG_REFERENCE &&
               this->contains(vegMembers[i])
             )
            return vegMembers[i];

       }

       break;

     }

     default:
       break;
   }

   return  NULL_VALUE_ID;
}

// change literals of a ValueIdList into ConstantParameters
void ValueIdList::normalizeForCache(CacheWA& cwa, BindWA& bindWA)
{
  // Iterate over all the values (scalar expressions) in this list.
  CollIndex ix, limit = entries();
  for (ix = 0; ix < limit; ix++) {
    ItemExpr *iePtr = at(ix).getItemExpr(); // original expr
    // apply normalizeForCache on the item expr
    ItemExpr *nePtr = iePtr->normalizeForCache(cwa, bindWA);
    // if normalizeForCache changed the original expr, update the list
    if (nePtr->castToItemExpr() != iePtr || nePtr->getValueId() != at(ix)) {
      at(ix) = nePtr->castToItemExpr()->getValueId();
    }
  }
}

ConstValue* ValueIdList::getConstant(ItemExpr* ie)
{
   switch (ie->getOperatorType())
     {
     case ITM_CACHE_PARAM:
       {
	 ConstantParameter*cp = (ConstantParameter*)ie;
	 return cp->getConstVal();
       }
       break;

     case ITM_CONSTANT:
       return (ConstValue*)ie;
       break;

     default:
       {
	 if ( ie->getOperatorType() == ITM_VEG_REFERENCE )
	   {
	     ValueIdSet result;
	     ie->findAll(ITM_CONSTANT, result, TRUE, FALSE);

	     if ( result.entries() == 0 )
	       ie->findAll(ITM_CACHE_PARAM, result, TRUE, FALSE);

	     if ( result.entries() == 1 )
	       {
		 for (ValueId vid= result.init();  result.next(vid); result.advance(vid))
		   {
		     ConstValue * constVal = getConstant(vid.getItemExpr());
		     return constVal;
		   } // for
	       } // if
	   } // if
       } // default
       break;
     } // switch

   return NULL;
}

void ValueIdList::convertToTextKey(const ValueIdList& keyList, NAString& result)
{
  result.resize(0);

  CollIndex i = 0;
  for (i = 0; i < entries(); i++)
  {
     ItemExpr* ie = at(i).getItemExpr();

     ConstValue* constVal = getConstant(ie);

     if ( constVal ) {
       const NAType &type = keyList.at(i).getType();
       const NAType *constType = constVal->getType();

       NAString val = *constVal->getRawText();
       //       val = val.strip(NAString::leading, ' ');
       short len = 0;

       ///////////////////////////////////////////////////////////////////////
       // Value Layout:
       //    2 bytes total length     |  2 bytes null value, if nullable | data
       //    (null indicator length(2 bytes) + data length)   |
       ////////////////////////////////////////////////////////////////////////
       if (type.supportsSQLnull())
	 {
	   len = 2;
	 }

       if (constVal->isNull())
	 {
	   if (type.supportsSQLnull())
	     {
	       result.append((char*)&len, sizeof(short));

	       short nullVal = -1;
	       result.append((char*)&nullVal, sizeof(short));
	     }
	 }
       else if ((val == "<min>") ||
		(val == "<max>"))
	 {
	   Lng32 bufLen =
	     (type.isVaryingLen() ?
	      (type.getNominalSize() + type.getVarLenHdrSize()) :
	      type.getNominalSize());
	   char * buf = new(CmpCommon::statementHeap()) char[bufLen+10];

	   NAString *mmVal = NULL;
	   if (val == "<min>")
	     {
	       type.minRepresentableValue(buf, &bufLen, &mmVal,
					  CmpCommon::statementHeap());

	       if ((type.getTypeQualifier() == NA_DATETIME_TYPE) ||
		   (type.getTypeQualifier() == NA_INTERVAL_TYPE))
		 {
		   // string value returned is of the form: DATE '2013-06-20' or
		   // INTERVAL '10' YEAR.
		   // Extract the actual string from the returned value.
		   Lng32 start = mmVal->index("'");
		   if (start > 0)
		     {
		       Lng32 end = mmVal->index("'", start+1);
		       if (end > 0)
			 {
			   *mmVal = (*mmVal)(start+1, (end-start-1));

			    if (type.getTypeQualifier() == NA_INTERVAL_TYPE)
			      {
				// prepend '-' to the output
				(*mmVal).prepend('-', 1);
			      }
			 }
		     }
		 }
               else if (type.getTypeQualifier() == NA_CHARACTER_TYPE)
                 {
                   // string literal looks like _ISO88591'abc' and is
                   // in UTF-8, what we want here is the actual character
                   // values in the type's character set
                   *mmVal = NAString(buf, bufLen);
                 }
	     }
	   else
	     {
	       type.maxRepresentableValue(buf, &bufLen, &mmVal,
					  CmpCommon::statementHeap());

	       if ((type.getTypeQualifier() == NA_DATETIME_TYPE) ||
		   (type.getTypeQualifier() == NA_INTERVAL_TYPE))
		 {
		   // string value returned is of the form: DATE '2013-06-20' or
		   // INTERVAL '10' YEAR.
		   // Extract the actual string from the returned value.
		   Lng32 start = mmVal->index("'");
		   if (start > 0)
		     {
		       Lng32 end = mmVal->index("'", start+1);
		       if (end > 0)
			 {
			   *mmVal = (*mmVal)(start+1, (end-start-1));
			 }
		     }
		 }
               else if (type.getTypeQualifier() == NA_CHARACTER_TYPE)
                 {
                   // string literal looks like _ISO88591'abc' and is
                   // in UTF-8, what we want here is the actual character
                   // values in the type's character set
                   *mmVal = NAString(buf, bufLen);
                 }
	     }

	   short vLen = 0;
	   if (type.isVaryingLen())
	     {
	       vLen = *(short*)mmVal->data();
	     }
	   else
	     {
	       vLen = mmVal->length();
	     }

	   len += vLen;
	   result.append((char*)&len, sizeof(short));
	   if (type.supportsSQLnull())
	     {
	       short nullVal = 0;
	       result.append((char*)&nullVal, sizeof(short));
	     }

	   if (type.isVaryingLen())
	     result.append(&mmVal->data()[type.getVarLenHdrSize()], vLen);
	   else
	     result.append(mmVal->data(), vLen);
	 }
       else
	 {
	   short vLen = val.length();

	   if ((constType->getTypeQualifier()  == NA_NUMERIC_TYPE) &&
	       (((NumericType*)constType)->isExact()) &&
               (NOT ((NumericType&)type).isBigNum()) &&
	       (constType->getScale() > 0))
	     {
	       NAString newVal;
	       if (vLen <= constType->getScale())
		 {
		   newVal = "0.";
		   for (Lng32 i = 0; i < (constType->getScale() - vLen); i++)
		     {
		       newVal += "0";
		     }
		   newVal += val;
		 }
	       else
		 {
                   // get digits to the left of scale
		   newVal = val(0, vLen - constType->getScale() );

		   newVal += ".";
		   newVal += val(vLen - constType->getScale(), constType->getScale());
		 }

	       val = newVal;
	       vLen = val.length();
	     }

	   len += vLen;

	   result.append((char*)&len, sizeof(short));

	   if (type.supportsSQLnull())
	     {
	       short nullVal = 0;
	       result.append((char*)&nullVal, sizeof(short));
	     }

	   result.append(val.data(), vLen);
	 }
     } else
        return;
  } // for
}

Int32 ValueIdList::countConstantsAsPrefixes()
{
  Int32 ct = 0;
  for (CollIndex i = 0; i < entries(); i++)
  {
     ItemExpr* ie = at(i).getItemExpr();

     switch (ie->getOperatorType()) {
       case ITM_CACHE_PARAM:
       case ITM_CONSTANT:
         ct++;
         continue;

       case ITM_VEG_REFERENCE:
       case ITM_VEG_PREDICATE:
         {
         ValueIdSet result;
         ie->findAll(ITM_CONSTANT, result, TRUE, FALSE);
         ie->findAll(ITM_CACHE_PARAM, result, TRUE, FALSE);

         ct += result.entries();
         }
         continue;

       default:
         break;
     }
  }

  return ct;
}

// change literals of a ValueIdSet into ConstantParameters
void ValueIdSet::normalizeForCache(CacheWA& cwa, BindWA& bindWA)
{
  NABoolean changed = FALSE;
  ValueIdSet newExpr;
  // Iterate over all the values (scalar expressions) in this set.
  for (ValueId exprId = init(); next(exprId); advance(exprId)) {
    ItemExpr *iePtr = exprId.getItemExpr();  // original expr.
    // apply normalizeForCache on the item expr
    ItemExpr *nePtr = iePtr->normalizeForCache(cwa, bindWA);
    // if normalizeForCache changed the original expr, update the set
    if (nePtr != iePtr || nePtr->getValueId() != exprId) {
	  changed = TRUE;
	  subtractElement(exprId); // delete original expression from set
	  // accumulate new expressions in another set
	  if (nePtr) {
	    nePtr->convertToValueIdSet(newExpr);
      }
    }
  }
  if (changed) {
    addSet(newExpr); // add normalized expressions to the given set
  }
}

//---------------------------------------------------------------------------
//Check whether the Valudidset contains any CAST expressions && and replace
// it with the original expression
//---------------------------------------------------------------------------
void ValueIdSet::replaceCastExprWithOriginal(const ValueIdSet &originalOutputs,
                                             const RelExpr * parent)
{
  ValueId vid, vid1;
  RelExpr *child = parent->child(0);
  ValueIdSet childOutputs(child->getGroupAttr()->getCharacteristicOutputs());

  for (vid = originalOutputs.init();
       originalOutputs.next(vid);
       originalOutputs.advance(vid) )
  {
    if (vid.getItemExpr()->getOperatorType() == ITM_CAST)
    {
      Cast *castExpr = (Cast *)vid.getItemExpr();

      // can the child produce the valueid vid1?
      vid1 = castExpr->getExpr()->getValueId();

      if  (childOutputs.contains(vid1))
      {
        subtractElement(vid);
        addElement(vid1);
      }
      // for case statement, do not produce any expressions downwards
      // compute the case statement at the root
      else if (castExpr->getExpr()->getOperatorType() == ITM_CASE)
      {
        ValueIdSet coveredValues, emptySet;
        const GroupAttributes emptyGA;
        castExpr->getExpr()->getLeafValuesForCoverTest(coveredValues, emptyGA, emptySet);
        // take an intersection of child outputs and covered values
        // and request from child those ooutputs
        coveredValues.intersectSet(childOutputs);
	//10-070201-2242 -Begin
	//Replace the cast itemExpr only if the child can
	//provide ALL values to evaluate it.
	if(!coveredValues.isEmpty())
	{
	  NABoolean found = TRUE;
	  for(ValueId v = coveredValues.init();
	      coveredValues.next(v);
	      coveredValues.advance(v))
	  {
      	    if(!childOutputs.contains(v))
	      {
		   found = FALSE;
		   break;
	      }
	  }
	  if(found)
	  {
            subtractElement(vid);
            addSet(coveredValues);
	  }
	//10-070201-2242-End
      }
      }
    }
  }
} // ValueIdSet::replaceCastExprWithOriginal()

//-----------------------------------------------------------------------
// Check whether the ValueIdSet contains expressions of the form
// InstNull(Cast(aggregate))) and modify them to aggregate. This is done
// if the left child of the argument joinExpr can potentially produce
// the aggregate; typically the valueid set represents output values of
// a join operator. This is called from Join::pushdownCoveredExpr().
// Input: joinExpression
// Potentially sideeffects the this object
//-----------------------------------------------------------------------
void ValueIdSet::replaceInstnullCastAggregateWithAggregateInLeftJoins
                                            ( RelExpr *joinExpr)
{
  if (joinExpr->getOperatorType() != REL_LEFT_JOIN)
    return;

  ValueId vid;
  for (vid = init();
          next(vid);
          advance(vid) )
  {
     ItemExpr *ie= vid.getItemExpr();
     if (ie->getOperatorType() != ITM_INSTANTIATE_NULL)
       continue;
     if (ie->child(0)->getOperatorType() != ITM_CAST)
       continue;
     Cast *castIE = (Cast *)ie->child(0)->castToItemExpr();
     if (castIE->getExpr()->isAnAggregate())
     {
       // can the right child produce the aggregate?
       ValueIdSet outputs;
       joinExpr->child(1)->getPotentialOutputValues(outputs);
       if (outputs.contains(castIE->getExpr()->getValueId()))

       {
         subtractElement(vid);
         addElement(castIE->getExpr()->getValueId());
       }

     }
  }
} // ValueIdSet::replaceInstnullCastAggregateWithAggregateInLeftJoins

// -----------------------------------------------------------------------
// This method is a slight modification of intersectSet. Here instead of
// modifying this operand it returns the modified set
// -----------------------------------------------------------------------
ValueIdSet ValueIdSet::intersect(const ValueIdSet & v) const
{
  ValueIdSet thisCopy(*this);
  thisCopy.intersectSet(v);
  return thisCopy;
}

ValueIdSet& ValueIdSet::intersectSetDeep(const ValueIdSet & v)
{
  for (ValueId tgt = init(); next(tgt); advance(tgt))
    {
      NABoolean found = FALSE;
      for (ValueId vid = v.init(); v.next(vid) && !found; v.advance(vid))
        {
          if (vid.getItemExpr()->referencesTheGivenValue(tgt,FALSE,FALSE))
            found = TRUE; // keep it
        }
      if (!found)
        subtractElement(tgt); // remove unreferenced element
    }
  return *this;
}

// --------------------------------------------------------------------
// return true iff ValueIdSet has predicates that guarantee
// that opd is not nullable
// --------------------------------------------------------------------
NABoolean ValueIdSet::isNotNullable(const ValueId& opd)
{
  // if opd's type is not nullable then return TRUE
  if (!opd.getType().supportsSQLnullLogical()) {
    return TRUE;
  }
  // opd's type is nullable.

  // search ValueIdSet for a predicate conjunct
  // that can guarantee that opd is not null
  for (ValueId vid = init(); next(vid); advance(vid) ) {
    // predicates are implicitly connected by AND
    ItemExpr *iePtr = vid.getItemExpr();
    switch (iePtr->getOperatorType()) {
    case ITM_IS_NOT_NULL:
      if (iePtr->child(0)->containsTheGivenValue( opd )) {
        // found "opd IS NOT NULL" predicate conjunct
        return TRUE; // opd is not null
      }
      break; // keep looking
    case ITM_EQUAL:
    case ITM_NOT_EQUAL:
    case ITM_LESS:
    case ITM_LESS_EQ:
    case ITM_GREATER:
    case ITM_GREATER_EQ:
      if (iePtr->child(0)->containsTheGivenValue( opd ) ||
          iePtr->child(1)->containsTheGivenValue( opd )) {
        // found "opd compop expr" predicate conjunct
        return TRUE; // opd is not null
      }
      break; // keep looking
    case ITM_IS_NULL:
      if (iePtr->child(0)->containsTheGivenValue( opd )) {
        // found "opd IS NULL" predicate conjunct
        return FALSE; // opd is null
      }
      break;
    default:
      break; // keep looking
    }
  }
  return FALSE;
}

void ValueIdList::addMember(ItemExpr* x)
{
   insert(x->getValueId());
}

void ValueIdSet::addMember(ItemExpr* x)
{
   (*this) += (x->getValueId());
}

Lng32 ValueIdList::findPrefixLength(const ValueIdSet& x) const
{
  CollIndex count = this->entries();
  Lng32 ct = 0;
  for (CollIndex i=0; i<count; i++)
    {
      if ( x.contains((*this)[i]) )
         ct++;
      else
         break;
    }
  return ct;
}

// -----------------------------------------------------------------------
// replace any ColReference (of the given column name) in of this value
// expression with the given expression.
// used in ValueId::computeEncodedKey() to assign key values into the
// salt/DivisionByto expression.
// ----------------------------------------------------------------------
void ValueId::replaceColReferenceWithExpr(const NAString& colName,
                                          const ValueId & vid)
{
  ItemExpr* thisItemExpr = getItemExpr();
  for( Lng32 i = 0; i < thisItemExpr->getArity(); i++ )
  {
    ValueId childValueId = thisItemExpr->child(i).getValueId();
    ItemExpr* childItemExpr = childValueId.getItemExpr();

    if( childItemExpr->getOperatorType() == ITM_REFERENCE)
    {
      if( ((ColReference*)childItemExpr)->getColRefNameObj().getColName() == colName )
        thisItemExpr->setChild( i, vid.getItemExpr() );
    }
    childValueId.replaceColReferenceWithExpr( colName, vid );
  }
}

char*
ValueIdList::computeEncodedKey(const TableDesc* tDesc, NABoolean isMaxKey,
                               char*& encodedKeyBuffer, Int32& keyBufLen) const
{
   const NATable*  naTable = tDesc->getNATable();

   CollIndex count = entries();
   NAString** inputStrings = new (STMTHEAP) NAStringPtr[count];

   for (Int32 j=0; j<count; j++ )
       inputStrings[j] = NULL;

   for (Int32 j=0; j<count; j++ ) {

      ValueId vid = (*this)[j];
      ItemExpr* ie = vid.getItemExpr();

      if ( ie->getOperatorType() != ITM_CONSTANT ) {

          ConstValue* value = NULL;
          if ( ie->doesExprEvaluateToConstant(TRUE, TRUE) ) {
             ValueIdSet availableValues;
             // do a simple VEG replacement with no available values
             // and no inputs, all VEGies should have constants in
             // them and should be replaced with those
             ie = ie->replaceVEGExpressions(availableValues, availableValues);
             value = ie->evaluate(STMTHEAP);
             if ( !value )
                return NULL;
          } else
             return NULL;

          inputStrings[j] = new (STMTHEAP) NAString(value->getConstStr(FALSE));
      } else  {
         // no need to prefix with charset prefix.
         inputStrings[j] = new (STMTHEAP) NAString(((ConstValue*) ie)->getConstStr(FALSE));

         if ( *inputStrings[j] == "<min>" ||  *inputStrings[j] == "<max>" )
            inputStrings[j] = NULL;
      }
   }

   const NAFileSet * naf = naTable->getClusteringIndex();
   const desc_struct * tableDesc = naTable->getTableDesc();
   desc_struct * colDescs = tableDesc->body.table_desc.columns_desc;
   desc_struct * keyDescs = (desc_struct*)naf->getKeysDesc();

   // cast away const since the method may compute and store the length
   keyBufLen = ((NAFileSet*)naf)->getEncodedKeyLength();

   if ( naTable->isHbaseCellTable() || naTable->isHbaseRowTable() ) {
      // the encoded key for Native Hbase table is a null-terminated string ('<key>')
      NAString key;
      key.append("(");

      size_t idx = inputStrings[0]->index("_ISO88591");
      if ( idx == 0 )
         key.append(inputStrings[0]->remove(0, 9));
      else
         key.append(*inputStrings[0]);

      key.append(")");

      keyBufLen = inputStrings[0]->length() + 5; // extra 4 bytes for (,', ', ), and one byte for null.

      if (!encodedKeyBuffer )
         encodedKeyBuffer = new (STMTHEAP) char[keyBufLen];

      memcpy(encodedKeyBuffer, key.data(), key.length());
      encodedKeyBuffer[key.length()] = NULL;

      return encodedKeyBuffer;

   } else {
      keyBufLen = ((NAFileSet*)naf)->getEncodedKeyLength();

      if (!encodedKeyBuffer )
         encodedKeyBuffer = new (STMTHEAP) char[keyBufLen];

      short ok = encodeKeyValues(colDescs, keyDescs,
                      inputStrings,    // INPUT
                      FALSE,           // not isIndex
                      isMaxKey,
                      encodedKeyBuffer,// OUTPUT
                      STMTHEAP, CmpCommon::diags());

      NADELETEARRAY(inputStrings, count, NAStringPtr, STMTHEAP);

      return ( ok == 0 ) ? encodedKeyBuffer : NULL;
   }
}