@@ -11343,19 +11343,6 @@ short HbaseAccess::extractHbaseFilterPreds(Generator * generator,
        preds.advance(vid))
     {
       ItemExpr * ie = vid.getItemExpr();
-
-      // if it is AND operation, recurse through left and right children
-      if (ie->getOperatorType() == ITM_AND)
-        {
-          ValueIdSet leftPreds;
-          ValueIdSet rightPreds;
-          leftPreds += ie->child(0)->castToItemExpr()->getValueId();
-          rightPreds += ie->child(1)->castToItemExpr()->getValueId();
-          extractHbaseFilterPreds(generator, leftPreds, newExePreds);
-          extractHbaseFilterPreds(generator, rightPreds, newExePreds);
-          continue; 
-        }
-      
       ValueId colVID;
       ValueId valueVID;
       NABoolean removeFromOrigList = FALSE;
/**********************************************************************
// @@@ START COPYRIGHT @@@
//
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License.  You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied.  See the License for the
// specific language governing permissions and limitations
// under the License.
//
// @@@ END COPYRIGHT @@@
**********************************************************************/
/* -*-C++-*-
 *****************************************************************************
 *
 * File:         GenPreCode.C
 * Description:  Fixes up the query tree before code generation.
 *               This is the post-opt and pre-gen stage.
 * Created:      4/15/95
 * Language:     C++
 *
 *
 *****************************************************************************
 */

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

#include "Platform.h"
#include <math.h>
#include "OperTypeEnum.h"

#include "Sqlcomp.h"
#include "GroupAttr.h"
#include "AllRelExpr.h"
#include "RelPackedRows.h"
#include "ReadTableDef.h"
#include "Generator.h"
#include "GenExpGenerator.h"
#include "dfs2rec.h"
#include "vegrewritepairs.h"
#include "exp_clause_derived.h"
#include "keycolumns.h"
#include "ValueDesc.h"
#include "BindWA.h"
#include "TriggerDB.h"
#include "Cost.h"
#include "CostMethod.h"
#include "ItmFlowControlFunction.h"
#include "UdfDllInteraction.h"
#include "StmtDDLNode.h"

#include "NATable.h"
#include "NumericType.h"

#include "CmpStatement.h"
#include "OptimizerSimulator.h"
#include "ItemFunc.h"
#include "ControlDB.h"
#include "CmpSeabaseDDL.h"
#include "NAExecTrans.h"
#include "exp_function.h"
#include "SqlParserGlobals.h"      // must be last #include

extern ItemExpr * buildComparisonPred (	ItemExpr *, ItemExpr *, ItemExpr *,
					OperatorTypeEnum,
					NABoolean specialNulls=FALSE //++MV - Irena
				      );


// -----------------------------------------------------------------------
// generateKeyExpr()
//
// This method is used by the code generator for building expressions
// that are of the form <key column> = <value> for each key column.
//
// Parameters:
//
// const ValueIdSet & externalInputs
//    IN : The set of values that are available here and can be
//         used for replacing any wildcards that appear in the
//         listOfKeyValues.
//
// const ValueIdList & listOfKeyColumns
//    IN : A read-only reference to the list of key columns
//         corresponding to which certain key values have
//         been chosen.
//
// const ValueIdList & listOfKeyValues
//    IN : A read-only reference to a list of key values that
//         are chosen for the corresponding listOfKeyColumns.
//         Values for missing key columns have already been
//         computed and supplied in this list.
//
// ValueIdList & listOfKeyExpr
//    OUT: An assignment expression of the form <key column> = <value>
//         for each key column.
//
// -----------------------------------------------------------------------
static void generateKeyExpr(const ValueIdSet & externalInputs,
			    const ValueIdList & listOfKeyColumns,
			    const ValueIdList & listOfKeyValues,
                            ValueIdList & listOfKeyExpr,
			    Generator* generator,
                            NABoolean replicatePredicates = FALSE)
  {
  ItemExpr * keyExpr;
  CollIndex keyCount = listOfKeyColumns.entries();

  for (CollIndex keyNum = 0; keyNum < keyCount; keyNum++)
    {
      // Build the assignment expression.
      ItemExpr *ieKeyVal = listOfKeyValues[keyNum].getItemExpr()
	->replaceVEGExpressions(externalInputs, externalInputs,
                                FALSE, NULL, replicatePredicates);
      ItemExpr *ieKeyCol = listOfKeyColumns[keyNum].getItemExpr();
      ValueId KeyColId = ieKeyCol->getValueId();

      keyExpr = new(generator->wHeap()) BiRelat(ITM_EQUAL,
						ieKeyCol,
						ieKeyVal);

      // Synthesize its type for and assign a ValueId to it.
      keyExpr->synthTypeAndValueId();

      // INsert it in the list of key expressions
      listOfKeyExpr.insertAt(keyNum, keyExpr->getValueId());
    } // end For Loop

} // static generateKeyExpr()

static NABoolean processConstHBaseKeys(Generator * generator,
                                       RelExpr *relExpr,
                                       const SearchKey *skey,
                                       const IndexDesc *idesc,
                                       const ValueIdSet &executorPreds,
                                       NAList<HbaseSearchKey*> &mySearchKeys,
                                       ListOfUniqueRows &listOfUpdUniqueRows,
                                       ListOfRangeRows  &listOfUpdSubsetRows)
{
  if (! skey)
    return TRUE;

  // convert built-in search key to entries with constants, if possible
  if (skey->areAllKeysConstants(TRUE))
    {
      ValueIdSet nonKeyColumnSet;
      idesc->getNonKeyColumnSet(nonKeyColumnSet);

      // seed keyPreds with only the full key predicate from skey
      ValueIdSet keyPreds = skey->getFullKeyPredicates();

      // include executorPreds and selection predicates 
      // but exclude the full key predicates.
      ValueIdSet exePreds;

      exePreds += executorPreds;
      exePreds += relExpr->getSelectionPred();
      exePreds.subtractSet(keyPreds);

      HbaseSearchKey::makeHBaseSearchKeys(
           skey,
           skey->getIndexDesc()->getIndexKey(),
           skey->getIndexDesc()->getOrderOfKeyValues(),
           relExpr->getGroupAttr()->getCharacteristicInputs(),
           TRUE, /* forward scan */
           keyPreds,
           nonKeyColumnSet,
           idesc,
           relExpr->getGroupAttr()->getCharacteristicOutputs(),
           mySearchKeys);

      // Include any remaining key predicates that have not been 
      // picked up (to be used as the HBase search keys).
      exePreds += keyPreds;

      TableDesc *tdesc = NULL;
      if (mySearchKeys.entries()>0)
        {
          switch (relExpr->getOperatorType())
            {
            case REL_HBASE_ACCESS:
              {
                HbaseAccess *hba = static_cast<HbaseAccess *>(relExpr);
                hba->setSearchKey(NULL);
                hba->executorPred() = exePreds;
                tdesc = hba->getTableDesc();
              }
              break;

            case REL_HBASE_DELETE:
              {
                HbaseDelete *hbd = static_cast<HbaseDelete *>(relExpr);
                hbd->setSearchKey(NULL);
                hbd->beginKeyPred().clear();
                hbd->endKeyPred().clear();
                hbd->executorPred() = exePreds;
                tdesc = hbd->getTableDesc();
              }
              break;

            case REL_HBASE_UPDATE:
              {
                HbaseUpdate *hbu = static_cast<HbaseUpdate *>(relExpr);
                hbu->setSearchKey(NULL);
                hbu->beginKeyPred().clear();
                hbu->endKeyPred().clear();
                hbu->executorPred() = exePreds;
                tdesc = hbu->getTableDesc();
              }
              break;

            default:
              CMPASSERT(tdesc); // unsupported operator type
              break;
            }  // switch
          relExpr->selectionPred().clear();
        }

      if (HbaseAccess::processSQHbaseKeyPreds(generator, 
					      mySearchKeys,
					      listOfUpdUniqueRows,
					      listOfUpdSubsetRows))
	return FALSE;

    } // key uses all constants
  return TRUE;
}

//
// replaceVEGExpressions1() - a helper routine for ItemExpr::replaceVEGExpressions()
//
// NOTE: The code in this routine came from the previous version of 
//       ItemExpr::replaceVEGExpressions().   It has been pulled out
//       into a separate routine so that the C++ compiler will produce
//       code that needs signficantly less stack space for the 
//       recursive ItemExpr::replaceVEGExpressions() routine.
//
ItemExpr * ItemExpr::replaceVEGExpressions1( VEGRewritePairs* lookup )
{
   // see if this expression is already in there
   ValueId rewritten;
   if (lookup->getRewritten(rewritten /* out */, getValueId()))
   {
     if (rewritten == NULL_VALUE_ID)
       return NULL;
     else
       return rewritten.getItemExpr();
   }
   return (ItemExpr *)( (char *)(NULL) -1 ) ;
}

//
// replaceVEGExpressions2() - a helper routine for ItemExpr::replaceVEGExpressions()
//
// NOTE: The code in this routine came from the previous version of
//       ItemExpr::replaceVEGExpressions().   It has been pulled out
//       into a separate routine so that the C++ compiler will produce
//       code that needs signficantly less stack space for the
//       recursive ItemExpr::replaceVEGExpressions() routine.
//
void ItemExpr::replaceVEGExpressions2( Int32 index 
                                     , const ValueIdSet& availableValues
                                     , const ValueIdSet& inputValues
                                     ,       ValueIdSet& currAvailableValues
                                     , const GroupAttributes * left_ga
                                     , const GroupAttributes * right_ga
                                     )
{
   // If we have asked that the EquiPredicate resolve 
   // each child of the equipred by available values from the 
   // respectively input GAs, make sure we pick the right one.

   // First we find out what GA covers the current EquiPred child
   // we are processing (0 or 1), and pick the one that covers, unless
   // both GAs do. If both GAs cover, the just make sure we pick a 
   // different one for each child. The hash join will later fix up
   // the predicate expression to match its children.
   // If none of the GAs covers, we have a problem...

   // This fix was put in to solve solution: 10-100722-1962

   ValueIdSet dummy;

   NABoolean leftGaCovers = left_ga->covers(child(index)->getValueId(),
                                             inputValues,
                                             dummy);
   NABoolean rightGaCovers = right_ga->covers(child(index)->getValueId(),
                                             inputValues,
                                             dummy);

   if (leftGaCovers == FALSE && rightGaCovers == FALSE)
     {
       // for the moment it is assumed that this code is only
       // executed for hash and merge joins, and in general each 
       // side of the expression should be coverd by a child.
       // So if we have neither, we have a problem ..
       cout << "Unable to pick GA to use: " << getArity() << endl;
       CMPASSERT(FALSE);
     }
   else
     {
       const GroupAttributes *coveringGa =  NULL;
       currAvailableValues.clear();
       currAvailableValues += inputValues;
       if (leftGaCovers && rightGaCovers)
         coveringGa = (index == 0 ? left_ga : right_ga);
       else
         coveringGa = (leftGaCovers ? left_ga : right_ga);

       currAvailableValues += coveringGa->getCharacteristicOutputs();
       
     }
}

// -----------------------------------------------------------------------
// ItemExpr::replaceVEGExpressions()
// It performs a top-down, left-to-right tree walk in the ItemExpr tree
// and expands any wildcards (VEGReference or VEGPredicate expressions)
// by replacing them with an expression that belongs to the
// availableValues.
// IF isKeyPredicate is TRUE then the ItemExpr is a KeyPredicate:
// A KeyPredicate is of a restricted form. If we are here it is
// because the predicate is a KeyPredicate. Then, it must satisfy
// very specific characteristics (see Key::isAKeyPredicate(...))
// for instance, one of its sides must be a key column
// This method *guarantees* that a key predicate will be
// generated from the rewritten predicate (i.e. we avoid
// cases like VegRef{T1.A, 2} > 7 being generated like
// 2 > 7 when T1.A is a key column.
// -----------------------------------------------------------------------
ItemExpr * ItemExpr::replaceVEGExpressions
                        (const ValueIdSet& availableValues,
                         const ValueIdSet& inputValues,
			 NABoolean thisIsAnMdamKeyPredicate,
			 VEGRewritePairs* lookup,
			 NABoolean replicateExpression,
                         const ValueIdSet * joinInputAndPotentialOutput,
                         const IndexDesc * iDesc,
                         const GroupAttributes * left_ga,
                         const GroupAttributes * right_ga)
{
  // ---------------------------------------------------------------------
  // If this expression has already been resolved because it exists in
  // availableValues, the replacement of VEGReferences is not required.
  // ---------------------------------------------------------------------
  if (availableValues.contains(getValueId()))
    return this;  // terminate processing

  ItemExpr* iePtr = this;

  if (lookup && replicateExpression)  // if lookup table is present
    {
       ItemExpr* tmpIePtr = ItemExpr::replaceVEGExpressions1( lookup ) ;
       if ( tmpIePtr != (ItemExpr *)( (char *)(NULL) -1 ) )
          return tmpIePtr ;
    };

  if (replicateExpression)
    iePtr = copyTopNode(0, CmpCommon::statementHeap());
  // virtual copy constructor

  // -----------------------------------------------------------------------
  // In the case of mdam key predicates we need to be careful with
  // binary operators whose child is a VegRef that contains both a
  // key column and a constant because the rewrite logic for VEGRef
  // favors the generation of constants over other ItemExprs. In
  // MDAM we *need* to generate the key column and not the constant.
  // With the gated logic below we ensure this.
  // -----------------------------------------------------------------------

  if (thisIsAnMdamKeyPredicate)
    {

#if DEBUG
      // at the moment it is assumed the left and right ga's are only
      // used for hash/merge joins equijoin predicates and with the
      // mdamKeyPredicate flag turned off. If this assumption is no longer
      // true we need to add some additional code in this "if" clause.
      GENASSERT(left_ga == NULL && right_ga == NULL);
#endif

      switch (getArity())
	{
	case 0: // const, VEGRef, and VEGPred have arity 0
	  break; // If it reached here it means that
	  // the ItemExpr does not need to do any special
	  // processing for this operator (i.e. a constant)
	  // VEG predicates should never reach here
	case 1: // Example: T1.A IS NULL
	  {
	    ItemExpr *newChild;
	    // the child must be a key column:
	    newChild =
	      child(0)->replaceVEGExpressions(availableValues
					      ,inputValues
					      ,TRUE // no constants!
					      ,lookup
					      ,replicateExpression
                                              ,joinInputAndPotentialOutput
                                       ,iDesc
					      );
	    if (newChild != iePtr->child(0))
	      {
		if (replicateExpression)
		  iePtr = iePtr->copyTopNode(NULL, CmpCommon::statementHeap());
		iePtr->child(0) = newChild;
	      }
	  }
	  break;
	case 2:
	case 3:
	  {

	    // Rewrite children (one of them MUST be a key column, the
	    // other MUST be a constant or a host var)
	    ItemExpr
	      *leftChild = NULL,
	      *rightChild = NULL,
	      *thirdChild = NULL;
	    OperatorTypeEnum newOperType = getOperatorType();

	    if ((child(0)->getOperatorType() == ITM_VEG_REFERENCE)
		OR
		(child(1)->getOperatorType() == ITM_VEG_REFERENCE))
	      {

		//---------------------------------------------------------
		// Assume we have an expression of
                // the form VegRef{T1.A, 2} > 7
		//------------------------------------------------------

		// Force the generation of a key column by
		// telling replacevegexprs not to generate them:
		leftChild =
		  child(0)->replaceVEGExpressions(availableValues
						  ,inputValues
						  ,TRUE // want key col
						  ,lookup
						  ,replicateExpression
                                                  ,joinInputAndPotentialOutput
                                     ,iDesc
                                                  );
                // generate a constant in this branch
		rightChild =
		  child(1)->replaceVEGExpressions(availableValues
						  ,inputValues
						  ,FALSE // want constant
						  ,lookup
						  ,replicateExpression
                                                  ,joinInputAndPotentialOutput
                                                  ,iDesc
                                                  );

		// However, the above will fail if the predicate is
		// of the form
                // 7 < VegRef{T1.A,2}, thus, if it failed, redrive with
		// the roles reversed:
		if (leftChild == NULL OR rightChild == NULL)
		  {
		    leftChild =
		      child(1)->replaceVEGExpressions(availableValues
						      ,inputValues
						      ,TRUE // want constant
						      ,lookup
						      ,replicateExpression
                                                      ,joinInputAndPotentialOutput
                                         ,iDesc
                                                      );
		    rightChild =
		      child(0)->replaceVEGExpressions(availableValues
						      ,inputValues
						      ,FALSE // want key col
						      ,lookup
						      ,replicateExpression
                                                      ,joinInputAndPotentialOutput
                                         ,iDesc
                                                      );

		    // We have reversed the operands, reverse
		    // the operator if it is a greater/eq BiRelat operator:
		    switch(getOperatorType())
		      {
		      case ITM_LESS:
		      case ITM_LESS_EQ:
		      case ITM_GREATER:
		      case ITM_GREATER_EQ:
			// need to reverse!
			newOperType =
			  ((BiRelat*)iePtr)->getReverseOperatorType();
			break;
		      }

		  } // if need to reverse operands

		// now we must have succeeded!
		CMPASSERT(leftChild != NULL && rightChild != NULL);

	      } // if one of the children of the operator is a reference
	    else
	      {
		// No children are references, normal rewrite:

		leftChild =
		  child(0)->replaceVEGExpressions(availableValues,
						  inputValues,
						  FALSE, // constants OK
						  lookup,
						  replicateExpression,
                                      joinInputAndPotentialOutput,
                                      iDesc);
		rightChild =
		  child(1)->replaceVEGExpressions(availableValues,
						  inputValues,
						  FALSE, // constants OK
						  lookup,
						  replicateExpression,
                                      joinInputAndPotentialOutput,
                                      iDesc);

		CMPASSERT(leftChild != NULL && rightChild != NULL);

	      }

	    if (getArity() == 3)
	      { // rewrite the exclusion part of the PA key predicate:
		thirdChild =
		  child(2)->replaceVEGExpressions(availableValues,
						  inputValues,
						  thisIsAnMdamKeyPredicate,
						  lookup,
						  replicateExpression,
                                      joinInputAndPotentialOutput,
                                      iDesc);
	      }

	    if (iePtr->child(0) != (void *)leftChild OR
		iePtr->child(1) != (void *)rightChild OR
		(thirdChild AND iePtr->child(2) != (void *)thirdChild) OR
		iePtr->getOperatorType() != newOperType)
	      {
		// we have to change data members, make a copy of the
		// node if other users may share this node
		if (replicateExpression)
		  iePtr = iePtr->copyTopNode(NULL, CmpCommon::statementHeap());

		// Set the left and right children of the iePtr
		// to their rewritten nodes:
		// $$ What happens to all those nodes that were
		// $$ replicated and the rewrite failed?
		iePtr->child(0) = leftChild;
		iePtr->child(1) = rightChild;
		if (thirdChild)
		  iePtr->child(2) = thirdChild;
                iePtr->setOperatorType(newOperType);
	      }
	    break;
	  } // case 2, case 3

	default:
	  // $$ modify this when predicates of arity > 3 come into
	  // $$ existance
	  cout << "Invalid arity: " << getArity() << endl;
	  CMPASSERT(FALSE); // No predicates of arity > 3 (so far)
	}
    }
  else // ItemExpr is not an mdam key predicate, go ahead with the rewrite:
    for (Lng32 index = 0; index < getArity(); index++)
      {
        ValueIdSet currAvailableValues(availableValues);

        if (left_ga != NULL && 
            right_ga != NULL && 
            getArity() == 2 )
          {
            ItemExpr::replaceVEGExpressions2( index 
                                            , availableValues
                                            , inputValues
                                            , currAvailableValues
                                            , left_ga
                                            , right_ga
                                            ) ;
          }

	ItemExpr *newChild = child(index)->replaceVEGExpressions(
             currAvailableValues,
	     inputValues,
	     FALSE, // this is not a key predicate
	     lookup,
	     replicateExpression,
             joinInputAndPotentialOutput,
             iDesc);

        if ( newChild->isPreCodeGenNATypeChanged())
           iePtr->setpreCodeGenNATypeChangeStatus();

	// is the result a different ItemExpr or does iePtr not point to
	// the (possibly unchanged) result yet?
	if (iePtr->child(index) != (void *)newChild)
	  {
	    if (iePtr == this AND replicateExpression)
	      {
		// don't change "this" if it may be shared, make a
		// copy instead and also copy the unchanged children
		// so far
		iePtr = iePtr->copyTopNode(NULL, CmpCommon::statementHeap());
		for (Int32 j = 0; j < index; j++)
		  iePtr->child(j) = this->child(j);
	      }
	    iePtr->child(index) = newChild;
	  }
      }

  if(lookup && replicateExpression && iePtr != this)
    {
      iePtr->synthTypeAndValueId(FALSE);
      lookup->insert(getValueId(), iePtr->getValueId());
    }

  return iePtr;
} // ItemExpr::replaceVEGExpressions()

// -----------------------------------------------------------------------
// ValueIdUnion::replaceVEGExpressions()
// The parameter replicateExpression is ignored because the
// ValueIdUnion implements a special policy for rewriting
// an ItemExpr, in that it manages three sets of values.
// -----------------------------------------------------------------------
ItemExpr * ValueIdUnion::replaceVEGExpressions
                            (const ValueIdSet& availableValues,
			     const ValueIdSet& inputValues,
			     NABoolean thisIsAnMdamKeyPredicate,
			     VEGRewritePairs* lookup,
                             NABoolean replicateExpression,
                             const ValueIdSet * joinInputAndPotentialOutput,
                             const IndexDesc * iDesc,
                             const GroupAttributes * left_ga,
                             const GroupAttributes * right_ga)

{
  CMPASSERT(NOT thisIsAnMdamKeyPredicate); // sanity check
  // we are ignoring the replicateExpression and 
  // joinInputAndPotentialOutput flags ..

  ValueIdUnion * viduPtr = (ValueIdUnion *)this;

  // ---------------------------------------------------------------------
  // If this expression has already been resolved because it exists in
  // availableValues, the replacement of VEGExpressions is not required.
  // ---------------------------------------------------------------------

  if (availableValues.contains(getValueId()) )
    return this;

  for(CollIndex i = 0; i < entries(); i++) {
    viduPtr->
#pragma nowarn(1506)   // warning elimination
      setSource(i,
#pragma warn(1506)  // warning elimination
#pragma nowarn(1506)   // warning elimination
		(viduPtr->getSource(i).getItemExpr()
#pragma warn(1506)  // warning elimination
		 ->replaceVEGExpressions(availableValues,inputValues,
                                   thisIsAnMdamKeyPredicate,lookup, 
                                   FALSE, /* replicateExpression default */ 
                                   NULL,/*joinInputAndPotentialOutput default*/
                                   iDesc,
                                   left_ga,
                                   right_ga))
		->getValueId());
  }

  // If the result is not this ValueIdUnion
  if (viduPtr->getResult() != viduPtr->getValueId())
    viduPtr->setResult((viduPtr->getResult().getItemExpr()
			->replaceVEGExpressions(availableValues,
						inputValues,
						thisIsAnMdamKeyPredicate,
                                                  lookup,
                                                  FALSE,/*replicateExpression*/
                                                  NULL, /*joinInputAndPotentialOutput*/ 
                                                  iDesc,
                                                  left_ga,
                                                  right_ga))
		       ->getValueId());

  return this;
} // ValueIdUnion::replaceVEGExpressions()


// -----------------------------------------------------------------------
// VEGPredicate::replaceVEGExpressions()
// The parameter replicateExpression is ignored because the
// VEGPredicate implements a special policy for rewriting
// an ItemExpr. The policies are implemented by replaceVEGPredicate().
// -----------------------------------------------------------------------
ItemExpr * VEGPredicate::replaceVEGExpressions
                            (const ValueIdSet& availableValues,
			     const ValueIdSet& inputValues,
			     NABoolean /* thisIsAnMdamKeyPredicate*/,
			     VEGRewritePairs* lookup,
			     NABoolean /*replicateExpression*/,
                             const ValueIdSet * joinInputAndPotentialOutput,
                             const IndexDesc * iDesc,
                             const GroupAttributes * /* left_ga */,
                             const GroupAttributes * /* right_ga */)
{
  // we ignore the thisIsAnMdamKeyPredicate flag, and so we also ignore the
  // iDesc for VEGPredicates. No need to guarantee a keyColumn.

  return replaceVEGPredicate(availableValues,inputValues,lookup,joinInputAndPotentialOutput);

} // VEGPredicate::replaceVEGExpressions()


// -----------------------------------------------------------------------
// VEGReference::replaceVEGExpressions()
// The parameter replicateExpression is ignored because the
// VEGReference implements a special policy for rewriting
// an ItemExpr. The policies are implemented by replaceVEGReference().
// -----------------------------------------------------------------------
ItemExpr * VEGReference::replaceVEGExpressions
                            (const ValueIdSet& availableValues,
			     const ValueIdSet& inputValues,
			     NABoolean thisIsAnMdamKeyPredicate,
			     VEGRewritePairs* /*lookup*/,
			     NABoolean /*replicateExpression*/,
                             const ValueIdSet * joinInputAndPotentialOutput,
                             const IndexDesc * iDesc,
                             const GroupAttributes * /* left_ga */ ,
                             const GroupAttributes * /* right_ga */ )
{
  // we ignore the replicateExpression, lookup and 
  // joinInputAndPotentialOutput parameters.

  return replaceVEGReference(availableValues,inputValues,
                             thisIsAnMdamKeyPredicate, iDesc);

} // VEGReference::replaceVEGExpressions()

// -----------------------------------------------------------------------
// ItemExpr::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 ItemExpr::replaceOperandsOfInstantiateNull(
                                           const ValueIdSet & availableValues,
                                           const ValueIdSet & inputValues)
{
  switch (getOperatorType())
  {
    case ITM_INSTANTIATE_NULL:
    {
      child(0) = child(0)->replaceVEGExpressions(availableValues,inputValues);
      break;
    }

    default:
    {
      for (Lng32 i = 0; i < getArity(); i++)
      {
        child(i) = child(i)->replaceVEGExpressions(availableValues,
                                                   inputValues);
      }
      break;
    }
  }

} // ItemExpr::replaceOperandsOfInstantiateNull()

// -----------------------------------------------------------------------
// VEG::setBridgeValue()
// -----------------------------------------------------------------------
void VEG::setBridgeValue(const ValueId & bridgeValueId)
{
  bridgeValues_ += bridgeValueId;
} // VEG::setBridgeValue()

// -----------------------------------------------------------------------
// VEG::markAsReferenced()
// Add a member of the set to the referenced values set to indicate
// that it has been used (at least once) in a "=" predicate that
// was generated by the code generator.
// -----------------------------------------------------------------------
void VEG::markAsReferenced(const ValueId & vid)
{
  referencedValues_ += vid;
  switch (vid.getItemExpr()->getOperatorType())
    {
    case ITM_INDEXCOLUMN:
      // Also add the ValueId of the column from the base table, which is
      // used as the key column for an index.
      referencedValues_ += ((IndexColumn *)(vid.getItemExpr()))
	                      ->getDefinition();
      break;
    default:
      break;
    }

} // VEG::markAsReferenced()

// -----------------------------------------------------------------------
// VEGPredicate::replaceVEGPredicate
//
// This method is used by the code generator for replacing a
// reference to a VEGPredicate with an tree of equality predicates.
// Each equality predicate is between two values that belong to
// the VEG as well as to availableValues.
//
// Terminology :
// ***********
// VEG
//   A ValueId Equality Group. It is a set of values such that its members
//   have an equality predicate specified on them.
//
// availableValues
//   This is the set of values that are available at the relational operator
//   with which the VEGPredicate is associated. It is usually the set union
//   of the Charactersitic Inputs of the operator with the Characteristic
//   Outputs of each of its children.
//
// inputValues
//   This is the set of values that is being provided to this node
//   from above, and therefore is constant for each invocation of
//   the operator when executing.
//   This are good values to use to build key predicates.
//
// bridgeValues
//   This is a set of values for which "=" predicates MUST be generated
//   for correctness as well as to guarantee that transitivity is upheld.
//   For example, the following query:
//
//    select ax, by, cx, dy
//      from (select A.x, B.y from A join B on A.x = B.y) T1(ax,by)
//      join (select C.x, D.y from C join D on C.x = D.y) T2(cx,dy)
//        on T1.ax = T2.cx
//
//   shows two "islands" (self-contained pool of rows) defined by the
//   derived tables T1 and T2 respectively. It is possible to deduce
//   that A.x = D.y only after the predicate A.x = C.x has been applied.
//   The values A.x, C.x establish the transitivity between the two
//   islands. Such values are called inter-island links or bridge values.
//
// referencedValues
//   A subset of the members of the VEG. Each member in this set is
//   referenced in at least one "=" predicate that was generated by
//   a call to replaceVEGPredicate.
//
// unboundValues
//   The unbound values of a VEG are those that require an "="
//   predicate to be generated between them. It is given by
//   bridge values union available values intersect members of the VEG.
//
// Note that if the outputs of the join have already been resolved then 
// joinInputAndPotentialOutput should really be joinInputAndOutputValues.
// All potential output values are no longer available, only the resolved
// values. Please see similar comment in Hashjoin::PrecodeGen.
// -----------------------------------------------------------------------
ItemExpr * VEGPredicate::replaceVEGPredicate(const ValueIdSet& origAvailableValues,
                                             const ValueIdSet& origInputValues,
                                             VEGRewritePairs* lookup,
                                             const ValueIdSet * joinInputAndPotentialOutput)
{
  // If we want processing to be idempotent, check to see if we have
  // already written this VEGPredicate.  And if so, return the rewritten
  // result.
  if (lookup)  // if lookup table is present
    {
      // see if this expression is already in there
      ValueId rewritten;
      if (lookup->getRewritten(rewritten /* out */,getValueId()))
	{
	  if (rewritten == NULL_VALUE_ID)
	    return NULL;
	  else
	    return rewritten.getItemExpr();
	}
    };

  // We assume that inputValues is a (perhaps improper) subset of
  // available values. Verify this.
  ValueIdSet scratchPad;
  scratchPad = origInputValues;
  scratchPad -= origAvailableValues;
  GenAssert(scratchPad.isEmpty(),"NOT scratchPad.isEmpty()");

  // Replace VEGReferences in the members of this VEG.
  // Copy values in the set and expand wild cards in the copy.
  ValueIdSet vegMembers;
  vegMembers.replaceVEGExpressionsAndCopy(getVEG()->getAllValues());

  // Constants are not passed as input values but they are available.
  // Have availableValues and availableInputs contain the VEG members
  // that are constant values.
  ValueIdSet availableValues = origAvailableValues;
  ValueIdSet inputValues = origInputValues;

  ValueIdSet vegConstants;
  vegMembers.getConstants(vegConstants);
  availableValues += vegConstants;
  inputValues += vegConstants;

  // If each member of this VEG is referenced in at least one "=" predicate
  // that was generated here and there is only one "unbound" value remaining,
  // then we are done. Terminate the generation of more "=" predicates.
  if ( (vegMembers == getVEG()->getReferencedValues())
       AND (getVEG()->getBridgeValues().entries() < 2) )
    return NULL;

  ItemExpr * rootPtr = NULL;
  // We can only bind those values that are available here.
  ValueIdSet valuesToBeBound = vegMembers;
  valuesToBeBound.intersectSet(availableValues);

  ValueIdSet unReferencedValues = vegMembers;
  unReferencedValues -= getVEG()->getReferencedValues();

    // Compute the set of values that are available, but
    // are already referenced and are not a bridge value.
    scratchPad = valuesToBeBound;
    scratchPad -= unReferencedValues;
    scratchPad -= getVEG()->getBridgeValues();
    valuesToBeBound -= scratchPad;

  // look for an invariant among the input values
  ValueIdSet vegInputs = valuesToBeBound;
  vegInputs.intersectSet(inputValues);

  // If we didn't have any input values that were a member of the
  // VEG then pick the invariant from the bridge Values
  if (vegInputs.isEmpty())
    {
      vegInputs = valuesToBeBound;
      vegInputs.intersectSet(getVEG()->getBridgeValues());
    }

  // If no input values are part of the VEG and there are
  // no available bridge value then just pick any of the
  // remaining (unreferenced) values
  if (vegInputs.isEmpty())
    {
      vegInputs = valuesToBeBound;
    }

  // look for an invariant value
  ValueId iterExprId, invariantExprId;
  NABoolean invariantChosen = FALSE;

  if (NOT vegInputs.isEmpty())
    {
      for (invariantExprId = vegInputs.init();
	   vegInputs.next(invariantExprId);
	   vegInputs.advance(invariantExprId))
	{
	  //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 - Solution 10-020912-1647
	  if (invariantExprId.getItemExpr()->doesExprEvaluateToConstant(FALSE))

	    {
              invariantChosen = TRUE;
	      break;
	    }

	} // endfor
      // if invariantExprId does not contain the ValueId of a constant value,
      // then it must be initialized to contain any one value from
      // the input values.
      if (NOT invariantChosen)
	{
          if (vegInputs.entries() <= 1)
            vegInputs.getFirst(invariantExprId);
          else {
            // The  EXISTS query reported in case 10-091027-8459, soln
            // 10-091028-5770 exposed a flaw in this code that used to 
            // implicitly assume that the first element of vegInputs is
            // always a valid choice for an invariantExprId. When replacing
            // a semijoin's VEGPredicate, the invariantExprId must be a
            // member of that semijoin's characteristic output. Otherwise,
            // *Join::preCodeGen hjp.replaceVEGExpressions() will silently
            // delete that equijoin predicate and incorrectly generate a
            // cartesian product.
            scratchPad = vegInputs;
            if (joinInputAndPotentialOutput) {
              // for an outer join, joinInputAndPotentialOutput will have
              // instantiate_null wrappers. intersectSetDeep digs into
              // those wrappers.
              scratchPad.intersectSetDeep(*joinInputAndPotentialOutput);
            }
#ifdef _DEBUG
            // we want to GenAssert here but regress/core/test027 raises
            // a false alarm. So, for now, we don't.
            // GenAssert(!scratchPad.isEmpty(),"vegInputs.isEmpty()");
#endif
            if (scratchPad.isEmpty())
              vegInputs.getFirst(invariantExprId); 
            else
              scratchPad.getFirst(invariantExprId);
          }
	}

      // remove it from further consideration
      valuesToBeBound -= invariantExprId;

    } // endif (NOT vegInputs.isEmpty())
  else // have no values
    {
      // The predicate pushdown logic places predicates on those
      // operators where it knows that values will be available
      // for evaluating the predicate.
      // If you have reached this point because of a bug,
      // ****************************************************************
      // DO NOT EVEN CONSIDER COMMENTING OUT THE FOLLOWING ASSERT.
      // ****************************************************************
      GenAssert(NOT valuesToBeBound.isEmpty(),"valuesToBeBound.isEmpty()");
      // ****************************************************************
      // YOU WILL BE DELIBERATELY MASKING OUT A SERIOUS BUG IF YOU
      // DISABLE THE ASSERT STATEMENT ABOVE. DON'T TOUCH IT!
      // ****************************************************************
    }

  if (valuesToBeBound.entries() >=  1)
    {
      // Replace this reference to the VEG with a tree of '=' predicates.
      for (iterExprId = valuesToBeBound.init();
	   valuesToBeBound.next(iterExprId);
	   valuesToBeBound.advance(iterExprId))
	{
	  rootPtr = buildComparisonPred
			( rootPtr, iterExprId.getItemExpr(),
			  invariantExprId.getItemExpr(), ITM_EQUAL,
			  getSpecialNulls() //++MV - Irena
			);
	  getVEG()->markAsReferenced(iterExprId);
	}
    }
  else
    {
      // We have only the invariant. Generate an IS NOT NULL if it
      // is nullable and has not been compared with someone else.
      // MVs:
      // If specialNulls option is set, nulls are values (null=null)
      // and ITM_IS_NOT_NULL  filters out some valid rows also.
      // For more info on specialNulls -- see <ItemOther.h>
      if (NOT getVEG()->getReferencedValues().contains(invariantExprId) &&
          invariantExprId.getType().supportsSQLnull() &&
	  NOT getVEG()->getVEGPredicate()->getSpecialNulls() // ++MV - Irena
	 )
        {
          rootPtr = new(CmpCommon::statementHeap())
		UnLogic(ITM_IS_NOT_NULL, invariantExprId.getItemExpr());
        }
    }

  // mark as referenced the invariant. Make it the Bridge value
  getVEG()->markAsReferenced(invariantExprId);
  getVEG()->removeBridgeValues(valuesToBeBound);
  getVEG()->setBridgeValue(invariantExprId);

  // Assign a ValueId to the "=" and synthesize the type for the expression.
  if (rootPtr != NULL) {
    rootPtr->synthTypeAndValueId();
  // If there is a lookup table, enter the rewritten tree in the table
  if (lookup)
    {
    if (rootPtr)
      lookup->insert(getValueId(),rootPtr->getValueId());
    else
      lookup->insert(getValueId(),NULL_VALUE_ID);
    }
  }
  // Return the tree of '=' predicates (or NULL)
  return rootPtr;
} // VEGPredicate::replaceVEGPredicate()

// -----------------------------------------------------------------------
// VEGReference::replaceVEGReference
// This method is used by the code generator. for replacing a
// VEGReference with one of its candidate values
// thisIsAnMdamKeyPredicate is FALSE by default. However, when
// key predicates are being rewritten, it should be set to TRUE
// when we need to guarantee that a key column must be generated by
// the veg reference.
// In this case,
// then bridge values MUST NOT be usen because we need to pick either
// a constant or a key column (depending on the child we are
// working on (see ItemExpr::replaceVEGExpressions(...))
// -----------------------------------------------------------------------
ItemExpr *
VEGReference::replaceVEGReference(const ValueIdSet &origAvailableValues,
                                  const ValueIdSet &origInputValues,
                                  NABoolean thisIsAnMdamKeyPredicate,
                                  const IndexDesc *iDesc)
{

  ItemExpr *result = NULL;

  #ifndef _DEBUG
    const NABoolean VEG_DEBUG = FALSE;
  #else
    NABoolean VEG_DEBUG = getenv("VEG_DEBUG") != NULL;
  #endif

  // We assume that inputValues is a (perhaps improper) subset of
  // available values. Verify it.
  ValueIdSet scratchPad;
  scratchPad = origInputValues;
  scratchPad -= origAvailableValues;
  GenAssert(scratchPad.isEmpty(),"NOT scratchPad.isEmpty()");

  // Copy values in the set and expand wild cards in the copy.
  ValueIdSet valuesToBeBound;
  valuesToBeBound.replaceVEGExpressionsAndCopy(getVEG()->getAllValues());

  // Constants are not passed as input values but they are available
  // Have availableValues and availableInputs contain the VEG members
  // that are constant values
  ValueIdSet availableValues = origAvailableValues;
  ValueIdSet inputValues = origInputValues;

  // --------------------------------------------------------------------
  // Don't add constants if the caller don't want them to be generated
  // from this vegref (i.e. when thisIsAnMdamKeyPredicate is TRUE)
  // --------------------------------------------------------------------

  ValueIdSet vegConstants;
  valuesToBeBound.getConstants(vegConstants);
  if (NOT thisIsAnMdamKeyPredicate)
    {
      availableValues += vegConstants;
      inputValues += vegConstants;
    }

  if (VEG_DEBUG)
    {
      NAString av,iv,vb;
      availableValues.unparse(av);
      inputValues.unparse(iv);
      valuesToBeBound.unparse(vb);
      cout << endl;
	  cout << "VEGReference " << getValueId() << " :" << endl;
      cout << "AV: " << av << endl;
      cout << "IV: " << iv << endl;
      cout << "VB: " << vb << endl;
    }

  // -----------------------------------------------------------------------
  // 
  // The commented out code implements a different resolution strategies
  // for VEGReference. Inputs are no longer favored. This is in order to
  // handle peculiar scenario where a predicate is not pushed down to the
  // right hand side of a NJ even if it's covered because of the special
  // semantics of the NJ itself (left join). The inputs from the operators
  // in the right leg of the NJ shouldn't be used to resolve the output
  // values since the VEGPred which relates the two hasn't been evaluated.
  //
  // This support is not ready yet for FCS, and therefore the code has been
  // commented out.
  // -----------------------------------------------------------------------
#if 0
  // non-input available values:
  ValueIdSet nonInputAvailableValues = availableValues;
  nonInputAvailableValues -= inputValues;
#endif

  // We can only bind those values that are available here.
  valuesToBeBound.intersectSet(availableValues);

#if 0
  // try using nonInputAvailableValues first.
  ValueIdSet nonInputValuesToBeBound = valuesToBeBound;
  nonInputValuesToBeBound.intersectSet(nonInputAvailableValues);

  // try not to use input values since some predicate might not have
  // be evaluated yet.
  if ( (NOT thisIsAnMdamKeyPredicate) AND
       (NOT nonInputValuesToBeBound.isEmpty()) )
  {
    // Try to pick a bridge value.
    ValueIdSet candidateValues = nonInputValuesToBeBound;
    candidateValues.intersectSet(getVEG()->getBridgeValues());

    // If unsuccessful, try to pick any of the remaining unreferenced.
    if (candidateValues.isEmpty())
    {
      candidateValues = nonInputValuesToBeBound;
    }

    CMPASSERT(NOT candidateValues.isEmpty());
    ValueId resultVid;
    candidateValues.getFirst(resultVid);
    return resultVid.getItemExpr();
  }
#endif


  if (thisIsAnMdamKeyPredicate )
    {
      GenAssert(iDesc != NULL,"VEGReference::replaceVEGReference: Mdam KeyPredicates flag requires an iDesc to go with");
      if (iDesc != NULL)
        {
        ValueIdSet keyCols = iDesc->getIndexKey();
  
        for (ValueId exprId = keyCols.init();
             keyCols.next(exprId);
             keyCols.advance(exprId))
          {
   
            // pick the first value - assuming it is the key column..
            if (valuesToBeBound.contains(exprId)) 
              {
                result = exprId.getItemExpr();
                break;
              }
          }
        }

      if (result && NOT (result->getValueId().getType() == getValueId().getType()) )
          result->setpreCodeGenNATypeChangeStatus();

      return result; // A null is fine here.

    }

  // look for an invariant among the input values
  ValueIdSet vegInputs = valuesToBeBound;
  vegInputs.intersectSet(inputValues);

  // If we didn't have any input values that were a member of the
  // VEG then pick the invariant from the bridge Values
  // Do not use bridge values for key predicates:
  if ((NOT thisIsAnMdamKeyPredicate) && vegInputs.isEmpty())
    {
      vegInputs = valuesToBeBound;
      vegInputs.intersectSet(getVEG()->getBridgeValues());
      if (VEG_DEBUG)
	{
	  NAString vb,br;
	  valuesToBeBound.unparse(vb);
	  // Stupid, ValueIdSet::unparse should be declared const;
	  // for now, just cast away constness...
	  ValueIdSet(getVEG()->getBridgeValues()).unparse(br);
	  cout << "VB: " << vb << endl;
	  cout << "BR: " << br << endl;
	}
    }

  // If no input values are part of the VEG and there are
  // no available bridge value then just pick any of the
  // remaining (unreferenced) values
  if (vegInputs.isEmpty())
    {
      vegInputs = valuesToBeBound;
    }

  // look for a constant value
  ValueId invariantExprId;
  NABoolean invariantChosen = FALSE;

  if (NOT vegInputs.isEmpty())
    {
      for (invariantExprId = vegInputs.init();
	   vegInputs.next(invariantExprId);
	   vegInputs.advance(invariantExprId))
	{
	  //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 - Solution 10-020912-1647
	  if (invariantExprId.getItemExpr()->doesExprEvaluateToConstant(FALSE))
	    {
              invariantChosen = TRUE;
	      break;
	    }

	} // endfor
      // if invariantExprId does not contain the ValueId of a constant value,
      // then it must be initialized to contain any one value from
      // the input values.
      if (NOT invariantChosen)
	{
	  vegInputs.getFirst(invariantExprId);
	}

      // we found the invariant assign it!
      result = invariantExprId.getItemExpr();
      CMPASSERT(result != NULL);

    } // endif (NOT vegInputs.isEmpty())
  else // have no values
    {
      // It is ok for an MDAM key pred to not have valuesToBeBound because
      // this is how ItemExpr::replaceVEGExpressions guarantees the generation of
      // key predicates. It expects a NULL pointer sometimes
      if (NOT thisIsAnMdamKeyPredicate)
      {
        // If there is a VEGReference to the value then a member of
        // the VEG should be available.
        GenAssert(NOT valuesToBeBound.isEmpty(),"valuesToBeBound.isEmpty()");
      }
    }

  // result can be NULL only if thisIsAnMdamKeyPredicate is TRUE (see note above)
  if (NOT thisIsAnMdamKeyPredicate)
  {
    CMPASSERT(result);
  }

  if (VEG_DEBUG)
  {
    // coverity cid 10004 thinks result may be null but we know it is not.
    // coverity[var_deref_model]
	cout << "Result: " << result->getValueId() << endl;
  }

  // see if NAType has changed, if so need to rebind it
  if (result && NOT (result->getValueId().getType() == getValueId().getType()) )
  {
     result->setpreCodeGenNATypeChangeStatus();
  }
  return result;

} // VEGReference::replaceVEGReference()


// -----------------------------------------------------------------------
// RelExpr::getOutputValuesOfMyChilren()
// Accumulates the characteristic outputs of all my children for
// operators that have one or more children. Returns the
// potential output values for operators that can have no children.
// -----------------------------------------------------------------------
void RelExpr::getOutputValuesOfMyChildren(ValueIdSet & vs) const
{
  ValueIdSet valueMask;
  Lng32 nc = getArity();
  if (nc > 0)
    {
      for (Lng32 i = 0; i < nc; i++)
	{
	  valueMask += child(i)->getGroupAttr()->getCharacteristicOutputs();
	}
    }
  else // if leaf operators, use all available values
    {
      getPotentialOutputValues(valueMask);
    }

  // Copy values in the set and expand wild cards in the copy.
  vs.clear();
  vs.replaceVEGExpressionsAndCopy(valueMask);

} // RelExpr::getOutputValuesOfMyChildren()

// -----------------------------------------------------------------------
// RelExpr::getInputValuesFromParentAndChildren()
// Uses getOutputValuesOfMyChildren() to collect the output values
// and adds the characteristic input values of this operator to them.
// -----------------------------------------------------------------------
void RelExpr::getInputValuesFromParentAndChildren(ValueIdSet & vs) const
{
  getOutputValuesOfMyChildren(vs);
  vs += getGroupAttr()->getCharacteristicInputs();
} // RelExpr::getInputValuesFromParentAndChildren()

// -----------------------------------------------------------------------
// RelExpr::getInputAndPotentialOutputValues()
// Uses getPotentialOutputs() to collect the output values
// and adds the characteristic input values of this operator to them.
// -----------------------------------------------------------------------
void RelExpr::getInputAndPotentialOutputValues(ValueIdSet & vs) const
{
  ValueIdSet potentialOutputValues;
  getPotentialOutputValues(potentialOutputValues);
  potentialOutputValues += getGroupAttr()->getCharacteristicInputs();
  vs.clear();
  vs.replaceVEGExpressionsAndCopy(potentialOutputValues);

} // RelExpr::getInputAndPotentialOutputValues()

// -----------------------------------------------------------------------
// GenericUpdate::replaceVEGExpressionsAndGet...
// -----------------------------------------------------------------------
void GenericUpdate::getInputValuesFromParentAndChildren(ValueIdSet & vs) const
{
  ValueIdSet updTableCols;
  ValueIdSet vs2;

  updTableCols.insertList (getIndexDesc()->getIndexColumns());
  //      updTableCols.insertList(getTableDesc()->getColumnVEGList());
  vs2.replaceVEGExpressionsAndCopy(updTableCols);


  getOutputValuesOfMyChildren(vs);
  vs += getGroupAttr()->getCharacteristicInputs();
  vs += vs2;
} // GenericUpdate::getInputValuesFromParentAndChildren()

// -----------------------------------------------------------------------
// HbaseDelete::replaceVEGExpressionsAndGet...
// -----------------------------------------------------------------------
void HbaseDelete::getInputValuesFromParentAndChildren(ValueIdSet & vs) const
{
  // Do not include IndexColumn as the input values. Otherwise, we will
  // have duplicated predicates in Executor predicate in HbaseDelete.

  getOutputValuesOfMyChildren(vs);
  vs += getGroupAttr()->getCharacteristicInputs();
} // HbaseDelete::getInputValuesFromParentAndChildren()

// -----------------------------------------------------------------------
// RelExpr::preCodeGen()
//
// RelExpr * result
//    OUT: a node that calls preCodeGen for its child should replace
//         that child with the result value. This allows preCodeGen
//         to transform the RelExpr tree. Examples for such trans-
//         formations are additional exchange nodes for repartitioning.
// Generator * generator
//  INOUT: a global work area with useful helper methods
// const ValueIdSet & externalInputs
//     IN: a value id set with values that already have been
//         replaced such that they don't contain VEGies any more.
//         Use this set to replace VEGies for expressions that depend
//         on the characteristic inputs of the node.
// ValueIdSet & pulledNewInputs
//    OUT: a set of value ids that the node wants to add to its
//         characteristic inputs ("pull" from its parent). There are
//         several cases in which we need to add value ids to
//         characteristic inputs during preCodeGen:
//         a) partition input variables for parallel execution,
//         b) the COMMON datetime function which needs to be generated
//            by the root node,
//         c) an "open cursor timestamp" that helps a materialize node
//            to decide whether it can reuse its materialized table.
// -----------------------------------------------------------------------
RelExpr * RelExpr::preCodeGen(Generator * generator,
			      const ValueIdSet & externalInputs,
			      ValueIdSet &pulledNewInputs)
{
  if (nodeIsPreCodeGenned())
    return this;

  // Check if the pivs of this operator and it's child are the same.
  // If they are not, make them the same.
  replacePivs();

  // Resolve the VEGReferences and VEGPredicates, if any, that appear
  // in the Characteristic Inputs, in terms of the externalInputs.
  getGroupAttr()->resolveCharacteristicInputs(externalInputs);

  // My Characteristic Inputs become the external inputs for my children.
  Int32 nc = getArity();
  for (Int32 index = 0; index < nc; index++)
    {
      ValueIdSet childPulledInputs;

      child(index) = child(index)->preCodeGen(generator,
					      externalInputs,
					      childPulledInputs);

      if (! child(index).getPtr())
	return NULL;

      // process additional input value ids the child wants
      getGroupAttr()->addCharacteristicInputs(childPulledInputs);
      pulledNewInputs += childPulledInputs;
    }

  // The VEG expressions in the selection predicates and the characteristic
  // outputs can reference any expression that is either a potential output
  // or a characteristic input for this RelExpr. Supply these values for
  // rewriting the VEG expressions.
  ValueIdSet availableValues;
  getInputAndPotentialOutputValues(availableValues);

  // Rewrite the selection predicates.
  NABoolean replicatePredicates = TRUE;
  selectionPred().replaceVEGExpressions
                     (availableValues,
		      getGroupAttr()->getCharacteristicInputs(),
		      FALSE, // no need to generate key predicates here
		      0 /* no need for idempotence here */,
		      replicatePredicates
		     );

  getGroupAttr()->resolveCharacteristicOutputs
                     (availableValues,
		      getGroupAttr()->getCharacteristicInputs());

  markAsPreCodeGenned();

  return this;
} // RelExpr::preCodeGen

//
// Recuvsively call the method on each RelExpr node, accumulating
// # of rows from each node.
//
void RelExpr::prepareDopReduction(Generator* generator)
{
  pcgEspFragment* currentEspFragmentPCG = generator->getCurrentEspFragmentPCG();

  if ( currentEspFragmentPCG )
     currentEspFragmentPCG->accumulateRows(getEstRowsUsed());

  Int32 nc = getArity();

  for (Lng32 i = 0; i < nc; i++)
  {
     child(i)->prepareDopReduction(generator);
  }
}

void Exchange::prepareDopReduction(Generator* generator)
{
   pcgEspFragment* parentEspFragPCG = generator->getCurrentEspFragmentPCG();

   //
   // Save the current pcg fragment and add myself as the child to it.
   //
   if ( parentEspFragPCG ) {
     parentEspFragPCG->accumulateRows(getEstRowsUsed());
     parentEspFragPCG->addChild(this);
   }

   //
   // Let the global pointer point at my pcg esp fragment (for the
   // fragment rooted at me). Do this only for above-DP2 Exchanges.
   // Note a PA is represented by an Exchange with "execute in Master or ESP"
   // as location. So a PA exchange with a SCAN as a child will have an empty
   // childPcgEsp array.
   //
   generator->setCurrentEspFragmentPCG
     (
       (getPhysicalProperty()->getPlanExecutionLocation() != EXECUTE_IN_DP2)
               ? getEspFragPCG() : NULL
     );

  child(0)->prepareDopReduction(generator);

  //
  // Restore the pcg esp fragment
  //
  generator->setCurrentEspFragmentPCG(parentEspFragPCG);

  // Try to reduce the dop and if it fails, invalidate any proposed
  // dop reductions for this.
  //
  if ( parentEspFragPCG &&
       parentEspFragPCG ->tryToReduceDoP() == FALSE )
     parentEspFragPCG->invalidate();
}

RelExpr * RelRoot::preCodeGen(Generator * generator,
			      const ValueIdSet & /* externalInputs */,
			      ValueIdSet &pulledNewInputs)
{
  if (nodeIsPreCodeGenned())
    return this;

  // For all the inputVars, if it is with UNKNOWN data type, make it a
  // varchar type. This is from SQL/MP extension. Example query
  // select ?p1 from any-table;
  if (isTrueRoot()) {
    CollIndex i;
    ValueId vid;
    ValueIdList vidList = inputVars();
    for ( i=0; i < vidList.entries(); i++ )
      if ((vid=vidList[i]).getType().getTypeQualifier() == NA_UNKNOWN_TYPE) {
	vid.coerceType(NA_CHARACTER_TYPE);
      }
  }

  // if root has GET_N indication set, insert a FirstN node.
  // Usually this transformation is done in the binder, but in
  // some special cases it is not.
  // For example, if there is an 'order by' in the query, then
  // the Sort node is added by the optimizer. In this case, we
  // want to add the FirstN node on top of the Sort node and not
  // below it. If we add the FirstN node in the binder, the optimizer
  // will add the Sort node on top of the FirstN node. Maybe we
  // can teach optimizer to do this.
  if ((getFirstNRows() != -1) || (getFirstNRowsParam()))
    {
      RelExpr * firstn = new(generator->wHeap()) FirstN(child(0),
							getFirstNRows(),
                                                        getFirstNRowsParam());

      // move my child's attributes to the firstN node.
      // Estimated rows will be mine.
      firstn->setEstRowsUsed(getEstRowsUsed());
      firstn->setMaxCardEst(getMaxCardEst());
      firstn->setInputCardinality(child(0)->getInputCardinality());
      firstn->setPhysicalProperty(child(0)->getPhysicalProperty());
      firstn->setGroupAttr(child(0)->getGroupAttr());
      //10-060516-6532 -Begin
      //When FIRSTN node is created after optimization phase, the cost
      //of that node does not matter.But, display_explain and explain
      //show zero operator costs and rollup cost which confuses the user.
      //Also, the VQP crashes when cost tab for FIRSTN node is selected.
      //So, creating a cost object will fix this.
      //The operator cost is zero and rollup cost is same as it childs.
      Cost* firstnNodecost = new HEAP Cost();
      firstn->setOperatorCost(firstnNodecost);
      Cost* rollupcost = (Cost *)(child(0)->getRollUpCost());
      *rollupcost += *firstnNodecost;
      firstn->setRollUpCost(rollupcost);
      //10-060516-6532 -End

      setChild(0, firstn);

      // reset firstN indication in the root node.
      setFirstNRows(-1);
      setFirstNRowsParam(NULL);
    }

  if (isTrueRoot())
    {
      // Set the internal format to use for the plan being generated ...
      // Checks the CQD COMPRESSED_INTERNAL_FORMAT to decide whether to use
      // SQLARK_EXPLODED_FORMAT or SQLMX_ALIGNED_FORMAT as the internal
      // data format
      // When the CIF CQD is set to SYSTEM we decide whether to use aligned or exploded format
      // as the tuple format for the whole query. In precodeGEn we visit all the copy
      // operators (Hash join, hash group by, exchange and sort) in a query
      // tree and keep a count of the nodes that are in favor of aligned format and those
      // that are in favor of exploded format.
      // The final decision about the tuple format for the whole query will depend on those two
      // numbers. if the number of nodes in favor of aligned format is greater than those
      // in favor of exploded than aligned format is select otherwise exploded is selected
      // The function that determine the format for each of the copy operators + relroot
      // is determineInternalFormat(..) is is called in the precodeGen of the copy operators
      generator->initNNodes();
      isCIFOn_ = FALSE;

      if ((CmpCommon::getDefault(COMPRESSED_INTERNAL_FORMAT) == DF_ON )||
          generator->isFastExtract())
      {
         isCIFOn_ = TRUE;
         generator->setCompressedInternalFormat();
      }
      else
      if ( CmpCommon::getDefault(COMPRESSED_INTERNAL_FORMAT) == DF_OFF )
      {
        generator->setExplodedInternalFormat();
      }
      else
      {
         NABoolean resize = FALSE;
         NABoolean considerBufferDefrag = FALSE;
         ValueIdSet vidSet = child(0)->getGroupAttr()->getCharacteristicOutputs();
         ExpTupleDesc::TupleDataFormat tupleFormat =
                                 generator->determineInternalFormat(
                                                   vidSet,
                                                   this,
                                                   resize,
                                                   RelExpr::CIF_SYSTEM,
                                                   FALSE,
                                                   considerBufferDefrag);

         if (tupleFormat == ExpTupleDesc::SQLMX_ALIGNED_FORMAT)
         {
           generator->incNCIFNodes();
         }
         else
         {
           generator->decNCIFNodes();
         }
      }
      //generator->setInternalFormat();

      // Some operators will revert the internal format back to exploded format
      // when they are directly under the root node - such as the top level ESPs,
      // Sort, and HJ operators.
      // This is so there is no bottleneck in the master flipping the data back
      // to exploded format (required for bulk move out).
      child(0)->setParentIsRoot( TRUE );

      // create a list of NATypes corresponding to each entry in the
      // userColumnList_ in RETDesc. Used by generator to convert to
      // this type during output expr code gen.
      // The value ids in userColumnList_ cannot be used as the type
      // corresponding to that value id may change due to VEG transformation
      // in the preCodeGen phase.
      if (getRETDesc()->createNATypeForUserColumnList(CmpCommon::statementHeap()))
	{
	  // error case.
	  GenAssert(FALSE, "error from createNATypeForUserColumnList.");
	}

      if ( (child(0)->getOperatorType() == REL_EXCHANGE) &&
	   (child(0)->child(0)->getOperatorType() == REL_COMPOUND_STMT) )
	{
	  ((Exchange *)((RelExpr *)child(0)))->setDP2TransactionIndicator( TRUE );
	}
    }

  unsigned short prevNumBMOs = 0;
  CostScalar prevBMOsMemoryUsage;

  if (isTrueRoot())
    {
      if (oltOptInfo().oltAnyOpt())
        {
          if (treeContainsEspExchange())
            {
              // turn off oltQueryOptimization if the query plan contains an
              // esp_exchange.
              // 10-070316-3325: childOperType_ = REL_UNARY_DELETE
              // 10-080118-9942: select query contains esp_exchange that is
              // not directly under root.
              oltOptInfo().setOltOpt(FALSE);
            }
          else if (childOperType() == REL_SCAN)
	    {
              // if this was a scan query to start with but is no longer
              // a scan query(which means it got transformed to join, etc),
              // then turn off oltQueryOptimization.
	      RelExpr *childExpr = child(0)->castToRelExpr();

	      if (childExpr->getOperatorType() == REL_FIRST_N)
		childExpr = childExpr->child(0)->castToRelExpr();

              if ((childExpr->getOperatorType() != REL_EXCHANGE) &&
		  (childExpr->getOperatorType() != REL_HBASE_ACCESS))
                oltOptInfo().setOltCliOpt(FALSE);
            }
        } // oltAnyOpt

      *generator->oltOptInfo() = oltOptInfo();
 
      if (generator->oltOptInfo()->oltAnyOpt())
	{
	  // Also, PubSub streams' STREAM_TIMEOUT not handled by opt'd root
          if (getGroupAttr()->isStream())
            {
	      generator->oltOptInfo()->setOltCliOpt(FALSE);
            }


	  if ((CmpCommon::getDefault(EID_SPACE_USAGE_OPT) == DF_ON) &&
	      (NOT generator->downrevCompileNeeded()))
	    {
	      generator->setDoEidSpaceUsageOpt(TRUE);
	    }
	  else
	    {
	      generator->setDoEidSpaceUsageOpt(FALSE);
	    }

	  // olt opt not chosen if ALL stats are being collected.
	  // We may support this case later.
          // In case of operator stats, don't disable OLT optimization
          // But, when the query is OLT optimized, switch it to pertable stats
	  if ((generator->computeStats()) &&
	      ((generator->collectStatsType() == ComTdb::ALL_STATS)))
 	    generator->oltOptInfo()->setOltOpt(FALSE);
	  
	  if (CmpCommon::getDefault(OLT_QUERY_OPT) == DF_OFF)
	    generator->oltOptInfo()->setOltOpt(FALSE);

	  // In the case of an embedded insert,
	  // do not execute the query OLT optimized.
	  
	  if (getGroupAttr()->isEmbeddedInsert())
            generator->oltOptInfo()->setOltMsgOpt(FALSE);
	  
#ifdef _DEBUG
	  if (getenv("NO_OLT_QUERY_OPT"))
	    generator->oltOptInfo()->setOltOpt(FALSE);
#endif

	  if (generator->oltOptInfo()->oltEidOpt())
	    {
	      generator->oltOptInfo()->setOltEidLeanOpt(FALSE);

	      if (generator->doEidSpaceUsageOpt())
		{
		  generator->oltOptInfo()->setOltEidLeanOpt(TRUE);
		}
	    }

	  if (generator->downrevCompileNeeded())
	    generator->oltOptInfo()->setOltEidLeanOpt(FALSE);

	  if (CmpCommon::getDefault(OLT_QUERY_OPT_LEAN) == DF_OFF)
	    generator->oltOptInfo()->setOltEidLeanOpt(FALSE);
	} // oltAnyOpt

      // mark exchange operator for maxOneRow optimization.
      RelExpr *childExpr = child(0)->castToRelExpr();
      NABoolean doMaxOneRowOpt = TRUE;
      NABoolean doMaxOneInputRowOpt = FALSE;
      NABoolean firstN = FALSE;
      RelExpr *exchExpr = NULL;
      if (NOT generator->doEidSpaceUsageOpt())
	{
	  doMaxOneRowOpt = FALSE;
	  doMaxOneInputRowOpt = FALSE;
	}
      else
	{
	  doMaxOneRowOpt = TRUE;
	  doMaxOneInputRowOpt = TRUE;
	}

      if (childExpr->getOperatorType() == REL_FIRST_N)
	{
	  firstN = TRUE;
	  if (((FirstN *)childExpr)->getFirstNRows() != 1)
	    doMaxOneRowOpt = FALSE;

	  childExpr = childExpr->child(0)->castToRelExpr();
	}

      if ((childExpr->getOperatorType() != REL_EXCHANGE) ||
	  (childExpr->child(0)->castToRelExpr()->
	   getPhysicalProperty()->getPlanExecutionLocation() != EXECUTE_IN_DP2))
	{
	  doMaxOneRowOpt = FALSE;
	  doMaxOneInputRowOpt = FALSE;
	}
      else
	{
	  exchExpr = childExpr;
	  childExpr = childExpr->child(0)->castToRelExpr();
          if (NOT childExpr->getOperator().match(REL_FORCE_ANY_SCAN))
	    {
	      doMaxOneInputRowOpt = FALSE;
	    }
	  else if (childExpr->getOperatorType() == REL_FILE_SCAN)
	    {
	      FileScan * s = (FileScan *)childExpr;
	      if (NOT firstN)
		doMaxOneRowOpt = FALSE;

	      if ((s->getGroupAttr()->isStream()) ||
		  (s->accessOptions().accessType() == SKIP_CONFLICT_))
		{
		  //doMaxOneInputRowOpt = FALSE;
		  //doMaxOneRowOpt = FALSE;
		}
	    }
	}

      if (doMaxOneRowOpt)
	{
	  exchExpr->oltOptInfo().setMaxOneRowReturned(TRUE);
	}

      if (doMaxOneInputRowOpt)
	{
	  exchExpr->oltOptInfo().setMaxOneInputRow(TRUE);
	}

      generator->setUpdErrorInternalOnError(FALSE);

      if (rollbackOnError())
	generator->setUpdErrorOnError(FALSE);
      else
	generator->setUpdErrorOnError(TRUE);

      if (CmpCommon::getDefault(UPD_ABORT_ON_ERROR) == DF_ON)
	generator->setUpdAbortOnError(TRUE);
      else
	generator->setUpdAbortOnError(FALSE);

      if (CmpCommon::getDefault(UPD_PARTIAL_ON_ERROR) == DF_ON)
	generator->setUpdPartialOnError(TRUE);
      else
	generator->setUpdPartialOnError(FALSE);

      if (CmpCommon::getDefault(UPD_SAVEPOINT_ON_ERROR) == DF_ON)
	generator->setUpdSavepointOnError(TRUE);
      else
	generator->setUpdSavepointOnError(FALSE);

      generator->setSkipUnavailablePartition(FALSE);
      if ((childOperType() == REL_SCAN) &&
	  (CmpCommon::getDefault(SKIP_UNAVAILABLE_PARTITION) == DF_ON))
	generator->setSkipUnavailablePartition(TRUE);

      if (avoidHalloween_)
        { 
          // At beginning of preCodeGen, assume DP2Locks will be 
          // used.  The NestedJoin::preCodeGen will change this
          // if its left child is a sort.
          generator->setHalloweenProtection(Generator::DP2LOCKS);
        }

      if (generator->getBindWA()->getUdrStoiList().entries () > 0)
        generator->setAqrEnabled(FALSE);

      // Reset the accumulated # of BMOs and memory usages in 
      // the generator 
      prevNumBMOs = generator->replaceNumBMOs(0);
      prevBMOsMemoryUsage = generator->replaceBMOsMemoryUsage(0);

    } // true root

  // propagate the need to return top sorted N rows to all sort
  // nodes in the query.
  if (needFirstSortedRows() == TRUE)
    {
      needSortedNRows(TRUE);
    }

  // Delete any VEGReference that appear in the Characteristic Inputs.
  // The Characteristic Inputs of the root of the execution plan MUST
  // only contain external dataflow inputs that are provided by the
  // user. The VEGReferences may have been introduced as a side-effect
  // of predicate pushdown. They are redundant in the Characteristic
  // Inputs of the root.
  ValueIdSet availableValues;
  for (ValueId exprId = getGroupAttr()->getCharacteristicInputs().init();
                        getGroupAttr()->getCharacteristicInputs().next(exprId);
                        getGroupAttr()->getCharacteristicInputs().advance(exprId) )
    {
      if (exprId.getItemExpr()->getOperatorType() != ITM_VEG_REFERENCE)
	availableValues += exprId;
    }

  getGroupAttr()->setCharacteristicInputs(availableValues);

  // If this is the root for a parallel extract producer query then
  // there should be an Exchange node immediately below and we need to
  // set a flag in that Exchange.
  if (numExtractStreams_ > 0)
  {
    if (child(0)->getOperatorType() == REL_EXCHANGE)
    {
      Exchange *e = (Exchange *) child(0)->castToRelExpr();
      e->setExtractProducerFlag();
    }
    // fix for soln 10-090506-1407: parallel extract for a union distinct 
    // can sometimes have root->mapvalueidsl->exchange. It should be OK.
    else if (child(0)->getOperatorType() == REL_MAP_VALUEIDS &&
             child(0)->child(0)->getOperatorType() == REL_EXCHANGE)
    {
      Exchange *e = (Exchange *) child(0)->child(0)->castToRelExpr();
      e->setExtractProducerFlag();
    }
  }

  //
  // If there is no hard requirement on #ESPs, reduce the dop based on 
  // the total # of rows processed per ESP. The reduction can modify
  // the number of partitions attribute of the partition function stored
  // in the synthesized physical property of an Exchange operator.
  // 
  // CQD DOP_REDUCTION_ROWCOUNT_THRESHOLD set to 0.0 will disable the 
  // feature.

   float threshold;
   ActiveSchemaDB()->
      getDefaults().getFloat(DOP_REDUCTION_ROWCOUNT_THRESHOLD, threshold);

  if ( threshold > 0.0 && CURRSTMT_OPTDEFAULTS->getRequiredESPs() <= 0 ) {

    generator->setCurrentEspFragmentPCG(NULL); // reset the 'global' 
                                               // to the current esp frag.

    RelExpr::prepareDopReduction(generator);
    RelExpr::doDopReduction();
  }

  // Now walk through the execution plan and initialize it for code generation.
  child(0) = child(0)->preCodeGen(generator,
				  getGroupAttr()->getCharacteristicInputs(),
				  pulledNewInputs);
  if (! child(0).getPtr())
    return NULL;

  if (! RelExpr::preCodeGen(
       generator,
       getGroupAttr()->getCharacteristicInputs(),
       pulledNewInputs))
      return NULL;

  if ( isTrueRoot() && CmpCommon::getDefault(COMPRESSED_INTERNAL_FORMAT) == DF_SYSTEM)
  {
    if (generator->getNCIFNodes()>0)
    {
      isCIFOn_ = TRUE;
      generator->setCompressedInternalFormat();
    }
    else
    {
      generator->setExplodedInternalFormat();
      isCIFOn_ = FALSE;
    }

  }


  // If the RelRoot is marked as a parallel extract producer then the
  // root's child must be an Exchange and the child must also be
  // marked for parallel extract. Even though we checked the type of
  // the child a few lines above, we do it again here because the call
  // to RelExpr::preCodeGen can potentially eliminate Exchange nodes.
  NABoolean extractPlanLooksOK = TRUE;
  if (numExtractStreams_ > 0)
  {
    if (child(0)->getOperatorType() == REL_EXCHANGE)
    {
      Exchange *e = (Exchange *) child(0)->castToRelExpr();
      if (!e->getExtractProducerFlag())
        extractPlanLooksOK = FALSE;
    }
    // fix for soln 10-090506-1407: parallel extract for a union distinct 
    // can sometimes have root->mapvalueidsl->exchange. It should be OK.
    else if (child(0)->getOperatorType() == REL_MAP_VALUEIDS &&
             child(0)->child(0)->getOperatorType() == REL_EXCHANGE)
    {
      Exchange *e = (Exchange *) child(0)->child(0)->castToRelExpr();
      if (!e->getExtractProducerFlag())
        extractPlanLooksOK = FALSE;
    }
    else
    {
      extractPlanLooksOK = FALSE;
    }
    if (!extractPlanLooksOK)
    {
      *CmpCommon::diags() << DgSqlCode(-7004);
      GenExit();
      return NULL;
    }
  }
  
  // Accumulate the values that are provided as inputs by my parent
  // together with the values that are produced as outputs by my
  // children. Use these values for rewriting the VEG expressions.
  getInputValuesFromParentAndChildren(availableValues);

  // Rebuild the computable expressions using a bridge value, if possible
  compExpr().replaceVEGExpressions
                (availableValues, getGroupAttr()->getCharacteristicInputs());
  // Rebuild the required order
  reqdOrder().replaceVEGExpressions
                 (availableValues, getGroupAttr()->getCharacteristicInputs());
  // Rebuild the pkey list
  pkeyList().replaceVEGExpressions
                 (availableValues, getGroupAttr()->getCharacteristicInputs());

  // add internally generated inputs to the input vars and make sure that
  // the root isn't left with "pulled" input values that aren't "internal"
  // inputs (the assert will most likely fire for leftover partition input
  // variables)
  inputVars().insertSet(generator->getInternalInputs());
  pulledNewInputs -= (ValueIdSet) inputVars();
  GenAssert(pulledNewInputs.isEmpty(),"root can't produce these values");

  // propagate the need to return top sorted N rows to all sort
  // nodes in the query.
  if (needFirstSortedRows() == TRUE)
    {
      needSortedNRows(TRUE);
    }

  // Do not rollback on error for INTERNAL REFRESH commands.
  if (isRootOfInternalRefresh())
    {
      generator->setUpdErrorInternalOnError(TRUE);
      generator->setUpdAbortOnError(FALSE);
      generator->setUpdPartialOnError(FALSE);
      generator->setUpdSavepointOnError(FALSE);
    }

  // do not abort transaction for internal compiles, even if abort
  // is needed for this statement.
  // Catman depends on no abort for individual IUD stmts.
  // It aborts the transaction when it gets an error from cli.
  if ( ( CmpCommon::context()->internalCompile() == CmpContext::INTERNAL_MODULENAME ) ||
       ( CmpCommon::statement()->isSMDRecompile() )
     )
    {
      generator->setUpdErrorInternalOnError(TRUE);
      generator->setUpdAbortOnError(FALSE);
      generator->setUpdPartialOnError(FALSE);
      generator->setUpdSavepointOnError(FALSE);
    }

  oltOptInfo().setOltCliOpt(generator->oltOptInfo()->oltCliOpt());

  if ((isTrueRoot()) &&
      (CmpCommon::getDefault(LAST0_MODE) == DF_ON) &&
      (child(0)))
      {
	OperatorTypeEnum op = child(0)->getOperatorType();
	if (op != REL_DESCRIBE &&
	    op != REL_EXPLAIN &&
	    op != REL_DDL &&
	    op != REL_LOCK &&
	    op != REL_UNLOCK &&
	    op != REL_SET_TIMEOUT && 
	    op != REL_STATISTICS &&
	    op != REL_TRANSACTION &&
	    op != REL_EXE_UTIL)
	  {
	    // do not return any rows at runtime.
	    // Setting of -2 tells executor to simulate [last 0]
	    // without having to put [last 0] in the query.
	    setFirstNRows(-2);
	  }
      }

  if (isTrueRoot())
    {
      // if warnings 6008 or 6011 were raised, set missingStats indication.
      if (CmpCommon::diags()->containsWarning(SINGLE_COLUMN_STATS_NEEDED) ||
	  CmpCommon::diags()->containsWarning(SINGLE_COLUMN_STATS_NEEDED_AUTO)) 
      {
	generator->compilerStatsInfo().setMissingStats(TRUE);
      }

      // change the following number(16) to whatever is considered 'large'.
      //#define LARGE_NUMBER_OF_JOINS 16      
      //if (generator->compilerStatsInfo().totalJoins() > LARGE_NUMBER_OF_JOINS)
      //generator->compilerStatsInfo().setLargeNumOfJoins(TRUE);

      // set mandatoryXP indication in generator.
      if (hasMandatoryXP()) 
      generator->compilerStatsInfo().setMandatoryCrossProduct(TRUE);

      // Remember # of BMOs that children's preCodeGen found for my fragment.
      setNumBMOs( generator->replaceNumBMOs(prevNumBMOs) );

      setBMOsMemoryUsage( generator->replaceBMOsMemoryUsage(prevBMOsMemoryUsage) );

      // Compute the total available memory quota for BMOs
      NADefaults &defs               = ActiveSchemaDB()->getDefaults();

      // total per CPU
      double m = defs.getAsDouble(EXE_MEMORY_LIMIT_PER_CPU) * (1024*1024);

      // total memory usage for all nBMOs 
      double m1 = (generator->getTotalNBMOsMemoryPerCPU()).value();

      // total memory limit for all BMOs
      double m2 = m-m1;

      double ratio = 
          defs.getAsDouble(EXE_MEMORY_LIMIT_NONBMOS_PERCENT) / 100;

      if ( m2 < 0 ) {
         // EXE_MEMORY_LIMIT_PER_CPU is set too small, set the total 
         // memory limit for BMOs to zero. When the memory quota for
         // each BMO is computed (via method RelExpr::computeMemoryQuota()),
         // the lower-bound for each BMO will kick in and each will receive
         // a quota equal to the lower-bound value.
         m2 = 0;
      } else { 

         // nBMOs use more memory than the portion, adjust m2 to 
         // that of (1-ratio)*m
         if (m1 > m*ratio )
           m2 = m*(1-ratio);
      }

      generator->setBMOsMemoryLimitPerCPU(m2);

    }


  if (isTrueRoot())
    {
      if (generator->isAqrWnrInsert())
        {
          ExeUtilWnrInsert * wi = new(generator->getBindWA()->wHeap())
            ExeUtilWnrInsert(generator->utilInsertTable(),
                             child(0)->castToRelExpr());
          child(0)->markAsBound();
          wi->bindNode(generator->getBindWA());
          if (generator->getBindWA()->errStatus())
            return NULL;

          // Use the same characteristic inputs and outputs as my child
          wi->setGroupAttr(new(generator->wHeap())
                           GroupAttributes(*(child(0)->getGroupAttr())));

          //pass along some of the  estimates
          wi->setEstRowsUsed(child(0)->getEstRowsUsed());
          wi->setMaxCardEst(child(0)->getMaxCardEst());
          wi->setInputCardinality(child(0)->getInputCardinality());
          wi->setPhysicalProperty(child(0)->getPhysicalProperty());
          wi->setOperatorCost(0);
          wi->setRollUpCost(child(0)->getRollUpCost());

          if (! wi->preCodeGen(generator,
                    getGroupAttr()->getCharacteristicInputs(),
                    pulledNewInputs))
            return NULL;

          child(0) = wi;
        }

    }

  
  // if blob values are being selected out, retrieve them and return them either in file
  // or as a stream
  if (isTrueRoot())
    {
      RETDesc * rd = getRETDesc();
      const ColumnDescList * cdl = rd->getColumnList();
      for (CollIndex i = 0; i < compExpr().entries(); i++)
	{
	  ValueId val_id = compExpr()[i];
	  ItemExpr * expr = val_id.getItemExpr();
	  if ((val_id.getType().isLob()) &&
	      ((expr->getOperatorType() == ITM_BASECOLUMN) ||
	       (expr->getOperatorType() == ITM_INDEXCOLUMN)))
	    {
	      LOBconvertHandle * lc = new(generator->wHeap())
		LOBconvertHandle(val_id.getItemExpr(), LOBoper::STRING_);
	      
	      lc->bindNode(generator->getBindWA());
	      lc->preCodeGen(generator);
	      
	      compExpr().removeAt(i);
	      compExpr().insertAt(i, lc->getValueId());

	      ColumnDesc  *cd = (*cdl)[i];
	      
	      NAColumn * col = cd->getValueId().getNAColumn(TRUE);
	      lc->lobNum() = col->lobNum();
	      lc->lobStorageType() = col->lobStorageType();
	      lc->lobStorageLocation() = col->lobStorageLocation();
	      
	      cd->setValueId(lc->getValueId());

	      rd->changeNATypeForUserColumnList(i, &lc->getValueId().getType());

	    }
	} // for

   
      if (getPredExprTree())
        {
          getPredExprTree()->preCodeGen(generator);
        }
    } // isTrueRoot
  
  setHdfsAccess(generator->hdfsAccess());

  markAsPreCodeGenned();

#ifdef _DEBUG
  if(getenv("SHOW_PLAN"))
  {
    NAString plan;
    unparse(plan);
    printf("PLAN: %s\n",convertNAString(plan,generator->wHeap()));
  }
#endif

  return this;
} // RelRoot::preCodeGen

RelExpr * Join::preCodeGen(Generator * generator,
			   const ValueIdSet & externalInputs,
			   ValueIdSet &pulledNewInputs)
{
  if (nodeIsPreCodeGenned())
    return this;

  // Check if the pivs of this operator and it's child are the same.
  // If they are not, make them the same.
  replacePivs();

  // In the case of an embedded insert,
  // and there is a selection predicate,
  // we need to retrieve the stored available outputs
  // from the GenericUpdate group attr.

  ValueIdSet availableGUOutputs;

  // clear any prefix sort key 
  generator->clearPrefixSortKey();

  if (getGroupAttr()->isEmbeddedInsert() &&
      !selectionPred().isEmpty()         &&
      getArity() > 1)
    {
      if (child(1)->getArity() > 0)
	child(1)->child(0)->getInputAndPotentialOutputValues(availableGUOutputs);
    }


  NABoolean isALeftJoin = (getOperator().match(REL_ANY_LEFT_JOIN));
  NABoolean isARightJoin = (getOperator().match(REL_ANY_RIGHT_JOIN));
  ValueIdSet availableValues;
  ValueIdSet childPulledInputs;

   if (isALeftJoin)
    {
      ValueId instNullId, exprId, vid;

      // Prune the nullInstatiatedOutputs list.Retain only those values
      // that are either:
      //   1) The external dataflow inputs to the Join.
      //   2) The Characteristic Outputs of the Join.
      //   3) The Characteristic Outputs of the first child of the Join.
      //   4) Values required for evaluating the selection expression
      //      on the Join.
      // Discard all other values.

      availableValues = getGroupAttr()->getCharacteristicInputs();
      availableValues += child(0)->getGroupAttr()->getCharacteristicOutputs();

      ValueIdSet discardSet;
      CollIndex ne = nullInstantiatedOutput().entries();
      for (CollIndex j = 0; j < ne; j++)              // NT_PORT FIX SK 07/16/96
	{
	  instNullId = nullInstantiatedOutput_[j];
	  GenAssert(instNullId.getItemExpr()->getOperatorType() == ITM_INSTANTIATE_NULL,"NOT instNullId.getItemExpr()->getOperatorType() == ITM_INSTANTIATE_NULL");
	  // Access the operand of the InstantiateNull
	  exprId = (((InstantiateNull *)(instNullId.getItemExpr()))
					    ->getExpr()->getValueId());
	  if ( (NOT availableValues.contains(exprId)) AND
	       (NOT getGroupAttr()->getCharacteristicOutputs()
		                      .referencesTheGivenValue(instNullId, vid)) AND
	       (NOT selectionPred().referencesTheGivenValue(instNullId, vid)) )
            {
	      discardSet += nullInstantiatedOutput_[j];
            }
	}
      // Delete all those elements that do not require null instantiation.
      for (exprId = discardSet.init(); discardSet.next(exprId);
	   discardSet.advance(exprId))
	{
	  nullInstantiatedOutput_.remove(exprId);
	}
    } // endif (getOperator().match(REL_ANY_LEFT_JOIN))
  else                                 // Null Instantiation will not be necessary.
    nullInstantiatedOutput().clear();  // clear in case a LJ was transformed to an IJ


  if (isARightJoin)
    {
      ValueId instNullIdForRightJoin, exprIdForRightJoin, vidForRightJoin;
      ValueIdSet discardSetForRightJoin;

      // Prune the nullInstatiatedOutputs list.Retain only those values
      // that are either:
      //   1) The external dataflow inputs to the Join.
      //   2) The Characteristic Outputs of the Join.
      //   3) The Characteristic Outputs of the second  child of the Join.
      //   4) Values required for evaluating the selection expression
      //      on the Join.
      // Discard all other values.

      availableValues = getGroupAttr()->getCharacteristicInputs();
      availableValues += child(1)->getGroupAttr()->getCharacteristicOutputs();

      CollIndex neR = nullInstantiatedForRightJoinOutput().entries();
      for (CollIndex j = 0; j < neR; j++)              // NT_PORT FIX SK 07/16/96
	{
	  instNullIdForRightJoin = nullInstantiatedForRightJoinOutput_[j];
	  GenAssert(instNullIdForRightJoin.getItemExpr()->getOperatorType() == ITM_INSTANTIATE_NULL,"NOT instNullId.getItemExpr()->getOperatorType() == ITM_INSTANTIATE_NULL");
	  // Access the operand of the InstantiateNull
	  exprIdForRightJoin  = (((InstantiateNull *)(instNullIdForRightJoin.getItemExpr()))
					    ->getExpr()->getValueId());
	  if ( (NOT availableValues.contains(exprIdForRightJoin)) AND
	       (NOT getGroupAttr()->getCharacteristicOutputs()
		                      .referencesTheGivenValue(instNullIdForRightJoin, 
							       vidForRightJoin)) AND
	       (NOT selectionPred().referencesTheGivenValue(instNullIdForRightJoin, 
							    vidForRightJoin)) )
            {
	      discardSetForRightJoin += nullInstantiatedForRightJoinOutput_[j];
            }
	}
      // Delete all those elements that do not require null instantiation.
      for (exprIdForRightJoin = discardSetForRightJoin.init(); 
	   discardSetForRightJoin.next(exprIdForRightJoin);
	   discardSetForRightJoin.advance(exprIdForRightJoin))
	{
	  nullInstantiatedForRightJoinOutput_.remove(exprIdForRightJoin);
	}
    } // endif (getOperator().match(REL_ANY_RIGHT_JOIN))
  else                                 // Null Instantiation will not be necessary.
    nullInstantiatedForRightJoinOutput().clear();  // clear in case a LJ was transformed to an IJ
  
  // Resolve the VEGReferences and VEGPredicates, if any, that appear
  // in the Characteristic Inputs, in terms of the externalInputs.
  getGroupAttr()->resolveCharacteristicInputs(externalInputs);
  availableValues = getGroupAttr()->getCharacteristicInputs();

  bool precodeHalloweenLHSofTSJ = false;
  bool savePrecodeHalloweenLHSofTSJ = false;
  if ((getHalloweenForceSort() != NO_SELF_REFERENCE) &&
      (generator->getR251HalloweenPrecode()))
  {
    savePrecodeHalloweenLHSofTSJ = 
          generator->setPrecodeHalloweenLHSofTSJ(true);
    precodeHalloweenLHSofTSJ  = true;
    
    if (getHalloweenForceSort() == FORCED)
      generator->setHalloweenSortForced();
  }
  
  NABoolean savedOltMsgOpt = generator->oltOptInfo()->oltMsgOpt();

  // My Characteristic Inputs become the external inputs for my left child.
  child(0) = child(0)->preCodeGen(generator,availableValues,childPulledInputs);
  if (! child(0).getPtr())
    return NULL;

  // For HashJoin Min/Max optimization 
  if (isHashJoin()) 
    {
      HashJoin *hj = (HashJoin *)this;

      for(CollIndex i = hj->getStartMinMaxIndex(); i < hj->getEndMinMaxIndex(); i++) 
        {
          // A scan may have decided to use the min/max values that
          // belongs to this join, remove them from the
          // childPulledInputs.  We do not need to pull them from the
          // parent as this Hash Join will generate them.
          if(generator->getWillUseMinMaxKeys()[i] != NULL_VALUE_ID) {
            childPulledInputs -= generator->getMinVals()[i];
            childPulledInputs -= generator->getMaxVals()[i];
          }

          // Clear the candidate values generated by this HashJoin, We
          // are done with the left child, so no one else can use
          // these values.
          generator->getMinMaxKeys()[i] = NULL_VALUE_ID;
          generator->getMinVals()[i] =  NULL_VALUE_ID;
          generator->getMaxVals()[i] = NULL_VALUE_ID;

        }

    }

  if (precodeHalloweenLHSofTSJ)
  {
    generator->setPrecodeHalloweenLHSofTSJ(savePrecodeHalloweenLHSofTSJ);
    if (generator->getUnblockedHalloweenScans() == 0)
      {
        // Turn off DP2_LOCKS for codeGen, using either the FORCED_SORT
        // or PASSIVE values.
        if (getHalloweenForceSort() == FORCED)
          {
            generator->setHalloweenProtection(Generator::FORCED_SORT);
         }
        else
          generator->setHalloweenProtection(Generator::PASSIVE);
      }
    else if (updateSelectValueIdMap() && updateTableDesc() && 
	    (NOT updateTableDesc()->getNATable()->getClusteringIndex()->hasSyskey()))
      {
        // if the key columns of the table being inserted into are 
        // equal to constants or inputs then no sort is required 
        // to enforce Halloween blocking. Example statements are
        // update tt set a = 1  ;(a is the primary key for table tt)
        // insert into tt select * from tt where a = 1 ;
        ValueIdList reqdOrder ;
        updateSelectValueIdMap()->rewriteValueIdListDown(
            updateTableDesc()->getClusteringIndex()->getOrderOfKeyValues(),
            reqdOrder);
        reqdOrder.removeCoveredExprs(
            getGroupAttr()->getCharacteristicInputs());
        if (reqdOrder.isEmpty())
          {
            generator->setHalloweenProtection(Generator::PASSIVE);
          }
      }
  }

  NABoolean leftMultipleRowsReturned =
    generator->oltOptInfo()->multipleRowsReturned();

  // if nested join and left child could return multiple rows, then
  // disable olt msg opt for the right child. This is done since
  // olt msg opt can only handle input and output of max 1 row.
  if ((getOperatorType() == REL_NESTED_JOIN) ||
      (getOperatorType() == REL_LEFT_NESTED_JOIN) ||
      (getOperatorType() == REL_NESTED_SEMIJOIN) ||
      (getOperatorType() == REL_NESTED_ANTI_SEMIJOIN) ||
      (getOperatorType() == REL_NESTED_JOIN_FLOW))
    {
      if (generator->oltOptInfo()->multipleRowsReturned())
	{
	  generator->oltOptInfo()->setOltMsgOpt(FALSE);
	}
    }

  // process additional input value ids the child wants
  // (see RelExpr::preCodeGen())
  getGroupAttr()->addCharacteristicInputs(childPulledInputs);
  pulledNewInputs += childPulledInputs;
  availableValues += childPulledInputs;
  childPulledInputs.clear();

  // If this is a tuple substitution join that is implemented by the nested join
  // method, then the values produced as output by my left child can be used as
  // "external" inputs by my right child.
  NABoolean replicatePredicates = TRUE;
  
  ValueIdSet joinInputAndPotentialOutput;
  getInputAndPotentialOutputValues(joinInputAndPotentialOutput);

  if (isTSJ())
    {
      availableValues += child(0)->getGroupAttr()->getCharacteristicOutputs();

      // For a TSJ the joinPred() is a predicate between the inputs
      // and the first child that could not be pushed down to the first
      // child because it is either a left join or an anti-semi-join

      // Rebuild the join predicate tree now
      joinPred().replaceVEGExpressions
                    (availableValues,
                     getGroupAttr()->getCharacteristicInputs(),
                     FALSE, // no key predicates here
                     0 /* no need for idempotence here */,
                     replicatePredicates,
                     NULL /* not a groupByAgg */,
                     &joinInputAndPotentialOutput
                    );
    }

  bool didSetRHS = false;
  bool saveSetRHS = false;
  if (generator->getPrecodeHalloweenLHSofTSJ() &&
      isNestedJoin())
  {
    saveSetRHS = generator->setPrecodeRHSofNJ(true);
    didSetRHS = true;
  }

  // Process the right child
  child(1) = child(1)->preCodeGen(generator,availableValues,childPulledInputs);

  if (! child(1).getPtr())
    return NULL;

  if (didSetRHS)
    generator->setPrecodeRHSofNJ(saveSetRHS);

  NABoolean rightMultipleRowsReturned =
    generator->oltOptInfo()->multipleRowsReturned();

  if (leftMultipleRowsReturned || rightMultipleRowsReturned)
    generator->oltOptInfo()->setMultipleRowsReturned(TRUE);

  // process additional input value ids the child wants
  // (see RelExpr::preCodeGen())
  getGroupAttr()->addCharacteristicInputs(childPulledInputs);
  pulledNewInputs += childPulledInputs;

  // Accumulate the values that are provided as inputs by my parent
  // together with the values that are produced as outputs by my
  // children. Use these values for rewriting the VEG expressions.
  getInputValuesFromParentAndChildren(availableValues);

  // Rebuild the join predicate tree
  if (! isTSJ())
    joinPred().replaceVEGExpressions
                  (availableValues,
		   getGroupAttr()->getCharacteristicInputs(),
		   FALSE, // no key predicates here
		   0 /* no need for idempotence here */,
		   replicatePredicates,
                   NULL /* not a groupByAgg */,
                   &joinInputAndPotentialOutput
                  );

  if (isALeftJoin)
    {

      // Replace the operands of the ITM_INSTANTIATE_NULL with values from
      // the Characteristic Outputs of the right child.
      // The following values are available for resolving the nullInstantiatedOuptut
      //   1) The external dataflow inputs to the Join.
      //   2) The Characteristic Outputs of the second (right) child of the Join.
      //   3) The Characteristic Outputs of the first(left)child of the Join.
      //      Needed when nested_join plan is chosen.

      availableValues = getGroupAttr()->getCharacteristicInputs();
      availableValues += child(1)->getGroupAttr()->getCharacteristicOutputs();
      availableValues += child(0)->getGroupAttr()->getCharacteristicOutputs();

      nullInstantiatedOutput_.replaceOperandsOfInstantiateNull
                                 (availableValues,
				  getGroupAttr()->getCharacteristicInputs());
    }

  if (isARightJoin)
    {

      // Replace the operands of the ITM_INSTANTIATE_NULL with values from
      // the Characteristic Outputs of the left child.
      // The following values are available for resolving the nullInstantiatedForRightJoinOutput
      //   1) The external dataflow inputs to the Join.
      //   2) The Characteristic Outputs of the first (left) child of the Join.

      availableValues = getGroupAttr()->getCharacteristicInputs();
      availableValues += child(0)->getGroupAttr()->getCharacteristicOutputs();

      nullInstantiatedForRightJoinOutput_.replaceOperandsOfInstantiateNull
	(availableValues,
	 getGroupAttr()->getCharacteristicInputs());
    }

  // The VEG expressions in the selection predicates and the characteristic
  // outputs can reference any expression that is either a potential output
  // or a characteristic input for this RelExpr. Supply these values for
  // rewriting the VEG expressions.
  getInputAndPotentialOutputValues(availableValues);

  // If this is an embedded insert, with a selection predicate,
  // add in the characteristic outputs from the generic update RelExpr
  if (getGroupAttr()->isEmbeddedInsert() &&
      !selectionPred().isEmpty())
    {
      availableValues += availableGUOutputs;
    }

  // Rebuild the selection predicate tree.
  selectionPred().replaceVEGExpressions
                     (availableValues,
		      getGroupAttr()->getCharacteristicInputs(),
		      FALSE, // no need for key predicates here
		      0 /* no need for idempotence here */,
		      replicatePredicates
		     );

  //New code was added to avoid the following situation:
  //
  // Query: select max(t1.a) from t1,t2 where t1.a = t2.b;
  // Plan:         shortcut_groupby
  //                        |
  //                  esp_exchange
  //                        |
  //                    merge_join in parallel 4 ways on
  //                        |
  //                    |         |
  //                  scan t2    scan T1
  //
  //   By the time we get to precodegen merge_join has orderby
  //  on VEG(a,b) and characteristic output VEG(a,b)
  //  because scan T2 get precode gen'd first it resolves its
  //  orderby VEG(a,b) to t2.b this also changes orderby VEG
  //  in merge_join and thereafter to T2.b. Now when merge join
  // resolves it characteristic output it resolves it to T1.a because
  // T1 is first in the from clause and T1.a has a smaller value id and
  // so the combined set of T1. and T2's characteristic output has T1.a
  // in front of T2.b. Now esp_exchange during code gen time expects
  // T2.b to be characteristic output of the child because it needs to
  // do merge of sorted streams of its orderby value which is T2.b.
  // this causes an assertion failure because merge_join produces T1.a.
  // Following code counters that by making sure that if the sort key is
  // part of the available values then characteristic output first gets
  // resolved by sortkey then by rest of the available values.
  //

  ValueIdSet sortKey = getPhysicalProperty()->getSortKey();
  sortKey = sortKey.simplifyOrderExpr();
  sortKey.intersectSet(availableValues);

  if(sortKey.entries())
  {
    ValueIdSet reqOutput = getGroupAttr()->getCharacteristicOutputs();
    ValueIdSet copyOfSet(reqOutput);
    ValueIdSet inputValues;
    ValueIdSet newExpr;
    ItemExpr * iePtr;
  // ---------------------------------------------------------------------
  // Iterate over the predicate factors in the given predicate tree.
  // ---------------------------------------------------------------------
  for (ValueId exprId = copyOfSet.init();
        copyOfSet.next(exprId); copyOfSet.advance(exprId))
    {
      // -----------------------------------------------------------------
      // Walk through the item expression tree and replace any
      // VEGPredicates or VEGReferences that are found.
      // -----------------------------------------------------------------
      iePtr = exprId.getItemExpr()->replaceVEGExpressions(availableValues,
							  inputValues,
							  FALSE,
							  NULL,
							  FALSE);
      if (iePtr)			      // expression was not discarded
	{
	  iePtr->synthTypeAndValueId(TRUE);   // redrive type synthesis
          if (iePtr != exprId.getItemExpr())  // a replacement was done
	    {
	      reqOutput.subtractElement(exprId);        // remove existing ValueId
	      reqOutput += iePtr->getValueId(); // replace with a new one
	    }
	}

    } // loop over predTree



    getGroupAttr()->setCharacteristicOutputs(reqOutput);
  }
  // Rewrite the Characteristic Outputs.
  getGroupAttr()->resolveCharacteristicOutputs
                     (availableValues,
		      getGroupAttr()->getCharacteristicInputs());

  // propagate the children olt settings in case of a pushed down to dp2 NLJ
  if ( !getPhysicalProperty()->executeInDP2() OR
       !(generator->getBindWA()->getTopRoot()->getInliningInfo()).isUsedForMvLogging()
     )
  {

     generator->oltOptInfo()->setOltMsgOpt(savedOltMsgOpt);
  }

  // In the case of an embedded insert,
  // set the generator is embedded insert flag to TRUE.

  if (getGroupAttr()->isEmbeddedInsert())
    generator->setEmbeddedInsert(TRUE) ;
  
  markAsPreCodeGenned();

  // Done.
  return this;
} // Join::preCodeGen()

RelExpr * GenericUtilExpr::preCodeGen(Generator * generator,
				      const ValueIdSet & externalInputs,
				      ValueIdSet &pulledNewInputs)
{
  if (nodeIsPreCodeGenned())
    return this;

  if (! RelExpr::preCodeGen(generator,externalInputs,pulledNewInputs))
    return NULL;

  if (xnNeeded())
    {
      generator->setUpdSavepointOnError(FALSE);
      generator->setUpdPartialOnError(FALSE);
    }

  markAsPreCodeGenned();

  // Done.
  return this;
}

RelExpr * ExeUtilExpr::preCodeGen(Generator * generator,
				  const ValueIdSet & externalInputs,
				  ValueIdSet &pulledNewInputs)
{
  if (nodeIsPreCodeGenned())
    return this;

  if (! GenericUtilExpr::preCodeGen(generator,externalInputs,pulledNewInputs))
    return NULL;

  if (NOT aqrSupported())
    generator->setAqrEnabled(FALSE);

  markAsPreCodeGenned();

  // Done.
  return this;
}

// returns true if the whole ddl operation can run in one transaction
// and transaction can be started by caller(master executor or arkcmp)
// before executing this ddl.
short DDLExpr::ddlXnsInfo(NABoolean &isDDLxn, NABoolean &xnCanBeStarted)
{
  ExprNode * ddlNode = getDDLNode();

  xnCanBeStarted = TRUE;
  // no DDL transactions.
  if ((NOT ddlXns()) &&
      ((dropHbase()) ||
       (purgedataHbase()) ||
       (initHbase()) ||
       (createMDViews()) ||
       (dropMDViews()) ||
       (initAuthorization()) ||
       (dropAuthorization()) ||
       (addSeqTable()) ||
       (createRepos()) ||
       (dropRepos()) ||
       (upgradeRepos()) ||
       (addSchemaObjects()) ||
       (updateVersion())))
    {
      // transaction will be started and commited in called methods.
      xnCanBeStarted = FALSE;
    }
  
  // no DDL transactions
  if (((ddlNode) && (ddlNode->castToStmtDDLNode()) &&
       (NOT ddlNode->castToStmtDDLNode()->ddlXns())) &&
      ((ddlNode->getOperatorType() == DDL_DROP_SCHEMA) ||
       (ddlNode->getOperatorType() == DDL_CLEANUP_OBJECTS) ||
       (ddlNode->getOperatorType() == DDL_ALTER_TABLE_ADD_CONSTRAINT_PRIMARY_KEY) ||
       (ddlNode->getOperatorType() == DDL_ALTER_TABLE_ALTER_COLUMN_SET_SG_OPTION) ||
       (ddlNode->getOperatorType() == DDL_CREATE_INDEX) ||
       (ddlNode->getOperatorType() == DDL_POPULATE_INDEX) ||
       (ddlNode->getOperatorType() == DDL_CREATE_TABLE) ||
       (ddlNode->getOperatorType() == DDL_ALTER_TABLE_DROP_COLUMN) ||
       (ddlNode->getOperatorType() == DDL_ALTER_TABLE_ALTER_COLUMN_DATATYPE) ||
       (ddlNode->getOperatorType() == DDL_DROP_TABLE)))
    {
      // transaction will be started and commited in called methods.
      xnCanBeStarted = FALSE;
    }

  isDDLxn = FALSE;
  if ((ddlXns()) || 
      ((ddlNode && ddlNode->castToStmtDDLNode() &&
        ddlNode->castToStmtDDLNode()->ddlXns())))
    isDDLxn = TRUE;

  // ddl transactions are on.
  // Following commands currently require transactions be started and
  // committed in the called methods.
  if ((ddlXns()) &&
      (
           (initHbase()) ||
           (dropHbase()) ||
           (purgedataHbase()) ||
           (initHbase()) ||
           (dropHbase()) ||
           (initAuthorization()) ||
           (dropAuthorization()) ||
           (upgradeRepos())
       )
      )
    {
      // transaction will be started and commited in called methods.
      xnCanBeStarted = FALSE;
    }

  // ddl transactions are on.
  // Cleanup and alter commands requires transactions to be started and commited
  // in the called method.
  if ((ddlNode && ddlNode->castToStmtDDLNode() &&
       ddlNode->castToStmtDDLNode()->ddlXns()) &&
      ((ddlNode->getOperatorType() == DDL_CLEANUP_OBJECTS) ||
       (ddlNode->getOperatorType() == DDL_DROP_SCHEMA) ||
       (ddlNode->getOperatorType() == DDL_ALTER_TABLE_DROP_COLUMN) ||
       (ddlNode->getOperatorType() == DDL_ALTER_TABLE_ALTER_COLUMN_DATATYPE)))
    {
      // transaction will be started and commited in called methods.
      xnCanBeStarted = FALSE;
    }

  return 0;
}

RelExpr * DDLExpr::preCodeGen(Generator * generator,
			      const ValueIdSet & externalInputs,
			      ValueIdSet &pulledNewInputs)
{
  if (nodeIsPreCodeGenned())
    return this;
  
  if (! GenericUtilExpr::preCodeGen(generator,externalInputs,pulledNewInputs))
    return NULL;
  
  if (specialDDL())
    {
      generator->setAqrEnabled(FALSE);
    }
  
  NABoolean startXn = FALSE;
  NABoolean ddlXns = FALSE;
  if (ddlXnsInfo(ddlXns, startXn))
    return NULL;

  if (ddlXns && startXn)
    xnNeeded() = TRUE;
  else
    xnNeeded() = FALSE;

  markAsPreCodeGenned();
  
  // Done.
  return this;
}

RelExpr * NestedJoinFlow::preCodeGen(Generator * generator,
				     const ValueIdSet &externalInputs,
				     ValueIdSet &pulledNewInputs)
{
  if (nodeIsPreCodeGenned())
    return this;

  /*  child(0) = child(0)->preCodeGen(
       generator,
       externalInputs,
       pulledNewInputs);
  if (! child(0).getPtr())
    return NULL;
  */

  RelExpr * nj =
    NestedJoin::preCodeGen(generator, externalInputs, pulledNewInputs);

  if (nj == NULL)
    return NULL;


  return nj;
}

RelExpr * NestedJoin::preCodeGen(Generator * generator,
                                 const ValueIdSet &externalInputs,
                                 ValueIdSet &pulledNewInputs)
{
  if (nodeIsPreCodeGenned())
    return this;

  NABoolean espExchangeWithMerge = FALSE;
  NABoolean childIsBlocking = FALSE;

  if ((getHalloweenForceSort() != NO_SELF_REFERENCE) &&
      (!generator->getR251HalloweenPrecode()))
    {
      GenAssert(Generator::NOT_SELF_REF != generator->getHalloweenProtection(),
              "Inconsistency in Generator and NestedJoin.");

      // Look for either of two patterns on the left hand side:
      // sort or exchange+sort.  
      if (child(0)->getOperatorType() == REL_SORT) 
        childIsBlocking = TRUE;
      else
        if ((child(0)->getOperatorType() == REL_EXCHANGE) &&
            (child(0)->child(0)->getOperatorType() == REL_SORT))
          {
            childIsBlocking = TRUE;

            // The espExchangeWithMerge flag is used to conditionally
            // assert that the exchange will merge.  The assertion
            // is deferred until after preCodeGen on the left subtree,
            // because the Exchange::doesMerge() method should not be
            // called until Exchange::preCodeGen is finished.
            espExchangeWithMerge = TRUE;
          }

      if (childIsBlocking)
        {
          if (getHalloweenForceSort() == FORCED)
            {
              if (espExchangeWithMerge)
                ((Sort *)(child(0)->child(0).getPtr()))->
                        markAsHalloweenProtection();
              else
                ((Sort *)(child(0).getPtr()))->markAsHalloweenProtection();

              generator->setHalloweenProtection(Generator::FORCED_SORT);
           }
          else
            generator->setHalloweenProtection(Generator::PASSIVE);
        }
      else if (updateSelectValueIdMap() && updateTableDesc() && 
	      (NOT updateTableDesc()->getNATable()->getClusteringIndex()->hasSyskey()))
        {
          // if the key columns of the table being inserted into are 
          // equal to constants or inputs then no sort is required 
          // to enforce Halloween blocking. Example statements are
          // update tt set a = 1  ;(a is the primary key for table tt)
          // insert into tt select * from tt where a = 1 ;
          ValueIdList reqdOrder ;
          updateSelectValueIdMap()->rewriteValueIdListDown(
              updateTableDesc()->getClusteringIndex()->getOrderOfKeyValues(),
              reqdOrder);
          reqdOrder.removeCoveredExprs(
              getGroupAttr()->getCharacteristicInputs());
          if (reqdOrder.isEmpty())
            {
              generator->setHalloweenProtection(Generator::PASSIVE);
            }
        }
    }

  // Insert a probe cache above the inner table if applicable
  if ( isProbeCacheApplicable(
       castToRelExpr()->getPhysicalProperty()->getPlanExecutionLocation()
                             )
     )
    {
      ProbeCache *probeCache = 
        new (generator->wHeap()) ProbeCache( 
          child(1), getDefault(GEN_PROBE_CACHE_NUM_ENTRIES),
          generator->wHeap());

      // look for an aggregate right child node
      RelExpr     *rightChildExpr = child(1).getPtr();
      GroupByAgg  *rightChildGrby = NULL;
      RelExpr     *rightChildExch = NULL;
      MapValueIds *rightChildMvi  = NULL;
      ValueIdMap  *optionalMap    = NULL;
      NABoolean   done            = FALSE;

      while (!done)
        {
          if (rightChildExpr->getOperator().match(REL_ANY_GROUP))
            {
              rightChildGrby = (GroupByAgg *) rightChildExpr;
              done = TRUE;
            }
          else if (rightChildExpr->getOperator() == REL_EXCHANGE)
            {
              if (rightChildExch == NULL)
                rightChildExch = rightChildExpr;
              else
                done = TRUE; // can't handle more than one exchange
            }
          else if (rightChildExpr->getOperator() == REL_MAP_VALUEIDS)
            {
              if (rightChildMvi == NULL)
                {
                  rightChildMvi = (MapValueIds *) rightChildExpr;
                  optionalMap   = &rightChildMvi->getMap();
                }
              else
                done = TRUE; // can't handle more than one MVI
            }
          else
            done = TRUE;

          if (!done)
            rightChildExpr = rightChildExpr->child(0);
        }

      // Among other things, this will give the probeCache
      // the characteristic inputs and outputs of the 
      // inner table.
      probeCache->setGroupAttr(new(generator->wHeap())
			    GroupAttributes(*(child(1)->getGroupAttr())));

      // Try to pull up predicates from the child, if that reduces
      // the char. inputs sent to the child. We only try this right
      // now if the child is an aggregate or groupby.
      if (rightChildGrby && 
          CmpCommon::getDefault(NESTED_JOIN_CACHE_PREDS) != DF_OFF &&
          (// if right child exchange exists, it must have same char inputs
           rightChildExch == NULL ||
           rightChildExch->getGroupAttr()->getCharacteristicInputs() ==
           rightChildGrby->getGroupAttr()->getCharacteristicInputs()) &&
          (rightChildMvi == NULL ||
           rightChildMvi->getGroupAttr()->getCharacteristicInputs() ==
           rightChildGrby->getGroupAttr()->getCharacteristicInputs()))
        {
          ValueIdSet pcAvailableInputs(
               probeCache->getGroupAttr()->getCharacteristicInputs());

          // predicates can refer to both char. inputs and outputs
          pcAvailableInputs += 
            probeCache->getGroupAttr()->getCharacteristicOutputs();

          // note that this will overwrite the ProbeCache's selection preds
          rightChildGrby->tryToPullUpPredicatesInPreCodeGen(
               pcAvailableInputs,
               probeCache->selectionPred(),
               optionalMap);

          // adjust char. inputs of intervening nodes - this is not
          // exactly good style, just overwriting the char. inputs, but
          // hopefully we'll get away with it at this stage in the
          // processing
          if (rightChildExch)
            rightChildExch->getGroupAttr()->setCharacteristicInputs(
                 rightChildGrby->getGroupAttr()->getCharacteristicInputs());
          if (rightChildMvi)
            rightChildMvi->getGroupAttr()->setCharacteristicInputs(
                 rightChildGrby->getGroupAttr()->getCharacteristicInputs());
        }

      // propagate estimates, physical properties, and costings 
      // from the child to the ProbeCache:
      probeCache->setEstRowsUsed(child(1)->getEstRowsUsed());
      probeCache->setMaxCardEst(child(1)->getMaxCardEst());
      probeCache->setInputCardinality(child(1)->getInputCardinality());
      probeCache->setPhysicalProperty(child(1)->getPhysicalProperty());
      probeCache->setOperatorCost(0);
      probeCache->setRollUpCost(child(1)->getRollUpCost());

      // Glue the ProbeCache to the NestedJoin's right leg.
      child(1) = probeCache;
    }                     
  if (isTSJForUndo())
  {
  
    Sort *sortNode = new(generator->wHeap()) Sort(child(0));

      ItemExpr *sk = new (generator->wHeap()) SystemLiteral(1);
      sk->synthTypeAndValueId(TRUE);

      ValueIdList skey;
      skey.insert(sk->getValueId());

      sortNode->getSortKey() = skey;

    // Use the same characteristic inputs and outputs as the left child
    sortNode->setGroupAttr(new(generator->wHeap())
			   GroupAttributes(*(child(0)->getGroupAttr())));
    //pass along some of the  estimates 
    sortNode->setEstRowsUsed(child(0)->getEstRowsUsed());
    sortNode->setMaxCardEst(child(0)->getMaxCardEst());
    sortNode->setInputCardinality(child(0)->getInputCardinality());
    sortNode->setPhysicalProperty(child(0)->getPhysicalProperty());
    sortNode->setCollectNFErrors();
    sortNode->setOperatorCost(0);
    sortNode->setRollUpCost(child(0)->getRollUpCost());
    child(0) = sortNode;
  }

  if ( childIsBlocking && 
      generator->preCodeGenParallelOperator() )
  {
    if (espExchangeWithMerge == FALSE) 
    {
      // A "halloween sort" needs to ensure that if it is parallel, but executes
      // in the same ESP as the generic update's TSJ flow node, then the Sort
      // will block until all scans are finished.  
      ((Sort *)(child(0).getPtr()))->doCheckAccessToSelfRefTable();
    }
    else
    {
      // An ESP Exchange can be eliminated in its preCodeGen method if it is 
      // redundant.  If this happens, then the Sort will be executing in the 
      // same ESP as the TSJ after all.  So we set this flag now, so that the 
      // Exchange preCodeGen will call doCheckAccessToSelfRefTable() for the 
      // Sort before eliminating itself.  This is part of the fix for Sol 
      // 10-090310-9876.
      ((Exchange *)(child(0).getPtr()))->markHalloweenSortIsMyChild();
    }
  }
  RelExpr * re =
    Join::preCodeGen(generator, externalInputs, pulledNewInputs);

  if ( espExchangeWithMerge &&
      (child(0)->getOperatorType() == REL_EXCHANGE))
    GenAssert(((Exchange *)((RelExpr *)child(0)))->doesMerge(), 
      "Exchange operator does not block for Halloween problem.");

  generator->compilerStatsInfo().nj()++;

  return re;
}


RelExpr * MergeJoin::preCodeGen(Generator * generator,
				const ValueIdSet & externalInputs,
				ValueIdSet &pulledNewInputs)
{
  if (nodeIsPreCodeGenned())
    return this;

  if (! Join::preCodeGen(generator, externalInputs, pulledNewInputs))
    return 0;

  // Accumulate the values that are provided as inputs by my parent
  // together with the values that are produced as outputs by my
  // children. Use these values for rewriting the VEG expressions.
  ValueIdSet availableValues;
  getInputValuesFromParentAndChildren(availableValues);

  // find if the left child and/or the right child will have atmost
  // one matching row. If so, an faster merge join implementation
  // will be used at runtime.
  ValueIdSet vidSet = getOrderedMJPreds();
  ValueIdSet valuesUsedForPredicates;

  computeValuesReqdForPredicates(vidSet,
				 valuesUsedForPredicates);
  leftUnique() =
    child(0)->getGroupAttr()->isUnique(valuesUsedForPredicates);

  rightUnique() =
    child(1)->getGroupAttr()->isUnique(valuesUsedForPredicates);


  ValueIdList mjp(getOrderedMJPreds());

  NABoolean replicatePredicates = TRUE;
  /* For merge join the characteristic outputs have already been resolved 
     by the time the equijoin preds are resolved below. The outputs are 
     resolved at the very end of Join::precodegen, which was called a few
     lines above. Therefore when we resolve the equijoin preds we have 
     only the actually resolved output values available. We do not have 
     all the potential output values available. 
  */
  ValueIdSet joinInputAndOutputValues;
  joinInputAndOutputValues = getGroupAttr()->getCharacteristicInputs();
  joinInputAndOutputValues += getGroupAttr()->getCharacteristicOutputs();

  // Pass in the children GAs so that the equipreds can have one side
  // resolved to one child and the other side resolved to the other child.
  // solution 10-100722-1962
  mjp.replaceVEGExpressions
         (availableValues,
	  getGroupAttr()->getCharacteristicInputs(),
	  FALSE, // no key predicates here
	  0 /* no need for idempotence here */,
	  replicatePredicates,
          NULL /* not a groupByAgg */,
          &joinInputAndOutputValues,
          NULL /* no indexDesc since we have no key preds*/,
          child(0)->getGroupAttr(),
          child(1)->getGroupAttr());

  // must have at least 1 merge join predicate
  GenAssert(!mjp.isEmpty(),"mjp.isEmpty()");

  // The generator expects the merge join predicates to be in the form
  // leftcol = rightcol where leftcol references a column from the left
  // table and rightcol references a column from the right table. Switch
  // the expression if it is the other way around. Also handle rare cases
  // where a VEGPred is resolved into two equalities connected by an AND.
  //
  ValueIdSet dummy1;
  ValueIdList newJoinPreds;
  ValueIdList newLeftOrder;
  ValueIdList newRightOrder;
  CollIndex ne = (CollIndex)(mjp.entries());
  NABoolean isANewJoinPred ;

  for (CollIndex i = 0; i < ne; i++)
  {
    // Will store all the conjuncts under the pred mjp[i] being considered.
    ValueIdSet conjuncts;
    conjuncts.clear();
    conjuncts.insert(mjp[i]);
    ValueIdSet finerConjuncts;

    do
    {
      finerConjuncts.clear();
      // Go through the set of conjuncts, breaking down any AND seen into
      // finer conjuncts.
      //
      for (ValueId vid = conjuncts.init();
                         conjuncts.next(vid);
                         conjuncts.advance(vid))
      {
        ItemExpr *pred = vid.getItemExpr();

        if (pred->getOperatorType() == ITM_AND)
        {
          // Found another AND, break it down into finer conjuncts. Store
          // them in finerConjuncts so that we can return to them later.
          //
          finerConjuncts.insert(pred->child(0)->getValueId());
          finerConjuncts.insert(pred->child(1)->getValueId());
        }
        else
        {
          // This is the "finest" conjunct - cannot be broken down further.
          // Make sure it's in the form of (leftCol = rightCol). Add the
          // equality predicate to the final list of MJ predicates. leftOrder
          // and rightOrder are set up correspondingly so that they match up
          // with the predicates.
          //
          GenAssert(pred->getOperatorType() == ITM_EQUAL,
                   "pred->getOperatorType() != ITM_EQUAL");

          ItemExpr *left = pred->child(0)->castToItemExpr();
          ItemExpr *right = pred->child(1)->castToItemExpr();
          isANewJoinPred = TRUE;

          NABoolean child0Covered = child(0).getGroupAttr()->covers(left->getValueId(),
					      getGroupAttr()->getCharacteristicInputs(),
					      dummy1) ;

          NABoolean child1Covered = child(1).getGroupAttr()->covers(right->getValueId(),
						  getGroupAttr()->getCharacteristicInputs(),
						  dummy1) ;

          if (NOT (child0Covered && child1Covered))
          {
	    //++MV - Irena
	    // save the pred's specialNulls_ flag before replacing the pred
 	    BiRelat *biRelat = new(generator->wHeap()) BiRelat(ITM_EQUAL, right, left);
	    // restore specialNulls_
	    biRelat->setSpecialNulls(((BiRelat*)pred)->getSpecialNulls());
	    biRelat->bindNode(generator->getBindWA());
	    pred = biRelat;
	    //--MV - Irena
	    
	    child0Covered = child(0).getGroupAttr()->covers(right->getValueId(),
						  getGroupAttr()->getCharacteristicInputs(),
						  dummy1) ;
	    
	    child1Covered = child(1).getGroupAttr()->covers(left->getValueId(),
						  getGroupAttr()->getCharacteristicInputs(),
						  dummy1) ;

            if(!(child0Covered && child1Covered))
            {
              if (isInnerNonSemiJoin())
              {
                selectionPred() += pred->getValueId();
              }
            else
              {
                // for an outer or semi join, the ON clause is stored in "joinPred"
                // while the WHERE clause is stored in "selectionPred".
                joinPred() += pred->getValueId();
              }
              isANewJoinPred = FALSE;
            }
          }

          if (isANewJoinPred)
          {
          // Store the finest conjuncts in the final list of MJ predicates.
          // Make sure the list is matched up with corresponding leftOrder
          // and rightOrder.
          //
          newJoinPreds.insert(pred->getValueId());
          newLeftOrder.insert(getLeftSortOrder()[i]);
          newRightOrder.insert(getRightSortOrder()[i]);
        }
        }
      } // for over conjuncts.

      // Come back to process the new set of broken-down conjuncts if the set
      // is non-empty.
      //
      conjuncts = finerConjuncts;
    } while (NOT conjuncts.isEmpty());
  } // for over mjp.
  if (ne > 0)
    GenAssert(NOT newJoinPreds.isEmpty(), "MergeJoin::PreCodeGen has no resolved join predicates");


  // Count merge join as a Big Memory Operator (BMO) if use of BMO quota
  // is enabled for merge join.
  if (CmpCommon::getDefaultLong(MJ_BMO_QUOTA_PERCENT) != 0)
  {
    generator->incrNumBMOs();
  }

  setOrderedMJPreds(newJoinPreds);
  setLeftSortOrder(newLeftOrder);
  setRightSortOrder(newRightOrder);

  generator->compilerStatsInfo().mj()++;

  markAsPreCodeGenned();
  return this;

} //  MergeJoin::preCodeGen()

RelExpr * HashJoin::preCodeGen(Generator * generator,
			       const ValueIdSet & externalInputs,
			       ValueIdSet &pulledNewInputs)
{
  if (nodeIsPreCodeGenned())
    return this;

  if ( CmpCommon::getDefault(COMPRESSED_INTERNAL_FORMAT) == DF_SYSTEM)
  {
    NABoolean resize = FALSE;
    NABoolean defrag = FALSE;
    ValueIdSet vidSet0 = child(0)->getGroupAttr()->getCharacteristicOutputs();
    ValueIdSet vidSet1 = child(1)->getGroupAttr()->getCharacteristicOutputs();

    ExpTupleDesc::TupleDataFormat tupleFormat =
                  determineInternalFormat( vidSet1,
                                           vidSet0,
                                           this,
                                           resize,
                                           generator,
                                           FALSE,
                                           defrag);

    cacheTupleFormatAndResizeFlag(tupleFormat, resize, defrag);

    if (tupleFormat == ExpTupleDesc::SQLMX_ALIGNED_FORMAT)
    {
      generator->incNCIFNodes();
    }
    else
    {
      generator->decNCIFNodes();
    }
	}	
  // Determine if we should attempt to use the HashJoin min/max optimization.
  NABoolean useMinMaxOpt = 
    ((CmpCommon::getDefault(GEN_HSHJ_MIN_MAX_OPT) == DF_ON) &&
     ! getEquiJoinPredicates().isEmpty() &&
     ! isLeftJoin() &&
     ! isRightJoin() &&
     ! isAntiSemiJoin());

  // These indexes define the subset of min max values which belong to this HashJoin.
  CollIndex startMinMaxIndex = 0;
  CollIndex endMinMaxIndex = 0;

  // If min/max opt is used, these lists are used to hold local copies of the
  // generators min and max values.  These are the min and max values
  // generated by HashJoins that may be used by scans.
  ValueIdList myMinVals;
  ValueIdList myMaxVals;

  // If min/max opt is used, this list are used to hold a local copy
  // of the generators minmaxKeys.  These are the values for which min
  // and max values are available
  ValueIdList myMinMaxKeys;

  if (useMinMaxOpt) {

    // This HashJoin will append to the end of the generator lists.
    //
    startMinMaxIndex = generator->getMinMaxKeys().entries();

    // Find the candidate values from the right hand side of the join.
    // For now, only consider VEGPreds.
    for (ValueId valId = getEquiJoinPredicates().init();
	 getEquiJoinPredicates().next(valId);
	 getEquiJoinPredicates().advance(valId)) {
      ItemExpr * itemExpr = valId.getItemExpr();

      NAType *mmType = NULL;
      if (itemExpr->getOperatorType() == ITM_VEG_PREDICATE) {

        VEGPredicate *vPred = (VEGPredicate *)itemExpr;
        VEGReference *vRef = vPred->getVEG()->getVEGReference();

        mmType = vRef->getValueId().getType().newCopy(generator->wHeap());

      }

      // mmType is the type of the VEGRef relating a left and right value.
      // We will compute the Min and Max using this type
      if(mmType) {

        // Min/Max are typed as nullable.
        mmType->setNullable(true);

        // Construct the host vars which will represent the min and
        // max values for this join key.

        char name[80];
        sprintf(name, "_sys_MinVal%d", generator->getMinMaxKeys().entries());

        ItemExpr *minVal = new(generator->wHeap()) 
          HostVar(name,
                  mmType,
                  TRUE);

        sprintf(name, "_sys_MaxVal%d", generator->getMinMaxKeys().entries());

        ItemExpr *maxVal = new(generator->wHeap())
          HostVar(name,
                  mmType,
                  TRUE);

        minVal->synthTypeAndValueId();
        maxVal->synthTypeAndValueId();

        // Insert the value and min and max into generator lists to
        // make the available to scans as key predicates.
        generator->getMinMaxKeys().insert(itemExpr->getValueId());
        generator->getMinVals().insert(minVal->getValueId());
        generator->getMaxVals().insert(maxVal->getValueId());
        
        // Initialize the 'will use' list to a NULL_VALUE_ID.  A scan
        // that decides to use the min max values will change this
        // entry to be the same as the corresponding entry in the
        // minMaxKeys list.
        generator->getWillUseMinMaxKeys().insert(NULL_VALUE_ID);

      }
    }
    
    // This is the end index (exclusive) for this HashJoin.
    endMinMaxIndex = generator->getMinMaxKeys().entries();

    // Keep local copies of the generators lists.
    myMinVals = generator->getMinVals();
    myMaxVals = generator->getMaxVals();
    myMinMaxKeys = generator->getMinMaxKeys();

  }

  // Register the start and end indexes for this Hash Join
  // (Join::preCodeGen() needs to have access to the indexes)
  setStartMinMaxIndex(startMinMaxIndex);
  setEndMinMaxIndex(endMinMaxIndex);

  if (! Join::preCodeGen(generator, externalInputs, pulledNewInputs))
    return NULL;

  // List for min and max values that will be used by a scan and which
  // will be generated by this HashJoin
  minMaxVals_.clear();
  minMaxCols_.clear();

  {

    // For each min/max value belonging to this HashJoin, check to see
    // if any scan decided to use it.  If so, add the min and max
    // values to the list.  Also, clear the 'will use' entry as no
    // other HashJoin can supply this value.
    for (CollIndex i = startMinMaxIndex; i < endMinMaxIndex; i++)
      {
        if (generator->getWillUseMinMaxKeys()[i] != NULL_VALUE_ID) 
          {

            minMaxVals_.insert(myMinVals[i]);
            minMaxVals_.insert(myMaxVals[i]);

            VEGPredicate *vPred = (VEGPredicate *)myMinMaxKeys[i].getItemExpr();
            VEGReference *vRef = vPred->getVEG()->getVEGReference();

            minMaxCols_.insert(vRef->getValueId());

            generator->getWillUseMinMaxKeys()[i] = NULL_VALUE_ID;
          }
      }

    // If we have some minMaxCols, then replace any VEGReferences.
    if (minMaxCols_.entries()) 
      {
        ValueIdSet availForMinMax;
        availForMinMax += child(1)->getGroupAttr()->getCharacteristicOutputs();
        availForMinMax += getGroupAttr()->getCharacteristicInputs();
        minMaxCols_.replaceVEGExpressions(availForMinMax,
                                          getGroupAttr()->getCharacteristicInputs());
      }
  }

  // Accumulate the values that are provided as inputs by my parent
  // together with the values that are produced as outputs by my
  // children. Use these values for rewriting the VEG expressions.
  ValueIdSet availableValues;


  getInputValuesFromParentAndChildren(availableValues);

  ValueIdSet hjp(getEquiJoinPredicates());

  NABoolean replicatePredicates = TRUE;

  /* For hash join the characteristic outputs have already been resolved 
     by the time the equijoin preds are resolved below. The outputs are 
     resolved at the very end of Join::precodegen, which was called a few
     lines above. Therefore when we resolve the equijoin preds we have 
     only the actually resolved output values available. We do not have 
     all the potential output values available. 
  */
  ValueIdSet joinInputAndOutputValues;
  joinInputAndOutputValues = getGroupAttr()->getCharacteristicInputs();
  joinInputAndOutputValues += getGroupAttr()->getCharacteristicOutputs();

  // Pass in the children GAs so that the equipreds can have one side
  // resolved to one child and the other side resolved to the other child.
  // solution 10-100722-1962
  hjp.replaceVEGExpressions
         (availableValues,
	  getGroupAttr()->getCharacteristicInputs(),
	  FALSE, // no key predicates here
	  0 /* no need for idempotence here */,
	  replicatePredicates,
          NULL /* not a groupByAgg */,
          &joinInputAndOutputValues,
          NULL /* no indexDesc since we have no key preds*/,
          child(0)->getGroupAttr(),
          child(1)->getGroupAttr());
  

  // Will store the rewritten hjp's which compile with the format of
  // leftCol= rightCol.
  //
  ValueIdSet newJoinPreds;

  if (hjp.isEmpty())
  {
    if (generator->downrevCompileNeeded())
      {
	// This is a cartesian product.
	// create a join predicate " 1 = 1 " which will always be true.
	//
	ItemExpr *left = new(generator->wHeap()) ConstValue(1);
	ItemExpr *right = new(generator->wHeap()) ConstValue(1);

	BiRelat *pred = new(generator->wHeap()) BiRelat(ITM_EQUAL,left,right);
	pred->bindNode(generator->getBindWA());
	newJoinPreds.insert(pred->getValueId());
      }
  }
  else
  {
    // The generator expects the hash join predicates to be in the form
    // leftcol = rightcol where leftcol references a column from the left
    // table and rightcol references a column from the right table. Switch
    // the expression if it is the other way around. Also handle rare cases
    // where a VEGPred is resolved into two equalities connected by an AND.
    //
    ValueIdSet dummy1;
    NABoolean isANewJoinPred ;


    do
    {
      ValueIdSet finerConjuncts;
      finerConjuncts.clear();


      for (ValueId vid = hjp.init();
                         hjp.next(vid);
                         hjp.advance(vid))
      {
        ItemExpr *pred = vid.getItemExpr();

        // Break this up into the finer conjuncts. Store them in a separate
        // set so that we can return to it later.
        // of the set so that we could return
        if (pred->getOperatorType() == ITM_AND)
        {
          finerConjuncts.insert(pred->child(0)->getValueId());
          finerConjuncts.insert(pred->child(1)->getValueId());
        }
        else
        {
          GenAssert(pred->getOperatorType() == ITM_EQUAL,
                   "pred->getOperatorType() != ITM_EQUAL");

          ItemExpr *left = pred->child(0)->castToItemExpr();
          ItemExpr *right = pred->child(1)->castToItemExpr();
          isANewJoinPred = TRUE;

          NABoolean child0Covered = child(0).getGroupAttr()->covers(left->getValueId(),
					      getGroupAttr()->getCharacteristicInputs(),
					      dummy1) ;
	  
          NABoolean child1Covered = child(1).getGroupAttr()->covers(right->getValueId(),
						  getGroupAttr()->getCharacteristicInputs(),
						  dummy1) ;

          if (NOT (child0Covered && child1Covered))
          {
	    //++MV - Irena
	    // save the pred's specialNulls_ flag before replacing the pred
 	    BiRelat *biRelat = new(generator->wHeap()) BiRelat(ITM_EQUAL, right, left);
	    // restore specialNulls_
	    biRelat->setSpecialNulls(((BiRelat*)pred)->getSpecialNulls());
	    biRelat->bindNode(generator->getBindWA());
	    pred = biRelat;
	    //--MV - Irena
	    
	    child0Covered = child(0).getGroupAttr()->covers(right->getValueId(),
						  getGroupAttr()->getCharacteristicInputs(),
						  dummy1) ;
	    
	    child1Covered = child(1).getGroupAttr()->covers(left->getValueId(),
						  getGroupAttr()->getCharacteristicInputs(),
						  dummy1) ;

            if(!(child0Covered && child1Covered))
            {
              if (isInnerNonSemiJoin())
              {
                selectionPred() += pred->getValueId();
              }
            else
              {
                // for an outer or semi join, the ON clause is stored in "joinPred"
                // while the WHERE clause is stored in "selectionPred".
                joinPred() += pred->getValueId();
              }
              isANewJoinPred = FALSE;
            }
          }
          if (isANewJoinPred)
          newJoinPreds.insert(pred->getValueId());
	}
    } // for over hjp.
    
    // Come back to process the new set of broken-down conjuncts if the set
    // is non-empty.
    //
    hjp = finerConjuncts;
    } while (NOT hjp.isEmpty());
    GenAssert(NOT newJoinPreds.isEmpty(), "HashJoin::PreCodeGen has no resolved join predicates");
  }

  // Value IDs given to the right/inner child
  ValueIdSet valuesGivenToRightChild =
    child(1)->getGroupAttr()->getCharacteristicInputs();

  if ( ! valuesGivenToRightChild.isEmpty() )  {

    // Accumulate the values that are provided as inputs by my parent
    // together with the values that are produced as outputs by my
    // children. Use these values for rewriting the VEG expressions.
    ValueIdSet availableValues;
    const ValueIdSet & HJInputs = getGroupAttr()->getCharacteristicInputs();
    getInputValuesFromParentAndChildren(availableValues);

    valuesGivenToRightChild.replaceVEGExpressions(availableValues, HJInputs);
  }

  // before computing the move and check expressions, add one more
  // value to "valuesGivenToRightChild": a statement execution count
  // that will cause re-hashing each time the statement is
  // re-executed. It is not legal to keep a hash table across
  // statement executions (and possibly transactions).
  ValueId execCount = generator->getOrAddStatementExecutionCount();
  valuesGivenToRightChild += execCount;
  pulledNewInputs += execCount;
  getGroupAttr()->addCharacteristicInputs(pulledNewInputs);

  // add move and search expressions
  for (ValueId val_id = valuesGivenToRightChild.init();
       valuesGivenToRightChild.next(val_id);
       valuesGivenToRightChild.advance(val_id))  {

    ItemExpr * item_expr = val_id.getItemExpr();

    // add this converted value to the map table.
    Convert * conv_node = new(generator->wHeap()) Convert (item_expr);

    // bind/type propagate the new node
    conv_node->bindNode(generator->getBindWA());

    moveInputValues().insert(conv_node->getValueId());

    // add the search condition
    BiRelat * bi_relat = new(generator->wHeap())
      BiRelat(ITM_EQUAL, item_expr, conv_node);
    bi_relat->allocValueId();
    checkInputValues().insert(bi_relat->getValueId());

  }  // for val_id

  // Count this BMO and add its needed memory to the total needed
  generator->incrNumBMOs();

  if ((ActiveSchemaDB()->getDefaults()).getAsDouble(EXE_MEMORY_LIMIT_PER_CPU) > 0)
    generator->incrBMOsMemory(getEstimatedRunTimeMemoryUsage(TRUE));


  // store the transformed predicates back into the hash join node
  storeEquiJoinPredicates(newJoinPreds);

  generator->compilerStatsInfo().hj()++;

  //
  // case of hash anti semi join optimization (NOT IN)
  // add/build expression to detect inner and outer null :
  // checkOuteNullexpr_ and checkInnerNullExpr_ 
  addCheckNullExpressions(generator->wHeap());

  markAsPreCodeGenned();
  return this;

} //  HashJoin::preCodeGen()

RelExpr * FileScan::preCodeGen(Generator * generator,
			       const ValueIdSet & externalInputs,
			       ValueIdSet &pulledNewInputs)
{
  if (nodeIsPreCodeGenned())
    return this;

  const PartitioningFunction* myPartFunc = getPartFunc();

  NABoolean usePartKeyPreds =
    (isHbaseTable() &&
     myPartFunc &&
     myPartFunc->isPartitioned() &&
     !myPartFunc->isAReplicationPartitioningFunction());

  if (isRewrittenMV())
    generator->setNonCacheableMVQRplan(TRUE);

  if (usePartKeyPreds)
    {
      // partition key predicates will be applied to this file scan,
      // "pull" the partition input values from the parent
      pulledNewInputs += myPartFunc->getPartitionInputValues();
      getGroupAttr()->addCharacteristicInputs(myPartFunc->getPartitionInputValues());
    }

  // Resolve the VEGReferences and VEGPredicates, if any, that appear
  // in the Characteristic Inputs, in terms of the externalInputs.
  getGroupAttr()->resolveCharacteristicInputs(externalInputs);

  // The VEG expressions in the selection predicates and the characteristic
  // outputs can reference any expression that is either a potential output
  // or a characteristic input for this RelExpr. Supply these values for
  // rewriting the VEG expressions.
  ValueIdSet availableValues;

  getInputAndPotentialOutputValues(availableValues);

  sampledColumns().replaceVEGExpressions
    (availableValues, getGroupAttr()->getCharacteristicInputs());

  // Rewrite the partitioning function in terms of the available values.
  if (getIndexDesc()->isPartitioned())
    getIndexDesc()->getPartitioningFunction()->preCodeGen(availableValues);

  // VEGPredicates that are key predicates but are also replicated in
  // the executor predicates must be replaced with the same expression
  // in both the places after they are rewritten.  The VEGRewritePairs
  // data structure, when passed to replaceVEGExpressions(), causes
  // replaceVEGExpressions() to be idempotent.

  VEGRewritePairs  vegPairs(generator->wHeap());
  ValueIdSet partKeyPredsHBase;

  if (usePartKeyPreds)
    {
      // add the partitioning key predicates to this scan node,
      // to make sure that each ESP reads only the part of the
      // data that it is supposed to process

      ValueId saltCol;

      if (myPartFunc->isATableHashPartitioningFunction())
        {
          // find the _SALT_ column and make a partitioning key
          // predicate for it
          const ValueIdList &keyCols = getIndexDesc()->getIndexKey();

          // the first salt column we find in the key is the one
          // we are looking for
          for (CollIndex i=0; i<keyCols.entries(); i++)
            if (keyCols[i].isSaltColumn())
              {
                saltCol = keyCols[i];
                break;
              }

          if (saltCol != NULL_VALUE_ID)
            ((TableHashPartitioningFunction *) myPartFunc)->
              createPartitioningKeyPredicatesForSaltedTable(saltCol);
        }

      partKeyPredsHBase = myPartFunc->getPartitioningKeyPredicates();
    }

  if (getMdamKeyPtr() != NULL)
    {

      NABoolean replicatePredicates = TRUE;

      //      mdamKeyPtr()->print(); // for debugging purposes

      ValueIdSet executorPredicates;

      ValueIdSet augmentedPreds = getSelectionPredicates();

      const LogPhysPartitioningFunction *logPhysPartFunc =
	getPartFunc()->castToLogPhysPartitioningFunction();

      if (!partKeyPredsHBase.isEmpty())
        {
          augmentedPreds += partKeyPredsHBase;
          mdamKeyPtr()->setNoExePred(FALSE);
        }

      augmentedPreds += getComputedPredicates();

      if ( logPhysPartFunc != NULL )
      {
	LogPhysPartitioningFunction::logPartType logPartType =
	  logPhysPartFunc->getLogPartType();
	if ( logPartType == LogPhysPartitioningFunction::LOGICAL_SUBPARTITIONING
	  OR logPartType == LogPhysPartitioningFunction::HORIZONTAL_PARTITION_SLICING
	  )
	  augmentedPreds += logPhysPartFunc->getPartitioningKeyPredicates();
      }

      mdamKeyPtr()->preCodeGen(executorPredicates,
			       augmentedPreds,
			       availableValues,
			       getGroupAttr()->getCharacteristicInputs(),
			       &vegPairs,
			       replicatePredicates,
                               !partKeyPredsHBase.isEmpty());
      setExecutorPredicates(executorPredicates);

      //      mdamKeyPtr()->print(); // for debugging purposes


    }
  else if (! isHiveTable() &&
           (getSearchKey() || !partKeyPredsHBase.isEmpty()))
    {
      // ---------------------------------------------------
      // --------------------- Rewrite preds for search key:
      // ---------------------------------------------------

      if (!partKeyPredsHBase.isEmpty())
        {
          // These predicates can compete with other key predicates;
          // decide which of them to use as key preds and which as
          // executor preds:

          // - No search key: Use part key preds as search key
          // - Search key with non-unique preds: Replace it with
          //   a new search key with part key preds
          // - Search key with unique preds (unlikely, this shouldn't
          //   have been a parallel query): add part key preds as
          //   executor preds

          ValueIdSet combinedInputs(externalInputs);
          combinedInputs += pulledNewInputs;
          ValueIdSet existingKeyPreds;

          if (getSearchKey()) 
            existingKeyPreds += getSearchKey()->getKeyPredicates();
   
          // create a new search key that has the partitioning key preds
          SearchKey * partKeySearchKey = 
            myPartFunc->createSearchKey(getIndexDesc(),
                                        combinedInputs,
                                        existingKeyPreds);
          ValueIdSet exePreds(partKeySearchKey->getExecutorPredicates());
          NABoolean replaceSearchKey = !(getSearchKey() &&
                                         getSearchKey()->isUnique());

          if (getSearchKey()) 
            exePreds += getSearchKey()->getExecutorPredicates();

          // pick one search key and add the remaining
          // predicates (if any) to exePreds
          if (replaceSearchKey)
            setSearchKey(partKeySearchKey);
          else
            exePreds += partKeySearchKey->getKeyPredicates();
          searchKey()->setExecutorPredicates(exePreds);
        }

      NABoolean replicatePredicates = TRUE;

      setExecutorPredicates(searchKey()->getExecutorPredicates());

      // Rebuild the search key expressions
      ValueIdSet& keyPred = searchKey()->keyPredicates();
      keyPred.replaceVEGExpressions
	(availableValues,
	 getGroupAttr()->getCharacteristicInputs(),
	 FALSE, // no need for key predicate generation here
	 &vegPairs,
	 replicatePredicates);

      // Rebuild the executor  predicate tree
      executorPred().replaceVEGExpressions
	(availableValues,
	 getGroupAttr()->getCharacteristicInputs(),
	 FALSE, // no need for key predicate generation here
	 &vegPairs,
	 replicatePredicates
	 );

      // Generate the begin and end keys.

      if ( getDoUseSearchKey() ) {
     
      generateKeyExpr(getGroupAttr()->getCharacteristicInputs(),
		      getIndexDesc()->getIndexKey(),
		      getSearchKey()->getBeginKeyValues(),
		      beginKeyPred_,
		      generator,
                      replicatePredicates);
      generateKeyExpr(getGroupAttr()->getCharacteristicInputs(),
		      getIndexDesc()->getIndexKey(),
		      getSearchKey()->getEndKeyValues(),
		      endKeyPred_,
		      generator,
                      replicatePredicates);
      }

      // Check to see if there are any MIN/MAX values coming from a
      // HashJoin which could be used as begin/end key values for the
      // leading key of this scan.  Don't consider doing this if this
      // is a unique scan (can't improve on that) or if the leading
      // key is already unique or if both the begin and end key are
      // exclusive (min max are inclusive and no easy way to mix
      // them).
      if (generator->getMinMaxKeys().entries() &&
         (getSearchKey()->getBeginKeyValues()[0] !=
          getSearchKey()->getEndKeyValues()[0]) &&
         (!getSearchKey()->isBeginKeyExclusive() ||
          !getSearchKey()->isEndKeyExclusive())) {

        // The keys of the scan.
        const ValueIdList &keys = getIndexDesc()->getIndexKey();
        ValueId      minMaxKeyCol = keys[0];
        IndexColumn *ixCol = (IndexColumn *) (minMaxKeyCol.getItemExpr());
        BaseColumn  *baseCol = NULL;
        ValueId      underlyingCol;
        NABoolean    needToComputeActualMinMax = FALSE;
        ItemExpr    *computedColExpr = NULL;
        
        // The candidate values for min and max.
        const ValueIdList &minMaxKeys = generator->getMinMaxKeys();
    
        CollIndex keyIdx = NULL_COLL_INDEX;

        // Determine how min/max is related to begin/end.  depends
        // on ordering (ASC vs DESC) and scan direction (forward vs
        // reverse)
        NABoolean ascKey = 
          getIndexDesc()->getNAFileSet()->getIndexKeyColumns().isAscending(0);

        if(getReverseScan())
          ascKey = !ascKey;

        // If the leading key column is a divisioning column, then
        // look for min/max values of an underlying column
        GenAssert(ixCol->getOperatorType() == ITM_INDEXCOLUMN,
                  "unexpected object type");
        baseCol = 
          (BaseColumn *) (((IndexColumn *) ixCol)->getDefinition().getItemExpr());
        GenAssert(baseCol->getOperatorType() == ITM_BASECOLUMN,
                  "unexpected object type");
        if (baseCol->getNAColumn()->isDivisioningColumn()) {
          ValueIdSet underlyingCols;
          baseCol->getUnderlyingColumnsForCC(underlyingCols);

          if (underlyingCols.entries() == 1) {
            // We have a leading division column that's computed from
            // 1 base column, now get the underlying column and the
            // divisioning expression
            needToComputeActualMinMax = TRUE;
            underlyingCols.getFirst(minMaxKeyCol);
            computedColExpr = baseCol->getComputedColumnExpr().getItemExpr();
            BaseColumn  *underlyingBaseCol =
              (BaseColumn *) minMaxKeyCol.getItemExpr();
            GenAssert(underlyingBaseCol->getOperatorType() == ITM_BASECOLUMN,
                      "unexpected object type");
            // the computed column expression has been rewritten to use
            // VEGRefs, so get the corresponding VEGRef for the underlying column
            underlyingCol = underlyingBaseCol->getTableDesc()->
              getColumnVEGList()[underlyingBaseCol->getColNumber()];
          }
        }

        // Check all the candidate values.  If any one of them matches
        // the leading key of this scan, then select it for use in the
        // begin/end key value of the leading key.

        // Scalar min/max functions cause an exponential growth when
        // combined with each other, see ItmScalarMinMax::codeGen()
        Int32 limitItems = 3 ; // use at most 3

        for(CollIndex i = 0; i < minMaxKeys.entries() && limitItems; i++) {
          ValueId mmKeyId = minMaxKeys[i];
          if(mmKeyId != NULL_VALUE_ID) {
            ItemExpr *mmItem = mmKeyId.getItemExpr();
      
            if (mmItem->getOperatorType() == ITM_VEG_PREDICATE) {
              VEGPredicate *vPred = (VEGPredicate *)mmItem;
              const ValueIdSet &members = vPred->getVEG()->getAllValues();

              if (members.contains(minMaxKeyCol)) {

                // some other operator is producing min/max values
                // for our leading key column, now check whether we
                // can use them

                keyIdx = i;

                // Indicate in the 'will use' list that we will use these
                // min/max values.  This will indicate to the HashJoin that
                // it should produce these values.
                generator->getWillUseMinMaxKeys()[keyIdx] =
                  generator->getMinMaxKeys()[keyIdx];
                addMinMaxHJColumn(baseCol->getValueId());

                limitItems-- ; // one more is used

                // If we can use a min/max value for the begin key, do so...
                if(!getSearchKey()->isBeginKeyExclusive()) {
                  ItemExpr *keyPred = getBeginKeyPred()[0].getItemExpr();
                  ItemExpr *currentBeg = keyPred->child(1);

                  // Get the proper begin key (min or max) that came from
                  // the HashJoin
                  ValueId hashJoinBeg = (ascKey ?
                                         generator->getMinVals()[keyIdx] :
                                         generator->getMaxVals()[keyIdx]);

                  // Construct an expression which determines at runtime
                  // which BK to use.  Either the existing one or the one
                  // coming from HashJoin whichever is larger (smaller).
                  // 
                  ItemExpr *newBeg = hashJoinBeg.getItemExpr();

                  if (needToComputeActualMinMax) {
                    ValueIdMap divExprMap;
                    ValueId computedBeg;

                    // If hashJoinBeg is :sysHV1 and the computed column
                    // expression is A/100, then the begin value for
                    // the computed column is :sysHV1/100. Do this
                    // rewrite by using a ValueIdMap
                    divExprMap.addMapEntry(underlyingCol, hashJoinBeg);
                    divExprMap.rewriteValueIdDown(computedColExpr->getValueId(),
                                                  computedBeg);
                    newBeg = computedBeg.getItemExpr();
                  }

                  newBeg = new (generator->wHeap())
                    ItmScalarMinMax((ascKey ? ITM_SCALAR_MAX : ITM_SCALAR_MIN),
                                    currentBeg, 
                                    newBeg);
                  newBeg->synthTypeAndValueId();
                  // Replace the RHS of the key pred.
                  keyPred->child(1) = newBeg->getValueId();

                  // The value coming from the HashJoin must be in out inputs.
                  getGroupAttr()->addCharacteristicInputs(hashJoinBeg);

                  // And we must pull those values from the HashJoin.
                  pulledNewInputs += hashJoinBeg;
                  availableValues += hashJoinBeg;
                }

                // If we can use a min/max value for the end key, do so...
                if(!getSearchKey()->isEndKeyExclusive()) {
                  ItemExpr *keyPred = getEndKeyPred()[0].getItemExpr();
                  ItemExpr *currentEnd = keyPred->child(1);

                  // Get the proper end key (max or min) that came from
                  // the HashJoin
                  ValueId hashJoinEnd = (ascKey ?
                                         generator->getMaxVals()[keyIdx] :
                                         generator->getMinVals()[keyIdx]);

                  // Construct an expression which determines at runtime
                  // which EK to use.  Either the existing one or the one
                  // coming from HashJoin whichever is smaller (larger).
                  // 
                  ItemExpr *newEnd = hashJoinEnd.getItemExpr();

                  if (needToComputeActualMinMax) {
                    ValueIdMap divExprMap;
                    ValueId computedEnd;

                    divExprMap.addMapEntry(underlyingCol, hashJoinEnd);
                    divExprMap.rewriteValueIdDown(computedColExpr->getValueId(),
                                                  computedEnd);
                    newEnd = computedEnd.getItemExpr();
                  }

                  newEnd = new (generator->wHeap())
                    ItmScalarMinMax((ascKey ? ITM_SCALAR_MIN : ITM_SCALAR_MAX),
                                    currentEnd, 
                                    newEnd);
                  newEnd->synthTypeAndValueId();

                  // Replace the RHS of the key pred.
                  keyPred->child(1) = newEnd->getValueId();

                  // The value coming from the HashJoin must be in out inputs.
                  getGroupAttr()->addCharacteristicInputs(hashJoinEnd);

                  // And we must pull those values from the HashJoin.
                  pulledNewInputs += hashJoinEnd;
                  availableValues += hashJoinEnd;
                }
              }
            }
          }
        }
      }
    }
  else
    {
      // Hive table scan (HBase scan has executor preds set up already)
      if (isHiveTable())
        setExecutorPredicates(selectionPred());

      // Rebuild the executor  predicate tree
      executorPred().replaceVEGExpressions
	(availableValues,
	 getGroupAttr()->getCharacteristicInputs(),
	 FALSE, // no need for key predicate generation here
	 &vegPairs,
	 TRUE);

      if (isHiveTable())
	// assign individual files and blocks to each ESPs
	((NodeMap *) getPartFunc()->getNodeMap())->assignScanInfos(hiveSearchKey_);
    }

  // Selection predicates are not needed anymore:
  selectionPred().clear();

  // Add the sampled columns to the set of available values. This is
  // basically a kluge to get the GroupAttributes right.

  availableValues += sampledColumns();

  // This call also rewrites predicates
  // $$$ Does it need vegPairs too? $$$
  getGroupAttr()->resolveCharacteristicOutputs
    (availableValues,
     getGroupAttr()->getCharacteristicInputs());

  generator->oltOptInfo()->mayDisableOperStats(&oltOptInfo());
  markAsPreCodeGenned();
  return this;
} // FileScan::preCodeGen()


RelExpr * GenericUpdate::preCodeGen(Generator * generator,
				    const ValueIdSet & externalInputs,
				    ValueIdSet &pulledNewInputs)
{
  if (nodeIsPreCodeGenned())
    return this;

  if (! RelExpr::preCodeGen(generator,externalInputs,pulledNewInputs))
    return NULL;

  // Determine whether OLT optimization must be avoided.
  if (getGroupAttr()->isEmbeddedUpdateOrDelete())
    {
      generator->oltOptInfo()->setOltMsgOpt(FALSE);

      generator->setUpdAbortOnError(TRUE);
      generator->setUpdSavepointOnError(FALSE);
      generator->setUpdPartialOnError(FALSE);
      generator->setUpdErrorOnError(FALSE);
    }

  if ((accessOptions().accessType() == SKIP_CONFLICT_) ||
      (getGroupAttr()->isStream()) ||
      (newRecBeforeExprArray().entries() > 0)) // set on rollback
    {
      generator->oltOptInfo()->setOltEidOpt(FALSE);
      oltOptInfo().setOltEidOpt(FALSE);
      setExpandShortRows(FALSE);

      generator->setUpdAbortOnError(TRUE);
      generator->setUpdSavepointOnError(FALSE);
      generator->setUpdPartialOnError(FALSE);
      generator->setUpdErrorOnError(FALSE);
    }

  // If RI, IM, MV or triggers are being used, abort on error.
  // This is because internal data consistency
  // cannot be guaranteed for these cases.
  if ((getInliningInfo().hasInlinedActions()) ||
      (getInliningInfo().isEffectiveGU()))
    {
      // cannot do partial updates.
      generator->setUpdPartialOnError(FALSE);

      if (CmpCommon::getDefault(COMP_BOOL_206) == DF_ON)
	{
	  if (NOT ((getInliningInfo().hasTriggers()) ||
		   (getInliningInfo().hasRI()) ||
		   (getInliningInfo().hasIM()) ||
		   (getInliningInfo().isMVLoggingInlined())))
	    {
	      generator->setUpdAbortOnError(TRUE);
	      generator->setUpdSavepointOnError(FALSE);
	      generator->setUpdErrorOnError(FALSE);
	    }
	  else
	    generator->setUpdErrorOnError(FALSE);
	}
      else
	{
	  // abort on error for non-IM cases(RI,MV,Trig).
	  if ((NOT getInliningInfo().hasIM()) ||
	      (getInliningInfo().hasRI()))
	    {
	      generator->setUpdAbortOnError(TRUE);
	      generator->setUpdSavepointOnError(FALSE);
	      generator->setUpdErrorOnError(FALSE);
	    }
	  else
	    generator->setUpdErrorOnError(FALSE);
	}
    }

  // If RI, MV or triggers are being used, turn off the lean optimization for
  // the complete plan; all other optimizations will still apply.
  if ( generator->oltOptInfo()->oltEidLeanOpt() &&
       ( getInliningInfo().hasTriggers()  ||
         getInliningInfo().hasRI()        ||
         getInliningInfo().isMVLoggingInlined() ) )
  {
    generator->oltOptInfo()->setOltEidLeanOpt(FALSE);
    oltOptInfo().setOltEidLeanOpt(FALSE);
  }

  // Accumulate the values that are provided as inputs by my parent
  // together with the values that are produced as outputs by my
  // children. Use these values for rewriting the VEG expressions.
  ValueIdSet availableValues;
  getInputValuesFromParentAndChildren(availableValues);

  newRecExpr_.replaceVEGExpressions
                 (availableValues,
		  getGroupAttr()->getCharacteristicInputs());

  newRecBeforeExpr_.replaceVEGExpressions
                 (availableValues,
		  getGroupAttr()->getCharacteristicInputs());

  executorPred().replaceVEGExpressions
	          (availableValues,
		    getGroupAttr()->getCharacteristicInputs());

  // VEGPredicates that are key predicates but are also replicated
  // in the executor predicates must be replaced with the same
  // expression in both places after they are rewritten.
  // Therefore, we want replaceVEGExpressions() processing to be
  // idempotent.  By passing the VEGRewritePairs data structure
  // to replaceVEGExpressions(), we get idempotence.

  VEGRewritePairs lookup(generator->wHeap());   // so replaceVEGExpressions will be idempotent

  if (getSearchKey() == NULL)
    {
      // Begin and end key preds may already be available.
      beginKeyPred_.replaceVEGExpressions
                       (availableValues,
			getGroupAttr()->getCharacteristicInputs(),
			FALSE, // no need for key predicate generation here
			&lookup);
      endKeyPred_.replaceVEGExpressions
                     (availableValues,
		      getGroupAttr()->getCharacteristicInputs(),
		      FALSE,  // no need for key predicate generation here
		      &lookup);

      // In the case of an embedded insert from VALUES,
      // any predicates need to have their VEGreferences resolved.
      if (getGroupAttr()->isEmbeddedInsert())
	{

          NABoolean replicatePredicates = TRUE;

	  // Rebuild the executor predicate tree
	  executorPred().replaceVEGExpressions
			    (availableValues,
			     getGroupAttr()->getCharacteristicInputs(),
			     FALSE,  // no need for key predicate generation
			     &lookup,
			     replicatePredicates
			    );
	}
    }
  else
    {
      // Build begin and end key predicates from the search key structure.

      //## It *might* be a good idea to add here:
      //##   CMPASSERT(beginKeyPred_.isEmpty() && endKeyPred_.isEmpty());
      //## as that *seems* to be the assumption here.
      //## (But I haven't the time to make the change and test it.)

      ValueIdSet& keyPred = getSearchKey()->keyPredicates();

      NABoolean replicatePredicates = TRUE;

      // Rebuild the search key expressions
      keyPred.replaceVEGExpressions
                 (availableValues,
		  getGroupAttr()->getCharacteristicInputs(),
		  FALSE, // no need for key predicate generation
		  &lookup,
		  replicatePredicates);

      // Rebuild the executor  predicate tree
      executorPred().replaceVEGExpressions
	                (availableValues,
			 getGroupAttr()->getCharacteristicInputs(),
			 FALSE,  // no need for key predicate generation
			 &lookup,
			 replicatePredicates
			);

      // Generate the begin and end keys.
      generateKeyExpr(getGroupAttr()->getCharacteristicInputs(),
		      getIndexDesc()->getIndexKey(),
		      getSearchKey()->getBeginKeyValues(),
		      beginKeyPred_,
		      generator);
      generateKeyExpr(getGroupAttr()->getCharacteristicInputs(),
		      getIndexDesc()->getIndexKey(),
		      getSearchKey()->getEndKeyValues(),
		      endKeyPred_,
		      generator);
    }

  // ---------------------------------------------------------------------
  // Rewrite the check constraint expressions.
  // ---------------------------------------------------------------------
  checkConstraints().replaceVEGExpressions
                        (availableValues,
			 getGroupAttr()->getCharacteristicInputs());

  generator->setFoundAnUpdate(TRUE);
  generator->setPartnAccessChildIUD();

#ifdef _DEBUG
  // Compile in the index maintenance ... just for testing
  //
  if(getenv("IM_COMPILE"))
    generator->imUpdateRel() = this;
#endif

  if (oltOptLean() &&
      ((isinBlockStmt()) ||
       (getTableDesc()->getNATable()->hasAddedColumn()) ||
       (getTableDesc()->getNATable()->hasVarcharColumn())))
  {
    oltOptInfo().setOltEidLeanOpt(FALSE);
  }

  generator->setSkipUnavailablePartition(FALSE);

  if (isMtsStatement())
    generator->setEmbeddedIUDWithLast1(TRUE) ;

  if (isMerge())
    {
      // Accumulate the values that are provided as inputs by my parent
      // together with the values that are produced as outputs by my
      // children. Use these values for rewriting the VEG expressions.
      ValueIdSet availableValues;
      getInputValuesFromParentAndChildren(availableValues);
      
      mergeInsertRecExpr().replaceVEGExpressions
	(availableValues,
	 getGroupAttr()->getCharacteristicInputs());

      mergeUpdatePred().replaceVEGExpressions
	(availableValues,
	 getGroupAttr()->getCharacteristicInputs());

      ValueIdList tempVIDlist;
      getTableDesc()->getIdentityColumn(tempVIDlist);
      NAColumn *identityCol = NULL;
      if (tempVIDlist.entries() > 0)
	{
	  ValueId valId = tempVIDlist[0];
	  identityCol = valId.getNAColumn();
	}

      if (((getOperatorType() == REL_HBASE_DELETE) ||
           (getOperatorType() == REL_HBASE_UPDATE)) &&
          (getTableDesc()->getNATable()->getClusteringIndex()->hasSyskey()))
	{
	  *CmpCommon::diags() << DgSqlCode(-3241) 
			      << DgString0(" SYSKEY not allowed.");
	  GenExit();
	}

      if ((getOperatorType() != REL_HBASE_UPDATE) &&
          (mergeInsertRecExpr().entries() > 0) &&
          (CmpCommon::getDefault(COMP_BOOL_175) == DF_OFF))
	{
          // MERGE with INSERT is limited to HBase updates unless
          // the CQD is on
	  *CmpCommon::diags() << DgSqlCode(-3241)
			      << DgString0(" This MERGE is not allowed with INSERT.");
	  GenExit();
	}

      if (oltOpt())
	{
	  // if no update expr and only insert expr is specified for 
	  // this MERGE stmt, turn off olt opt.
	  // 
	  if (newRecExprArray().entries() == 0)
	    oltOptInfo().setOltEidOpt(FALSE);

	  oltOptInfo().setOltEidLeanOpt(FALSE);
	}

      generator->setUpdErrorOnError(FALSE);
      generator->setUpdSavepointOnError(FALSE);
    } // isMerge

  generator->oltOptInfo()->mayDisableOperStats(&oltOptInfo());

  // Part of the fix for Soln 10-100425-9755.  Don't AQR a 
  // positioned update/delete because part of the recovery
  // for the error that triggers the AQR is rollback transaction
  // and this causes the referenced cursor to be closed.  The other
  // part of the fix is in compiler cache: positioned update/deletes
  // will not be cached, and this should reduce the need to handle
  // errors with AQR, e.g., timestamp mismatch errors.
  if (updateCurrentOf())
    generator->setAqrEnabled(FALSE);

  if (getTableDesc()->getNATable()->hasLobColumn())
    {
      oltOptInfo().setOltOpt(FALSE);
      generator->oltOptInfo()->setOltOpt(FALSE);
      generator->setAqrEnabled(FALSE);
      generator->setUpdAbortOnError(TRUE);
      generator->setUpdSavepointOnError(FALSE);
    }

  if ((isNoRollback()) ||
      (generator->getTransMode()->getRollbackMode() == TransMode::NO_ROLLBACK_))
    {
      generator->setWithNoRollbackUsed(isNoRollback());
      if (CmpCommon::getDefault(AQR_WNR) == DF_OFF)
        generator->setAqrEnabled(FALSE);
    }

  if (((getInliningInfo().hasInlinedActions()) ||
       (getInliningInfo().isEffectiveGU())) &&
      (getInliningInfo().hasRI()))
    {
      generator->setRIinliningForTrafIUD(TRUE);
    }

  if (precondition_.entries() > 0)
  {
    ValueIdSet availableValues;
    getInputValuesFromParentAndChildren(availableValues);  
    precondition_.
      replaceVEGExpressions(availableValues,
			    getGroupAttr()->getCharacteristicInputs());
  }

  markAsPreCodeGenned();

  return this;
} // GenericUpdate::preCodeGen()

RelExpr * Update::preCodeGen(Generator * generator,
			     const ValueIdSet & externalInputs,
			     ValueIdSet &pulledNewInputs)
{
  if (nodeIsPreCodeGenned())
    return this;
  
  if (! GenericUpdate::preCodeGen(generator,externalInputs,pulledNewInputs))
    return NULL;

  markAsPreCodeGenned();

  return this;
}

RelExpr * MergeUpdate::preCodeGen(Generator * generator,
				  const ValueIdSet & externalInputs,
				  ValueIdSet &pulledNewInputs)
{
  if (nodeIsPreCodeGenned())
    return this;
  
  if (! Update::preCodeGen(generator,externalInputs,pulledNewInputs))
    return NULL;

  markAsPreCodeGenned();

  return this;
}

RelExpr * UpdateCursor::preCodeGen(Generator * generator,
				   const ValueIdSet & externalInputs,
				   ValueIdSet &pulledNewInputs)
{
  if (nodeIsPreCodeGenned())
    return this;

  if (! Update::preCodeGen(generator,externalInputs,pulledNewInputs))
    return NULL;

  // primary key columns cannot be updated, yet. After RI support
  // is in, they could be updated.
   const NAColumnArray & key_column_array =
     getTableDesc()->getNATable()->getClusteringIndex()->getIndexKeyColumns();

  ValueIdSet& val_id_set = newRecExpr();
  ValueId val_id;
  for (val_id = val_id_set.init(); val_id_set.next(val_id); val_id_set.advance(val_id))
    {
      ItemExpr * item_expr = val_id.getItemExpr();

      for (short i = 0; i < getTableDesc()->getNATable()->getKeyCount(); i++)
	{
	  const char * key_colname = key_column_array[i]->getColName();
	  const char * upd_colname = ((BaseColumn *)
	  			      (item_expr->child(0)->castToItemExpr()))->
				      getColName();

	  if ((strcmp(key_colname, upd_colname) == 0) &&
              (item_expr->getOperatorType() == ITM_ASSIGN) &&
              (((Assign*)item_expr)->isUserSpecified()))
	    {
	      *CmpCommon::diags() << DgSqlCode(-4033) 
				  << DgColumnName(key_colname);

	      GenExit();
	    }
	}
    }
  generator->oltOptInfo()->mayDisableOperStats(&oltOptInfo());
  markAsPreCodeGenned();

  return this;
} // UpdateCursor::preCodeGen()

RelExpr * Delete::preCodeGen(Generator * generator,
                             const ValueIdSet & externalInputs,
                             ValueIdSet &pulledNewInputs)
{
  if (nodeIsPreCodeGenned())
    return this;
  
  if (! GenericUpdate::preCodeGen(generator,externalInputs,pulledNewInputs))
    return NULL;

  markAsPreCodeGenned();

  return this;
}

RelExpr * MergeDelete::preCodeGen(Generator * generator,
				  const ValueIdSet & externalInputs,
				  ValueIdSet &pulledNewInputs)
{
  if (nodeIsPreCodeGenned())
    return this;
  
  if (! Delete::preCodeGen(generator,externalInputs,pulledNewInputs))
    return NULL;

  markAsPreCodeGenned();

  return this;
}

static NABoolean hasColReference(ItemExpr * ie)
{
  if (! ie)
    return FALSE;

  if ((ie->getOperatorType() == ITM_BASECOLUMN) ||
      (ie->getOperatorType() == ITM_INDEXCOLUMN) ||
      (ie->getOperatorType() == ITM_REFERENCE))
    return TRUE;

  for (Lng32 i = 0; i < ie->getArity(); i++)
    {
      if (hasColReference(ie->child(i)))
	return TRUE;
    }
  
  return FALSE;
}

void HbaseAccess::addReferenceFromItemExprTree(ItemExpr * ie,
                                               NABoolean addCol, NABoolean addHBF,
                                               ValueIdSet &colRefVIDset)
{
  if (! ie)
    return;
  
  if ((ie->getOperatorType() == ITM_BASECOLUMN) ||
      (ie->getOperatorType() == ITM_INDEXCOLUMN) ||
      (ie->getOperatorType() == ITM_REFERENCE))
    {
      if (addCol)
        colRefVIDset.insert(ie->getValueId());

      return;
    }

  if (ie->getOperatorType() == ITM_HBASE_TIMESTAMP)
    {
      if (addHBF)
        {
          colRefVIDset.insert(ie->getValueId());
        }

      return;
    }

  if (ie->getOperatorType() == ITM_HBASE_VERSION)
    {
      if (addHBF)
        {
          colRefVIDset.insert(ie->getValueId());
        }

      return;
    }

  for (Lng32 i = 0; i < ie->getArity(); i++)
    {
      addReferenceFromItemExprTree(ie->child(i), addCol, addHBF, colRefVIDset);
    }
  
  return;
}

void HbaseAccess::addColReferenceFromVIDlist(const ValueIdList &exprList,
					     ValueIdSet  &colRefVIDset)
{
  for (CollIndex i = 0; i < exprList.entries(); i++)
    {
      addReferenceFromItemExprTree(exprList[i].getItemExpr(), 
                                   TRUE, FALSE, colRefVIDset);
    }
}

void HbaseAccess::addReferenceFromVIDset(const ValueIdSet &exprList,
                                         NABoolean addCol, NABoolean addHBF,
                                         ValueIdSet  &colRefVIDset)
{
  for (ValueId v = exprList.init(); exprList.next(v); exprList.advance(v))
    {
      addReferenceFromItemExprTree(v.getItemExpr(), addCol, addHBF, colRefVIDset);
    }
}

void HbaseAccess::addColReferenceFromRightChildOfVIDarray(ValueIdArray &exprList,
							  ValueIdSet &colRefVIDset)
{

  for (CollIndex i = 0; i < exprList.entries(); i++)
    {
      addReferenceFromItemExprTree(exprList[i].getItemExpr()->child(1), 
                                   TRUE, FALSE, colRefVIDset);
    }
}

static NABoolean isEqGetExpr(ItemExpr * ie, ValueId &vid, NABoolean &isConstParam,
			     const char * colName)
{
  NABoolean found = FALSE;
  isConstParam = FALSE;

  if (ie && ie->getOperatorType() == ITM_EQUAL)
    {
      ItemExpr * child0 = ie->child(0)->castToItemExpr();
      ItemExpr * child1 = ie->child(1)->castToItemExpr();
      
      if ((ie->child(0)->getOperatorType() == ITM_BASECOLUMN) &&
	  (((BaseColumn*)ie->child(0)->castToItemExpr())->getNAColumn()->getColName() == colName) &&
	  (NOT hasColReference(ie->child(1))))
	{
	  if (ie->child(1)->getOperatorType() == ITM_CONSTANT)
	    {
	      found = TRUE;
	      vid = ie->child(1)->getValueId();
	    }
	  else if (ie->child(1)->getOperatorType() == ITM_CACHE_PARAM)
	    {
	      found = TRUE;
	      isConstParam = TRUE;
	      vid = ie->child(1)->getValueId();
	    }
	}
      else if ((ie->child(1)->getOperatorType() == ITM_BASECOLUMN) &&
	       (((BaseColumn*)ie->child(1)->castToItemExpr())->getNAColumn()->getColName() == colName) &&
	       (NOT hasColReference(ie->child(0))))
	{
	  if (ie->child(0)->getOperatorType() == ITM_CONSTANT)
	    {
	      found = TRUE;
	      vid = ie->child(0)->getValueId();
	    }
	  else if (ie->child(0)->getOperatorType() == ITM_CACHE_PARAM)
	    {
	      found = TRUE;
	      isConstParam = TRUE;
	      vid = ie->child(0)->getValueId();
	    }
	}
      else if ((ie->child(0)->getOperatorType() == ITM_INDEXCOLUMN) &&
	       (((IndexColumn*)ie->child(0)->castToItemExpr())->getNAColumn()->getColName() == colName) &&
	       (NOT hasColReference(ie->child(1))))
	{
	  if (ie->child(1)->getOperatorType() == ITM_CONSTANT)
	    {
	      found = TRUE;
	      vid = ie->child(1)->getValueId();
	    }
	  else if (ie->child(1)->getOperatorType() == ITM_CACHE_PARAM)
	    {
	      found = TRUE;
	      isConstParam = TRUE;
	      vid = ie->child(1)->getValueId();
	    }
	}
      else if ((ie->child(1)->getOperatorType() == ITM_INDEXCOLUMN) &&
	       (((IndexColumn*)ie->child(1)->castToItemExpr())->getNAColumn()->getColName() == colName) &&
	       (NOT hasColReference(ie->child(0))))
	{
	  if (ie->child(0)->getOperatorType() == ITM_CONSTANT)
	    {
	      found = TRUE;
	      vid = ie->child(0)->getValueId();
	    }
	  else if (ie->child(0)->getOperatorType() == ITM_CACHE_PARAM)
	    {
	      found = TRUE;
	      isConstParam = TRUE;
	      vid = ie->child(0)->getValueId();
	    }
	}
      else if ((ie->child(0)->getOperatorType() == ITM_REFERENCE) &&
	       (((ColReference*)ie->child(0)->castToItemExpr())->getCorrNameObj().getQualifiedNameObj().getObjectName() == colName)  &&
	       (NOT hasColReference(ie->child(1))))
	{
	  if (ie->child(1)->getOperatorType() == ITM_CONSTANT)
	    {
	      found = TRUE;
	      vid = ie->child(1)->getValueId();
	    }
	  else if (ie->child(1)->getOperatorType() == ITM_CACHE_PARAM)
	    {
	      found = TRUE;
	      isConstParam = TRUE;
	      vid = ie->child(1)->getValueId();
	    }
	}
      else if ((ie->child(1)->getOperatorType() == ITM_REFERENCE) &&
	       (((ColReference*)ie->child(1)->castToItemExpr())->getCorrNameObj().getQualifiedNameObj().getObjectName() == colName)  &&
	       (NOT hasColReference(ie->child(0))))
	{
	  if (ie->child(0)->getOperatorType() == ITM_CONSTANT)
	    {
	      found = TRUE;
	      vid = ie->child(0)->getValueId();
	    }
	  else if (ie->child(0)->getOperatorType() == ITM_CACHE_PARAM)
	    {
	      found = TRUE;
	      isConstParam = TRUE;
	      vid = ie->child(0)->getValueId();
	    }
	}
    }

  return found;
}

RelExpr * HbaseDelete::preCodeGen(Generator * generator,
				  const ValueIdSet & externalInputs,
				  ValueIdSet &pulledNewInputs)
{
  if (nodeIsPreCodeGenned())
    return this;

  // if a column list is specified, make sure all column names are of valid hbase
  // column name format ("ColFam:ColNam")
  if (csl())
    {
      for (Lng32 i = 0; i < csl()->entries(); i++)
	{
	  const NAString * nas = (*csl())[i];

	  std::string colFam;
	  std::string colName;
	  if (nas)
	    {
	      ExFunctionHbaseColumnLookup::extractColFamilyAndName(
								   nas->data(), -1, FALSE, colFam, colName);
	    }
	  
	  if (colFam.empty())
	    {
	      *CmpCommon::diags() << DgSqlCode(-1426)
				  << DgString0(nas->data());
	      GenExit();
	    }
	  
	} // for
    } // if

  if (!processConstHBaseKeys(
           generator,
           this,
           getSearchKey(),
           getIndexDesc(),
           executorPred(),
           getHbaseSearchKeys(),
           listOfDelUniqueRows_,
           listOfDelSubsetRows_))
    return NULL;

  if (! Delete::preCodeGen(generator, externalInputs, pulledNewInputs))
    return NULL;

  if (((getTableDesc()->getNATable()->isHbaseRowTable()) ||
       (getTableDesc()->getNATable()->isHbaseCellTable())) &&
      (producesOutputs()))
    {
      *CmpCommon::diags() << DgSqlCode(-1425)
			  << DgTableName(getTableDesc()->getNATable()->getTableName().
					 getQualifiedNameAsAnsiString())
                          << DgString0("Reason: Cannot return values from an hbase insert, update or delete.");
      GenExit();
    }
   NABoolean isAlignedFormat = getTableDesc()->getNATable()->isAlignedFormat(getIndexDesc());

  if  (producesOutputs()) 
    {
      retColRefSet_ = getIndexDesc()->getIndexColumns();
    }
  else
    {
      ValueIdSet colRefSet;

      // create the list of columns that need to be retrieved from hbase .
      // first add all columns referenced in the executor pred.
      HbaseAccess::addReferenceFromVIDset(executorPred(), TRUE, TRUE, colRefSet);

      if ((getTableDesc()->getNATable()->getExtendedQualName().getSpecialType() == ExtendedQualName::INDEX_TABLE))
        {
	  for (ValueId valId = executorPred().init();
	       executorPred().next(valId);
	       executorPred().advance(valId))
            {
              ItemExpr * ie = valId.getItemExpr();
              if (ie->getOperatorType() == ITM_EQUAL)
                {
                  BiRelat * br = (BiRelat*)ie;
                  br->setSpecialNulls(TRUE);
                }
            }
        } // index_table


      if ((getTableDesc()->getNATable()->isHbaseRowTable()) ||
	  (getTableDesc()->getNATable()->isHbaseCellTable()) ||
           isAlignedFormat)
	{
	  for (Lng32 i = 0; i < getIndexDesc()->getIndexColumns().entries(); i++)
	    {
	      retColRefSet_.insert(getIndexDesc()->getIndexColumns()[i]);
	    }
        }

      for (ValueId valId = colRefSet.init();
           colRefSet.next(valId);
           colRefSet.advance(valId))
        {
          ValueId dummyValId;
          if (NOT getGroupAttr()->getCharacteristicInputs().referencesTheGivenValue(valId, dummyValId))
            {
              if ((valId.getItemExpr()->getOperatorType() == ITM_HBASE_TIMESTAMP) ||
                  (valId.getItemExpr()->getOperatorType() == ITM_HBASE_VERSION))
                {
                  *CmpCommon::diags() << DgSqlCode(-3242)
                                      << DgString0("Illegal use of Hbase Timestamp or Hbase Version function.");

                  GenExit();
                }

              retColRefSet_.insert(valId);
            }
        }

      if (NOT ((getTableDesc()->getNATable()->isHbaseRowTable()) ||
               (getTableDesc()->getNATable()->isHbaseCellTable()) ||
               (isAlignedFormat)))
        {
          // add all the key columns. If values are missing in hbase, then atleast the key
          // value is needed to retrieve a row. 
          HbaseAccess::addColReferenceFromVIDlist(getIndexDesc()->getIndexKey(), retColRefSet_);
        }

      if (getTableDesc()->getNATable()->hasLobColumn())
        {
          for (Lng32 i = 0; i < getIndexDesc()->getIndexColumns().entries(); i++)
            {
              const ValueId vid = getIndexDesc()->getIndexColumns()[i];
              retColRefSet_.insert(vid);
            }
        }
    }

  NABoolean inlinedActions = FALSE;
  if ((getInliningInfo().hasInlinedActions()) ||
      (getInliningInfo().isEffectiveGU()))
    inlinedActions = TRUE;
 
  NABoolean isUnique = FALSE;
  if (listOfDelSubsetRows_.entries() == 0)
    {
      if ((getSearchKey() && getSearchKey()->isUnique()) &&
	  (listOfDelUniqueRows_.entries() == 0))
	isUnique = TRUE;
      else if ((NOT (getSearchKey() && getSearchKey()->isUnique())) &&
	       (listOfDelUniqueRows_.entries() == 1) &&
	       (listOfDelUniqueRows_[0].rowIds_.entries() == 1))
	isUnique = TRUE;
    }
 
  if (getInliningInfo().isIMGU()) {
     // There is no need to do checkAndDelete for IM
     canDoCheckAndUpdel() = FALSE;
     uniqueHbaseOper() = FALSE;
     if ((generator->oltOptInfo()->multipleRowsReturned()) &&
	  (CmpCommon::getDefault(HBASE_ROWSET_VSBB_OPT) == DF_ON) &&
         (NOT generator->isRIinliningForTrafIUD()) &&
         (NOT getTableDesc()->getNATable()->hasLobColumn()))
       uniqueRowsetHbaseOper() = TRUE;
  }
  else
  if (isUnique)
    {
      //If this unique delete is not part of a rowset operation , 
      //don't allow it to be cancelled. 
      if (!generator->oltOptInfo()->multipleRowsReturned())
	generator->setMayNotCancel(TRUE);
      uniqueHbaseOper() = TRUE;
      canDoCheckAndUpdel() = FALSE;
      if ((NOT producesOutputs()) &&
	  (NOT  inlinedActions) &&
          (executorPred().isEmpty()))
	{
	  if ((generator->oltOptInfo()->multipleRowsReturned()) &&
	      (CmpCommon::getDefault(HBASE_ROWSET_VSBB_OPT) == DF_ON) &&
	      (NOT generator->isRIinliningForTrafIUD()) &&
              (NOT getTableDesc()->getNATable()->hasLobColumn()))
	    uniqueRowsetHbaseOper() = TRUE;
	  else if ((NOT generator->oltOptInfo()->multipleRowsReturned()) &&
		   (listOfDelUniqueRows_.entries() == 0))
	    {
	      if ((CmpCommon::getDefault(HBASE_CHECK_AND_UPDEL_OPT) == DF_ON) &&
		  (CmpCommon::getDefault(HBASE_SQL_IUD_SEMANTICS) == DF_ON) &&
                  (NOT isAlignedFormat))
	      canDoCheckAndUpdel() = TRUE;
	    }
	}
    }

  if ((producesOutputs()) &&
      ((NOT isUnique) || (getUpdateCKorUniqueIndexKey())))
    {
      // Cannot do olt msg opt if:
      //   -- values are to be returned and unique operation is not being used.
      //   -- or this delete was transformed from an update of pkey/index key
      // set an indication that multiple rows will be returned.
      generator->oltOptInfo()->setMultipleRowsReturned(TRUE);
      generator->oltOptInfo()->setOltCliOpt(FALSE);
    }

  if (getTableDesc()->getNATable()->hasLobColumn())
    {
      canDoCheckAndUpdel() = FALSE;
      uniqueRowsetHbaseOper() = FALSE;
    }

  generator->setUpdSavepointOnError(FALSE);
  generator->setUpdPartialOnError(FALSE);
  
  if (CmpCommon::getDefault(TRAF_NO_DTM_XN) == DF_ON)
    noDTMxn() = TRUE;
  
  // if unique oper with no index maintanence and autocommit is on, then
  // do not require a trnsaction. Hbase guarantees single row consistency.
  Int64 transId = -1;
  if (((uniqueHbaseOper()) &&
       (NOT cursorHbaseOper()) &&
       (NOT uniqueRowsetHbaseOper()) &&
       (NOT inlinedActions) &&
       (generator->getTransMode()->getAutoCommit() == TransMode::ON_) &&
       (! NAExecTrans(0, transId)) &&
       (NOT generator->oltOptInfo()->multipleRowsReturned())) ||
      (noDTMxn()))
    {
      // no transaction needed
    }
  else
    {
      generator->setTransactionFlag(TRUE);

      if ((NOT uniqueHbaseOper()) ||
	  (cursorHbaseOper()) ||
	  (uniqueRowsetHbaseOper()) ||
	  (inlinedActions) ||
	  (generator->oltOptInfo()->multipleRowsReturned()))
	generator->setUpdAbortOnError(TRUE);
    }

  // flag for hbase tables
  generator->setHdfsAccess(TRUE);
  
  markAsPreCodeGenned();

  return this;  
}

RelExpr * HbaseUpdate::preCodeGen(Generator * generator,
				  const ValueIdSet & externalInputs,
				  ValueIdSet &pulledNewInputs)
{
  if (nodeIsPreCodeGenned())
    return this;

  if (!processConstHBaseKeys(
           generator,
           this,
           getSearchKey(),
           getIndexDesc(),
           executorPred(),
           getHbaseSearchKeys(),
           listOfUpdUniqueRows_,
           listOfUpdSubsetRows_))
    return NULL;

  //  if (! GenericUpdate::preCodeGen(generator, externalInputs, pulledNewInputs))
  //    return NULL;
  if (! UpdateCursor::preCodeGen(generator, externalInputs, pulledNewInputs))
    return NULL;

  CollIndex totalColCount = getTableDesc()->getColumnList().entries();
  NABoolean isAlignedFormat = getTableDesc()->getNATable()->isAlignedFormat(getIndexDesc());

  if (isAlignedFormat &&
      (newRecExprArray().entries() > 0) &&
      (newRecExprArray().entries() <  totalColCount))
    {
      ValueIdArray holeyArray(totalColCount);
      
      Lng32 i;
      for (i = 0; i < newRecExprArray().entries(); i++)
        {
          ItemExpr * assign = newRecExprArray()[i].getItemExpr();
          const NAColumn *nacol = assign->child(0).getNAColumn();
          Lng32 colPos = nacol->getPosition();
          holeyArray.insertAt(colPos, assign->getValueId());
        } // for
      
      for (i = 0; i < totalColCount; i++)
       {
         if (! (holeyArray.used(i)))
           {
             BaseColumn * bc = (BaseColumn*)getTableDesc()->getColumnList()[i].getItemExpr();
             CMPASSERT(bc->getOperatorType() == ITM_BASECOLUMN);

             ValueId srcId = getIndexDesc()->getIndexColumns()[i];
             
             ItemExpr * an = 
               new(generator->wHeap()) Assign(bc, srcId.getItemExpr(), FALSE);
             an->bindNode(generator->getBindWA());
             holeyArray.insertAt(i, an->getValueId());
           } // if
       } // for
      
      newRecExprArray().clear();
      newRecExprArray() = holeyArray;
    } // if aligned

  if ((isMerge()) &&
      (mergeInsertRecExpr().entries() > 0))
    {
      if ((listOfUpdSubsetRows_.entries() > 0) ||
	  (getSearchKey() && (NOT getSearchKey()->isUnique())))
	{
	  *CmpCommon::diags() << DgSqlCode(-3241)
			      << DgString0(" Non-unique ON clause not allowed with INSERT.");
	  GenExit();
	}
    }

  if (((getTableDesc()->getNATable()->isHbaseRowTable()) ||
       (getTableDesc()->getNATable()->isHbaseCellTable())) &&
      (producesOutputs()))
    {
      *CmpCommon::diags() << DgSqlCode(-1425)
			  << DgTableName(getTableDesc()->getNATable()->getTableName().
					 getQualifiedNameAsAnsiString())
                          << DgString0("Reason: Cannot return values from an hbase insert, update or delete.");
      GenExit();
    }

  NABoolean canDoRowsetOper = TRUE;
  NABoolean canDoCheckAndUpdate = TRUE;
  NABoolean needToGetCols = FALSE;
  if (producesOutputs())
    {
      retColRefSet_ = getIndexDesc()->getIndexColumns();
    }
  else
    {
      ValueIdSet colRefSet;

      // create the list of columns that need to be retrieved from hbase .
      // first add all columns referenced in the executor pred.
      HbaseAccess::addReferenceFromVIDset(executorPred(), TRUE, TRUE, colRefSet);

      if ((getTableDesc()->getNATable()->getExtendedQualName().getSpecialType() == ExtendedQualName::INDEX_TABLE))
        {
	  for (ValueId valId = executorPred().init();
	       executorPred().next(valId);
	       executorPred().advance(valId))
            {
              ItemExpr * ie = valId.getItemExpr();
              if (ie->getOperatorType() == ITM_EQUAL)
                {
                  BiRelat * br = (BiRelat*)ie;
                  br->setSpecialNulls(TRUE);
                }
            }
        }

      // add all columns referenced in the right side of the update expr.
      HbaseAccess::addColReferenceFromRightChildOfVIDarray(newRecExprArray(), colRefSet);

      if (isMerge())
	HbaseAccess::addReferenceFromVIDset(mergeUpdatePred(), TRUE, FALSE, colRefSet);

      if ((getTableDesc()->getNATable()->isHbaseRowTable()) ||
	  (getTableDesc()->getNATable()->isHbaseCellTable()) ||
          (isAlignedFormat))
	{
	  for (Lng32 i = 0; i < getIndexDesc()->getIndexColumns().entries(); i++)
	    {
	      retColRefSet_.insert(getIndexDesc()->getIndexColumns()[i]);
	    }
	}
      else
	{
	  for (ValueId valId = colRefSet.init();
	       colRefSet.next(valId);
	       colRefSet.advance(valId))
	    {
	      ValueId dummyValId;
	      if (NOT getGroupAttr()->getCharacteristicInputs().referencesTheGivenValue(valId, dummyValId))
                {
                  if ((valId.getItemExpr()->getOperatorType() == ITM_HBASE_TIMESTAMP) ||
                      (valId.getItemExpr()->getOperatorType() == ITM_HBASE_VERSION))
                    {
                      *CmpCommon::diags() << DgSqlCode(-3242)
                                          << DgString0("Illegal use of Hbase Timestamp or Hbase Version function.");
                      
                      GenExit();
                    }
                  
                  retColRefSet_.insert(valId);
                }
	    }
	}

      if (retColRefSet_.entries() > 0)
	{
	  needToGetCols = TRUE;
	  canDoRowsetOper = FALSE;
	  canDoCheckAndUpdate = FALSE;
	}

      // nullable and added columns in the row may be missing. That will cause
      // a row to not be returned if those are the only columns that are being
      // retrieved. 
      // To make sure that a row is always returned, add the key columns. These are
      // guaranteed to be present in an hbase row.
      HbaseAccess::addColReferenceFromVIDlist(getIndexDesc()->getIndexKey(), retColRefSet_);
    }

  NABoolean inlinedActions = FALSE;
  if ((getInliningInfo().hasInlinedActions()) ||
      (getInliningInfo().isEffectiveGU()))
    inlinedActions = TRUE;
  
  NABoolean isUnique = FALSE;
  if (listOfUpdSubsetRows_.entries() == 0)
    {
      if ((getSearchKey() && getSearchKey()->isUnique()) &&
	  (listOfUpdUniqueRows_.entries() == 0))
	isUnique = TRUE;
      else if ((NOT (getSearchKey() && getSearchKey()->isUnique())) &&
	       (listOfUpdUniqueRows_.entries() == 1) &&
	       (listOfUpdUniqueRows_[0].rowIds_.entries() == 1))
	isUnique = TRUE;
    }
  if (getInliningInfo().isIMGU()) {
     // There is no need to checkAndPut for IM
     canDoCheckAndUpdel() = FALSE;
     uniqueHbaseOper() = FALSE;
     if ((generator->oltOptInfo()->multipleRowsReturned()) &&
	      (CmpCommon::getDefault(HBASE_ROWSET_VSBB_OPT) == DF_ON) &&
	      (NOT generator->isRIinliningForTrafIUD()))
	 uniqueRowsetHbaseOper() = TRUE;
  }
  else
  if (isUnique)
    {
      //If this unique delete is not part of a rowset operation , 
      //don't allow it to be cancelled.
      if (!generator->oltOptInfo()->multipleRowsReturned())
	generator->setMayNotCancel(TRUE);
      uniqueHbaseOper() = TRUE;

      canDoCheckAndUpdel() = FALSE;

      if ((NOT isMerge()) &&
	  (NOT producesOutputs()) &&
	  (executorPred().isEmpty()) &&
	  (NOT needToGetCols) &&
	  (NOT inlinedActions))
	{
	  if ((generator->oltOptInfo()->multipleRowsReturned()) &&
	      (CmpCommon::getDefault(HBASE_ROWSET_VSBB_OPT) == DF_ON) &&
	      (NOT generator->isRIinliningForTrafIUD()))
	    uniqueRowsetHbaseOper() = TRUE;
	  else if ((NOT generator->oltOptInfo()->multipleRowsReturned()) &&
		   (listOfUpdUniqueRows_.entries() == 0))
	    {
	      if ((CmpCommon::getDefault(HBASE_CHECK_AND_UPDEL_OPT) == DF_ON) &&
                  (NOT isAlignedFormat))
		canDoCheckAndUpdel() = TRUE;
	    }
	}
    }
  else if (producesOutputs())
    {
      // Cannot do olt msg opt if:
      //   -- values are to be returned and unique operation is not being used.
      // set an indication that multiple rows will be returned.
      generator->oltOptInfo()->setMultipleRowsReturned(TRUE);
      generator->oltOptInfo()->setOltCliOpt(FALSE);
    }

  generator->setUpdSavepointOnError(FALSE);
  generator->setUpdPartialOnError(FALSE);

  // if seq gen metadata is being updated through an internal query 
  // and we are running under a user Xn,
  // do not mark this stmt as a transactional stmt.
  // This is done so those updates can run in its own transaction and not be
  // part of the enclosing user Xn.
  // When we have support for local transactions and repeatable read, we
  // will then run this update in local transactional mode.
  if (CmpCommon::getDefault(TRAF_NO_DTM_XN) == DF_ON)
    noDTMxn() = TRUE;

  // if unique oper with no index maintanence and autocommit is on, then
  // do not require a transaction. Hbase guarantees single row consistency.
  Int64 transId = -1;
  if (((uniqueHbaseOper()) &&
       (NOT isMerge()) &&
       (NOT cursorHbaseOper()) &&
       (NOT uniqueRowsetHbaseOper()) &&
       (NOT inlinedActions) &&
       (generator->getTransMode()->getAutoCommit() == TransMode::ON_) &&
       (! NAExecTrans(0, transId)) &&
       (NOT generator->oltOptInfo()->multipleRowsReturned())) ||
      (noDTMxn()))
    {
      // no transaction needed
    }
  else
    {
      generator->setTransactionFlag(TRUE);

      if ((NOT uniqueHbaseOper()) ||
	  (isMerge()) ||
	  (cursorHbaseOper()) ||
	  (uniqueRowsetHbaseOper()) ||
	  (inlinedActions) ||
	  (generator->oltOptInfo()->multipleRowsReturned()))
	generator->setUpdAbortOnError(TRUE);
    }

  // flag for hbase tables
  generator->setHdfsAccess(TRUE);
  if (getTableDesc()->getNATable()->hasLobColumn())
    {
      for (CollIndex i = 0; i < newRecExprArray().entries(); i++)
	{
	  NAColumn * col = 
	    newRecExprArray()[i].getItemExpr()->child(0)->castToItemExpr()->
	    getValueId().getNAColumn(TRUE);

	  ItemExpr * val = 
	    newRecExprArray()[i].getItemExpr()->child(1)->castToItemExpr();
	  
	  if ((col->getType()->isLob()) &&
	      (val->getOperatorType() == ITM_LOBUPDATE))
	    {
	      LOBupdate * lu = (LOBupdate*)val;

	      lu->updatedTableObjectUID() = 
		getIndexDesc()->getPrimaryTableDesc()->
		getNATable()->objectUid().castToInt64();
	      
	      lu->updatedTableSchemaName() = "\"";
	      lu->updatedTableSchemaName() += 
		getTableDesc()->getNATable()->
		getTableName().getCatalogName();
	      lu->updatedTableSchemaName().append("\".\"");
	      lu->updatedTableSchemaName().
		append(getTableDesc()->getNATable()->
		       getTableName().getSchemaName());
	      lu->updatedTableSchemaName() += "\"";
              lu->lobSize() = col->getType()->getPrecision();
	      lu->lobNum() = col->lobNum();
	      lu->lobStorageType() = col->lobStorageType();
	      lu->lobStorageLocation() = col->lobStorageLocation();
	    }
	} // for
    } // if
 
  markAsPreCodeGenned();

  return this;  
}

RelExpr * HiveInsert::preCodeGen(Generator * generator,
                              const ValueIdSet & externalInputs,
                              ValueIdSet &pulledNewInputs)
{
  if (nodeIsPreCodeGenned())
    return this;

  generator->setHiveAccess(TRUE);
  return GenericUpdate::preCodeGen(generator, externalInputs, pulledNewInputs);
}


RelExpr * HbaseInsert::preCodeGen(Generator * generator,
                              const ValueIdSet & externalInputs,
                              ValueIdSet &pulledNewInputs)
{
  if (nodeIsPreCodeGenned())
    return this;

  // char. outputs are set to empty after in RelExpr::genPreCode sometimes,
  // after a call to resolveCharOutputs. We need to remember if a returnRow
  // tdb flag should be set, even if no output columns are required
  if (getIsTrafLoadPrep() && !getGroupAttr()->getCharacteristicOutputs().isEmpty())
    setReturnRow(TRUE);

  if (! GenericUpdate::preCodeGen(generator, externalInputs, pulledNewInputs))
    return NULL;

  NABoolean inlinedActions = FALSE;
  if ((getInliningInfo().hasInlinedActions()) ||
      (getInliningInfo().isEffectiveGU()))
    inlinedActions = TRUE;

  if (((getTableDesc()->getNATable()->isHbaseRowTable()) ||
       (getTableDesc()->getNATable()->isHbaseCellTable())) &&
      (producesOutputs()))
    {
      *CmpCommon::diags() << DgSqlCode(-1425)
			  << DgTableName(getTableDesc()->getNATable()->getTableName().
					 getQualifiedNameAsAnsiString())
                          << DgString0("Reason: Cannot return values from an hbase insert, update or delete.");
      GenExit();
    }

  if ((isUpsert()) &&
      ((getInsertType() == Insert::VSBB_INSERT_USER) ||
       (getInsertType() == Insert::UPSERT_LOAD)))
    {
      if ((inlinedActions || producesOutputs())&& !getIsTrafLoadPrep())
 	setInsertType(Insert::SIMPLE_INSERT);
    }

  
  // if there are blob columns, use simple inserts.
  if ( getTableDesc()->getNATable()->hasLobColumn())
    {
      setInsertType(Insert::SIMPLE_INSERT);

      NAColumnArray colArray;
      NAColumn *col;

      for (CollIndex ii = 0;
           ii < newRecExprArray().entries(); ii++)
	{
	  ItemExpr *assignExpr =
	    newRecExprArray()[ii].getItemExpr();
	  
	  ValueId tgtValueId =
	    assignExpr->child(0)->castToItemExpr()->getValueId();

	  ValueId srcValueId =
	    assignExpr->child(1)->castToItemExpr()->getValueId();

	  col = tgtValueId.getNAColumn( TRUE );
	  
	  ItemExpr * child1Expr = assignExpr->child(1);
	  if (srcValueId.getType().isLob())
	    {
	      LOBinsert * li = NULL;
	      if ((child1Expr->getOperatorType() != ITM_LOBINSERT) &&
		  (child1Expr->getOperatorType() != ITM_LOBUPDATE))
		{
		  li = new(generator->wHeap())
		    LOBinsert(child1Expr, NULL, LOBoper::LOB_);

		  li->insertedTableObjectUID() = 
		    getIndexDesc()->getPrimaryTableDesc()->
		    getNATable()->objectUid().castToInt64();

		  li->insertedTableSchemaName() = "\"";
		  li->insertedTableSchemaName() += 
		    getTableDesc()->getNATable()->
		    getTableName().getCatalogName();
		  li->insertedTableSchemaName().append("\".\"");
		  li->insertedTableSchemaName().
		    append(getTableDesc()->getNATable()->
			   getTableName().getSchemaName());
		  li->insertedTableSchemaName() += "\"";
		  
		  //		  li->lobNum() = col->getPosition();
		  // li->lobSize() = srcValueId.getType().getPrecision();
                  li->lobSize() = tgtValueId.getType().getPrecision();
		  li->lobFsType() = tgtValueId.getType().getFSDatatype();

		  li->lobNum() = col->lobNum();
		  li->lobStorageType() = col->lobStorageType();
		  li->lobStorageLocation() = col->lobStorageLocation();

		  li->bindNode(generator->getBindWA());

		  child1Expr = li;

		  assignExpr->child(1) = child1Expr;
		}
	      else if (child1Expr->getOperatorType() == ITM_LOBINSERT)
		{
		  li = (LOBinsert*)child1Expr;
		  li->insertedTableObjectUID() = 
		    getIndexDesc()->getPrimaryTableDesc()->
		    getNATable()->objectUid().castToInt64();

		  li->insertedTableSchemaName() = "\"";
		  li->insertedTableSchemaName() += 
		    getTableDesc()->getNATable()->
		    getTableName().getCatalogName();
		  li->insertedTableSchemaName().append("\".\"");
		  li->insertedTableSchemaName().
		    append(getTableDesc()->getNATable()->
			   getTableName().getSchemaName());
		  li->insertedTableSchemaName() += "\"";
		  
		  li->lobNum() = col->lobNum();
		  li->lobStorageType() = col->lobStorageType();
		  li->lobStorageLocation() = col->lobStorageLocation();
		  
		  li->lobSize() = tgtValueId.getType().getPrecision();

		  if (li->lobFsType() != tgtValueId.getType().getFSDatatype())
		    {
		      // create a new LOBinsert node since fsType has changed.
		      ItemExpr * liChild = li->child(0);
		      ItemExpr * liChild1 = li->child(1);
		      li = new(generator->wHeap())
			LOBinsert(liChild, liChild1, li->getObj());
		      
		      li->insertedTableObjectUID() = 
			getIndexDesc()->getPrimaryTableDesc()->
			getNATable()->objectUid().castToInt64();
		      
		      li->insertedTableSchemaName() = "\"";
		      li->insertedTableSchemaName() += 
			getTableDesc()->getNATable()->
			getTableName().getCatalogName();
		      li->insertedTableSchemaName().append("\".\"");
		      li->insertedTableSchemaName().
			append(getTableDesc()->getNATable()->
			       getTableName().getSchemaName());
		      li->insertedTableSchemaName() += "\"";
		      
		      //li->lobSize() = srcValueId.getType().getPrecision();
                      li->lobSize() = tgtValueId.getType().getPrecision();
		      li->lobFsType() = tgtValueId.getType().getFSDatatype();

		      li->lobNum() = col->lobNum();
		      li->lobStorageType() = col->lobStorageType();
		      li->lobStorageLocation() = col->lobStorageLocation();
		      
		      li->bindNode(generator->getBindWA());

		      assignExpr->child(1) = li;
		    }
		} // lobinsert

	      GenAssert(li, "must have a LobInsert node");
#ifdef __ignore 
	      LOBload * ll = new(generator->wHeap()) 
		LOBload(li->child(0), li->getObj());
	      ll->insertedTableObjectUID() = li->insertedTableObjectUID();
	      ll->insertedTableSchemaName() = li->insertedTableSchemaName();

	      ll->lobNum() = col->lobNum();
	      ll->lobStorageType() = col->lobStorageType();
	      ll->lobStorageLocation() = col->lobStorageLocation();
	      ll->bindNode(generator->getBindWA());
	      lobLoadExpr_.insert(ll->getValueId());
#endif
	    } // lob
	}
    }


  if ((getInsertType() == Insert::SIMPLE_INSERT)  &&
      (NOT getTableDesc()->getNATable()->hasLobColumn()))
    uniqueHbaseOper() = TRUE;

  generator->setUpdSavepointOnError(FALSE);
  generator->setUpdPartialOnError(FALSE);

  if (CmpCommon::getDefault(TRAF_NO_DTM_XN) == DF_ON)
    noDTMxn() = TRUE;
  
  // if unique oper with no index maintanence and autocommit is on, then
  // do not require a trnsaction. Hbase guarantees single row consistency.
  Int64 transId = -1;
  if (((uniqueHbaseOper()) &&
       (NOT uniqueRowsetHbaseOper()) &&
       (NOT inlinedActions) &&
       (generator->getTransMode()->getAutoCommit() == TransMode::ON_) &&
       (! NAExecTrans(0, transId)) &&
       (NOT generator->oltOptInfo()->multipleRowsReturned())) ||
      (isNoRollback()) ||
      ((isUpsert()) && (insertType_ == UPSERT_LOAD)) ||
      (noDTMxn()))
    {
      // no transaction needed
    }
  else
    {
      generator->setTransactionFlag(TRUE);

      if ((NOT uniqueHbaseOper()) ||
	  (uniqueRowsetHbaseOper()) ||
	  (inlinedActions) ||
	  (generator->oltOptInfo()->multipleRowsReturned()))
	generator->setUpdAbortOnError(TRUE);
    }

  return this;
}

RelExpr * ExeUtilFastDelete::preCodeGen(Generator * generator,
					const ValueIdSet & externalInputs,
					ValueIdSet &pulledNewInputs)
{
  if (nodeIsPreCodeGenned())
    return this;

  return ExeUtilExpr::preCodeGen(generator,externalInputs,pulledNewInputs);
}

RelExpr * ExeUtilLobExtract::preCodeGen(Generator * generator,
                                       const ValueIdSet & externalInputs,
                                       ValueIdSet &pulledNewInputs)
{
  if (nodeIsPreCodeGenned())
    return this;

  if (! ExeUtilExpr::preCodeGen(generator,externalInputs,pulledNewInputs))
    return NULL;

  ValueIdSet availableValues;
  for (ValueId exprId = getGroupAttr()->getCharacteristicInputs().init();
       getGroupAttr()->getCharacteristicInputs().next(exprId);
       getGroupAttr()->getCharacteristicInputs().advance(exprId) )
    {
      if (exprId.getItemExpr()->getOperatorType() != ITM_VEG_REFERENCE)
       availableValues += exprId;
    }
  
  getGroupAttr()->setCharacteristicInputs(availableValues);
  getInputValuesFromParentAndChildren(availableValues);

  if (handle_)
    handle_->replaceVEGExpressions
      (availableValues, getGroupAttr()->getCharacteristicInputs());
  
  markAsPreCodeGenned();

   // Done.
   return this;
 }

RelExpr * HashGroupBy::preCodeGen(Generator * generator,
                                 const ValueIdSet & externalInputs,
                                 ValueIdSet &pulledNewInputs)
{
  if (nodeIsPreCodeGenned())
    return this;


  if ( CmpCommon::getDefault(COMPRESSED_INTERNAL_FORMAT) == DF_SYSTEM)
  {
    NABoolean resize = FALSE;
    NABoolean defrag = FALSE;
    ValueIdSet vidSet = child(0)->getGroupAttr()->getCharacteristicOutputs();

    ExpTupleDesc::TupleDataFormat tupleFormat =
                  determineInternalFormat( vidSet,
                                           this,
                                           resize,
                                           generator,
                                           FALSE,
                                           defrag);

    cacheTupleFormatAndResizeFlag(tupleFormat, resize, defrag);

    if (tupleFormat == ExpTupleDesc::SQLMX_ALIGNED_FORMAT)
    {
      generator->incNCIFNodes();
    }
    else
    {
      generator->decNCIFNodes();
    }
  }


  return GroupByAgg::preCodeGen(generator, externalInputs, pulledNewInputs);

}

RelExpr * GroupByAgg::preCodeGen(Generator * generator,
				 const ValueIdSet & externalInputs,
				 ValueIdSet &pulledNewInputs)
{
  if (nodeIsPreCodeGenned())
    return this;

  // Check if the pivs of this operator and it's child are the same.
  // If they are not, make them the same.
  replacePivs();

  generator->clearPrefixSortKey();
  // Resolve the VEGReferences and VEGPredicates, if any, that appear
  // in the Characteristic Inputs, in terms of the externalInputs.
  getGroupAttr()->resolveCharacteristicInputs(externalInputs);
  // My Characteristic Inputs become the external inputs for my child.
  child(0) = child(0)->preCodeGen(generator,
				  getGroupAttr()->getCharacteristicInputs(),
				  pulledNewInputs);
  if (! child(0).getPtr())
    return NULL;

  if ((getOperatorType() == REL_SHORTCUT_GROUPBY)
      && (getFirstNRows() == 1))
    {
      RelExpr * firstnNode = new(generator->wHeap()) FirstN(child(0),
							    getFirstNRows());
      firstnNode->setEstRowsUsed(getEstRowsUsed());
      firstnNode->setMaxCardEst(getMaxCardEst());
      firstnNode->setInputCardinality(child(0)->getInputCardinality());
      firstnNode->setPhysicalProperty(child(0)->getPhysicalProperty());
      firstnNode->setGroupAttr(child(0)->getGroupAttr());
      //10-060516-6532 -Begin
      //When FIRSTN node is created after optimization phase, the cost
      //of that node does not matter.But, display_explain and explain
      //show zero operator costs and rollup cost which confuses the user.
      //Also, the VQP crashes when cost tab for FIRSTN node is selected.
      //So, creating a cost object will fix this.
      //The operator cost is zero and rollup cost is same as it childs.
      Cost* firstnNodecost = new HEAP Cost();
      firstnNode->setOperatorCost(firstnNodecost);
      Cost* rollupcost = (Cost *)(child(0)->getRollUpCost());
      *rollupcost += *firstnNodecost;
      firstnNode->setRollUpCost(rollupcost);
      //10-060516-6532 -End

      firstnNode =
	firstnNode->preCodeGen(generator,
			       getGroupAttr()->getCharacteristicInputs(),
			       pulledNewInputs);
      if (! firstnNode)
	return NULL;

      setChild(0, firstnNode);
    }

  getGroupAttr()->addCharacteristicInputs(pulledNewInputs);

  // Accumulate the values that are provided as inputs by my parent
  // together with the values that are produced as outputs by my
  // children. Use these values for rewriting the VEG expressions.
  ValueIdSet availableValues;
  getInputValuesFromParentAndChildren(availableValues);
  NABoolean replicatePredicates = TRUE;

  // Rebuild the grouping expressions tree. Use bridge values, if possible
  groupExpr().replaceVEGExpressions
                 (availableValues,
		  getGroupAttr()->getCharacteristicInputs(),
                  FALSE, // No key predicates need to be generated here
		  NULL,
		  replicatePredicates,
                  &getGroupAttr()->getCharacteristicOutputs());

  // Rebuild the aggregate expressions tree
  aggregateExpr().replaceVEGExpressions
                     (availableValues,
  	 	      getGroupAttr()->getCharacteristicInputs());

  if (CmpCommon::getDefault(COMP_BOOL_211) == DF_ON) 
  {
    ValueIdSet constantsInGroupExpr ;
    groupExpr().getConstantExprs(constantsInGroupExpr,FALSE);
    if (constantsInGroupExpr.entries() > 0)
    {
      if (constantsInGroupExpr.entries() == groupExpr().entries())
      {
        ValueId vid ;
        constantsInGroupExpr.getFirst(vid);
        constantsInGroupExpr.remove(vid);
      }
      groupExpr() -= constantsInGroupExpr ;
    }
  }

  // The VEG expressions in the selection predicates and the characteristic
  // outputs can reference any expression that is either a potential output
  // or a characteristic input for this RelExpr. Supply these values for
  // rewriting the VEG expressions.
  getInputAndPotentialOutputValues(availableValues);

  selectionPred().replaceVEGExpressions
                     (availableValues,
		      getGroupAttr()->getCharacteristicInputs(),
		      FALSE, // No key predicates need to be generated here
		      NULL,
		      replicatePredicates);

  getGroupAttr()->resolveCharacteristicOutputs
                      (availableValues,
		       getGroupAttr()->getCharacteristicInputs());

  // if the grouping is executed in DP2, we don't do overflow
  // handling. This also means, that it is a partial group by
  // Do not do overflow handling for any partial groupby.
  //
  NABoolean isPartialGroupBy = (isAPartialGroupByNonLeaf() ||
                                isAPartialGroupByLeaf());

  // The old way, only groupbys in DP2 are considered partial
  //
  if (CmpCommon::getDefault(COMP_BOOL_152) == DF_ON) {
    isPartialGroupBy = executeInDP2();
  }
  
  if ((getOperatorType() == REL_HASHED_GROUPBY) && !isPartialGroupBy) {
    // Count this BMO and add its needed memory to the total needed
    generator->incrNumBMOs();

  if ((ActiveSchemaDB()->getDefaults()).getAsDouble(EXE_MEMORY_LIMIT_PER_CPU) > 0)
      generator->incrBMOsMemory(getEstimatedRunTimeMemoryUsage(TRUE));

  }

  markAsPreCodeGenned();

  // Done.
  return this;
} // GroupByAgg::preCodeGen()

RelExpr * MergeUnion::preCodeGen(Generator * generator,
                                 const ValueIdSet & externalInputs,
                                 ValueIdSet &pulledNewInputs)
{
  if (nodeIsPreCodeGenned())
    return this;

  // A temporary union (blocked union introduced for inlining after trigger)
  // should not get here. Should be removed in optimization phase.
  GenAssert(!getIsTemporary(), "Expecting this blocked union to be removed by this phase");

  // Check if the pivs of this operator and it's child are the same.
  // If they are not, make them the same.
  replacePivs();

  // clear any prefix sort key in generator work area
  generator->clearPrefixSortKey();

  // Resolve the VEGReferences and VEGPredicates, if any, that appear
  // in the Characteristic Inputs, in terms of the externalInputs.
  getGroupAttr()->resolveCharacteristicInputs(externalInputs);

  // Predicate pushdown causes the Characteristic Inputs and Outputs
  // of the union to be set precisely to those values that are
  // required by one of its descendants or by one of its ancestors,
  // respectively. However, the colMapTable_ contains all the values
  // that the MergeUnion is capable of producing. The colMapTable_
  // is rebuilt here to contain exactly those values that appear in
  // the Characteristic Outputs.
  //
  // The output of the union is defined by the ValueIdUnion
  // expressions that are maintained in the colMapTable_.
  //

  ValueIdSet charOutputs = getGroupAttr()->getCharacteristicOutputs();
  colMapTable().clear();

  for (ValueId v = charOutputs.init();
       charOutputs.next(v); charOutputs.advance(v))
  {
    if (v.getItemExpr()->getOperatorType() != ITM_VALUEIDUNION)
    {
      // "other" available values besides the value being considered.
      ValueIdSet availableValues = charOutputs;
      availableValues -= v;

      // -------------------------------------------------------------------
      // see whether the value being considered is covered by the remaining
      // values. that is, whether it is an expression in termes of the
      // other vid union's.
      // -------------------------------------------------------------------
      ValueIdSet outputId;
      outputId.insert(v);
      outputId.removeUnCoveredExprs(availableValues);

      // -------------------------------------------------------------------
      // v removed from outputId. that means it's not covered by remaining
      // vid union's. add the vid union's v is in terms of to colMapTable.
      // the node needs to produce it. Instead of producing the expression,
      // change the node to produce just the vid union, the expression can
      // be evaluatated at the parent.
      // -------------------------------------------------------------------
      if (outputId.isEmpty())
      {
#pragma nowarn(1506)   // warning elimination
        Int32 leftIndex = getLeftMap().getTopValues().index(v);
#pragma warn(1506)  // warning elimination
#pragma nowarn(1506)   // warning elimination
        Int32 rightIndex = getRightMap().getTopValues().index(v);
#pragma warn(1506)  // warning elimination

        CMPASSERT((leftIndex != NULL_COLL_INDEX) &&
                  (rightIndex != NULL_COLL_INDEX));

        ItemExpr *ptr = new(CmpCommon::statementHeap())
          ValueIdUnion(getLeftMap().getBottomValues()[leftIndex],
                       getRightMap().getBottomValues()[rightIndex],v);
        v.replaceItemExpr(ptr);
	colMapTable().insert(v);
      }
    }
    else
      colMapTable().insert(v);
  }

  // My Characteristic Inputs become the external inputs for my children.
  Lng32 nc = (Lng32)getArity();
  const ValueIdSet & inputs = getGroupAttr()->getCharacteristicInputs();
  for (Lng32 index = 0; index < nc; index++)
  {
    ValueIdSet pulledInputs;
    child(index) = child(index)->preCodeGen(generator,inputs,pulledInputs);
    if (child(index).getPtr() == NULL) return NULL;
    pulledNewInputs += pulledInputs;
  }

  // Accumulate the values that are provided as inputs by my parent
  // together with the values that are produced as outputs by my
  // children. Use these values for rewriting the VEG expressions.
  ValueIdSet availableValues;
  getInputValuesFromParentAndChildren(availableValues);

  // Rebuild the colMapTable
  colMapTable().replaceVEGExpressions(availableValues,inputs);

  // Rebuild the sortOrder.
  sortOrder_.replaceVEGExpressions(availableValues,inputs);

  // Rebuild the merge expression
  if (mergeExpr_)
  {
    mergeExpr_ = mergeExpr_->replaceVEGExpressions(availableValues,inputs);
    //10-061219-1283:Set the second arugment to TRUE to redrive typesynthesis of children.
    mergeExpr_->synthTypeAndValueId(TRUE,TRUE);
  }

  // The VEG expressions in the selection predicates and the characteristic
  // outputs can reference any expression that is either a potential output
  // or a characteristic input for this RelExpr. Supply these values for
  // rewriting the VEG expressions.
  getInputAndPotentialOutputValues(availableValues);

  // Rebuild the selection predicate tree.
  selectionPred().replaceVEGExpressions(availableValues,inputs);
  getGroupAttr()->resolveCharacteristicOutputs(availableValues,inputs);
  // Rebuild the conditional expression.
  condExpr().replaceVEGExpressions(availableValues,
				   getGroupAttr()->getCharacteristicInputs());

  if (!getUnionForIF() && !getInliningInfo().isIMUnion())
    generator->oltOptInfo()->setMultipleRowsReturned(TRUE);

  markAsPreCodeGenned();

  return this;
} // MergeUnion::preCodeGen()

RelExpr * MapValueIds::preCodeGen(Generator * generator,
				  const ValueIdSet & externalInputs,
				  ValueIdSet &pulledNewInputs)
{
  const ValueIdList &upperValues = map_.getTopValues();
  const ValueIdList &lowerValues = map_.getBottomValues();

  if (nodeIsPreCodeGenned())
    return this;

  // Check if the pivs of this operator and it's child are the same.
  // If they are not, make them the same.
  replacePivs();

  // Resolve the VEGReferences and VEGPredicates, if any, that appear
  // in the Characteristic Inputs, in terms of the externalInputs.
  getGroupAttr()->resolveCharacteristicInputs(externalInputs);

  // My Characteristic Inputs become the external inputs for my children.
  child(0) = child(0)->preCodeGen(
       generator,
       getGroupAttr()->getCharacteristicInputs(),
       pulledNewInputs);
  if (child(0).getPtr() == NULL)
    return NULL;

  getGroupAttr()->addCharacteristicInputs(pulledNewInputs);

  // ---------------------------------------------------------------------
  // The MapValueIds node describes a mapping between expressions used
  // by its child tree and expressions used by its parent tree. The
  // generator will make sure that the output values of the child tree
  // and the input values from the parent get passed in the correct
  // buffers.
  // ---------------------------------------------------------------------

  // ---------------------------------------------------------------------
  // Replacing VEGReferences in those mapped expressions is not possible
  // in all cases; we have to restrict the kind of mappings that can
  // be done for expressions involving VEGs. This method assumes that
  // references to VEGs do not get altered during the rewrite, in other
  // words it assumes mappings of the kind
  //
  //     a)          sum(VEGRef(a,b,c))    <---->    VEGRef(a,b,c)
  //
  // and it disallows mappings of the kind
  //
  //     b)          count(VEGRef(a,b,c))  <----->   1
  //     c)          VEGRef(a,b,c)         <----->   VEGRef(d,e,f)
  //
  // Mappings of type b) will still work, as long as the VEGRef is contained
  // in some other mapped expression. A possible extension is to store
  // in the MapValueIds node which element(s) of which VEGRef should
  // be replaced in this step, but this information is hard to get
  // during optimization, unless we are looking at a scan node.
  // ---------------------------------------------------------------------

  // ---------------------------------------------------------------------
  // The map contains many mappings, not all of which will have to
  // be evaluated by the generator. Only those values that are either
  // characteristic output values or are referenced by characteristic
  // output values will actually be mapped at execution time. Therefore
  // we first determine the actually needed mappings with the coverTest
  // method.
  // ---------------------------------------------------------------------

  GroupAttributes emptyGA;
  ValueIdSet coveredExpr;
  ValueIdSet referencedUpperValues;
  ValueIdMap newMap;

  emptyGA.setCharacteristicInputs(getGroupAttr()->getCharacteristicInputs());

  emptyGA.coverTest(
       getGroupAttr()->getCharacteristicOutputs(), // the expressions needed
       upperValues,            // offer the upper values as extra inputs
       coveredExpr,            // doesn't matter which outputs are covered
       referencedUpperValues); // get those upper values needed by the outputs

  // Compute the values that are available here.
  ValueIdSet lowerAvailableValues;
  getOutputValuesOfMyChildren(lowerAvailableValues);
  lowerAvailableValues += getGroupAttr()->getCharacteristicInputs();

  // The VEGReferences that are resolved can appear as leaves of the
  // expressions contained in lowerAvailableValues. These values are
  // required for remapping the upperValues.
  ValueIdSet leafValues;

  ValueId x;
  for (x = lowerAvailableValues.init();
       lowerAvailableValues.next(x);
       lowerAvailableValues.advance(x))
    x.getItemExpr()->getLeafValueIds(leafValues);
  lowerAvailableValues += leafValues;

  // upperAvailableValues is needed for mvqr. The addition of the lower 
  // available values is only necessary to avoid an assertion failure in
  // VEGReference::replaceVEGReference().
  ValueIdSet upperAvailableValues(valuesForVEGRewrite());
  upperAvailableValues += lowerAvailableValues;

  // ---------------------------------------------------------------------
  // now walk through each needed mapping and replace wildcards in both its
  // upper and lower expressions
  // ---------------------------------------------------------------------
  for (CollIndex i = 0; i < upperValues.entries(); i++)
    {
      if (referencedUpperValues.contains(upperValues[i]))
	{
	  ItemExpr *newUpper;
	  ItemExpr *newLower;
	  // This mapping is actually required, expand wild cards for it

          // We used to resolve the upper values using the
          // upperAvailableValues.  Note that these available values
          // might not actually be available to this node.  This could
          // sometimes cause problems if the VEGRef was resolved to the
          // 'wrong' value and the value is in a VEGPRed above.  This
          // would cause VEGPRed to be resolved incorrectly and
          // possibly drop some join predicates.

          // Don't need to replace the VEGgies in the upper since they
          // will never be codeGen'ed.  Just need to replace them with
          // a suitable substitute.

          // If it is a VEG_REF, then replace it with a surrogate
          // (NATypeToItem) otherwise leave it as is.  (Don't use the
          // surrogate for all upper values because there are some
          // MVIds that have BaseColumns in the upper values. These
          // MVIds are introduced by Triggers.  And these BaseColumns
          // are used in other operators in other parts of the tree
          // where they are expected to always be BaseColumns. So
          // mapping them here will cause problems elsewhere).  In any
          // case, all we need to do here is to get rid of the
          // VEGRefs.
          //

	  newLower = lowerValues[i]
                       .getItemExpr()
                           ->replaceVEGExpressions
                                (lowerAvailableValues,
				 getGroupAttr()->getCharacteristicInputs());

          newUpper = upperValues[i].getItemExpr();

          if (upperValues[i] != lowerValues[i]) 
          {
             if (newUpper->getOperatorType() == ITM_VEG_REFERENCE) 
             {
               if (usedByMvqr())
                 // If this node is used to map the outputs of an MV added by
                 // MVQR, upperAvailableValues has been constructed to
                 // contain the base column a vegref should map to, so we use
                 // that instead of a created surrogate.
                 newUpper = newUpper->replaceVEGExpressions
                                (upperAvailableValues,
				 getGroupAttr()->getCharacteristicInputs());
               else {
                 NAType *mapType =
                   upperValues[i].getType().newCopy(generator->wHeap());
       
                 // Create replacement for VEGRef
                 //
                 ItemExpr *mapping =
                   new(generator->wHeap()) NATypeToItem(mapType);
       
                 ValueId id = upperValues[i];
       
                 // Replace in ValueDescArray.  All instances of this ID
                 // will now map to the surrogate.
                 //
                 id.replaceItemExpr(mapping);
       
                 newUpper = upperValues[i].getItemExpr();
               }
             }
          } else {
                // since they are the same, make upper equal to lower..
             newUpper = newLower;
          }


	  // add the mapping that may have been rewritten to the new map
	  newMap.addMapEntry(newUpper->getValueId(),newLower->getValueId());
	}
    }


  // now replace the map with the recomputed mappings
  map_ = newMap;

  // The selectionPred() on a MapValueId should have been pushed down
  // by the optimizer.
  GenAssert(selectionPred().isEmpty(),"NOT selectionPred().isEmpty()");

  // The VEG expressions in the selection predicates and the characteristic
  // outputs can reference any expression that is either a potential output
  // or a characteristic input for this RelExpr. Supply these values for
  // rewriting the VEG expressions.
  // Be thrifty. Reuse coveredExpr for gathering the input and output values.
  getInputAndPotentialOutputValues(coveredExpr);

  // Add the value that is being fabricated by the MapValueIds to the values
  // that are produced by its child and flow throught the MapValueIds.
  lowerAvailableValues += coveredExpr;

  getGroupAttr()->resolveCharacteristicOutputs
                     (lowerAvailableValues,
		      getGroupAttr()->getCharacteristicInputs());

  markAsPreCodeGenned();

  return this;
} // MapValueIds::preCodeGen()

RelExpr * Sort::preCodeGen(Generator * generator,
			   const ValueIdSet & externalInputs,
			   ValueIdSet &pulledNewInputs)
{
  if (nodeIsPreCodeGenned())
      return this;
    //else
    //  cerr << "Possible error..."

  // Check if the pivs of this operator and it's child are the same.
  // If they are not, make them the same.
  replacePivs();

  // Resolve the VEGReferences and VEGPredicates, if any, that appear
  // in the Characteristic Inputs, in terms of the externalInputs.
  getGroupAttr()->resolveCharacteristicInputs(externalInputs);

  // if doing Partial Sorting, store partial sort key in generator work area
  // if the split-top node is providing this underneath, protect the order
  // else clear the partial sort key
  ValueIdList prefixSortKey = getPrefixSortKey();

  generator->clearPrefixSortKey();

  if (!prefixSortKey.isEmpty())
    generator->setPrefixSortKey(prefixSortKey);

  PhysicalProperty* unPreCodeGendPP = NULL;

  // Protect against scan of self-referencing table partitions 
  // completing asynchronously, thus allowing the various instances
  // of SORT to start returning rows before all scans are complete.
  // Let the PartitionAccess::preCodeGen and Exchange::preCodeGen
  // work together to detect this.  Part of the fix for solution 
  // 10-071204-9253.

  bool doCheckUnsycHalloweenScans = false;
  
  // solution 10-100310-8659
  bool fixSolution8659 = false;   
  int numUnblockedHalloweenScansBefore = 
    generator->getUnblockedHalloweenScans();
  bool needToRestoreLSH = false;
  bool saveLSH = generator->getPrecodeHalloweenLHSofTSJ();
  
  // This is the pre-R2.5.1 test that triggers the check unblocked access.
  // Note that it indirectly depends on COMP_BOOL_166 OFF.
  if (checkAccessToSelfRefTable_)
    doCheckUnsycHalloweenScans = true;

  // This is the R2.5.1 way -- see solution 10-100310-8659.
  if ((generator->getPrecodeHalloweenLHSofTSJ()) &&
      (!generator->getPrecodeRHSofNJ()))
  {
    if (generator->getHalloweenSortForced())
      markAsHalloweenProtection();

    if (generator->preCodeGenParallelOperator() &&
        !generator->getHalloweenESPonLHS())
    {
      doCheckUnsycHalloweenScans = true;
      fixSolution8659 = true;
    }
    else
    {
      // This serial sort is enough to block the 
      // scan of the target table.  No need for further
      // checking.  Notice this serial vs. parallel sort test
      // was made in NestedJoin::preCodeGen before the fix
      // for 10-100310-8659.
      doCheckUnsycHalloweenScans  = false;

      // More for 10-100310-8659 - don't call incUnblockedHalloweenScans
      // below this node. 
      generator->setPrecodeHalloweenLHSofTSJ(false);
      needToRestoreLSH = true;

      GenAssert(generator->unsyncdSortFound() == FALSE, 
        "Unknown operator set unsyncdSortFound.");
    }
  }

  if (doCheckUnsycHalloweenScans)
  {
    generator->setCheckUnsyncdSort(TRUE);

    // Preserve a copy of the child's physical properties
    // as it is before preCodeGen is called for the child.  
    // Also, in this copy of the physical properties, use 
    // a copy of the child's partitioning function.  This 
    // will be used in case we need to insert an ESP for 
    // halloween protection.
    unPreCodeGendPP = new (CmpCommon::statementHeap()) 
        PhysicalProperty(*child(0)->getPhysicalProperty(),
		     child(0)->getPhysicalProperty()->getSortKey(),
                     child(0)->getPhysicalProperty()->getSortOrderType(), 
                     child(0)->getPhysicalProperty()->getDp2SortOrderPartFunc(),
		     child(0)->getPhysicalProperty()->
                            getPartitioningFunction()->copy()
                    );
  }

  if ( CmpCommon::getDefault(COMPRESSED_INTERNAL_FORMAT) == DF_SYSTEM)
  {
    NABoolean resize = FALSE;
    NABoolean defrag = FALSE;
    // get the char outputs and not  the child's
    ValueIdSet vidSet = getGroupAttr()->getCharacteristicOutputs();

    ExpTupleDesc::TupleDataFormat tupleFormat =
                  determineInternalFormat( vidSet,
                                           this,
                                           resize,
                                           generator,
                                           FALSE,
                                           defrag);

    cacheTupleFormatAndResizeFlag(tupleFormat, resize, defrag);

    if (tupleFormat == ExpTupleDesc::SQLMX_ALIGNED_FORMAT)
    {
      generator->incNCIFNodes();
    }
    else
    {
      generator->decNCIFNodes();
    }
  }

  // My Characteristic Inputs become the external inputs for my child.
  child(0) = child(0)->preCodeGen(generator,
				  getGroupAttr()->getCharacteristicInputs(),
				  pulledNewInputs);

  generator->clearPrefixSortKey();
  
  if (! child(0).getPtr())
    return NULL;

  if (needToRestoreLSH)
    generator->setPrecodeHalloweenLHSofTSJ(saveLSH);

  getGroupAttr()->addCharacteristicInputs(pulledNewInputs);

  // Accumulate the values that are provided as inputs by my parent
  // together with the values that are produced as outputs by my
  // children. Use these values for rewriting the VEG expressions.
  ValueIdSet availableValues;
  getInputValuesFromParentAndChildren(availableValues);

  // ----------------------------------------------------------------------
  // Replace VEGReferences in the order by list
  // Bugfix: sol# 10-020909-1555/56: the last argument, if not explicitly
  // stated, defaults to FALSE, and causes a shallow copy of the tree.
  // ----------------------------------------------------------------------
  sortKey_.replaceVEGExpressions
              (availableValues,
	       getGroupAttr()->getCharacteristicInputs(),
	       FALSE, // default
	       NULL,  // default
	       TRUE); // bugfix

  // The VEG expressions in the selection predicates and the characteristic
  // outputs can reference any expression that is either a potential output
  // or a characteristic input for this RelExpr. Supply these values for
  // rewriting the VEG expressions.
  getInputAndPotentialOutputValues(availableValues);

  getGroupAttr()->resolveCharacteristicOutputs
                     (availableValues,
		      getGroupAttr()->getCharacteristicInputs());

  //Consider Sort as part of BMO memory participant if not partial sort.
  if (prefixSortKey.entries() == 0 ||
     CmpCommon::getDefault(COMP_BOOL_84) == DF_ON)
    {
      if (CmpCommon::getDefault(SORT_MEMORY_QUOTA_SYSTEM) != DF_OFF) {
        generator->incrNumBMOs();

        if ((ActiveSchemaDB()->getDefaults()).getAsDouble(EXE_MEMORY_LIMIT_PER_CPU) > 0)
          generator->incrBMOsMemory(getEstimatedRunTimeMemoryUsage(TRUE));
      }
    }


  markAsPreCodeGenned();  

  // Part of the fix for solution 10-071204-9253.
  // Modified for 10-100310-8659
  if (doCheckUnsycHalloweenScans && generator->unsyncdSortFound())
    {
      RelExpr *newChild = generator->insertEspExchange(child(0), 
						       unPreCodeGendPP);
      
      ((Exchange *)newChild)->markAsHalloweenProtection();
      
      newChild = 
	newChild->preCodeGen(generator, externalInputs, pulledNewInputs);
      
      GenAssert(newChild->getOperatorType() == REL_EXCHANGE, 
		"Exchange eliminated despite our best efforts.");

      child(0) = newChild;
          
      // Now that an ESP is inserted above the scans, this sort operator
      // does block the scans, so we can discount them.
      if (fixSolution8659)
	{
	  generator->setUnsyncdSortFound(FALSE);
	  generator->setUnblockedHalloweenScans(
				       numUnblockedHalloweenScansBefore);
	}
    }
  return this;

} // Sort::preCodeGen()

RelExpr * SortFromTop::preCodeGen(Generator * generator,
				  const ValueIdSet & externalInputs,
				  ValueIdSet &pulledNewInputs)
{
  return Sort::preCodeGen(generator, externalInputs, pulledNewInputs);
}

RelExpr *ProbeCache::preCodeGen(Generator * generator,
			   const ValueIdSet & externalInputs,
			   ValueIdSet &pulledNewInputs)
{
  if (nodeIsPreCodeGenned())
    return this;

  // Check if the pivs of this operator and it's child are the same.
  // If they are not, make them the same.
  replacePivs();

  // Resolve the VEGReferences and VEGPredicates, if any, that appear
  // in the Characteristic Inputs, in terms of the externalInputs.
  getGroupAttr()->resolveCharacteristicInputs(externalInputs);

  // My Characteristic Inputs become the external inputs for my child.
  child(0) = child(0)->preCodeGen(generator,
				  getGroupAttr()->getCharacteristicInputs(),
				  pulledNewInputs);
  if (! child(0).getPtr())
    return NULL;

  // add one more value to "valuesGivenToChild_": a statement execution 
  // count that will invalidate cache each time the statement is 
  // re-executed. It would be incorrect to cache across
  // statement executions (and possibly transactions).
  ValueId execCount = generator->getOrAddStatementExecutionCount();
  pulledNewInputs += execCount;
  
  getGroupAttr()->addCharacteristicInputs(pulledNewInputs);

  // Accumulate the values that are provided as inputs by my parent
  // together with the values that are produced as outputs by my
  // children. Use these values for rewriting the VEG expressions.
  ValueIdSet availableValues;
  getInputValuesFromParentAndChildren(availableValues);

  // Rewrite the selection predicates.
  NABoolean replicatePredicates = TRUE;
  selectionPred().replaceVEGExpressions
                     (availableValues,
		      getGroupAttr()->getCharacteristicInputs(),
		      FALSE, // no need to generate key predicates here
		      0 /* no need for idempotence here */,
		      replicatePredicates
		     );

  getGroupAttr()->resolveCharacteristicOutputs
                     (availableValues,
		      getGroupAttr()->getCharacteristicInputs());

  /*
  TBD - maybe ProbeCache as BMO memory participant??
  if(CmpCommon::getDefault(PROBE_CACHE_MEMORY_QUOTA_SYSTEM) != DF_OFF)
    generator->incrNumBMOs();
  */

  if ((ActiveSchemaDB()->getDefaults()).getAsDouble(EXE_MEMORY_LIMIT_PER_CPU) > 0)
    generator->incrNBMOsMemoryPerCPU(getEstimatedRunTimeMemoryUsage(TRUE));

  markAsPreCodeGenned();
  return this;
    
} // ProbeCache::preCodeGen()


RelExpr * Exchange::preCodeGen(Generator * generator,
			       const ValueIdSet & externalInputs,
			       ValueIdSet &pulledNewInputs)
{
  if (nodeIsPreCodeGenned())
    return this;

  // Set a flag if this is a parallel extract consumer. The flag for
  // extract producer queries gets set earlier in RelRoot::codeGen()
  if (child(0)->getOperatorType() == REL_EXTRACT_SOURCE)
  {
    isExtractConsumer_ = TRUE;
    GenAssert(!isExtractProducer_,
              "One extact query cannot be both producer and consumer");
  }

  const PhysicalProperty* sppOfChild = child(0)->getPhysicalProperty();

  NABoolean PivsReplaced = FALSE;

  if (sppOfChild->getPlanExecutionLocation() == EXECUTE_IN_DP2) {
    // If this is not an ESP exchange, then check if the pivs of this op
    // and it's child are the same. If they are not, make them the same.
    // We don't do this for an ESP exchange because an ESP exchange
    // denotes an ESP process boundary and the child's pivs
    // do not have to be the same as the parent and in fact should
    // not be the same.
    replacePivs();
    PivsReplaced = TRUE;
  }

  RelExpr *result = this;

  // ---------------------------------------------------------------------
  // copy important info from the properties into data members
  // ---------------------------------------------------------------------
   
  storePhysPropertiesInNode(generator->getPrefixSortKey());

  // If this is a parallel extract producer query:
  // - do a few checks to make sure the plan is valid
  // - store a copy of the root's select list
  if (isExtractProducer_)
  {
    RelRoot *root = generator->getBindWA()->getTopRoot();

    // The plan is valid if this is an ESP exchange the number of
    // bottom partitions matches the number of requested streams.
    ComUInt32 numRequestedStreams = root->getNumExtractStreams();
    ComUInt32 numBottomEsps = (ComUInt32)
      getBottomPartitioningFunction()->getCountOfPartitions();
    if (!isEspExchange() || (numRequestedStreams != numBottomEsps))
    {
      *CmpCommon::diags() << DgSqlCode(-7004);
      GenExit();
      return NULL;
    }

    // Make a copy of the root's select list
    extractSelectList_ = new (generator->wHeap())
      ValueIdList(root->compExpr());

    // Do a coverage test to see find values in the select list that
    // this operator cannot already provide
    ValueIdSet valuesIDontHave(*extractSelectList_);
    ValueIdSet coveredExpr;
    ValueIdSet referencedUpperValues;
    getGroupAttr()->coverTest(valuesIDontHave,        // expressions needed
                              externalInputs,         // extra inputs
                              coveredExpr,            // covered exprs
                              referencedUpperValues); // new values needed

    // Add the needed values to characteristic inputs
    pulledNewInputs += referencedUpperValues;
    getGroupAttr()->addCharacteristicInputs(referencedUpperValues);
  }

  // ---------------------------------------------------------------------
  // Resolve the VEGReferences and VEGPredicates, if any, that appear
  // in the Characteristic Inputs, in terms of the externalInputs.
  // ---------------------------------------------------------------------
  ValueIdSet saveCharInputs = getGroupAttr()->getCharacteristicInputs();
  getGroupAttr()->resolveCharacteristicInputs(externalInputs);

  // variables that store the result of the major decisions:
  //
  // makeThisExchangeAPapa: if this is a PAPA node, then make this
  //                        node the PAPA (and add a PA below it)
  // eliminateThisExchange: get rid of this node either because
  //                        it represents a sole PA or because it is
  //                        a redundant ESP exchange
  // topPartFunc_:          the partitioning function produced by
  //                        this node after we're done with preCodeGen
  // bottomPartFunc_:       the partitioning function produced by
  //                        the child of this node
  // paPartFunc:            the partitioning function produced by the
  //                        PA node inserted below
  // lbpf                   LogPhysPartitioningFunction of the child,
  //                        if the child has such a part. function
  NABoolean makeThisExchangeAPapa            = FALSE;
  NABoolean eliminateThisExchange            = FALSE;
  const PartitioningFunction *paPartFunc     = topPartFunc_;
  const LogPhysPartitioningFunction *lppf    = NULL;


  if (isDP2Exchange() AND
      bottomPartFunc_->isALogPhysPartitioningFunction())
  {
    lppf = bottomPartFunc_->castToLogPhysPartitioningFunction();

    if (lppf->getUsePapa() || getGroupAttr()->isEmbeddedUpdateOrDelete())
    {

      // Will a merge of sorted streams need to be done?
      if (NOT sortKeyForMyOutput_.isEmpty())
      {
        Lng32 maxPartsPerGroup;

        // Since a merge of sorted streams is needed, we must
        // ensure that there is one PA for every partition in every
        // process. The optimizer should already have set this up
        // correctly, but sometimes, due to plan stealing, the value
        // can be wrong. This code is really a patch for the plan
        // stealing problem. We could try to fix the plan stealing
        // problem, but that would adversely affect compile time.
        // To set the number of clients (i.e. PAs) we must cast away
        // the const-ness, sorry.
        if (topPartFunc_->isAGroupingOf(*bottomPartFunc_,
                                        &maxPartsPerGroup))
        {
          ((LogPhysPartitioningFunction*)lppf)->setNumOfClients(
            maxPartsPerGroup * topPartFunc_->getCountOfPartitions());
        }
        else
        {
          ((LogPhysPartitioningFunction*)lppf)->setNumOfClients(
            bottomPartFunc_->getCountOfPartitions() *
            topPartFunc_->getCountOfPartitions());
        }
      }


      // Keep this exchange and make it the PAPA node. The PA
      // nodes below the PAPA will actually produce a partitioning
      // scheme that is identical to that of the DP2 operator below,
      // since the PAPA splits its requests into smaller ones that
      // do not span DP2 partition boundaries.
      makeThisExchangeAPapa = TRUE;
      paPartFunc = bottomPartFunc_;
    }
  }

  if  (!PivsReplaced && isRedundant_)
    replacePivs();

  // flag to decide whether to use the characteristic inputs or outputs
  // as input the to the CIF determineInternalFormatFunction
  // if the the child is an insert or update then we consider the chars input
  // otherwise we use the chars outputs
  NABoolean useCharInputs = FALSE;

  // ---------------------------------------------------------------------
  // If the child of this Exchange executes in DP2, then allocate a
  // PartitionAccess operator. It should have the same Group Attributes
  // as its child.
  // ---------------------------------------------------------------------
  NABoolean savedOltMsgOpt = generator->oltOptInfo()->oltMsgOpt();

  NABoolean inputOltMsgOpt = generator->oltOptInfo()->oltMsgOpt();

  unsigned short prevNumBMOs = generator->replaceNumBMOs(0);
  CostScalar prevBMOsMemoryUsage = generator->replaceBMOsMemoryUsage(0);

  // These are used to fix solution 10-071204-9253 and for 
  // solution 10-100310-8659.
  bool needToRestoreParallel = false;
  NABoolean savedParallelSetting = FALSE;
  bool needToRestoreCheckUnsync = false;
  NABoolean savedCheckUnsyncdSort = FALSE;
  bool needToRestoreLHS = false;
  bool halloweenLHSofTSJ = generator->getPrecodeHalloweenLHSofTSJ();
  bool needToRestoreESP = false;
  bool halloweenESPonLHS = generator->getHalloweenESPonLHS();

  if (isEspExchange() && getBottomPartitioningFunction()->isPartitioned())
    {
      // Tell any child NJ that its Halloween blocking operator (SORT)
      // is operating in parallel.
      savedParallelSetting = generator->preCodeGenParallelOperator();
      generator->setPreCodeGenParallelOperator(TRUE);
      needToRestoreParallel = true;
    }

  if (isEspExchange() && halloweenLHSofTSJ)
    {
      if ( !isRedundant_ )
        {
          // Tell any parallel SORT below that it doesn't have to check
          // unsyncd access.
          needToRestoreESP = true;
          generator->setHalloweenESPonLHS(true);
        }

      savedCheckUnsyncdSort = generator->checkUnsyncdSort();
      if (savedCheckUnsyncdSort == TRUE)
        {
          // savedCheckUnsyncdSort tells me there is a parallel SORT above this 
          // exchange.  This ESP guarantees that all instances of the SORT will
          // block until all instances of this ESP finish. So tell any child 
          // PARTITION ACCESS that its scan of a self-referencing is sync'd.
          generator->setCheckUnsyncdSort(FALSE);
          needToRestoreCheckUnsync = true;

          // More for 10-100310-8659 - don't call incUnblockedHalloweenScans
          // below this node. 
          halloweenLHSofTSJ = generator->setPrecodeHalloweenLHSofTSJ(false);
          needToRestoreLHS = true;
        }
    }
  else if (isEspExchange() && 
           // this isPartitioned() condition is probably a bug, but 
           // to be safe I am not fixing it now.
           getBottomPartitioningFunction()->isPartitioned())
    {

      // Tell any child PARTITION ACCESS that its scan of a self-referencing
      // table is synchronized by an ESP exchange.  That is, any blocking
      // SORT operator above this exchange will not get any rows until all
      // scans have finished.
      savedCheckUnsyncdSort = generator->checkUnsyncdSort();
      generator->setCheckUnsyncdSort(FALSE);

      needToRestoreCheckUnsync = true;
    }

  if (halloweenSortIsMyChild_ && isRedundant_)
  {
    // Before eliminating itself, and before preCodeGen'ing the child
    // tree, this Exchange will tell its child (a Sort) that it needs to 
    // check for unsynchronized access to the target table of a 
    // self-referencing update.  This is part of the fix for 
    // solution 10-090310-9876.
    ((Sort *)(child(0).getPtr()))->doCheckAccessToSelfRefTable();

    // Note for solution 10-100310-8659 -- the halloweenSortIsMyChild_
    // flag will only be set when the COMP_BOOL_166 is used to revert
    // to pre-bugfix behavior.  With the fix for 10-100310-8659, the 
    // Sort uses the Generator's flags (precodeHalloweenLHSofTSJ and
    // precodeRHSofNJ) to know if it needs check access to the target 
    // table.  In other words, unless COMP_BOOL_166 is used, this
    // is dead code.
  }
  if ( CmpCommon::getDefault(COMPRESSED_INTERNAL_FORMAT) == DF_SYSTEM)
  {
    NABoolean resize = FALSE;
    NABoolean defrag = FALSE;
    ValueIdSet vidSet;
    if (!useCharInputs)
    {
      vidSet = child(0)->getGroupAttr()->getCharacteristicOutputs();
    }
    else
    {
      vidSet = saveCharInputs;
    }

    ExpTupleDesc::TupleDataFormat tupleFormat =
                  determineInternalFormat( vidSet,
                                           this,
                                           resize,
                                           generator,
                                           FALSE,
                                           defrag);

    cacheTupleFormatAndResizeFlag(tupleFormat, resize, defrag);

    if (tupleFormat == ExpTupleDesc::SQLMX_ALIGNED_FORMAT)
    {
      generator->incNCIFNodes();
    }
    else
    {
      generator->decNCIFNodes();
    }
  }

  // For HashJoin MIN/MAX optimization.  If this is an ESP Exchange,
  // block all candidate values for min/max optimization from going
  // below this Exchange.  Restore them upon return from
  // preCodeGen'ing the child.
  ValueIdList minMaxKeys, minVals, maxVals, willUseMinMaxKeys;
  if(isEspExchange()) {

    // Save the current values.
    minMaxKeys = generator->getMinMaxKeys();
    minVals = generator->getMinVals();
    maxVals = generator->getMaxVals();
    willUseMinMaxKeys = generator->getWillUseMinMaxKeys();

    
    // Clear the current values.
    generator->getMinMaxKeys().clear();
    generator->getMinVals().clear();
    generator->getMaxVals().clear();
    generator->getWillUseMinMaxKeys().clear();
  }

  // ---------------------------------------------------------------------
  // Perform preCodeGen on the child (including PA node if we created it)
  // ---------------------------------------------------------------------
  child(0) = child(0)->preCodeGen(
       generator,
       getGroupAttr()->getCharacteristicInputs(),
       pulledNewInputs);

  // For HashJoin MIN/MAX optimization.
  if(isEspExchange()) {
    // Restore the saved values.
    generator->getMinMaxKeys() = minMaxKeys;
    generator->getMinVals() = minVals;
    generator->getMaxVals() = maxVals;
    generator->getWillUseMinMaxKeys() = willUseMinMaxKeys;
  }

  if (needToRestoreParallel)
    generator->setPreCodeGenParallelOperator(savedParallelSetting);
  if (needToRestoreCheckUnsync)
    generator->setCheckUnsyncdSort(savedCheckUnsyncdSort);
  if (needToRestoreLHS)
    generator->setPrecodeHalloweenLHSofTSJ(halloweenLHSofTSJ);
  if (needToRestoreESP)
    generator->setHalloweenESPonLHS(halloweenESPonLHS);

  setNumBMOs( generator->replaceNumBMOs(prevNumBMOs) );
  setBMOsMemoryUsage( generator->replaceBMOsMemoryUsage(prevBMOsMemoryUsage) );

  if (! child(0).getPtr())
    return NULL;

  generator->oltOptInfo()->setOltMsgOpt(savedOltMsgOpt);

  // Decide whether this Exchange should try to eliminate itself.
  if (child(0)->castToRelExpr()->getOperatorType() == REL_EXE_UTIL)
    {
      // No, the REL_EXE_UTIL must execute in an ESP.
    }
  else if (skipRedundancyCheck_)
    {
      // No, the ESP was inserted just to force blocking of 
      // data from SORT instances, to help prevent Halloween
      // problem -- see Soln 10-071204-9253.
    }
  else
    {
      // Yes, perform the redundancy check.
      eliminateThisExchange = (isRedundant_ OR
          (isDP2Exchange() AND NOT makeThisExchangeAPapa));
    }

  // ---------------------------------------------------------------------
  // Determine which partition input values need to be supplied by our
  // parent and which are produced by this exchange node.  PA or PAPA
  // exchange nodes (DP2 exchange nodes) do not produce any partition
  // input values themselves, just ask the parent to produce the PIVs
  // needed by the child. ESP exchanges produce the PIVs for their bottom
  // partition function, and this is also true for added repartitioning
  // exchanges.
  // ---------------------------------------------------------------------
  if (isEspExchange())
    {
      pulledNewInputs -= bottomPartFunc_->getPartitionInputValues();
      setBottomPartitionInputValues(
	   bottomPartFunc_->getPartitionInputValuesLayout());
    }

  getGroupAttr()->addCharacteristicInputs(pulledNewInputs);

  // ---------------------------------------------------------------------
  // The VEG expressions in the selection predicates and the characteristic
  // outputs can reference any expression that is either a potential output
  // or a characteristic input for this RelExpr. Supply these values for
  // rewriting the VEG expressions.
  // ---------------------------------------------------------------------
  ValueIdSet availableValues;

  getInputAndPotentialOutputValues(availableValues);

  // Accumulate the values that are provided as inputs by my parent
  // together with the values that are produced as outputs by my
  // children. Use these values for rewriting the VEG expressions.

  // ---------------------------------------------------------------------
  // Rewrite the copy of the sort key which will be used for merging
  // rows. The VEGRef on the column being sorted may be preceeded by 
  // an InverseOrder itemExpr (in case the shortcut_grby rule has fired)
  // The InverseOrder itemExpr will not perform a copy of the sortKey
  // before replacing VEGExpressions unless replicateExpression is set 
  // to TRUE below. This avoids inverse(VEGRef_60(T1.a = T2.a)) being 
  // resolved to T1.a in two different exchange nodes, even though T1.a 
  // is not available at the second exchange node.
  // ---------------------------------------------------------------------
  NABoolean replicateExpression = TRUE;
  sortKeyForMyOutput_.replaceVEGExpressions
    (availableValues,
     getGroupAttr()->getCharacteristicInputs(),
     FALSE, // no key predicates here
     0 /* no need for idempotence here */,
     replicateExpression
     );

  // ---------------------------------------------------------------------
  // Rewrite the partitioning expression, if the repartitioning function
  // contains one. A ReplicationPartitioningFunction does not contain
  // a partititioning expression because it uses a broadcast for
  // replicating rows to its consumers.
  // ---------------------------------------------------------------------
  if (isEspExchange())
  {
    PartitioningFunction * rpf;

    // need to cast away const-ness to create partitioning expr, sorry
    rpf = (PartitioningFunction *) topPartFunc_;

    rpf->createPartitioningExpression();
    rpf->preCodeGen(availableValues);
  }

  // ---------------------------------------------------------------------
  // For a parallel extract producer query, rewrite our copy of the
  // root's select list
  // ---------------------------------------------------------------------
  if (isExtractProducer_)
  {
    extractSelectList_->
      replaceVEGExpressions(availableValues,
                            getGroupAttr()->getCharacteristicInputs());
  }

  // ---------------------------------------------------------------------
  // Resolve characteristic outputs.
  // ---------------------------------------------------------------------
  getGroupAttr()->resolveCharacteristicOutputs
                      (availableValues,
		       getGroupAttr()->getCharacteristicInputs());

  generator->oltOptInfo()->mayDisableOperStats(&oltOptInfo());

  // ---------------------------------------------------------------------
  // From here on we add or remove exchange nodes, but this node is
  // ready and does not need to be processed again should we call
  // preCodeGen for it again.
  // ---------------------------------------------------------------------
  markAsPreCodeGenned();

  // ---------------------------------------------------------------------
  // Eliminate this exchange if it simply represented the PA node or
  // if it is redundant. Do not eliminate the exchange if it is a
  // parallel extract producer or consumer.
  // ---------------------------------------------------------------------
  if (isExtractProducer_ || isExtractConsumer_)
    eliminateThisExchange = FALSE;

  if (eliminateThisExchange)
  {
    result = child(0).getPtr();

    // transfer the # of BMOs and their memory usages to generator as
    // this exchange node is to be discarded.
    generator->incrBMOsMemoryPerFrag(getBMOsMemoryUsage());
    generator->incrNumBMOsPerFrag(getNumBMOs());
  }

  if ((isEspExchange()) &&
      (NOT eliminateThisExchange))
    {
      //      generator->setUpdAbortOnError(TRUE);
      generator->setUpdSavepointOnError(FALSE);
      generator->setUpdErrorOnError(FALSE);
      
      generator->compilerStatsInfo().exchangeOps()++;
      
      generator->compilerStatsInfo().dop() =
	(UInt16)MAXOF(generator->compilerStatsInfo().dop(),
		      getBottomPartitioningFunction()->getCountOfPartitions());
      
      
      if ( getNumBMOs() > 0 )
	generator->incTotalESPs();
      
      // If the exchange uses SeaMonster, set a flag in the generator
      // to indicate that some part of the query does use SeaMonster
      if (thisExchangeCanUseSM(generator->getBindWA()))
        generator->setQueryUsesSM(TRUE);
      
    } // isEspExchange() && !eliminateThisExchange
  
  if ((ActiveSchemaDB()->getDefaults()).getAsDouble(EXE_MEMORY_LIMIT_PER_CPU) > 0)
    generator->incrNBMOsMemoryPerCPU(getEstimatedRunTimeMemoryUsage(TRUE));
  
  return result;
  
} // Exchange::preCodeGen()

RelExpr * Tuple::preCodeGen(Generator * generator,
		       const ValueIdSet & externalInputs,
		       ValueIdSet &pulledNewInputs)
{
  if (nodeIsPreCodeGenned())
    return this;

  if (! RelExpr::preCodeGen(generator,externalInputs,pulledNewInputs))
    return NULL;

  // Accumulate the values that are provided as inputs by my parent
  // together with the values that are produced as outputs by my
  // children. Use these values for rewriting the VEG expressions.
  ValueIdSet availableValues = getGroupAttr()->getCharacteristicInputs();
  tupleExpr().replaceVEGExpressions
                 (availableValues,
		  getGroupAttr()->getCharacteristicInputs());

  return this;
}

ItemExpr * BuiltinFunction::preCodeGen(Generator * generator)
{
  ItemExpr * retExpr = NULL;

  if (nodeIsPreCodeGenned())
    return getReplacementExpr();
	
  if (CmpCommon::getDefault(OR_PRED_KEEP_CAST_VC_UCS2) == DF_ON) {
    // part of temporary workaround to yotta dp2 killer problem:
    // keep cast for upper(cast name as varchar(n) char set ucs2)
    switch (getOperatorType()) {
    case ITM_UPPER:
    case ITM_LOWER:
    case ITM_SUBSTR:
    case ITM_TRIM:
      if (child(0)->getOperatorType() == ITM_CAST) {
        Cast *arg = (Cast*)child(0)->castToItemExpr();
        const NAType& typ = arg->getValueId().getType();
        if (arg->matchChildType() &&
            arg->child(0)->getValueId().getType() == typ &&
            typ.getTypeQualifier() == NA_CHARACTER_TYPE && 
            typ.isVaryingLen() &&
            ((CharType*)(&typ))->getCharSet() == CharInfo::UCS2) {
          // don't skip codegen for the cast of 
          // "upper(cast name as varchar(n) char set ucs2) IN <inlist>"
          arg->setMatchChildType(FALSE);
        }
      }
    }
  }

  if (! ItemExpr::preCodeGen(generator))
    return NULL;

  switch (getOperatorType())
    {
    case ITM_QUERYID_EXTRACT:
      {
        // convert arguments to ISO88591 character set

        if (child(0)->castToItemExpr()->getValueId().getType().getTypeQualifier() ==
            NA_CHARACTER_TYPE)
          {
            const CharType &typ0 =
              (const CharType &) (child(0)->castToItemExpr()->getValueId().getType());
            if (typ0.getCharSet() != CharInfo::ISO88591)
              {
                // the executor method assumes an ASCII string for the query id, so
                // convert the value to a fixed char type in the ISO88591 char set
                SQLChar * newTyp0 = new(generator->wHeap())
                  SQLChar(typ0.getCharLimitInUCS2or4chars(),
                          typ0.supportsSQLnullLogical(),
                          typ0.isUpshifted(),
                          typ0.isCaseinsensitive(),
                          typ0.isVaryingLen(),
                          CharInfo::ISO88591);
                
                child(0) = new (generator->wHeap()) Cast(child(0), newTyp0);
                child(0)->bindNode(generator->getBindWA());
                child(0) = child(0)->preCodeGen(generator);
              }
          }

        if (child(1)->castToItemExpr()->getValueId().getType().getTypeQualifier() ==
            NA_CHARACTER_TYPE)
          {
            const CharType &typ1 =
              (const CharType &) (child(1)->castToItemExpr()->getValueId().getType());
            if (typ1.getCharSet() != CharInfo::ISO88591)
              {
                // the executor method assumes an ASCII string for the query id, so
                // convert the value to a fixed char type in the ISO88591 char set
                SQLChar * newTyp1 = new(generator->wHeap())
                  SQLChar(typ1.getCharLimitInUCS2or4chars(),
                          typ1.supportsSQLnullLogical(),
                          typ1.isUpshifted(),
                          typ1.isCaseinsensitive(),
                          typ1.isVaryingLen(),
                          CharInfo::ISO88591);
                
                child(1) = new (generator->wHeap()) Cast(child(1), newTyp1);
                child(1)->bindNode(generator->getBindWA());
                child(1) = child(1)->preCodeGen(generator);
              }
          }
      }
      retExpr = this;
      break;


    default:
      {
	retExpr = this;
      }
      break;
    } // switch

  setReplacementExpr(retExpr);

  markAsPreCodeGenned();
  return retExpr;
}

/*
ItemExpr * Abs::preCodeGen(Generator * generator)
{
  // The ABS function has the distinction of being the sole BuiltinFunction
  // that a) generates a new replacementExpr tree
  // and b) can appear in the select-list (compExpr).
  //
  // What happens is that code is generated for the ABS replacement CASE
  // TWICE, once in PartitionAccess eid, once in RelRoot generateOutputExpr:
  // the latter fails with a GenMapTable assert failing to find info for
  // the column in "SELECT ABS(col) FROM t;"
  // ("SELECT ABS(-1) FROM t;" and "SELECT ABS(col),col FROM T;" work fine --
  // but of course they generate twice as much code as necessary,
  // however harmless/idempotent it may be...)
  //
  // We therefore cannot handle this one discrepant case neatly in
  // preCodeGen/codeGen -- it is fixed instead by having the Binder
  // upstream rewrite an ABS as the equivalent CASE.
  //
  // Genesis 10-980112-5942.
  //
  GenAssert(FALSE, "Abs::preCodeGen should be unreachable code!");
  return NULL;

//if (nodeIsPreCodeGenned())
//  return getReplacementExpr();
//
//ItemExpr * newExpr =
//  generator->getExpGenerator()->createExprTree(
//    "CASE WHEN @A1 < 0 THEN - @A1 ELSE @A1 END", 0, 1, child(0));
//
//newExpr->bindNode(generator->getBindWA());
//setReplacementExpr(newExpr->preCodeGen(generator));
//markAsPreCodeGenned();
//return getReplacementExpr();

}
*/

ItemExpr * Abs::preCodeGen(Generator * generator)
{
  if (nodeIsPreCodeGenned())
    return getReplacementExpr();

  if (! ItemExpr::preCodeGen(generator))
    return NULL;

  NAType * result_type = (NAType *)(&(getValueId().getType()));
  NAType * type_op1 = (NAType *)(&(child(0)->castToItemExpr()->getValueId().getType()));

  if (! (*result_type == *type_op1))
    {
      // Insert a cast node to convert child to a result type.
      child(0) = new (generator->wHeap())
	Cast(child(0), result_type);

      child(0)->bindNode(generator->getBindWA());

      child(0) = child(0)->preCodeGen(generator);
      if (! child(0).getPtr())
	return NULL;
    }

  markAsPreCodeGenned();
  return this;
} // Abs::preCodeGen()

ItemExpr * AggrMinMax::preCodeGen(Generator * generator)
{
  if (nodeIsPreCodeGenned())
    return getReplacementExpr();

  if (! ItemExpr::preCodeGen(generator))
    return NULL;

  // if my child's attributes EXCEPT for nullability are not the
  // same as mine, do a conversion.
  NABoolean doConversion = FALSE;
  const NAType &myType = getValueId().getType();
  const NAType &childType = child(0)->castToItemExpr()->getValueId().getType();
  if (NOT (myType == childType)) // something is different
    {
      if ((myType.supportsSQLnull() &&
	   childType.supportsSQLnull()) ||
	  ((NOT myType.supportsSQLnull()) &&
	   (NOT childType.supportsSQLnull())))
	doConversion = TRUE; // both nullable or not nullable,
                             // something else is different
      else if (myType.supportsSQLnull() &&
	       NOT childType.supportsSQLnull())
	{
	  // create a new my type with the same null attr as child.
	  NAType * newType = myType.newCopy(generator->wHeap());
	  newType->resetSQLnullFlag();

	  if (NOT(*newType == childType))
	    doConversion = TRUE;

	  delete newType;
	}
      else
	{
	  // Fix for solution ID 10-031121-1505)
	  // I dont think we the following assert is correct
	  // During VEG resolution a MIN/MAX() function can have a
	  // NON-NULLABLE child replaced by a nullable child, consider
	  // as an example the following query where i2 is not null:
	  //
	  // SELECT MIN(T0.i2)
          // FROM D12 T0
          // WHERE
          //  ?pa2  =  T0.i2
          // GROUP BY T0.i1;
          //
          // In the above case i2 will be replaced by ?pa2 when the VEG
          // (i2, ?pa2) is resolved. Therefore it is possible to get a
          // nullable child for a non-nullable aggregate. In the above
          // case the aggregate is non-nullable because i2 is non-nullable.
          // In such a case MIN(?pa2) would never be executed if ?pa2 is NULL
          // because predicate '?pa2 = T0.i2' will not select any rows when
          // ?pa2 is NULL (I am not sure how a parameter is set to NULL, for host
          // vars we can use the NULL indicator, not sure how we pass in NULL using
          // parameters).
          //
          // Assert on the following condition
	  // The condition where I am not nullable and my child is nullable,
	  // is an error case.
	  //GenAssert(0, "AggrMinMax::preCodeGen::Should not reach here.");
	  doConversion = TRUE;
	}
    }

  if (doConversion)
    {
      // Insert a cast node to convert child to a result type.
      child(0) = new (generator->wHeap()) Cast(child(0), &myType);

      child(0)->bindNode(generator->getBindWA());

      child(0) = child(0)->preCodeGen(generator);
      if (! child(0).getPtr())
	return NULL;
    }

  markAsPreCodeGenned();
  return this;
} // AggrMinMax::preCodeGen()

ItemExpr * Between::preCodeGen(Generator * generator)
{
  if (nodeIsPreCodeGenned())
    return getReplacementExpr();

  // transform "A BETWEEN B AND C" to "A >= B AND A <= C"
  ItemExpr * newExpr =
    generator->getExpGenerator()->createExprTree(
      "@A1 >= @A2 AND @A1 <= @A3", 0, 3, child(0), child(1), child(2));

  newExpr->bindNode(generator->getBindWA());
  setReplacementExpr(newExpr->preCodeGen(generator));
  markAsPreCodeGenned();
  return getReplacementExpr();
}

// BiArithCount::preCodeGen
//
// The BiArithCount executor clause requires that all of the operands
// be of the same type. preCodeGen introduces cast operators on the
// input operands if necessary to enforce this requirement.
//
ItemExpr * BiArithCount::preCodeGen(Generator * generator)
{
  if (nodeIsPreCodeGenned())
    return this;

  // Get a local handle on common generator objects.
  //
  CollHeap *wHeap = generator->wHeap();

  const NAType &resultType = getValueId().getType();
  const NAType &op1Type = child(0)->castToItemExpr()->getValueId().getType();
  const NAType &op2Type = child(1)->castToItemExpr()->getValueId().getType();

  // If the first operand type does not match that of the result,
  // cast it to the result type.
  //
  if(!(op1Type == resultType))
    {
      child(0) = new(wHeap) Cast(child(0)->castToItemExpr(),
				resultType.newCopy(wHeap),
				ITM_CAST);
      child(0)->synthTypeAndValueId();
    }

  // Ditto for the second operand.
  //
  if(!(op2Type == resultType))
    {
      child(1) = new(wHeap) Cast(child(1)->castToItemExpr(),
				 resultType.newCopy(wHeap),
				 ITM_CAST);
      child(1)->synthTypeAndValueId();
    }

  return BiArith::preCodeGen(generator);
}

// BiArithSum::preCodeGen
//
// The BiArithSum executor clause requires that all of the operands
// be of the same type. preCodeGen introduces cast operators on the
// input operands if necessary to enforce this requirement.
//
ItemExpr * BiArithSum::preCodeGen(Generator * generator)
{
  if (nodeIsPreCodeGenned())
    return this;

  // Get a local handle on common generator objects.
  //
  CollHeap *wHeap = generator->wHeap();

  // Get a handle on the operand types.
  //
  const NAType &resultType = getValueId().getType();
  const NAType &op1Type = child(0)->castToItemExpr()->getValueId().getType();
  const NAType &op2Type = child(1)->castToItemExpr()->getValueId().getType();

  // If the first operand type does not match that of the result,
  // cast it to the result type.
  //
  if(!(op1Type == resultType))
    {
      child(0) = new(wHeap) Cast(child(0)->castToItemExpr(),
				resultType.newCopy(wHeap),
				ITM_CAST);
      child(0)->synthTypeAndValueId();
    }

  // Ditto for the second operand.
  //
  if(!(op2Type == resultType))
    {
      child(1) = new(wHeap) Cast(child(1)->castToItemExpr(),
				 resultType.newCopy(wHeap),
				 ITM_CAST);
      child(1)->synthTypeAndValueId();
    }

  ItemExpr *result = BiArith::preCodeGen(generator);
  if (! result)
    return NULL;

  ItemExpr *outExpr = NULL;
  Lng32 rc = generator->getExpGenerator()->foldConstants(child(0), &outExpr);
  if ((rc == 0) &&
      (outExpr))
    {
      child(0) = outExpr->preCodeGen(generator);
    }

  rc = generator->getExpGenerator()->foldConstants(child(1), &outExpr);
  if ((rc == 0) &&
      (outExpr))
    {
      child(1) = outExpr->preCodeGen(generator);
    }

  return this;
}

ItemExpr * BiArith::preCodeGen(Generator * generator)
{
  if (nodeIsPreCodeGenned())
    return this;

  if (! ItemExpr::preCodeGen(generator))
    return NULL;

  NAType * result_type = (NAType *)(&(getValueId().getType()));
  NAType * type_op1 = (NAType *)(&(child(0)->castToItemExpr()->getValueId().getType()));
  NAType * type_op2 = (NAType *)(&(child(1)->castToItemExpr()->getValueId().getType()));

  if (result_type->isComplexType())
    {
      if ((getOperatorType() == ITM_PLUS) ||
	  (getOperatorType() == ITM_MINUS))
	{
	  child(0) = generator->getExpGenerator()->matchScales(child(0)->getValueId(),
							       *result_type);

	  child(1) = generator->getExpGenerator()->matchScales(child(1)->getValueId(),
							       *result_type);
	}
      else
	if (getOperatorType() == ITM_DIVIDE)
	  {
	    // before doing the division, the numerator has to be upscaled.
	    // Lets find out how much.
	    // NS = numerator scale
	    // DS = denominator scale
	    // RS = result scale
	    // Upscale = (RS - NS) + DS
	    // Newscale = NS + Upscale = RS + DS

	    Lng32 newscale
	      = ((NumericType *)result_type)->getScale() +
		((NumericType *)type_op2)->getScale();

	    if (newscale != ((NumericType *)type_op1)->getScale()) {
	      NAType * new_type = result_type->newCopy(generator->wHeap());
	      ((NumericType *)new_type)->setScale(newscale);
	      child(0) = generator->getExpGenerator()->matchScales(
							 child(0)->getValueId(),
							 *new_type);
	    }
	  }

      type_op1 = (NAType *)(&(child(0)->getValueId().getType()));
      type_op2 = (NAType *)(&(child(1)->getValueId().getType()));

      if (result_type->getFSDatatype() == type_op1->getFSDatatype())
	{
	  if (((getOperatorType() == ITM_PLUS) ||
	       (getOperatorType() == ITM_MINUS) ||
	       (getOperatorType() == ITM_DIVIDE)) &&
	      (result_type->getNominalSize() != type_op1->getNominalSize()))
	    {
	      child(0) = new(generator->wHeap()) Cast(child(0), result_type);
	    }
	}
      else
	{
	  if ((getOperatorType() == ITM_PLUS) ||
	      (getOperatorType() == ITM_MINUS) ||
	      (getOperatorType() == ITM_DIVIDE))
	    {
	      child(0) = new(generator->wHeap()) Cast(child(0), result_type);
	    }
	  else
	    {
	      child(0) =
	        new(generator->wHeap()) Cast(child(0),
	                 result_type->synthesizeType(SYNTH_RULE_PASS_THRU_NUM,
                                                     *type_op1,
	                                             *result_type,
						     generator->wHeap()));
	    }
	}

      if (result_type->getFSDatatype() == type_op2->getFSDatatype())
	{
	  if (((getOperatorType() == ITM_PLUS) ||
	       (getOperatorType() == ITM_MINUS)) &&
	      (result_type->getNominalSize() != type_op2->getNominalSize()))
	    {
	      child(1) = new(generator->wHeap()) Cast(child(1), result_type);
	    }
	}
      else
	{
	  if ((getOperatorType() == ITM_PLUS) ||
	      (getOperatorType() == ITM_MINUS))
	    {
	      child(1) = new(generator->wHeap()) Cast(child(1), result_type);
	    }
	  else
	    {
	      child(1) =
	        new(generator->wHeap()) Cast(child(1),
	                 result_type->synthesizeType(SYNTH_RULE_PASS_THRU_NUM,
                                                     *type_op2,
	                                             *result_type,
						     generator->wHeap()));
	    }
	}

      child(0)->bindNode(generator->getBindWA());
      child(1)->bindNode(generator->getBindWA());

      child(0) = child(0)->preCodeGen(generator);
      if (! child(0).getPtr())
	return NULL;

      child(1) = child(1)->preCodeGen(generator);
      if (! child(1).getPtr())
	return NULL;

      markAsPreCodeGenned();

      return this;
    }

  // following is for simple types.
  SimpleType * attr_result = (SimpleType *)
    (ExpGenerator::convertNATypeToAttributes
     (getValueId().getType(), generator->wHeap()));
  SimpleType * attr_op1 = (SimpleType *)
    (ExpGenerator::convertNATypeToAttributes
     (child(0)->getValueId().getType(), generator->wHeap()));
  SimpleType * attr_op2 = (SimpleType *)
    (ExpGenerator::convertNATypeToAttributes
     (child(1)->getValueId().getType(), generator->wHeap()));

  // see if conversion needed before arithmetic operation could be done.

  Int32 matchScale = 0;
  if (result_type->getTypeQualifier() == NA_NUMERIC_TYPE)
    {
      // match scales
      if ((getOperatorType() == ITM_PLUS) ||
	  (getOperatorType() == ITM_MINUS))
	{
	  child(0) = generator->getExpGenerator()->matchScales(child(0)->getValueId(),
							       *result_type);

	  child(1) = generator->getExpGenerator()->matchScales(child(1)->getValueId(),
							       *result_type);
	}
      else
	if (getOperatorType() == ITM_DIVIDE)
	  {
	    // before doing the division, the numerator has to be upscaled.
	    // Lets find out how much.
	    // NS = numerator scale
	    // DS = denominator scale
	    // RS = result scale
	    // Upscale = (RS - NS) + DS
	    // Newscale = NS + Upscale = RS + DS

	    Lng32 newscale
	      = ((NumericType *)result_type)->getScale() +
		((NumericType *)type_op2)->getScale();

	    if (newscale != ((NumericType *)type_op1)->getScale()) {
	      NAType * new_type = result_type->newCopy(generator->wHeap());
	      ((NumericType *)new_type)->setScale(newscale);
	      child(0) = generator->getExpGenerator()->matchScales(
							 child(0)->getValueId(),
							 *new_type);
              matchScale = 1;
	    }
	  }
    }

  else if (result_type->getTypeQualifier() == NA_INTERVAL_TYPE) {
    switch (getOperatorType()) {
    case ITM_PLUS:
    case ITM_MINUS:
      if (type_op1->getTypeQualifier() == NA_DATETIME_TYPE) {
#pragma nowarn(1506)   // warning elimination
        Lng32 fp1 = ((DatetimeType *) type_op1)->getFractionPrecision();
#pragma warn(1506)  // warning elimination
#pragma nowarn(1506)   // warning elimination
        Lng32 fp2 = ((DatetimeType *) type_op2)->getFractionPrecision();
#pragma warn(1506)  // warning elimination
        if (fp1 < fp2) {
          child(0) = new(generator->wHeap()) Cast(child(0), type_op2);
          child(0)->bindNode(generator->getBindWA());
        } else if (fp1 > fp2) {
          child(1) = new(generator->wHeap()) Cast(child(1), type_op1);
          child(1)->bindNode(generator->getBindWA());
        }
      } else {
        child(0) = generator->getExpGenerator()->matchIntervalEndFields(
                                                   child(0)->getValueId(),
                                                   *result_type);
        child(1) = generator->getExpGenerator()->matchIntervalEndFields(
                                                   child(1)->getValueId(),
                                                   *result_type);
        child(0) = generator->getExpGenerator()->matchScales(
                                                   child(0)->getValueId(),
                                                   *result_type);
        child(1) = generator->getExpGenerator()->matchScales(
                                                   child(1)->getValueId(),
                                                   *result_type);
        type_op1 = (NAType *)(&(child(0)->getValueId().getType()));
        type_op2 = (NAType *)(&(child(1)->getValueId().getType()));
        if (result_type->getNominalSize() != type_op1->getNominalSize()) {
          child(0) = new(generator->wHeap()) Cast(child(0), result_type);
          child(0)->bindNode(generator->getBindWA());
        }
        if (result_type->getNominalSize() != type_op2->getNominalSize()) {
          child(1) = new(generator->wHeap()) Cast(child(1), result_type);
          child(1)->bindNode(generator->getBindWA());
        }
      }
      break;
    case ITM_TIMES: {
      //
      // Unfortunately, the multiply node may be the root ItemExpr node, and
      // we can't change the root ItemExpr node since its ValueId has already
      // been stored away in the parent RelExpr's ValueIdLists.  We'll have to
      // move the expression down, e.g.
      //
      //   *   <-- same root -->   *
      //  / \                     / \
      // I   N      becomes      I   1
      //                         |
      //                         *
      //                        / \
      //                       N   N
      //                       |
      //                       I
      //
      if (type_op1->getTypeQualifier() == NA_INTERVAL_TYPE)
        child(0) = generator->getExpGenerator()->convertIntervalToNumeric(
                                                   child(0)->getValueId());
      else
        child(1) = generator->getExpGenerator()->convertIntervalToNumeric(
                                                   child(1)->getValueId());
      char str[20];
      strcpy(str, "@A1 * @A2");
      child(0) = generator->getExpGenerator()->createExprTree(str, 0,
                                                              2,
                                                              child(0),
                                                              child(1));
      child(0)->bindNode(generator->getBindWA());
      child(0) = generator->getExpGenerator()->convertNumericToInterval(
                                                 child(0)->getValueId(),
                                                 *result_type);
      strcpy(str, "1");
      child(1) = generator->getExpGenerator()->createExprTree(str, CharInfo::ISO88591);
      child(1)->bindNode(generator->getBindWA());
      type_op2 = (NAType *)(&(child(1)->getValueId().getType()));
      if ((result_type->getNominalSize() != type_op2->getNominalSize()) ||
          (type_op2->getFSDatatype() != REC_BIN16_SIGNED)) {
        IntervalType *interval = (IntervalType *) result_type;
        const Int16 DisAmbiguate = 0;
        child(1) = new(generator->wHeap()) Cast(child(1),
                            new(generator->wHeap()) SQLNumeric(TRUE, /* signed */
#pragma nowarn(1506)   // warning elimination
                                           interval->getTotalPrecision(),
                                           0,
                                           DisAmbiguate, // added for 64bit proj.
                                           interval->supportsSQLnull()));
#pragma warn(1506)  // warning elimination
        child(1)->bindNode(generator->getBindWA());
      }
      break;
    }
    case ITM_DIVIDE: {
      //
      // Unfortunately, the divide node may be the root ItemExpr node, and
      // we can't change the root ItemExpr node since its ValueId has already
      // been stored away in the parent RelExpr's ValueIdLists.  We'll have to
      // move the expression down, e.g.
      //
      //  div  <-- same root -->  div
      //  / \                     / \
      // I   N      becomes      I   1
      //                         |
      //                        div
      //                        / \
      //                       N   N
      //                       |
      //                       I
      //
      child(0) = generator->getExpGenerator()->convertIntervalToNumeric(
                                                 child(0)->getValueId());
      char str[20];
      strcpy(str, "@A1 / @A2");
      child(0) = generator->getExpGenerator()->createExprTree(str, 0,
                                                              2,
                                                              child(0),
                                                              child(1));
      child(0)->bindNode(generator->getBindWA());
      child(0) = generator->getExpGenerator()->convertNumericToInterval(
                                                 child(0)->getValueId(),
                                                 *result_type);
      strcpy(str, "1");
      child(1) = generator->getExpGenerator()->createExprTree(str, CharInfo::ISO88591);
      child(1)->bindNode(generator->getBindWA());
      type_op2 = (NAType *)(&(child(1)->getValueId().getType()));
      if ((result_type->getNominalSize() != type_op2->getNominalSize()) ||
          (type_op2->getFSDatatype() != REC_BIN16_SIGNED)) {
        IntervalType *interval = (IntervalType *) result_type;
        const Int16 DisAmbiguate = 0;
        child(1) = new(generator->wHeap()) Cast(child(1),
                            new(generator->wHeap()) SQLNumeric(TRUE, /* signed */
#pragma nowarn(1506)   // warning elimination
                                           interval->getTotalPrecision(),
                                           0,
                                           DisAmbiguate, // added for 64bit proj.
                                           interval->supportsSQLnull()));
#pragma warn(1506)  // warning elimination
        child(1)->bindNode(generator->getBindWA());
      }
      break;
    }
    default:
      break;
    }
  } else if (result_type->getTypeQualifier() == NA_DATETIME_TYPE) {
    switch (getOperatorType()) {
    case ITM_PLUS:
    case ITM_MINUS: {
      if ((type_op1->getTypeQualifier() == NA_INTERVAL_TYPE) &&
          (((IntervalType*) type_op1)->getEndField() == REC_DATE_SECOND)) {
#pragma nowarn(1506)   // warning elimination
        Lng32 sourceScale = ((IntervalType *) type_op1)->getFractionPrecision();
        Lng32 targetScale = ((DatetimeType *) type_op2)->getFractionPrecision();
#pragma warn(1506)  // warning elimination
        child(0) = generator->getExpGenerator()->scaleBy10x(
                                                   child(0)->getValueId(),
                                                   targetScale - sourceScale);
      } else if ((type_op2->getTypeQualifier() == NA_INTERVAL_TYPE) &&
                 (((IntervalType*) type_op2)->getEndField() == REC_DATE_SECOND)) {
#pragma nowarn(1506)   // warning elimination
        Lng32 targetScale = ((DatetimeType *) type_op1)->getFractionPrecision();
        Lng32 sourceScale = ((IntervalType *) type_op2)->getFractionPrecision();
#pragma warn(1506)  // warning elimination
        child(1) = generator->getExpGenerator()->scaleBy10x(
                                                   child(1)->getValueId(),
                                                   targetScale - sourceScale);
      }

      // Extend the datetime to contain a YEAR field if needed.  The
      // value will need to be extended if it contains a DAY field but
      // does not already contain a YEAR field.  This is necessary
      // since with the introduction of non-standard SQL/MP datetime
      // types, it is possible to have a datetime value which has a
      // DAY field but not a YEAR or not a MONTH field.  In this
      // situation, it is not possible to define a meaningful way to
      // do the operation.  Does the DAY field wrap at 30, 31, 28, or
      // 29.  So to make this operation meaningful, the value is
      // extended to the current timestamp.
      //
      if (type_op1->getTypeQualifier() == NA_DATETIME_TYPE) {
        if(((DatetimeType *) type_op1)->containsField(REC_DATE_DAY) &&
           ! ((DatetimeType *) type_op1)->containsField(REC_DATE_YEAR)) {

          // Need to extend the given datetime value in order to be
          // able to do the operation.  Extend the value out to the
          // YEAR field.
          //
          DatetimeType *extendedType =
            DatetimeType::constructSubtype(type_op1->supportsSQLnull(),
                                           REC_DATE_YEAR,
                                           ((DatetimeType *)type_op1)->getEndField(),
                                           ((DatetimeType *)type_op1)->getFractionPrecision(),
                                           generator->wHeap());

          // Cast the given value to the extended type.
          //
          child(0) = new (generator->wHeap()) Cast(child(0), extendedType);
          child(0)->bindNode(generator->getBindWA());
        }
      } else {
        if(((DatetimeType *) type_op2)->containsField(REC_DATE_DAY) &&
           ! ((DatetimeType *) type_op2)->containsField(REC_DATE_YEAR)) {

          // Need to extend the given datetime value in order to be
          // able to do the operation.  Extend the value out to the
          // YEAR field.
          //
          DatetimeType *extendedType =
            DatetimeType::constructSubtype(type_op2->supportsSQLnull(),
                                           REC_DATE_YEAR,
                                           ((DatetimeType *)type_op2)->getEndField(),
                                           ((DatetimeType *)type_op2)->getFractionPrecision(),
                                           generator->wHeap());

          // Cast the given value to the extended type.
          //
          child(1) = new (generator->wHeap()) Cast(child(1), extendedType);
          child(1)->bindNode(generator->getBindWA());
        }
      }

      break;
    }
    default:
      break;
    }
  }

  // NABoolean convertRoundedDivResult = FALSE;

  // If this arith operation is supported at runtime, then no
  // conversion is needed. Done for result numeric type only.
  if (result_type->getTypeQualifier() == NA_NUMERIC_TYPE)
    {
      child(0) = child(0)->preCodeGen(generator);
      if (! child(0).getPtr())
	return NULL;

      child(1) = child(1)->preCodeGen(generator);
      if (! child(1).getPtr())
	return NULL;

      attr_result = (SimpleType *)
	(ExpGenerator::convertNATypeToAttributes
	 (getValueId().getType(), generator->wHeap()));
      attr_op1 = (SimpleType *)
	(ExpGenerator::convertNATypeToAttributes
	 (child(0)->getValueId().getType(), generator->wHeap()));
      attr_op2 = (SimpleType *)
	(ExpGenerator::convertNATypeToAttributes
	 (child(1)->getValueId().getType(), generator->wHeap()));

      ex_arith_clause temp_clause(getOperatorType(), NULL, NULL, 
				  getRoundingMode(), getDivToDownscale());
      if (temp_clause.isArithSupported(getOperatorType(),
				       attr_op1,
				       attr_op2,
				       attr_result
				       ))
	{
	  markAsPreCodeGenned();

	  return this;
	}
    }

  // if the datatype or lengths of child and this don't match, then
  // conversion is needed.
  type_op1 = (NAType *)(&(child(0)->getValueId().getType()));
  type_op2 = (NAType *)(&(child(1)->getValueId().getType()));
  if ((result_type->getTypeQualifier() != NA_INTERVAL_TYPE) &&
      (result_type->getTypeQualifier() != NA_DATETIME_TYPE) &&
      ((result_type->getFSDatatype() != type_op1->getFSDatatype()) ||
       (result_type->getNominalSize() != type_op1->getNominalSize())))
    {
      // If the result type is not a float, make sure that the following
      // Cast does not scale (for floats we have do do scaling). This is
      // done by using the result type but changing the scale to the scale
      // of the operand
      NAType * new_type = result_type->newCopy(generator->wHeap());
      if ((result_type->getFSDatatype() < REC_MIN_FLOAT) ||
	  (result_type->getFSDatatype() > REC_MAX_FLOAT)) {
	((NumericType *)new_type)->
	  setScale(((NumericType *)type_op1)->getScale());
      };
      child(0) = new(generator->wHeap()) Cast(child(0), new_type,
					      ITM_CAST, FALSE);
    }

  if ((result_type->getTypeQualifier() != NA_INTERVAL_TYPE) &&
      (result_type->getTypeQualifier() != NA_DATETIME_TYPE) &&
      ((result_type->getFSDatatype() != type_op2->getFSDatatype()) ||
       (result_type->getNominalSize() != type_op2->getNominalSize())))
    {
      NAType * new_type = result_type->newCopy(generator->wHeap());
      if ((result_type->getFSDatatype() < REC_MIN_FLOAT) ||
	  (result_type->getFSDatatype() > REC_MAX_FLOAT) ||
           matchScale)
      {
	((NumericType *)new_type)->
	  setScale(((NumericType *)type_op2)->getScale());
      };
      child(1) = new(generator->wHeap()) Cast(child(1), new_type,
					      ITM_CAST, FALSE);
    }

  child(0)->bindNode(generator->getBindWA());
  child(1)->bindNode(generator->getBindWA());

  child(0) = child(0)->preCodeGen(generator);
  if (! child(0).getPtr())
     return NULL;

  child(1) = child(1)->preCodeGen(generator);
  if (! child(1).getPtr())
     return NULL;

  markAsPreCodeGenned();

  return this;
} // BiArith::preCodeGen()

ItemExpr * BiLogic::preCodeGen(Generator * generator)
{
  if (nodeIsPreCodeGenned())
    return this;

  if (! ItemExpr::preCodeGen(generator))
    return NULL;

  ItemExpr *result = this;
  ItemExpr *INlhs = NULL;
  if (CmpCommon::getDefault(OR_PRED_ADD_BLOCK_TO_IN_LIST) == DF_ON 
      && createdFromINlist() && (INlhs=getINlhs())!=NULL)
    {
      // ItmBlockFunction serves like the "C/C++ comma" expression that
      // 1) evaluates its 1st operand, 2nd operand, and
      // 2) returns its 2nd operand as value of that expression.
      // ItmBlockFunction also has the codegen property that
      //   its 1st operand is evaluated (codegen'ed) only once
      //   even if 1st operand occurs multiple times in 2nd operand.
      // So, given "UPPER(n) IN ('a', 'b')" that has been converted to
      //     ItmBlockFunction
      //     /               \
      //    U                 OR
      //                    /    \
      //                  =        =
      //                /   \    /   \
      //               U     a  U     b
      // "UPPER(n)", represented as U, is evaluated once even if 
      // it's used multiple times in the OR expression.

      // Trying to add ItmBlockFunction early in the parser (ie, in
      // sqlparseraux.cpp convertINvaluesToOR() causes a lot of grief
      // especially in cardinality estimation code. So, we resort to
      // doing it late, here in precodegen.
      result = new(generator->wHeap()) ItmBlockFunction(INlhs, result);
      result->synthTypeAndValueId();
      result->markAsPreCodeGenned();
      return result;
    }

  markAsPreCodeGenned();
  return result;
}

ItemExpr * BiRelat::preCodeGen(Generator * generator)
{
  if (nodeIsPreCodeGenned())
    return this;

  // transform multivalue predicates to single-value comparisons.
  ItemExpr * newNode = transformMultiValuePredicate();
  if (newNode)
    {
      #ifdef _DEBUG
      // NAString unp;
      // unparse(unp);
      // cerr << "BiRelat::preCodeGen - " << unp << " needed to be transformed!"
      //    << endl;
      // I don't think we should ever have an untransformed MVP at this stage!
      #endif

      // transformMultiValuePredicate() cannot do synthTypeAndValue()
      // because it is also called from the normalizer in places
      // where it needs to postpone it.
      newNode->synthTypeAndValueId();
      return newNode->preCodeGen(generator);
    }

  if (! ItemExpr::preCodeGen(generator))
    return NULL;

  NAType * type_op1 = (NAType *)(&(child(0)->getValueId().getType()));
  NAType * type_op2 = (NAType *)(&(child(1)->getValueId().getType()));

  if ((type_op1->isComplexType()) || (type_op2->isComplexType()))
    {
      // find the 'super' type
      const NAType *result_type = type_op1->synthesizeType(SYNTH_RULE_UNION,
                                                           *type_op1,
                                                           *type_op2,
							   generator->wHeap());
      CMPASSERT(result_type);
      if (result_type->getTypeQualifier() == NA_NUMERIC_TYPE)
	{
	  // match scales
	  child(0) = generator->getExpGenerator()->matchScales(child(0)->getValueId(),
							       *result_type);

	  child(1) = generator->getExpGenerator()->matchScales(child(1)->getValueId(),
							       *result_type);
	}

      type_op1 = (NAType *)(&(child(0)->getValueId().getType()));
      type_op2 = (NAType *)(&(child(1)->getValueId().getType()));

      if ((result_type->getFSDatatype() != type_op1->getFSDatatype()) ||
	  (result_type->getNominalSize() != type_op1->getNominalSize()))
	{
	  child(0) = new(generator->wHeap()) Cast(child(0), result_type);
	}

      if ((result_type->getFSDatatype() != type_op2->getFSDatatype()) ||
	  (result_type->getNominalSize() != type_op2->getNominalSize()))
	{
	  child(1) = new(generator->wHeap()) Cast(child(1), result_type);
	}

      child(0)->bindNode(generator->getBindWA());
      child(1)->bindNode(generator->getBindWA());

      child(0) = child(0)->preCodeGen(generator);
      if (! child(0).getPtr())
	return NULL;

      child(1) = child(1)->preCodeGen(generator);
      if (! child(1).getPtr())
	return NULL;

      markAsPreCodeGenned();

      return this;
    }

  const NAType &type1A =
    child(0)->castToItemExpr()->getValueId().getType();
  const NAType &type2A =
    child(1)->castToItemExpr()->getValueId().getType();

  if ((type1A.getTypeQualifier() == NA_CHARACTER_TYPE) &&
      (type2A.getTypeQualifier() == NA_CHARACTER_TYPE))
    {
      const CharType &cType1A = (CharType&)type1A;
      const CharType &cType2A = (CharType&)type2A;
      
      CharInfo::Collation cType1A_coll = cType1A.getCollation();
      CharInfo::Collation cType2A_coll = cType2A.getCollation();

      //
      // When Implicit Casting And Translation feature is enabled, it is
      // possible for the binder to allow a comparision between an ISO88591-type
      // value and a UCS2-type value to be passed through to the generator.
      // If that happens, we throw in a Translate node at this point.
      //
      CharInfo::CharSet cType1A_CS  = cType1A.getCharSet() ;
      CharInfo::CharSet cType2A_CS = cType2A.getCharSet() ;

      if ( ( cType1A_CS  != cType2A_CS )               &&
           ( cType1A_CS  != CharInfo::UnknownCharSet ) &&
           ( cType2A_CS != CharInfo::UnknownCharSet ) )
      {
         Int32 chld_to_trans = 0;
         if ( cType1A_CS != CharInfo::ISO88591 )
         {
            if ( (cType1A_CS == CharInfo::UNICODE) ) chld_to_trans = 1;
            if ( (cType1A_CS == CharInfo::UTF8) && (cType2A_CS != CharInfo::UNICODE) ) chld_to_trans = 1;
            if ( (cType1A_CS == CharInfo::SJIS) && (cType2A_CS == CharInfo::ISO88591) ) chld_to_trans = 1;
         }
         Int32 tran_type = Translate::UNKNOWN_TRANSLATION;
         if ( chld_to_trans == 0 )
             tran_type = find_translate_type( cType1A_CS, cType2A_CS );
         else
             tran_type = find_translate_type( cType2A_CS, cType1A_CS );

	 ItemExpr * newChild = NULL;
         newChild = new (generator->wHeap()) Translate(child(chld_to_trans), tran_type);
         newChild = newChild->bindNode(generator->getBindWA());
         newChild = newChild->preCodeGen(generator);
         if (! newChild)
            return NULL;
         setChild(chld_to_trans, newChild);
      }
      else if ( cType1A_coll != cType2A_coll &&
                cType1A_CS == CharInfo::ISO88591 &&
                cType1A_CS == cType2A_CS &&
                child(1)->getOperatorType() == ITM_CONSTANT &&
                CollationInfo::isSystemCollation(cType1A_coll))
      {
         ItemExpr * pNewChild2 = NULL;
         NAType * pNewType2 = cType2A.newCopy(generator->wHeap());
         CharType * pNewCType2 = NULL;
         if (pNewType2 != NULL)
           pNewCType2 = (CharType*)pNewType2;
         if (pNewCType2 != NULL)
           pNewCType2->setCollation(cType1A_coll);
         pNewChild2 = new (generator->wHeap()) Cast(child(1), pNewCType2);
         pNewChild2 = pNewChild2->bindNode(generator->getBindWA());
         pNewChild2 = pNewChild2->preCodeGen(generator);
         if (pNewChild2 == NULL)
            return NULL;
         setChild(1, pNewChild2);
      }
      // Regenerate the types...before we continue with rest of code
      type_op1 = (NAType *)(&(child(0)->getValueId().getType()));
      type_op2 = (NAType *)(&(child(1)->getValueId().getType()));

      ItemExpr * pChild1 = child(1)->castToItemExpr();
      const NAType &type1 = pChild1->getValueId().getType();
      const CharType &cType1 = (CharType&)type1;

      ItemExpr * pChild2 = child(1)->castToItemExpr();
      const NAType &type2 = pChild2->getValueId().getType();
      const CharType &cType2 = (CharType&)type2;

      CharInfo::Collation coll1 = cType1.getCollation();
      CharInfo::Collation coll2 = cType2.getCollation();

      CMPASSERT(coll1==coll2);

//LCOV_EXCL_START : cnu - Should not count in Code Coverage until we support non-binary collation in SQ
	  if (CollationInfo::isSystemCollation(coll1))
	  {
	    setCollationEncodeComp(TRUE);

	    {

	      ItemExpr * newIe1 = child(0);
	      ItemExpr * newIe2 = child(1);
	      
	      if (! (cType1 == cType2)) 
	      {

		NAType *resultType ;
		Lng32 len = MAXOF(cType1.getMaxLenInBytesOrNAWChars(), cType2.getMaxLenInBytesOrNAWChars());
		Lng32 Prec= MAXOF(cType1.getStrCharLimit(), cType2.getStrCharLimit());
        	     
		if (len != cType1.getMaxLenInBytesOrNAWChars()) 
		{
		  if (DFS2REC::isAnyVarChar(cType1.getFSDatatype()))
		  {
		    resultType = new (generator->wHeap())
		      SQLVarChar( CharLenInfo(Prec, len),
				  cType1.supportsSQLnull(), 
				  cType1.isUpshifted(),
				  cType1.isCaseinsensitive(),
				  cType1.getCharSet(),
				  cType1.getCollation(),
				  cType1.getCoercibility()
				 );
		  }
		  else
		  {
		    resultType = new (generator->wHeap())
		      SQLChar( CharLenInfo(Prec, len),
				  cType1.supportsSQLnull(), 
				  cType1.isUpshifted(),
				  cType1.isCaseinsensitive(),
				  FALSE,
				  cType1.getCharSet(),
				  cType1.getCollation(),
				  cType1.getCoercibility()
				 );
		  }

		  newIe1 = new(generator->wHeap()) Cast(newIe1,resultType);
		}

		if (len != cType2.getMaxLenInBytesOrNAWChars()) 
		{
		  if (DFS2REC::isAnyVarChar(cType2.getFSDatatype()))
		  {
		    resultType = new (generator->wHeap())
		      SQLVarChar( CharLenInfo(Prec, len),
				  cType2.supportsSQLnull(), 
				  cType2.isUpshifted(),
				  cType2.isCaseinsensitive(),
				  cType2.getCharSet(),
				  cType2.getCollation(),
				  cType2.getCoercibility()
				 );
		  }
		  else
		  {
		    resultType = new (generator->wHeap())
		      SQLChar( CharLenInfo(Prec, len),
				  cType2.supportsSQLnull(), 
				  cType2.isUpshifted(),
				  cType2.isCaseinsensitive(),
				  FALSE,
				  cType2.getCharSet(),
				  cType2.getCollation(),
				  cType2.getCoercibility()
				 );
		  }

		  newIe2 = new(generator->wHeap()) Cast(newIe2,resultType);
		}
	      }

	      ItemExpr * newEncode;
	      
	      newEncode = 
		    new(generator->wHeap()) 
		    CompEncode(newIe1,FALSE, -1, CollationInfo::Compare);

	      newEncode->bindNode(generator->getBindWA());
	      newEncode = newEncode->preCodeGen(generator);
	      if (!newEncode)
		return NULL;
	      setChild(0, newEncode);


	      newEncode = 
		    new(generator->wHeap()) 
		    CompEncode(newIe2, FALSE, -1,CollationInfo::Compare);

	      newEncode->bindNode(generator->getBindWA());
	      newEncode = newEncode->preCodeGen(generator);
	      if (!newEncode)
		return NULL;
	      setChild(1, newEncode);
	    }

	  }
//LCOV_EXCL_STOP : cnu - Should not count in Code Coverage until we support non-binary collation in SQ
	  else
	  {
	     // update both operands if case insensitive comparions
	     // are to be done.

	    NABoolean doCIcomp =
	      ((cType1.isCaseinsensitive()) && (cType2.isCaseinsensitive()));

	    ItemExpr * newChild = NULL;
	    if ((doCIcomp) &&
		(NOT cType1.isUpshifted()))
	      {
		newChild = child(0);

		// Add UPPER except if it is NULL constant value.
		if (newChild->getOperatorType() != ITM_CONSTANT || !((ConstValue *)newChild)->isNull())
		    newChild = new (generator->wHeap()) Upper(newChild);

		newChild = newChild->bindNode(generator->getBindWA());
		if (! newChild || generator->getBindWA()->errStatus())
		  return NULL;

		newChild = newChild->preCodeGen(generator);
		if (! newChild)
		  return NULL;

		setChild(0, newChild);
	      }

	    if ((doCIcomp) &&
		(NOT cType2.isUpshifted()))
	      {
		newChild = child(1);

		// Add UPPER except if it is NULL constant value.
		if (newChild->getOperatorType() != ITM_CONSTANT || !((ConstValue *)newChild)->isNull())
		    newChild = new (generator->wHeap()) Upper(newChild);

		newChild = newChild->bindNode(generator->getBindWA());
		if (! newChild || generator->getBindWA()->errStatus())
		  return NULL;

		newChild = newChild->preCodeGen(generator);
		if (! newChild)
		  return NULL;

		setChild(1, newChild);
	      }
	    }
	  }


  // following is for simple types.

  SimpleType * attr_op1 = (SimpleType *)
    (ExpGenerator::convertNATypeToAttributes(
	 child(0)->getValueId().getType(), generator->wHeap()));
  SimpleType * attr_op2 = (SimpleType *)
    (ExpGenerator::convertNATypeToAttributes(
	 child(1)->getValueId().getType(), generator->wHeap()));

  ex_comp_clause temp_clause;

  temp_clause.set_case_index(getOperatorType(),
			     attr_op1,
			     attr_op2
			     );
  if (temp_clause.get_case_index() != ex_comp_clause::COMP_NOT_SUPPORTED)
    {
      NABoolean doConstFolding = FALSE;
      if ((temp_clause.get_case_index() == ex_comp_clause::ASCII_COMP) &&
	  (CmpCommon::getDefault(CONSTANT_FOLDING) == DF_ON))
	{
	  if (((child(0)->getOperatorType() == ITM_CONSTANT) &&
	       (child(1)->getOperatorType() != ITM_CONSTANT)) ||
	      ((child(1)->getOperatorType() == ITM_CONSTANT) &&
	       (child(0)->getOperatorType() != ITM_CONSTANT)) &&
	      (type_op1->getFSDatatype() == REC_BYTE_F_ASCII) &&
	      (type_op2->getFSDatatype() == REC_BYTE_F_ASCII))
	    {
	      if (((child(0)->getOperatorType() == ITM_CONSTANT) &&
		   (type_op1->getNominalSize() < type_op2->getNominalSize())) ||
		  ((child(1)->getOperatorType() == ITM_CONSTANT) &&
		   (type_op2->getNominalSize() < type_op1->getNominalSize())))
		{
		  doConstFolding = TRUE;
		}
	    }
	}

      if (NOT doConstFolding)
	{
	  markAsPreCodeGenned();

	  return this;
	}
    }

  // conversion needed before comparison could be done.

  // find the 'super' type
  UInt32 flags =
            ((CmpCommon::getDefault(LIMIT_MAX_NUMERIC_PRECISION) == DF_ON)
            ? NAType::LIMIT_MAX_NUMERIC_PRECISION : 0);

  const NAType *result_type = type_op1->synthesizeType(SYNTH_RULE_UNION,
                                                       *type_op1,
                                                       *type_op2,
						       generator->wHeap(),
                                          &flags);
  CMPASSERT(result_type);
  if (result_type->getTypeQualifier() == NA_NUMERIC_TYPE)
    {
      // match scales
      child(0) = generator->getExpGenerator()->matchScales(child(0)->getValueId(),
							   *result_type);
      child(1) = generator->getExpGenerator()->matchScales(child(1)->getValueId(),
							   *result_type);
    }
  else if (result_type->getTypeQualifier() == NA_DATETIME_TYPE) {
#pragma nowarn(1506)   // warning elimination
    Lng32 fp1 = ((DatetimeType *) type_op1)->getFractionPrecision();
#pragma warn(1506)  // warning elimination
#pragma nowarn(1506)   // warning elimination
    Lng32 fp2 = ((DatetimeType *) type_op2)->getFractionPrecision();
#pragma warn(1506)  // warning elimination
#pragma nowarn(1506)   // warning elimination
    Lng32 fpResult = ((DatetimeType *) result_type)->getFractionPrecision();
#pragma warn(1506)  // warning elimination
    if (fp1 != fpResult) {
      child(0) = new(generator->wHeap()) Cast(child(0), result_type,
					      ITM_CAST, FALSE);
      child(0)->bindNode(generator->getBindWA());
    }
    if (fp2 != fpResult) {
      child(1) = new(generator->wHeap()) Cast(child(1), result_type,
					      ITM_CAST, FALSE);
      child(1)->bindNode(generator->getBindWA());
    }
  } else if (result_type->getTypeQualifier() == NA_INTERVAL_TYPE) {
    child(0) = generator->getExpGenerator()->matchIntervalEndFields(
                                               child(0)->getValueId(),
                                               *result_type);
    child(1) = generator->getExpGenerator()->matchIntervalEndFields(
                                               child(1)->getValueId(),
                                               *result_type);
    child(0) = generator->getExpGenerator()->matchScales(
                                               child(0)->getValueId(),
                                               *result_type);
    child(1) = generator->getExpGenerator()->matchScales(
                                               child(1)->getValueId(),
                                               *result_type);
    type_op1 = (NAType *)(&(child(0)->getValueId().getType()));
    type_op2 = (NAType *)(&(child(1)->getValueId().getType()));
    if (result_type->getNominalSize() != type_op1->getNominalSize()) {
      child(0) = new(generator->wHeap()) Cast(child(0), result_type,
					      ITM_CAST, FALSE);
      child(0)->bindNode(generator->getBindWA());
    }
    if (result_type->getNominalSize() != type_op2->getNominalSize()) {
      child(1) = new(generator->wHeap()) Cast(child(1), result_type,
					      ITM_CAST, FALSE);
      child(1)->bindNode(generator->getBindWA());
    }
  }

  // if the datatype or lengths of child and this don't match, then
  // conversion is needed.
  type_op1 = (NAType *)(&(child(0)->getValueId().getType()));
  type_op2 = (NAType *)(&(child(1)->getValueId().getType()));
  if ((result_type->getTypeQualifier() != NA_INTERVAL_TYPE) &&
      ((result_type->getFSDatatype() != type_op1->getFSDatatype()) ||
       (result_type->getNominalSize() != type_op1->getNominalSize())))
    {
      child(0) = new(generator->wHeap()) Cast(child(0), result_type,
					      ITM_CAST, FALSE);
    }

  if ((result_type->getTypeQualifier() != NA_INTERVAL_TYPE) &&
      ((result_type->getFSDatatype() != type_op2->getFSDatatype()) ||
       (result_type->getNominalSize() != type_op2->getNominalSize())))
    {
      child(1) = new(generator->wHeap()) Cast(child(1), result_type,
					      ITM_CAST, FALSE);
    }

  // bind/type propagate the new nodes
  child(0)->bindNode(generator->getBindWA());
  child(1)->bindNode(generator->getBindWA());

  child(0) = child(0)->preCodeGen(generator);
  if (! child(0).getPtr())
     return NULL;

  child(1) = child(1)->preCodeGen(generator);
  if (! child(1).getPtr())
     return NULL;

  ItemExpr *outExpr = NULL;
  Lng32 rc = generator->getExpGenerator()->foldConstants(child(0), &outExpr);
  if ((rc == 0) &&
      (outExpr))
    {
      child(0) = outExpr->preCodeGen(generator);
    }

  rc = generator->getExpGenerator()->foldConstants(child(1), &outExpr);
  if ((rc == 0) &&
      (outExpr))
    {
      child(1) = outExpr->preCodeGen(generator);
    }

  markAsPreCodeGenned();

  return this;
} // BiRelat::preCodeGen()

ItemExpr * Assign::preCodeGen(Generator * generator)
{
  if (nodeIsPreCodeGenned())
    return this;

  child(1) = generator->getExpGenerator()->matchIntervalEndFields(
                                             child(1)->getValueId(),
                                             getValueId().getType());
  child(1) = generator->getExpGenerator()->matchScales(child(1)->getValueId(),
					     getValueId().getType());
  child(1)->bindNode(generator->getBindWA());
  child(1) =  child(1)->preCodeGen(generator);
  if (! child(1).getPtr())
    return NULL;

  markAsPreCodeGenned();

  return this;
} // Assign::preCodeGen()

ItemExpr * BaseColumn::preCodeGen(Generator * generator)
{
  if (nodeIsPreCodeGenned())
    return this;

  ItemExpr * i = convertExternalType(generator);
  if (i == NULL)
    return NULL;

  return i;
}

ItemExpr * BitOperFunc::preCodeGen(Generator * generator)
{
  if (nodeIsPreCodeGenned())
    return this;

  if (getOperatorType() == ITM_BITEXTRACT)
    {
      // convert 2nd and 3rd operands to Int32 signed.
      for (Int32 i = 1; i < getArity(); i++)
	{
	  const NAType &typ = child(i)->getValueId().getType();
       
	  if (typ.getFSDatatype() != REC_BIN32_UNSIGNED)
	    {
	      ItemExpr * newChild =
		new (generator->wHeap()) 
		Cast(child(i), 
		     new (generator->wHeap()) SQLInt(FALSE,
						 typ.supportsSQLnullLogical()));
	      setChild(i, newChild);	

	      child(i)->bindNode(generator->getBindWA());
	      
	      child(i) = child(i)->preCodeGen(generator);
	      if (! child(i).getPtr())
		return NULL;  
	    } // if
	} // for
    }
  else
    {
      for (Int32 i = 0; i < getArity(); i++)
	{
	  const NAType &typ = child(i)->getValueId().getType();
	  
	  if (NOT (getValueId().getType() == typ))
	    {
	      NAType *resultType = 
		getValueId().getType().newCopy(generator->wHeap());
	      
	      ItemExpr * newChild =
		new (generator->wHeap()) Cast(child(i), resultType);
	      setChild(i, newChild);
	    }
	  
	  child(i)->bindNode(generator->getBindWA());
	  
	  child(i) = child(i)->preCodeGen(generator);
	  if (! child(i).getPtr())
	    return NULL;
	}
    }

  markAsPreCodeGenned();
  return this;
} // BitOperFunc::preCodeGen()

ItemExpr * Cast::preCodeGen(Generator * generator)
{
  if (nodeIsPreCodeGenned())
    return this;

  child(0)->bindNode(generator->getBindWA());
  child(0) = child(0)->preCodeGen(generator);

  if (! child(0).getPtr())
    return NULL;

  // if a special cast node, see if my child's data attributes are
  // the same as my data attributes. If they are, return pointer to
  // my child.
  if ((matchChildType()) &&
      (child(0)->getValueId().getType() == getValueId().getType()))
    {
      markAsPreCodeGenned();
      return child(0);
    }

  NABuiltInTypeEnum sourceTypeQual =
    child(0)->getValueId().getType().getTypeQualifier();
  NABuiltInTypeEnum targetTypeQual =
    getValueId().getType().getTypeQualifier();

  // If this is a NARROW operation, but it is not possible to result
  // in an error, no reason to use NARROW.  Convert the NARROW to the
  // equivalent CAST.
  if (getOperatorType() == ITM_NARROW)
    {
      const NAType * sourceType = &(child(0)->getValueId().getType());

      const NAType * targetType = &(getValueId().getType());

      if (!sourceType->errorsCanOccur(*targetType))
        {

          ItemExpr *c = new(generator->wHeap()) Cast(child(0), targetType);
          c->bindNode(generator->getBindWA());
          return c->preCodeGen(generator);
        
        }
    }

  // Conversion to/from a tandem float type is only supported if
  // the from/to type is a float type.
  // If target is a tandem float type and source is not float or
  // target is not float and source is tandem, then convert source
  // to ieee float type (ieee double).
  short srcFsType = child(0)->getValueId().getType().getFSDatatype();
  short tgtFsType = getValueId().getType().getFSDatatype();

  if ((((tgtFsType == REC_TDM_FLOAT32) ||
	(tgtFsType == REC_TDM_FLOAT64)) &&
       ! ((srcFsType >= REC_MIN_FLOAT) &&
	  (srcFsType <= REC_MAX_FLOAT))) ||

      (((srcFsType == REC_TDM_FLOAT32) ||
	(srcFsType == REC_TDM_FLOAT64)) &&
       ! ((tgtFsType >= REC_MIN_FLOAT) &&
	  (tgtFsType <= REC_MAX_FLOAT))))
    {
      NAType * intermediateType =
	new(generator->wHeap()) SQLDoublePrecision(
	     child(0)->getValueId().getType().supportsSQLnull(),
	     generator->wHeap());

      // Genesis case 10-040126-9823.
      // Match the scales of the source with that of the intermediate type. If
      // this is not done, the cast to the intermediate type does not get scaled
      // properly, leading to incorrect results.
      child(0) = generator->getExpGenerator()->matchScales(
        child(0)->getValueId(), *intermediateType);

      child(0) = new(generator->wHeap()) Cast(child(0),intermediateType);

      child(0)->bindNode(generator->getBindWA());

      sourceTypeQual =
	child(0)->getValueId().getType().getTypeQualifier();
    }

  if ((sourceTypeQual == NA_NUMERIC_TYPE) &&
      (targetTypeQual == NA_DATETIME_TYPE))
    {
      // binder has already verified that this is a valid conversion
      // in special1 mode.
      NumericType &sourceType =
      (NumericType &)(child(0)->getValueId().getType());
      DatetimeType &targetType =
	(DatetimeType &)(getValueId().getType());

      if (sourceType.getFSDatatype() != REC_BIN64_SIGNED)
	{
	  // doing a numeric to date conversion
	  // convert source to largeint.
	  ItemExpr * newChild =
	    new (generator->wHeap())
	    Cast(child(0),
		 new (generator->wHeap())
		 SQLLargeInt(TRUE,
			     child(0)->castToItemExpr()->
			     getValueId().getType().supportsSQLnull()));
	  newChild = newChild->bindNode(generator->getBindWA());
	  newChild = newChild->preCodeGen(generator);
	  if (! newChild)
	    return NULL;

	  setChild(0, newChild);
	}
    }

  if ((sourceTypeQual == NA_DATETIME_TYPE) &&
      (targetTypeQual == NA_NUMERIC_TYPE))
    {
      // binder has already verified that this is a valid conversion
      // in special1 mode.
      DatetimeType &sourceType =
      (DatetimeType &)(child(0)->getValueId().getType());
      NumericType &targetType =
	(NumericType &)(getValueId().getType());

      if (targetType.getFSDatatype() != REC_BIN64_SIGNED)
	{
	  // doing a date to numeric conversion.
	  // convert source to largeint.
	  ItemExpr * newChild =
	    new (generator->wHeap())
	    Cast(child(0),
		 new (generator->wHeap())
		 SQLLargeInt(TRUE,
			     child(0)->castToItemExpr()->
			     getValueId().getType().supportsSQLnull()));
	  newChild = newChild->bindNode(generator->getBindWA());
	  newChild = newChild->preCodeGen(generator);
	  if (! newChild)
	    return NULL;

	  setChild(0, newChild);
	}

    } // numeric to date conversion

  if ((sourceTypeQual == NA_DATETIME_TYPE) &&
      (targetTypeQual == NA_DATETIME_TYPE)) {
    DatetimeType &sourceType =
      (DatetimeType &)(child(0)->getValueId().getType());
    DatetimeType &targetType =
      (DatetimeType &)(getValueId().getType());

    if (targetType.getStartField() < sourceType.getStartField()) {
      // Must provide some fields from the current time stamp
      //

      // The following code generates the current timestamp as a
      // string and extracts the needed leading fields and appends to
      // this the given value (child(0)) as a string. The result is a
      // string which contains the given datetime value extended to
      // the YEAR field with the current timestamp.
      //
      // Buffer to hold new expression string.
      //
      char str[200];

      // Offset (in bytes) from the start of the current timestamp
      // (represented as a char. string) to the first field needed in
      // the extension.
      //
      // - Subtract 1 from the start field to make the value zero based.
      //
      // - Each field has a least 3 bytes (2 for the value and 1 for the
      //   delimiter)
      //
      // - Add 1, since the substring function is 1 based.
      //
      Int32 leadFieldsOffset = ((targetType.getStartField() - 1) * 3) + 1;

      // - Add 2 extra for the year field if it is being skiped over
      //   since it has 4 bytes of value.
      //
      if (leadFieldsOffset > 1)
        leadFieldsOffset += 2;

      // Size (in bytes) of the leading fields represented as a
      // character string taken from the current timestamp
      //
      // - Subtract 1 from the start field to make the value zero based.
      //
      // - Each field has a least 3 bytes (2 for the value and 1 for the
      //   delimiter)
      //
      // - Add 2 extra for the year field (which will always be one of
      //   the extended fields) since it has 4 bytes of value.
      //
      // - Subtract the leadFieldsOffset ( - 1 to make it zero based).
      //
      Int32 leadFieldsSize = ((((sourceType.getStartField() - 1) * 3) + 2)
                            - (leadFieldsOffset - 1));

      // Size (in bytes) of the source value represented as a
      // character string.
      //
#pragma nowarn(1506)   // warning elimination
      Int32 sourceFieldsSize = sourceType.getDisplayLength();
#pragma warn(1506)  // warning elimination

      // Construct an expression (string) to concatinate the given
      // value with the required fields from the current timestamp as
      // a string, then cast this string as a datetime value, that can
      // be cast to the desired result.
      //
      // Example :
      //
      // cast(DATETIME 'dd hh:mm:ss' DAY TO SECOND as DATETIME MONTH to MINUTE)
      //
      // current timestamp (as string)       | "YYYY-MM-DD HH:MM:SS.FFFFFF"
      //                                     |
      // leadFieldsOffset = ((2-1)*3)+1 +2 = |  --6--^
      //                                     |
      // leadFieldsSize = (((3-1)*3)+2) - 5 =|       ^3^
      //                                     |
      // result of substring(cts from 1 to 8)|      "MM-"
      //                                     |
      // value to be extended (as string)    |         "dd hh:mm:ss"
      //                                     |
      // result of string concat. (as string)|      "MM-dd hh:mm:ss"
      //                                     |
      // Cast to a datetime MONTH TO SECOND  |    Mdhms
      //                                     |
      // Original (this) cast to result      |    Mdhm
      //
      str_sprintf(str,
                  "CAST((SUBSTRING(CAST(CURRENT AS CHAR(19)) "
                  "FROM %d FOR %d) || CAST(@A1 AS CHAR(%d))) "
                  "AS DATETIME %s TO %s)",
                  leadFieldsOffset,
                  leadFieldsSize,
                  sourceFieldsSize,
                  targetType.getFieldName(targetType.getStartField()),
                  ((sourceType.getEndField() == REC_DATE_SECOND)
                   ? "FRACTION(6)"
                   : sourceType.getFieldName(sourceType.getEndField())));

      GenAssert(str_len(str) < 199,"Internal Datetime Error Cast::preCodeGen");

      ItemExpr * newExpr =
        generator->getExpGenerator()->createExprTree(str, 0,
                                                     1, child(0));
      newExpr->bindNode(generator->getBindWA());
      child(0) = newExpr->preCodeGen(generator);

    }

  }

  // Call matchScales only if both datatypes aren't intervals.
  // (We make the exception for intervals because Cast is able
  // to match the scales of intervals itself.)
  // Also, we suppress the call to matchScales() for a narrow.
  // This is because narrow will handle the scaling differently.
  // Conversions from float to bignum are also not scaled here. Scaling
  // is done in BigNum::castFrom method.
  if (NOT ((getOperatorType() == ITM_NARROW) ||
	   ((sourceTypeQual == NA_INTERVAL_TYPE) &&
	    (targetTypeQual == NA_INTERVAL_TYPE)) ||
	   ((DFS2REC::isFloat(srcFsType)) &&
	    (DFS2REC::isBigNum(tgtFsType)))))
    {
      child(0) = generator->getExpGenerator()->matchScales(
					    child(0)->getValueId(),
				            getValueId().getType());
      child(0) = child(0)->preCodeGen(generator);
      if (! child(0).getPtr())
	return NULL;
    }

  //  For a numeric NARROW, check if scaling is needed.
  if (targetTypeQual == NA_NUMERIC_TYPE &&
      getOperatorType() == ITM_NARROW)
    {
      GenAssert(sourceTypeQual == NA_NUMERIC_TYPE,
        "source type and target type incompatible in NARROW");

      const NumericType * sourceNumType
	= (const NumericType *)(&child(0)->getValueId().getType());
      const NumericType * targetNumType
	= (const NumericType *)(&getValueId().getType());

      if (sourceNumType->getScale() != targetNumType->getScale())
        {
          // We need to scale the value.  We don't want to use the
	  // usual scaling method of simply multiplying or dividing
	  // the result because we need to capture truncations
	  // and overflows at run time.  The Narrow operator supports
	  // scaling for the BigNum-to-any-numeric type case.
	  // Therefore, we first cast the value to BigNum,
	  // then narrow it down.
	  // Soln 10-041105-1519
          // Dont introduce the CAST operator if the target is already a BigNum
          // because NARROW does not support scaling for the BigNum-to-BigNum
          // case. Use the usual scaling method instead.
          if (targetNumType->isBigNum())
          {
            child(0) = generator->getExpGenerator()->matchScales(
              child(0)->getValueId(), *targetNumType);
          }
          else
          {
	    Lng32 intermediatePrecision = sourceNumType->getPrecision();
	    Lng32 intermediateScale = sourceNumType->getScale();

	    // SQLBigNum takes decimal precision, so if the source
	    // has binary precision, we need to adjust.

	    if (sourceNumType->binaryPrecision())
	      {

		// Can fit three binary digits in the space of one
		// decimal digit. The '+5' in the precision calculation
		// allows for an extra digit before and after the
		// radix point.

		intermediatePrecision = (intermediatePrecision+5)/3;
	      }

	    // If we need to cast an approximate, increase the length
	    // and scale so that the number can be represented now that
	    // it won't have an exponent.

	    // In each of the cases below, the formula used to calculate
	    // precision is:
	    //
	    // intermediatePrecision = 2 * <max exponent>
	    //    + <# significant digits in mantissa> + 1
	    //
	    // We use 2 * <max exponent> to take into account the
	    // maximum positive exponent as well as the maximum
	    // negative exponent.
	    //
	    // The formula used to calculate scale is:
	    //
	    // intermediateScale = <max exponent> +
	    //   <# significant digits in mantissa> - 1
	    //
	    // Here the exponent and digits are understood to be decimal,
	    // not binary.
	    //
	    // For the various kinds of floats we have:
	    //
	    // Kind         Max exponent   Decimal digits in Mantissa
	    // -----------  ------------   --------------------------
	    // IEEE 32 bit            38        7
	    // IEEE 64 bit           308       17
	    // Tandem 32 bit          78        7
	    // Tandem 64 bit          78       18

	    if (sourceNumType->getFSDatatype() == REC_IEEE_FLOAT32)
	      {
		intermediatePrecision = 84;  // (2 x 38) + 7 + 1 = 84
		intermediateScale = 44;   // 38 + 7 - 1 = 44
	      }

	    else if (sourceNumType->getFSDatatype() == REC_IEEE_FLOAT64)
	      {
		intermediatePrecision = 634; // (2 x 308) + 17 + 1 = 634
		intermediateScale = 324;  // 308 + 17 - 1 = 324
	      }

	    else if (sourceNumType->getFSDatatype() == REC_TDM_FLOAT32)
	      {
		intermediatePrecision = 164; // (2 x 78) + 7 + 1 = 164
		intermediateScale = 84;  // 78 + 7 - 1 = 84
	      }

	    else if (sourceNumType->getFSDatatype() == REC_TDM_FLOAT64)
	      {
		intermediatePrecision = 175; // (2 x 78) + 18 + 1 = 175
		intermediateScale = 95;  // 78 + 18 - 1 = 95
	      }

	    NAType * intermediateType =
	      new(generator->wHeap())
		SQLBigNum(intermediatePrecision,
			  intermediateScale,
			  (sourceNumType->isBigNum() &&
			   ((SQLBigNum*)sourceNumType)->isARealBigNum()),
			  TRUE, // make it signed
			  sourceNumType->supportsSQLnull(),
			  NULL);

	    child(0) = new(generator->wHeap()) Cast(child(0),intermediateType);

	    child(0)->bindNode(generator->getBindWA());

	    // To suppress insertion of multiplying/dividing, mark Cast as
	    // already pre-code-genned.

	    child(0)->markAsPreCodeGenned();
	  }
	}
    }

 
  if ((sourceTypeQual == NA_CHARACTER_TYPE) &&
      ((tgtFsType == REC_BLOB) ||
       (tgtFsType == REC_CLOB)))
    {
      LOBconvertHandle * lc = new(generator->wHeap())
	LOBconvertHandle(child(0), LOBoper::LOB_);

      lc->bindNode(generator->getBindWA());
      lc->preCodeGen(generator);
      
      child(0) = lc;
    }

  if (getArity() > 1)
    {
      child(1)->bindNode(generator->getBindWA());
      child(1) = child(1)->preCodeGen(generator);
      if (! child(1).getPtr())
	return NULL;
    }

  ItemExpr *result = this;

  markAsPreCodeGenned();
  return result;
} // Cast::preCodeGen()

ItemExpr * CharFunc::preCodeGen(Generator * generator)
{
  if (nodeIsPreCodeGenned())
    return this;

  const NAType &typ1 = child(0)->getValueId().getType();

  // Insert a cast node to convert child to an INT.
  child(0) = new (generator->wHeap())
    Cast(child(0), new (generator->wHeap()) SQLInt(FALSE,
						   typ1.supportsSQLnullLogical()));

  child(0)->bindNode(generator->getBindWA());

  child(0) = child(0)->preCodeGen(generator);
  if (! child(0).getPtr())
    return NULL;

  markAsPreCodeGenned();
  return this;
} // CharFunc::preCodeGen()

ItemExpr * CompEncode::preCodeGen(Generator * generator)
{
  if (nodeIsPreCodeGenned())
    return this;

  // during key encode expr generation, no need to convert external
  // column types(like tandem floats) to their internal
  // equivalent(ieee floats). Avoid doing preCodeGen in these cases.
  // Do this only for child leaf nodes (columns, hostvar, params, literals).
  //
  if (NOT (child(0)->getValueId().getType().isExternalType() &&
	   child(0)->getArity() == 0)) {
    child(0) = child(0)->preCodeGen(generator);
  }

  markAsPreCodeGenned();

  return this;
} // CompEncode::preCodeGen()

ItemExpr * CompDecode::preCodeGen(Generator * generator)
{
  if (nodeIsPreCodeGenned())
    return this;

  return CompEncode::preCodeGen(generator);

} // CompDecode::preCodeGen()

ItemExpr * Convert::preCodeGen(Generator * generator)
{
  if (nodeIsPreCodeGenned())
    return this;

  // Since this CONVERT will convert its child to the original
  // ExternalType, no need to ask it to first be cast to an internal
  // type.  So, do not call precodegen in these cases.
  // Do this only for child leaf nodes (columns, hostvar, params, literals).
  //
  if (NOT (child(0)->getValueId().getType().isExternalType() &&
	   child(0)->getArity() == 0)) {
    child(0) = child(0)->preCodeGen(generator);
  }

  markAsPreCodeGenned();

  return this;
} // Convert::preCodeGen()

ItemExpr * ConvertTimestamp::preCodeGen(Generator * generator)
{
  if (nodeIsPreCodeGenned())
    return this;
  //
  // If the operand is not a largeint with a scale of 0, convert it to one.
  //
  NumericType *numeric = (NumericType *)(&(child(0)->getValueId().getType()));
  if ((numeric->getFSDatatype() != REC_BIN64_SIGNED) ||
      (numeric->getScale() != 0)) {
    child(0) = new(generator->wHeap())
                 Cast(child(0),
                      new(generator->wHeap())
                        SQLLargeInt(TRUE, numeric->supportsSQLnull()));
    child(0)->bindNode(generator->getBindWA());
  }
  child(0) = child(0)->preCodeGen(generator);
  if (! child(0).getPtr())
    return NULL;

  markAsPreCodeGenned();
  return this;
} // ConvertTimestamp::preCodeGen()

ItemExpr * Extract::preCodeGen(Generator * generator)
{
  if (nodeIsPreCodeGenned())
    return this;
  //
  // If the operand is an interval and the extract field is not the end field,
  // convert the interval to the units of the extract field.
  // Set the dataconversionerror param to Cast so conversion error
  // (truncation) could be ignored at runtime.
  //
  NAType * type_op1 = (NAType *)(&(child(0)->getValueId().getType()));
  if ((type_op1->getTypeQualifier() == NA_INTERVAL_TYPE) &&
      (getExtractField() < ((IntervalType *) type_op1)->getEndField())) {
    IntervalType *interval = (IntervalType *) type_op1;
    ItemExpr *dataConvError = new(generator->wHeap()) ConstValue(1234567890);
    child(0) = new(generator->wHeap())
                 Cast(child(0), dataConvError,
                      new(generator->wHeap())
                        SQLInterval(interval->supportsSQLnull(),
                                    interval->getStartField(),
                                    interval->getLeadingPrecision(),
                                    getExtractField()),
		      ITM_NARROW);
    child(0)->bindNode(generator->getBindWA());
  }
  child(0) = child(0)->preCodeGen(generator);
  if (! child(0).getPtr())
    return NULL;

  markAsPreCodeGenned();
  return this;
} // Extract::preCodeGen()

ItemExpr * Format::preCodeGen(Generator * generator)
{
  return BuiltinFunction::preCodeGen(generator);
}

ItemExpr * JulianTimestamp::preCodeGen(Generator * generator)
{
  if (nodeIsPreCodeGenned())
    return this;
  //
  // If the operand is not a timestamp with a fractional precision of 6,
  // convert it to one.
  //
  DatetimeType *dt = (DatetimeType *)(&(child(0)->getValueId().getType()));
  if ((dt->getSubtype() != DatetimeType::SUBTYPE_SQLTimestamp) ||
      (dt->getFractionPrecision() != 6)) {
    child(0) = new(generator->wHeap())
                 Cast(child(0),
                      new(generator->wHeap())
                        SQLTimestamp(dt->supportsSQLnull(), 6));
    child(0)->bindNode(generator->getBindWA());
  }
  child(0) = child(0)->preCodeGen(generator);
  if (! child(0).getPtr())
    return NULL;
  markAsPreCodeGenned();
  return this;
} // JulianTimestamp::preCodeGen()

ItemExpr * Hash::preCodeGen(Generator * generator)
{
  if (nodeIsPreCodeGenned())
    return getReplacementExpr();

  ItemExpr *result = this;

  // ---------------------------------------------------------------------
  // In the optimizer, a hash function accepts a comma-separated list
  // of columns. In the executor, replace this with the HashComb of the hash
  // functions of the individual list elements. NOTE: once error handling
  // is in place we need to make sure that no errors are generated from
  // this.
  // ---------------------------------------------------------------------
  if (child(0)->getOperatorType() == ITM_ITEM_LIST)
    {
      // child is a multi-valued expression, transform into multiple
      // hash expressions
      ExprValueId treePtr = child(0);

      ItemExprTreeAsList hashValues(&treePtr,
				    ITM_ITEM_LIST,
				    LEFT_LINEAR_TREE);

      // this expression becomes the hash operator for the first
      // hash value
      child(0) = hashValues[0];

      const NAType &childType = child(0)->getValueId().getType();

      if(childType.getTypeQualifier() == NA_CHARACTER_TYPE) {

	const CharType &chType = (CharType&)childType;
	CharInfo::Collation coll = chType.getCollation();
	
//LCOV_EXCL_START : cnu - Should not count in Code Coverage until we support non-binary collation in SQ
	if (CollationInfo::isSystemCollation(coll))
	    {
	      child(0) = new(generator->wHeap()) 
		CompEncode(child(0),FALSE, -1, CollationInfo::Compare);
	      child(0) = child(0)->bindNode(generator->getBindWA());
	    }
//LCOV_EXCL_STOP : cnu - Should not count in Code Coverage until we support non-binary collation in SQ
	  else
	    {
	      //--------------------------
	      if ((chType.isCaseinsensitive()) &&
		  (NOT casesensitiveHash()) &&
		  (NOT chType.isUpshifted())) {
		child(0) = new (generator->wHeap()) Upper(child(0));
		child(0) = child(0)->bindNode(generator->getBindWA());
	      }
	    }
	  }

      // add hash expressions for all other hash values and HashComb
      // them together
      CollIndex nc = hashValues.entries();
      for (CollIndex i = 1; i < nc; i++)
	{
          ItemExpr *hi = hashValues[i];

	  const NAType &childType = hi->getValueId().getType();

	  if(childType.getTypeQualifier() == NA_CHARACTER_TYPE) {

	    const CharType &chType = (CharType&)childType;
	    CharInfo::Collation coll = chType.getCollation();
	    
//LCOV_EXCL_START : cnu - Should not count in Code Coverage until we support non-binary collation in SQ
            if (CollationInfo::isSystemCollation(coll))
	      {
		hi = new(generator->wHeap()) 
		    CompEncode(hi,FALSE, -1, CollationInfo::Compare);

		hi = hi->bindNode(generator->getBindWA());
	      }
//LCOV_EXCL_STOP : cnu - Should not count in Code Coverage until we support non-binary collation in SQ
	      else
	      {
		//-----------------------------
		if ((chType.isCaseinsensitive()) &&
		    (NOT casesensitiveHash()) &&
		    (NOT chType.isUpshifted())) {
		  hi = new (generator->wHeap()) Upper(hi);
		  hi = hi->bindNode(generator->getBindWA());
		}
		  //-----------------------
	      }
	  }

	  ItemExpr *hv = new(generator->wHeap()) Hash(hi);
	  result = new(generator->wHeap()) HashComb(result,hv);
	}

      result->bindNode(generator->getBindWA());
    } else {
      const NAType &childType = child(0)->getValueId().getType();

      if(childType.getTypeQualifier() == NA_CHARACTER_TYPE) {

	const CharType &chType = (CharType&)childType;
	CharInfo::Collation coll = chType.getCollation();
	
//LCOV_EXCL_START : cnu - Should not count in Code Coverage until we support non-binary collation in SQ
        if (CollationInfo::isSystemCollation(coll))
	  {
	    child(0) = new (generator->wHeap()) 
	      CompEncode(child(0), FALSE, -1, CollationInfo::Compare);
	    
	    child(0) = child(0)->bindNode(generator->getBindWA());
          }
//LCOV_EXCL_STOP : cnu - Should not count in Code Coverage until we support non-binary collation in SQ
	  else
	  {
	    if ((chType.isCaseinsensitive()) &&
		(NOT casesensitiveHash()) &&
		(NOT chType.isUpshifted())) {
	      child(0) = new (generator->wHeap()) Upper(child(0));
	      child(0) = child(0)->bindNode(generator->getBindWA());
	    }
          }

      }
    }

  // do generic tasks for pre-code generation (e.g. recurse to the children)
  setReplacementExpr(result->ItemExpr::preCodeGen(generator));
  markAsPreCodeGenned();
  return getReplacementExpr();
} // Hash::preCodeGen()

ItemExpr * HiveHash::preCodeGen(Generator * generator)
{
  if (nodeIsPreCodeGenned())
    return getReplacementExpr();

  ItemExpr *result = this;

  // ---------------------------------------------------------------------
  // In the optimizer, a hash function accepts a comma-separated list
  // of columns. In the executor, replace this with the HashComb of the hash
  // functions of the individual list elements. NOTE: once error handling
  // is in place we need to make sure that no errors are generated from
  // this.
  // ---------------------------------------------------------------------
  if (child(0)->getOperatorType() == ITM_ITEM_LIST)
    {
      // child is a multi-valued expression, transform into multiple
      // hash expressions
      ExprValueId treePtr = child(0);

      ItemExprTreeAsList hivehashValues(&treePtr,
				    ITM_ITEM_LIST,
				    LEFT_LINEAR_TREE);

      // this expression becomes the hash operator for the first
      // hash value
      child(0) = hivehashValues[0];

      const NAType &childType = child(0)->getValueId().getType();

      if(childType.getTypeQualifier() == NA_CHARACTER_TYPE) {

	const CharType &chType = (CharType&)childType;
	CharInfo::Collation coll = chType.getCollation();
	
//LCOV_EXCL_START : cnu - Should not count in Code Coverage until we support non-binary collation in SQ
	if (CollationInfo::isSystemCollation(coll))
	    {
	      child(0) = new(generator->wHeap()) 
		CompEncode(child(0),FALSE, -1, CollationInfo::Compare);
	      child(0) = child(0)->bindNode(generator->getBindWA());
	    }
//LCOV_EXCL_STOP : cnu - Should not count in Code Coverage until we support non-binary collation in SQ
	  else
	    {
	      //--------------------------
	      if ((chType.isCaseinsensitive()) &&
		  (NOT casesensitiveHash()) &&
		  (NOT chType.isUpshifted())) {
		child(0) = new (generator->wHeap()) Upper(child(0));
		child(0) = child(0)->bindNode(generator->getBindWA());
	      }
	    }
	  }

      // add hash expressions for all other hash values and HiveHashComb
      // them together
      CollIndex nc = hivehashValues.entries();
      for (CollIndex i = 1; i < nc; i++)
	{
          ItemExpr *hi = hivehashValues[i];

	  const NAType &childType = hi->getValueId().getType();

	  if(childType.getTypeQualifier() == NA_CHARACTER_TYPE) {

	    const CharType &chType = (CharType&)childType;
	    CharInfo::Collation coll = chType.getCollation();
	    
//LCOV_EXCL_START : cnu - Should not count in Code Coverage until we support non-binary collation in SQ
            if (CollationInfo::isSystemCollation(coll))
	      {
		hi = new(generator->wHeap()) 
		    CompEncode(hi,FALSE, -1, CollationInfo::Compare);

		hi = hi->bindNode(generator->getBindWA());
	      }
//LCOV_EXCL_STOP : cnu - Should not count in Code Coverage until we support non-binary collation in SQ
	      else
	      {
		//-----------------------------
		if ((chType.isCaseinsensitive()) &&
		    (NOT casesensitiveHash()) &&
		    (NOT chType.isUpshifted())) {
		  hi = new (generator->wHeap()) Upper(hi);
		  hi = hi->bindNode(generator->getBindWA());
		}
		  //-----------------------
	      }
	  }

	  ItemExpr *hv = new(generator->wHeap()) HiveHash(hi);
	  result = new(generator->wHeap()) HiveHashComb(result,hv);
	}

      result->bindNode(generator->getBindWA());
    } else {
      const NAType &childType = child(0)->getValueId().getType();

      if(childType.getTypeQualifier() == NA_CHARACTER_TYPE) {

	const CharType &chType = (CharType&)childType;
	CharInfo::Collation coll = chType.getCollation();
	
//LCOV_EXCL_START : cnu - Should not count in Code Coverage until we support non-binary collation in SQ
        if (CollationInfo::isSystemCollation(coll))
	  {
	    child(0) = new (generator->wHeap()) 
	      CompEncode(child(0), FALSE, -1, CollationInfo::Compare);
	    
	    child(0) = child(0)->bindNode(generator->getBindWA());
          }
//LCOV_EXCL_STOP : cnu - Should not count in Code Coverage until we support non-binary collation in SQ
	  else
	  {
	    if ((chType.isCaseinsensitive()) &&
		(NOT casesensitiveHash()) &&
		(NOT chType.isUpshifted())) {
	      child(0) = new (generator->wHeap()) Upper(child(0));
	      child(0) = child(0)->bindNode(generator->getBindWA());
	    }
          }

      }
    }

  // do generic tasks for pre-code generation (e.g. recurse to the children)
  setReplacementExpr(result->ItemExpr::preCodeGen(generator));
  markAsPreCodeGenned();
  return getReplacementExpr();
} // Hash::preCodeGen()

// --------------------------------------------------------------
// member functions for HashDistPartHash operator
// Hash Function used by Hash Partitioning. This function cannot change
// once Hash Partitioning is released!  Defined for all data types,
// returns a 32 bit non-nullable hash value for the data item.
//--------------------------------------------------------------


ItemExpr * HashDistPartHash::preCodeGen(Generator * generator)
{
  if (nodeIsPreCodeGenned())
    return getReplacementExpr();

  ItemExpr *result = this;

  // ---------------------------------------------------------------------
  // In the optimizer, a hash function accepts a comma-separated list
  // of columns. Replace this with the HashComb of the hash functions
  // of the individual list elements.
  // ---------------------------------------------------------------------
  if (child(0)->getOperatorType() == ITM_ITEM_LIST)
    {
      // child is a multi-valued expression, transform into multiple
      // hash expressions
      ExprValueId treePtr = child(0);

      ItemExprTreeAsList hashValues(&treePtr,
				    ITM_ITEM_LIST,
				    LEFT_LINEAR_TREE);

      // this expression becomes the hash operator for the first
      // hash value
      child(0) = hashValues[0];

      const NAType &childType = child(0)->getValueId().getType();

      if(childType.getTypeQualifier() == NA_CHARACTER_TYPE) {

	const CharType &chType = (CharType&)childType;
	
	CharInfo::Collation coll = chType.getCollation();

//LCOV_EXCL_START : cnu - Should not count in Code Coverage until we support non-binary collation in SQ
        if (CollationInfo::isSystemCollation(coll))
	  {
	    if (child(0)->getOperatorType() == ITM_NARROW)
	    {
	      ItemExpr* narrowsChild = child(0)->child(0);
	      const NAType &narrowsChildType= narrowsChild->getValueId().getType();
	      CMPASSERT(narrowsChildType.getTypeQualifier() == NA_CHARACTER_TYPE);
	      NAType *newType= narrowsChildType.newCopy(generator->wHeap());
	      CharType * newCharType = (CharType *) newType;
	      newCharType->setDataStorageSize(chType.getDataStorageSize());
  	    
	      child(0)->getValueId().changeType(newCharType);

	    }

	    child(0) = new(generator->wHeap()) 
			CompEncode(child(0),FALSE, -1, CollationInfo::Compare);

	    child(0) = child(0)->bindNode(generator->getBindWA());
	  }
//LCOV_EXCL_STOP : cnu - Should not count in Code Coverage until we support non-binary collation in SQ
	  else
	  {
	    if ((chType.isCaseinsensitive()) &&
		(NOT chType.isUpshifted())) {
	      child(0) = new (generator->wHeap()) Upper(child(0));
	      child(0) = child(0)->bindNode(generator->getBindWA());
	    }
	  }
      }

      // add hash expressions for all other hash values and HashComb
      // them together
      CollIndex nc = hashValues.entries();
      for (CollIndex i = 1; i < nc; i++)
	{
          ItemExpr *hi = hashValues[i];

	  const NAType &childType = hi->getValueId().getType();

	  if(childType.getTypeQualifier() == NA_CHARACTER_TYPE) {

	    const CharType &chType = (CharType&)childType;

	    CharInfo::Collation coll = chType.getCollation();

//LCOV_EXCL_START : cnu - Should not count in Code Coverage until we support non-binary collation in SQ
            if (CollationInfo::isSystemCollation(coll))
	    {
	      //Solution 10-081216-8006
	      if (hi->getOperatorType() == ITM_NARROW)
	      {
		ItemExpr* narrowsChild = hi->child(0);
		const NAType &narrowsChildType= narrowsChild->getValueId().getType();
		CMPASSERT(narrowsChildType.getTypeQualifier() == NA_CHARACTER_TYPE);
		NAType *newType= narrowsChildType.newCopy(generator->wHeap());
		CharType * newCharType = (CharType *) newType;
		newCharType->setDataStorageSize(chType.getDataStorageSize());
    	    
		hi->getValueId().changeType(newCharType);

	      }

		hi = new(generator->wHeap()) 
		      CompEncode(hi,FALSE, -1, CollationInfo::Compare);

		hi = hi->bindNode(generator->getBindWA());
	    }
//LCOV_EXCL_STOP : cnu - Should not count in Code Coverage until we support non-binary collation in SQ
	    else
	    {
  		if ((chType.isCaseinsensitive()) &&
		    (NOT chType.isUpshifted())) {
		  hi = new (generator->wHeap()) Upper(hi);
		  hi = hi->bindNode(generator->getBindWA());
		}
	      }
          }

	  ItemExpr *hv =
            new(generator->wHeap()) HashDistPartHash(hi);
	  result = new(generator->wHeap())
            HashDistPartHashComb(result,hv);
	}

      result->bindNode(generator->getBindWA());
    } else {
      const NAType &childType = child(0)->getValueId().getType();

      if(childType.getTypeQualifier() == NA_CHARACTER_TYPE) {

	const CharType &chType = (CharType&)childType;

	CharInfo::Collation coll = chType.getCollation();

//LCOV_EXCL_START : cnu - Should not count in Code Coverage until we support non-binary collation in SQ
        if (CollationInfo::isSystemCollation(coll))
	{
	  //Solution 10-081216-8006
	  if (child(0)->getOperatorType() == ITM_NARROW)
	  {
	    ItemExpr* narrowsChild = child(0)->child(0);
	    const NAType &narrowsChildType= narrowsChild->getValueId().getType();
	    CMPASSERT(narrowsChildType.getTypeQualifier() == NA_CHARACTER_TYPE);
	    NAType *newType= narrowsChildType.newCopy(generator->wHeap());
	    CharType * newCharType = (CharType *) newType;
	    newCharType->setDataStorageSize(chType.getDataStorageSize());
	    
	    child(0)->getValueId().changeType(newCharType);

	  }

	  child(0) = new(generator->wHeap()) 
			CompEncode(child(0),FALSE, -1, CollationInfo::Compare);

	  child(0) = child(0)->bindNode(generator->getBindWA());
	}
//LCOV_EXCL_STOP : cnu - Should not count in Code Coverage until we support non-binary collation in SQ
	else
	{
	    if ((chType.isCaseinsensitive()) &&
		(NOT chType.isUpshifted())) {
	      child(0) = new (generator->wHeap()) Upper(child(0));
	      child(0) = child(0)->bindNode(generator->getBindWA());
	    }
	  }
      }
    }

  // do generic tasks for pre-code generation (e.g. recurse to the children)
  setReplacementExpr(result->ItemExpr::preCodeGen(generator));
  markAsPreCodeGenned();
  return getReplacementExpr();
} // HashDistPartHash::preCodeGen()


ItemExpr * HostVar::preCodeGen(Generator * generator)
{
  if (nodeIsPreCodeGenned())
    return this;

  ItemExpr * i = convertExternalType(generator);
  if (i == NULL)
    return NULL;

  return i;
}

ItemExpr * IndexColumn::preCodeGen(Generator * generator)
{
  if (nodeIsPreCodeGenned())
    return this;

  ItemExpr * i = convertExternalType(generator);
  if (i == NULL)
    return NULL;

  return i;
}

ItemExpr * Generator::addCompDecodeForDerialization(ItemExpr * ie, NABoolean isAlignedFormat)
{
  if (!ie)
    return NULL;

  if ((ie->getOperatorType() == ITM_BASECOLUMN) ||
      (ie->getOperatorType() == ITM_INDEXCOLUMN))
    {
      if (! isAlignedFormat && HbaseAccess::isEncodingNeededForSerialization(ie))
	{
	  ItemExpr * newNode = new(wHeap()) CompDecode
	    (ie, &ie->getValueId().getType(), FALSE, TRUE);

	  newNode->bindNode(getBindWA());
	  if (getBindWA()->errStatus())
	    return NULL;

	  newNode = newNode->preCodeGen(this);
	  if (! newNode)
	    return NULL;  
	  return newNode;
	}
      else
	return ie;
    }

  for (Lng32 i = 0; i < ie->getArity(); i++)
    {
      ItemExpr * nie = addCompDecodeForDerialization(ie->child(i), isAlignedFormat);
      if (nie)
	ie->setChild(i, nie);
    }

  return ie;
}

ItemExpr * HbaseTimestamp::preCodeGen(Generator * generator)
{
  if (nodeIsPreCodeGenned())
    return getReplacementExpr();

  if (! ItemExpr::preCodeGen(generator))
    return NULL;

  markAsPreCodeGenned();

  return this;
}

ItemExpr * HbaseVersion::preCodeGen(Generator * generator)
{
  if (nodeIsPreCodeGenned())
    return getReplacementExpr();

  if (! ItemExpr::preCodeGen(generator))
    return NULL;

  markAsPreCodeGenned();

  return this;
}

ItemExpr * LOBoper::preCodeGen(Generator * generator)
{
  generator->setProcessLOB(TRUE);

  return BuiltinFunction::preCodeGen(generator);
}

ItemExpr * LOBconvert::preCodeGen(Generator * generator)
{
  NAColumn * col = child(0)->getValueId().getNAColumn(TRUE);
  if (col)
    {
      lobNum() = col->lobNum();
      lobStorageType() = col->lobStorageType();
      lobStorageLocation() = col->lobStorageLocation();
    }
  
  return LOBoper::preCodeGen(generator);
}


ItemExpr * LOBupdate::preCodeGen(Generator * generator)
{
  return LOBoper::preCodeGen(generator);
}

ItemExpr * MathFunc::preCodeGen(Generator * generator)
{
  if (nodeIsPreCodeGenned())
    return this;

  for (Int32 i = 0; i < getArity(); i++)
    {
      const NAType &typ = child(i)->getValueId().getType();

      // Insert a cast node to convert child to a double precision.
      child(i) = new (generator->wHeap())
	Cast(child(i),
	     new (generator->wHeap()) SQLDoublePrecision(
		  typ.supportsSQLnullLogical()));

      child(i)->bindNode(generator->getBindWA());

      child(i) = child(i)->preCodeGen(generator);
      if (! child(i).getPtr())
	return NULL;
    }

  markAsPreCodeGenned();
  return this;
} // MathFunc::preCodeGen()

ItemExpr * Modulus::preCodeGen(Generator * generator)
{
  if (nodeIsPreCodeGenned())
    return this;

  for (Int32 i = 0; i < 2; i++)
    {
      const NumericType &typ
	= (NumericType&)child(i)->getValueId().getType();

      if (typ.isDecimal())
	{
	  // Insert a cast node to convert child to an LARGEINT.
	  child(i) = new (generator->wHeap())
	    Cast(child(i), new (generator->wHeap()) SQLLargeInt(TRUE,
								typ.supportsSQLnullLogical()));
	}

      child(i)->bindNode(generator->getBindWA());

      child(i) = child(i)->preCodeGen(generator);
      if (! child(i).getPtr())
	return NULL;
    }

  markAsPreCodeGenned();
  return this;
} // Modulus::preCodeGen()

ItemExpr * ItemExpr::convertExternalType(Generator * generator)
{
  BindWA * bindWA = generator->getBindWA();

  if (getValueId().getType().isExternalType())
    {
      // this type is not supported internally.
      // Convert it to an equivalent internal type.
      ItemExpr * c = new (bindWA->wHeap())
	Cast(this, getValueId().getType().equivalentType(bindWA->wHeap()));

      c->synthTypeAndValueId();

      // mark 'this' as precodegenned so we don't go thru
      // this path again.
      markAsPreCodeGenned();
      c = c->preCodeGen(generator);
      unmarkAsPreCodeGenned();

      return c;
    }
  else
    return this;
}

ItemExpr * Parameter::preCodeGen(Generator * generator)
{
  if (nodeIsPreCodeGenned())
    return this;

  ItemExpr * i = convertExternalType(generator);
  if (i == NULL)
    return NULL;

  return i;
}

ItemExpr * PivotGroup::preCodeGen(Generator * generator)
{
  if (nodeIsPreCodeGenned())
    return getReplacementExpr();

  if (! ItemExpr::preCodeGen(generator))
    return NULL;

  ItemExpr * childExpr = child(0)->castToItemExpr();

  const NAType &type1 = 
    childExpr->getValueId().getType();
 
  if (type1.getTypeQualifier() != NA_CHARACTER_TYPE) 
    {
      Lng32 displayLen = type1.getDisplayLength(
                                                type1.getFSDatatype(),
                                                type1.getNominalSize(),
                                                type1.getPrecision(),
                                                type1.getScale(),
                                                0);

      NAType * newType = new(generator->getBindWA()->wHeap()) 
        SQLVarChar(displayLen, type1.supportsSQLnull());

      childExpr = new (generator->getBindWA()->wHeap()) Cast(childExpr, newType);
      
      childExpr = childExpr->bindNode(generator->getBindWA());
      if (! childExpr || generator->getBindWA()->errStatus())
        return NULL;

      childExpr = childExpr->preCodeGen(generator);
      if (! childExpr)
	return NULL;

      child(0) = childExpr;
    }

  markAsPreCodeGenned();

  return this;
}

ItemExpr * RandomNum::preCodeGen(Generator * generator)
{
  if (nodeIsPreCodeGenned())
    return this;

  if (child(0))
    {
      const NAType &typ1 = child(0)->getValueId().getType();

      // Insert a cast node to convert child to an INT.
      child(0) = new (generator->wHeap())
	Cast(child(0), new (generator->wHeap()) SQLInt(FALSE,
						       typ1.supportsSQLnullLogical()));

      child(0)->bindNode(generator->getBindWA());

      child(0) = child(0)->preCodeGen(generator);
      if (! child(0).getPtr())
	return NULL;
    }

  markAsPreCodeGenned();
  return this;
} // RandomNum::preCodeGen()

ItemExpr * Repeat::preCodeGen(Generator * generator)
{
  if (nodeIsPreCodeGenned())
    return this;

  const NAType &typ2 = child(1)->getValueId().getType();

  // Insert a cast node to convert child 2 to an INT.
  child(1) = new (generator->wHeap())
    Cast(child(1), new (generator->wHeap()) SQLInt(FALSE,
						   typ2.supportsSQLnullLogical()));

  child(1)->bindNode(generator->getBindWA());

  for (Int32 i = 0; i < getArity(); i++)
    {
      if (child(i))
	{
	  child(i) = child(i)->preCodeGen(generator);
	  if (! child(i).getPtr())
	    return NULL;
	}
    }

  markAsPreCodeGenned();
  return this;
} // Repeat::preCodeGen()

ItemExpr *ReplaceNull::preCodeGen(Generator *generator)
{
  if (nodeIsPreCodeGenned())
    return getReplacementExpr();

  NAType *dstAType = getValueId().getType().newCopy(generator->wHeap());
  const NAType& dstBType = getValueId().getType();

  if(child(0) == child(1))
    {
      dstAType->setNullable(TRUE);
    }

  child(1) = new(generator->wHeap()) Cast(child(1), dstAType);
  child(2) = new(generator->wHeap()) Cast(child(2), &dstBType);

  child(1)->bindNode(generator->getBindWA());
  child(2)->bindNode(generator->getBindWA());

  setReplacementExpr(ItemExpr::preCodeGen(generator));
  markAsPreCodeGenned();
  return getReplacementExpr();
}

ItemExpr * TriRelational::preCodeGen(Generator * generator)
{
  if (nodeIsPreCodeGenned())
    return getReplacementExpr();

  // ---------------------------------------------------------------------
  // The executor does not handle tri-relational operators. It either
  // handles key exclusion expressions if the operator is part or a key
  // predicate, or the tri-relational operator gets converted into
  // a case statement (see comment in file ItemFunc.h).
  // ---------------------------------------------------------------------
  NABoolean lessOrLe = (getOperatorType() == ITM_LESS_OR_LE);
  BiRelat *exclusive = new(generator->wHeap()) BiRelat(
       (IFX lessOrLe THENX ITM_LESS ELSEX ITM_GREATER),
       child(0),
       child(1));
  BiRelat *inclusive = new(generator->wHeap()) BiRelat(
       (IFX lessOrLe THENX ITM_LESS_EQ ELSEX ITM_GREATER_EQ),
       child(0),
       child(1));
  exclusive->setSpecialNulls(getSpecialNulls());
  inclusive->setSpecialNulls(getSpecialNulls());

  ItemExpr * result = new(generator->wHeap()) Case(
       NULL,
       new(generator->wHeap()) IfThenElse(
	    child(2),
	    exclusive,
	    inclusive));

  result->bindNode(generator->getBindWA());

  // do generic tasks for pre-code generation (e.g. recurse to the children)
  setReplacementExpr(result->preCodeGen(generator));
  markAsPreCodeGenned();
  return getReplacementExpr();
} // TriRelational::preCodeGen()

ItemExpr *
HashDistrib::preCodeGen(Generator * generator)
{
  if (nodeIsPreCodeGenned())
    return this;

  if (! ItemExpr::preCodeGen(generator))
    return NULL;

  // Assert that the operands are unsigned int.
  //
  NumericType *numeric = (NumericType *)(&(child(0)->getValueId().getType()));
  GenAssert(numeric->getFSDatatype()==REC_BIN32_UNSIGNED &&
	    numeric->getScale()==0,
	    "invalid first operand type to function HashDistrib");

  numeric = (NumericType *)(&(child(1)->getValueId().getType()));
  GenAssert(numeric->getFSDatatype()==REC_BIN32_UNSIGNED &&
	    numeric->getScale()==0,
	    "invalid second operand type to function HashDistrib");

  markAsPreCodeGenned();
  return this;
}

ItemExpr * ProgDistribKey::preCodeGen(Generator * generator)
{
  if (nodeIsPreCodeGenned())
    return this;

  // Assert that all operands are of type unsigned int.
  //
  for (Int32 i=0; i<3; i++)
    {
      NumericType *numeric =
        (NumericType *)(&(child(i)->getValueId().getType()));

      GenAssert(numeric->getFSDatatype()==REC_BIN32_UNSIGNED &&
		numeric->getScale()==0,
		"invalid operand type to function ProgDistribKey");
    }

  markAsPreCodeGenned();
  return this;
}

ItemExpr *
PAGroup::preCodeGen(Generator * generator)
{
  if (nodeIsPreCodeGenned())
    return this;

  if (! ItemExpr::preCodeGen(generator))
    return NULL;

  // Assert that the operands are unsigned int.
  //
  NumericType *numeric = (NumericType *)(&(child(0)->getValueId().getType()));
  GenAssert(numeric->getFSDatatype()==REC_BIN32_UNSIGNED &&
	    numeric->getScale()==0,
	    "invalid first operand type to function PAGroup");

  numeric = (NumericType *)(&(child(1)->getValueId().getType()));
  GenAssert(numeric->getFSDatatype()==REC_BIN32_UNSIGNED &&
	    numeric->getScale()==0,
	    "invalid second operand type to function PAGroup");

  numeric = (NumericType *)(&(child(2)->getValueId().getType()));
  GenAssert(numeric->getFSDatatype()==REC_BIN32_UNSIGNED &&
	    numeric->getScale()==0,
	    "invalid third operand type to function PAGroup");

  markAsPreCodeGenned();
  return this;
}

ItemExpr *
ScalarVariance::preCodeGen(Generator *generator)
{
  if (nodeIsPreCodeGenned())
    return this;

  if (! ItemExpr::preCodeGen(generator))
    return NULL;

  NumericType *result_type =
    (NumericType *)(&(getValueId().getType()));

  NumericType *type_op1 =
    (NumericType *)(&(child(0)->castToItemExpr()->getValueId().getType()));

  NumericType *type_op2 =
    (NumericType *)(&(child(1)->castToItemExpr()->getValueId().getType()));

  NumericType *type_op3 =
    (NumericType *)(&(child(1)->castToItemExpr()->getValueId().getType()));

  GenAssert(result_type->getTypeQualifier() == NA_NUMERIC_TYPE &&
	    type_op1->getTypeQualifier() == NA_NUMERIC_TYPE &&
	    type_op2->getTypeQualifier() == NA_NUMERIC_TYPE &&
	    type_op3->getTypeQualifier() == NA_NUMERIC_TYPE &&
	    !result_type->isExact() &&
	    !type_op1->isExact() &&
	    !type_op2->isExact() &&
	    !type_op3->isExact() &&
	    result_type->getBinaryPrecision() == SQL_DOUBLE_PRECISION &&
	    type_op1->getBinaryPrecision() == SQL_DOUBLE_PRECISION &&
	    type_op2->getBinaryPrecision() == SQL_DOUBLE_PRECISION &&
	    type_op3->getBinaryPrecision() == SQL_DOUBLE_PRECISION,
	    "ScalarVariance: Invalid Inputs");

  markAsPreCodeGenned();
  return this;
}

ItemExpr * Substring::preCodeGen(Generator * generator)
{
  if (nodeIsPreCodeGenned())
    return this;

  child(0) = child(0)->preCodeGen(generator);
  if (! child(0).getPtr())
    return NULL;

  for (Int32 i = 1; i < getArity(); i++)
    {
      if (child(i))
	{
	  const NAType &typ1 = child(i)->getValueId().getType();

	  // Insert a cast node to convert child to an INT.
	  child(i) = new (generator->wHeap())
	    Cast(child(i), new (generator->wHeap()) SQLInt(TRUE,
							   typ1.supportsSQLnullLogical()));

	  child(i)->bindNode(generator->getBindWA());

	  child(i) = child(i)->preCodeGen(generator);
	  if (! child(i).getPtr())
	    return NULL;
	}
    }

  markAsPreCodeGenned();
  return this;
} // Substring::preCodeGen()


ItemExpr * ItemExpr::preCodeGen(Generator * generator)
{
  if (nodeIsPreCodeGenned())
    return this;

  Lng32 nc = (Lng32)getArity();

  for (Lng32 index = 0; index < nc; index++)
    {
      child(index) = child(index)->preCodeGen(generator);
      if (! child(index).getPtr())
	return NULL;
    }

  markAsPreCodeGenned();

  return this;
} // ItemExpr::preCodeGen()

// ---------------------------------------------------------
// Methods for class VEGRewritePairs
// ---------------------------------------------------------
VEGRewritePairs::VEGRewritePairs(CollHeap* heap)
  : heap_(heap),
    vegRewritePairs_(&valueIdHashFunc, 1009, TRUE, heap)
{
} 

ULng32 VEGRewritePairs::valueIdHashFunc(const CollIndex & v) 
{
  return (ULng32)v;
}

const VEGRewritePairs::VEGRewritePair *
VEGRewritePairs::getPair( const ValueId& original) const
{
  CollIndex k(original);
  return vegRewritePairs_.getFirstValue(&k);

} // getPair(..)


NABoolean VEGRewritePairs::
getRewritten(ValueId& rewritten, const ValueId& original) const
{
  NABoolean found = FALSE;
  const VEGRewritePairs::VEGRewritePair * vrPairPtr = NULL;
  if (vrPairPtr = getPair(original)){
      rewritten = vrPairPtr->getRewritten();
      found = TRUE;
  }

  return found;
} // getRewritten

VEGRewritePairs::~VEGRewritePairs()
{
  clear();

} // VEGRewritePairs::~VEGRewritePairs()

void
VEGRewritePairs::insert(const ValueId& original,
			const ValueId& rewritten)
{
  // Precondition:
  // original must have not been rewritten before:
  CMPASSERT(getPair(original) == NULL);

  VEGRewritePairs::VEGRewritePair * vrPairPtr =
    new (heap_) VEGRewritePairs::VEGRewritePair(original,rewritten);
  CMPASSERT(vrPairPtr != NULL);

  CollIndex* key = (CollIndex*) new (heap_) CollIndex(original);


  vegRewritePairs_.insert(key, vrPairPtr);
}


void VEGRewritePairs::VEGRewritePair::print(FILE *ofd) const
{
#pragma nowarn(1506)   // warning elimination
  Lng32 orId = CollIndex(original_),
#pragma warn(1506)  // warning elimination
#pragma nowarn(1506)   // warning elimination
    reId = CollIndex(rewritten_);
#pragma warn(1506)  // warning elimination
  fprintf(ofd,"<%d, %d>",orId,reId);
}


void VEGRewritePairs::print( FILE* ofd,
			     const char* indent,
			     const char* title) const
{
#pragma nowarn(1506)   // warning elimination
  BUMP_INDENT(indent);
#pragma warn(1506)  // warning elimination
  fprintf(ofd,"%s %s\n%s",NEW_INDENT,title,NEW_INDENT);

  CollIndex *key;
  VEGRewritePair *value;
  NAHashDictionaryIterator<CollIndex, VEGRewritePair> iter(vegRewritePairs_);

  for (CollIndex i=0; i < iter.entries(); i++)
    {
      iter.getNext(key, value);
      value->print(ofd);
    }
}

// PhysTranspose::preCodeGen() -------------------------------------------
// Perform local query rewrites such as for the creation and
// population of intermediate tables, for accessing partitioned
// data. Rewrite the value expressions after minimizing the dataflow
// using the transitive closure of equality predicates.
//
// PhysTranspose::preCodeGen() - is basically the same as the RelExpr::
// preCodeGen() except that here we replace the VEG references in the
// transUnionVals() as well as the selectionPred().
//
// Parameters:
//
// Generator *generator
//    IN/OUT : A pointer to the generator object which contains the state,
//             and tools (e.g. expression generator) to generate code for
//             this node.
//
// ValueIdSet &externalInputs
//    IN    : The set of external Inputs available to this node.
//
//
RelExpr * PhysTranspose::preCodeGen(Generator * generator,
				    const ValueIdSet &externalInputs,
				    ValueIdSet &pulledNewInputs)
{
  if (nodeIsPreCodeGenned())
    return this;

  // Check if the pivs of this operator and it's child are the same.
  // If they are not, make them the same.
  replacePivs();

  // Resolve the VEGReferences and VEGPredicates, if any, that appear
  // in the Characteristic Inputs, in terms of the externalInputs.
  //
  getGroupAttr()->resolveCharacteristicInputs(externalInputs);

  // My Characteristic Inputs become the external inputs for my children.
  //
  Int32 nc = getArity();
  for (Int32 index = 0; index < nc; index++)
    {
      ValueIdSet childPulledInputs;

      child(index) = child(index)->preCodeGen(generator,
					      externalInputs,
					      pulledNewInputs);
      if (! child(index).getPtr())
	return NULL;

      // process additional input value ids the child wants
      getGroupAttr()->addCharacteristicInputs(childPulledInputs);
      pulledNewInputs += childPulledInputs;
    }

  // The VEG expressions in the selection predicates and the characteristic
  // outputs can reference any expression that is either a potential output
  // or a characteristic input for this RelExpr. Supply these values for
  // rewriting the VEG expressions.
  //
  ValueIdSet availableValues;
  getInputValuesFromParentAndChildren(availableValues);

  // The transUnionVals have access to only the Input Values.
  // These can come from the parent of be the outputs of the child.
  //
  for(CollIndex v = 0; v < transUnionVectorSize(); v++) {
    ValueIdList valIdList = transUnionVector()[v];

    valIdList.replaceVEGExpressions
      (availableValues,
       getGroupAttr()->getCharacteristicInputs());
  }

  // The selectionPred has access to the output values generated by transpose.
  // as well as any input values from the parent or child.
  //
  getInputAndPotentialOutputValues(availableValues);


  // Rewrite the selection predicates.
  //
  NABoolean replicatePredicates = TRUE;
  selectionPred().replaceVEGExpressions
    (availableValues,
     getGroupAttr()->getCharacteristicInputs(),
     FALSE, // no key predicates here
     0 /* no need for idempotence here */,
     replicatePredicates
     );

  // Replace VEG references in the outputs and remove redundant
  // outputs.
  //
  getGroupAttr()->resolveCharacteristicOutputs
    (availableValues,
     getGroupAttr()->getCharacteristicInputs());
  generator->oltOptInfo()->setMultipleRowsReturned(TRUE);
  markAsPreCodeGenned();

  return this;
} // PhysTranspose::preCodeGen

// -----------------------------------------------------------------------
// PhyPack::preCodeGen() is basically the same as RelExpr::preCodeGen().
// It replaces the VEG's in its packingExpr_ as well as selectionPred_.
// -----------------------------------------------------------------------
RelExpr* PhyPack::preCodeGen(Generator* generator,
                             const ValueIdSet& externalInputs,
			     ValueIdSet &pulledNewInputs)
{
  if (nodeIsPreCodeGenned())
    return this;

  // Check if the pivs of this operator and it's child are the same.
  // If they are not, make them the same.
  replacePivs();

  // Resolve the VEGReferences and VEGPredicates, if any, that appear
  // in the Characteristic Inputs, in terms of the externalInputs.
  //
  getGroupAttr()->resolveCharacteristicInputs(externalInputs);

  // My Characteristic Inputs become the external inputs for my children.
  //
  Int32 nc = getArity();
  for(Int32 index = 0; index < nc; index++)
  {
    ValueIdSet childPulledInputs;

    child(index) = child(index)->preCodeGen(generator,
					    externalInputs,
					    pulledNewInputs);
    if(! child(index).getPtr()) return NULL;

    // process additional input value ids the child wants
    getGroupAttr()->addCharacteristicInputs(childPulledInputs);
    pulledNewInputs += childPulledInputs;
  }

  if (getFirstNRows() != -1)
    {
      RelExpr * firstn = new(generator->wHeap()) FirstN(child(0),
                                                        getFirstNRows());

      // move my child's attributes to the firstN node.
      // Estimated rows will be mine.
      firstn->setEstRowsUsed(getEstRowsUsed());
      firstn->setMaxCardEst(getMaxCardEst());
      firstn->setInputCardinality(child(0)->getInputCardinality());
      firstn->setPhysicalProperty(child(0)->getPhysicalProperty());
      firstn->setGroupAttr(child(0)->getGroupAttr());
      //10-060516-6532 -Begin
      //When FIRSTN node is created after optimization phase, the cost
      //of that node does not matter.But, display_explain and explain
      //show zero operator costs and rollup cost which confuses the user.
      //Also, the VQP crashes when cost tab for FIRSTN node is selected.
      //So, creating a cost object will fix this.
      //The operator cost is zero and rollup cost is same as it childs.
      Cost* firstnNodecost = new HEAP Cost();
      firstn->setOperatorCost(firstnNodecost);
      Cost* rollupcost = (Cost *)(child(0)->getRollUpCost());
      *rollupcost += *firstnNodecost;
      firstn->setRollUpCost(rollupcost);
      //10-060516-6532 -End

      firstn =
        firstn->preCodeGen(generator,
                           getGroupAttr()->getCharacteristicInputs(),
                           pulledNewInputs);
      if (! firstn)
        return NULL;

      setChild(0, firstn);
    }

  // The VEG expressions in the selection predicates and the characteristic
  // outputs can reference any expression that is either a potential output
  // or a characteristic input for this RelExpr. Supply these values for
  // rewriting the VEG expressions.
  //
  ValueIdSet availableValues;
  getInputValuesFromParentAndChildren(availableValues);
  const ValueIdSet& inputValues = getGroupAttr()->getCharacteristicInputs();

  // Replace VEG's in both the packing expression and the packing factor.
  //
  packingFactor().replaceVEGExpressions(availableValues,inputValues);
  packingExpr().replaceVEGExpressions(availableValues,inputValues);

  // The selectionPred has access to the output values generated by Pack.
  //
  getInputAndPotentialOutputValues(availableValues);

  // Rewrite the selection predicates.
  //
  NABoolean replicatePredicates = TRUE;
  selectionPred().replaceVEGExpressions(availableValues,
                                        inputValues,
                                        FALSE, // no key predicates here
                                        0 /* no need for idempotence here */,
                                        replicatePredicates
                                        );

  // Replace VEG references in the outputs and remove redundant outputs.
  //
  getGroupAttr()->resolveCharacteristicOutputs(availableValues,inputValues);

  markAsPreCodeGenned();
  return this;

} // PhyPack::preCodeGen()


//
//PrecodeGen method for class PhysicalTuple list
//This was put in as a fix for cr 10-010327-1947.
//Before the fix the RelExpr was getting to the generator
//with a VEGRef still in it, because the VEGRef from the
//tupleExpr had not be removed and resolved correctly.
RelExpr * PhysicalTuple::preCodeGen(Generator * generator,
                              const ValueIdSet& externalInputs,
                              ValueIdSet& pulledNewInputs_)
{
  ValueIdSet availableValues = externalInputs;
  tupleExpr().replaceVEGExpressions
                (availableValues, externalInputs);

  return (RelExpr::preCodeGen(generator, availableValues, pulledNewInputs_));
} // PhysicalTuple::preCodeGen()
//

RelExpr * PhysicalTupleList::preCodeGen(Generator * generator,
                              const ValueIdSet& externalInputs,
                              ValueIdSet& pulledNewInputs_)
{
  ValueIdSet availableValues = externalInputs;
  tupleExpr().replaceVEGExpressions
                (availableValues, externalInputs);

  generator->oltOptInfo()->setMultipleRowsReturned(TRUE);

  return (RelExpr::preCodeGen(generator, availableValues, pulledNewInputs_));
} // PhysicalTupleList::preCodeGen()

RelExpr * CompoundStmt::preCodeGen(Generator * generator,
			           const ValueIdSet & externalInputs,
			           ValueIdSet &pulledNewInputs)
{
  if (nodeIsPreCodeGenned())
    return this;

  // Check if the pivs of this operator and it's child are the same.
  // If they are not, make them the same.
  replacePivs();

  ValueIdSet availableValues;
  ValueIdSet childPulledInputs;

  // Resolve the VEGReferences and VEGPredicates, if any, that appear
  // in the Characteristic Inputs, in terms of the externalInputs.
  getGroupAttr()->resolveCharacteristicInputs(externalInputs);
  availableValues = getGroupAttr()->getCharacteristicInputs();

  // This is similar to what is done in Join::precodeGen when we have a TSJ.
  // A compound statement node behaves in a similar way to a TSJ node since
  // it flows values from left to right.

  // My Characteristic Inputs become the external inputs for my left child.
  child(0) = child(0)->preCodeGen(generator,availableValues,childPulledInputs);
  if (! child(0).getPtr())
    return NULL;

   // process additional input value ids the child wants
  // (see RelExpr::preCodeGen())
  getGroupAttr()->addCharacteristicInputs(childPulledInputs);
  pulledNewInputs += childPulledInputs;
  availableValues += childPulledInputs;
  childPulledInputs.clear();

  // The values produced as output by my left child can be used as
  // "external" inputs by my right child.
  availableValues += child(0)->getGroupAttr()->getCharacteristicOutputs();

  // Process the right child
  child(1) = child(1)->preCodeGen(generator,availableValues,childPulledInputs);
  if (! child(1).getPtr())
    return NULL;

  // process additional input value ids the child wants
  // (see RelExpr::preCodeGen())
  getGroupAttr()->addCharacteristicInputs(childPulledInputs);
  pulledNewInputs += childPulledInputs;

  // Accumulate the values that are provided as inputs by my parent
  // together with the values that are produced as outputs by my
  // children. Use these values for rewriting the VEG expressions.
  getInputValuesFromParentAndChildren(availableValues);

  // The VEG expressions in the selection predicates and the characteristic
  // outputs can reference any expression that is either a potential output
  // or a characteristic input for this RelExpr. Supply these values for
  // rewriting the VEG expressions.
  getInputAndPotentialOutputValues(availableValues);

  // Rewrite the selection predicates.
  NABoolean replicatePredicates = TRUE;
  selectionPred().replaceVEGExpressions
                     (availableValues,
		      getGroupAttr()->getCharacteristicInputs(),
		      FALSE, // no need to generate key predicates here
		      0 /* no need for idempotence here */,
		      replicatePredicates
		     );

  getGroupAttr()->resolveCharacteristicOutputs
                     (availableValues,
		      getGroupAttr()->getCharacteristicInputs());

  // Xn will be aborted if there is any IUD stmt within this CS and
  // an error occurs at runtime.
  if (generator->foundAnUpdate())
    {
      //generator->setUpdAbortOnError(TRUE);
      generator->setUpdSavepointOnError(FALSE);
      generator->setUpdErrorOnError(FALSE);
      //generator->setUpdPartialOnError(FALSE);
    }

  generator->setAqrEnabled(FALSE);

  markAsPreCodeGenned();

  return this;
} // CompoundStmt::preCodeGen

RelExpr * FirstN::preCodeGen(Generator * generator,
			     const ValueIdSet & externalInputs,
			     ValueIdSet &pulledNewInputs)
{
  if (nodeIsPreCodeGenned())
    return this;

  if (! RelExpr::preCodeGen(generator,externalInputs,pulledNewInputs))
    return NULL;

  markAsPreCodeGenned();

  return this;
} // FirstN::preCodeGen

RelExpr * RelRoutine::preCodeGen (Generator * generator,
					     const ValueIdSet &externalInputs,
					     ValueIdSet &pulledNewInputs)
{
  if (nodeIsPreCodeGenned())
    return this;
  
  if (!RelExpr::preCodeGen(generator,externalInputs,pulledNewInputs))
    return NULL;
  
  // The VEG expressions in the selection predicates and the characteristic
  // outputs can reference any expression that is either a potential output
  // or a characteristic input for this RelExpr. Supply these values for
  // rewriting the VEG expressions.
  //
  ValueIdSet availableValues;
  availableValues = getGroupAttr()->getCharacteristicInputs();

  const ValueIdSet &inputValues = getGroupAttr()->getCharacteristicInputs();
  getProcInputParamsVids().replaceVEGExpressions(availableValues, inputValues);
  generator->setAqrEnabled(FALSE);

  markAsPreCodeGenned();
  
  return this;
}

RelExpr * IsolatedNonTableUDR::preCodeGen (Generator * generator,
					     const ValueIdSet &externalInputs,
					     ValueIdSet &pulledNewInputs)
{
  if (nodeIsPreCodeGenned())
    return this;
  
  if (!RelRoutine::preCodeGen(generator,externalInputs,pulledNewInputs))
    return NULL;

  // The VEG expressions in the selection predicates and the characteristic
  // outputs can reference any expression that is either a potential output
  // or a characteristic input for this RelExpr. Supply these values for
  // rewriting the VEG expressions.
  //
  ValueIdSet availableValues;
  availableValues = getGroupAttr()->getCharacteristicInputs();

  const ValueIdSet &inputValues = getGroupAttr()->getCharacteristicInputs();
  getNeededValueIds().replaceVEGExpressions(availableValues, inputValues);
  
  markAsPreCodeGenned();
  
  return this;
}

RelExpr * PhysicalTableMappingUDF::preCodeGen(Generator * generator,
                                              const ValueIdSet &externalInputs,
                                              ValueIdSet &pulledNewInputs)
{
  if (nodeIsPreCodeGenned())
    return this;
  
  if (!RelRoutine::preCodeGen(generator,externalInputs,pulledNewInputs))
    return NULL;

  ValueIdSet availableValues;
  getInputValuesFromParentAndChildren(availableValues);

  for(Int32 i = 0; i < getArity(); i++)
  {
    getChildInfo(i)->getOutputIds().replaceVEGExpressions(
         availableValues,
         getGroupAttr()->getCharacteristicInputs());
  }

  planInfo_ = getPhysicalProperty()->getUDRPlanInfo();
  if (!getDllInteraction()->finalizePlan(this, planInfo_))
    return NULL;
  
  markAsPreCodeGenned();
  
  return this;
}

RelExpr * PhysicalFastExtract::preCodeGen (Generator * generator,
					     const ValueIdSet &externalInputs,
					     ValueIdSet &pulledNewInputs)
{
  if (nodeIsPreCodeGenned())
    return this;

  generator->setIsFastExtract(TRUE);  

  if (!RelExpr::preCodeGen(generator,externalInputs,pulledNewInputs))
    return NULL;

  ValueIdSet availableValues;
  getInputValuesFromParentAndChildren(availableValues);

  getSelectListIds().replaceVEGExpressions(availableValues, externalInputs);

  if (isAppend())
    generator->setAqrEnabled(FALSE);

  // This relation is a linear fit to cpu consumption data observed during a 
  // performance run, while extracting data from the LINEITEM table. CPU Usage
  // can go from 0% to 50% according to this relation. CPU Usage is determined
  // by 2 factors (a) bytes of data extracted and (b) % non-character 
  // (termed numeric below) columns in each row (computed based on total max 
  // row size and tol non-char column size). Both factors have equal weigth, 
  // i.e. they can contribute at most 25% towards Cpu usage. For upto 50 GB
  // extracted data the bytes of extracted data increases linearly from 0% to
  // 25%. After 50 GB (total volume across all partitions), the contribution to
  // cpu usage from bytes extracted does not increase. Similarly the a table
  // all non-char columns can contribute upto 25% towards cpu usage. The numeric
  // factor is also weighted by the volume of data extracted.

  const Int32  plateauTabSizeInGB = 50;
  const float  weightOfBaseExtract = 0.5;
  const float  weightOfNumericExpressionEval = 0.5;
  const Int32  maxPossibleCpuUsage = 50 ; // in percentage units
  Int32 rowLength = child(0).getGroupAttr()->getCharacteristicOutputs().getRowLength();
  Int32 numericRowLength = child(0).getGroupAttr()->
			getCharacteristicOutputs().getRowLengthOfNumericCols();
  float numericRowLengthRatio = ((float) numericRowLength)/rowLength ;

  double bytesExtractedInGB = (getEstRowsUsed().value()*rowLength)/(1024*1024*1024);
  double bytesExtractedRatio = bytesExtractedInGB/plateauTabSizeInGB ;
  if (bytesExtractedRatio > 1)
	bytesExtractedRatio = 1;

  Int32 maxCpuUsage = (Int32) (maxPossibleCpuUsage*bytesExtractedRatio*(weightOfBaseExtract + 
                        (weightOfNumericExpressionEval*numericRowLengthRatio)));
  generator->setMaxCpuUsage(maxCpuUsage);

  markAsPreCodeGenned();

  return this;
}

RelExpr * RelLock::preCodeGen (Generator * generator,
			       const ValueIdSet &externalInputs,
			       ValueIdSet &pulledNewInputs)
{

  if (nodeIsPreCodeGenned())
    return this;

  // Since the newExch node is added as the parent
  // to SequenceGenerator node, this method gets
  // called again during the preCodeGen of t
  // newExch.
  if(parallelExecution_) 
    {
      // Add an exchange node here so this could be executed in ESP.
      RelExpr * exchange = new(generator->wHeap()) Exchange (this);
      exchange->setPhysicalProperty(this->getPhysicalProperty());
      exchange->setGroupAttr(this->getGroupAttr());
      
      markAsPreCodeGenned();

      exchange = exchange->preCodeGen(generator, externalInputs, pulledNewInputs);

      // Done.
      return exchange;

      /*
      RelExpr *newExch = 
	generator->insertEspExchange(this, getPhysicalProperty());
      
      ((Exchange *)newExch)->makeAnESPAccess();
      
      markAsPreCodeGenned();

      RelExpr * exch = 
	newExch->preCodeGen(generator, externalInputs, pulledNewInputs);
      
      return exch;
      */
    }
  
  if (!RelExpr::preCodeGen(generator,externalInputs,pulledNewInputs))
    return NULL;

  markAsPreCodeGenned();

  return this;
}

RelExpr * StatisticsFunc::preCodeGen(Generator * generator,
				     const ValueIdSet & externalInputs,
				     ValueIdSet &pulledNewInputs)
{
  if (nodeIsPreCodeGenned())
    return this;

  if (! RelExpr::preCodeGen(generator,externalInputs,pulledNewInputs))
    return NULL;

  // don't collect stats for stats func itself
  generator->setComputeStats(FALSE);

  markAsPreCodeGenned();

  // Done.
  return this;
}

RelExpr * ExeUtilGetStatistics::preCodeGen(Generator * generator,
					   const ValueIdSet & externalInputs,
					   ValueIdSet &pulledNewInputs)
{
  if (nodeIsPreCodeGenned())
    return this;

  if (! ExeUtilExpr::preCodeGen(generator,externalInputs,pulledNewInputs))
    return NULL;

  // don't collect stats for stats func itself
  generator->setComputeStats(FALSE);

  markAsPreCodeGenned();

  // Done.
  return this;
}

RelExpr * ExeUtilWnrInsert::preCodeGen(Generator * generator,
                                   const ValueIdSet & externalInputs,
                                   ValueIdSet &pulledNewInputs)
{
  if (nodeIsPreCodeGenned())
    return this;

  if (! ExeUtilExpr::preCodeGen(generator,externalInputs,pulledNewInputs))
    return NULL;

  markAsPreCodeGenned();

  return this;
}



ItemExpr * PositionFunc::preCodeGen(Generator * generator)
{
  if (nodeIsPreCodeGenned())
    return this;

  if (! BuiltinFunction::preCodeGen(generator))
    return NULL;

  const NAType &type1 =
    child(0)->castToItemExpr()->getValueId().getType();
  const NAType &type2 =
    child(1)->castToItemExpr()->getValueId().getType();
  
  CMPASSERT(
      (type1.getTypeQualifier() == NA_CHARACTER_TYPE) &&
      (type2.getTypeQualifier() == NA_CHARACTER_TYPE))
  
  const CharType &cType1 = (CharType&)type1;
  const CharType &cType2 = (CharType&)type2;

  CharInfo::Collation coll1 = cType1.getCollation();
  CharInfo::Collation coll2 = cType2.getCollation();

  CMPASSERT(coll1==coll2);

  setCollation(coll1);

  if (CollationInfo::isSystemCollation(coll1))
  {
    
    {
      ItemExpr * newEncode = 
	new(generator->wHeap()) 
	CompEncode(child(0),FALSE, -1, CollationInfo::Search);

      newEncode = newEncode->bindNode(generator->getBindWA());
      newEncode = newEncode->preCodeGen(generator);
      if (!newEncode)
	return NULL;
      setChild(0, newEncode);


      newEncode = 
	new(generator->wHeap()) 
	CompEncode(child(1), FALSE, -1,CollationInfo::Search);

      newEncode->bindNode(generator->getBindWA());
      newEncode = newEncode->preCodeGen(generator);
      if (!newEncode)
	return NULL;
      setChild(1, newEncode);
    }

  }

  markAsPreCodeGenned();
  return this;

} // PositionFunc::preCodeGen()


ItemExpr * Trim::preCodeGen(Generator * generator)
{
  if (nodeIsPreCodeGenned())
    return this;

  if (! BuiltinFunction::preCodeGen(generator))
    return NULL;

  const NAType &type1 =
    child(0)->castToItemExpr()->getValueId().getType();
  const NAType &type2 =
    child(1)->castToItemExpr()->getValueId().getType();
  
  CMPASSERT(
      (type1.getTypeQualifier() == NA_CHARACTER_TYPE) &&
      (type2.getTypeQualifier() == NA_CHARACTER_TYPE))
  
  const CharType &cType1 = (CharType&)type1;
  const CharType &cType2 = (CharType&)type2;

  CharInfo::Collation coll1 = cType1.getCollation();
  CharInfo::Collation coll2 = cType2.getCollation();

  CMPASSERT(coll1==coll2);

  setCollation(coll1);

  markAsPreCodeGenned();
  return this;

} // Trim::preCodeGen()

ItemExpr * NotIn::preCodeGen(Generator * generator)
{
  if (child(0)->getOperatorType() == ITM_ITEM_LIST)
  {//Multicolumn NotIn should not reach this far
    GenAssert(FALSE,"Multicolumn NotIn should not have reached this far");
    return NULL;
  }

  if (nodeIsPreCodeGenned())
  {
    return getReplacementExpr();
  }
  // if single column NOT IN reaches pre-code generation, then replace it with 
  // non equi-predicate form (NE)
  // An example of cases where NotIn reaches this far is a aquery like
  // select * from ta where (select sum(a2) from ta) not in (select b2 from tb);
  // where the NotIn predicate gets pushed down and is not caught at optimization 
  // time

  ValueId vid = createEquivNonEquiPredicate();

  ItemExpr * newPred = vid.getItemExpr();

  setReplacementExpr(newPred->preCodeGen(generator));
  markAsPreCodeGenned();

  return getReplacementExpr();


} // NotIn::preCodeGen()

short HbaseAccess::processSQHbaseKeyPreds(Generator * generator,
					  NAList<HbaseSearchKey*>& searchKeys,
					  ListOfUniqueRows &listOfUniqueRows,
					  ListOfRangeRows &listOfRangeRows)
{
  Int32 ct = 0;
  HbaseUniqueRows getSpec;
  getSpec.rowTS_ = -1;
  
  for (CollIndex i = 0; i<searchKeys.entries(); i++ ) 
    {
      HbaseSearchKey* searchKey = searchKeys[i];

      ValueIdSet newSelectionPreds;
      
      if ( searchKey->isUnique() ) 
	{
	  // Since we fill one rowId per entry, we will be using getRow() form of Get.
	  if ( (ct=searchKey->getCoveredLeadingKeys()) > 0 )
	    {
	      NAString result;
	      ValueIdList keyValues = searchKey->getBeginKeyValues();
	      
	      keyValues.convertToTextKey(searchKey->getKeyColumns(), result);
	      getSpec.rowIds_.insert(result);
	    } 
	  
	  //	  getSpec.addColumnNames(searchKey->getRequiredOutputColumns());
	} 
      else 
	{
	  // Multiple rows. Do Scan
	  HbaseRangeRows scanSpec;
	  scanSpec.beginKeyExclusive_ = FALSE;
	  scanSpec.endKeyExclusive_ = FALSE;
	  scanSpec.rowTS_ = -1;
	  
	  if ( !searchKey->areAllBeginKeysMissing() )
	    {
	      if ( (ct=searchKey->getCoveredLeadingKeys()) > 0 )
		{
		  ValueIdList beginKeyValues = searchKey->getBeginKeyValues();
		  beginKeyValues.convertToTextKey(searchKey->getKeyColumns(), scanSpec.beginRowId_);
		  scanSpec.beginKeyExclusive_ = searchKey->isBeginKeyExclusive();
		} 
	    } 
	  
	  if ( !searchKey->areAllEndKeysMissing() ) 
	    {
	      if ( (ct=searchKey->getCoveredLeadingKeys()) )
		{
		  ValueIdList endKeyValues = searchKey->getEndKeyValues();
		  endKeyValues.convertToTextKey(searchKey->getKeyColumns(), scanSpec.endRowId_);
		  scanSpec.endKeyExclusive_ = searchKey->isEndKeyExclusive();
		} 
	    } 
	  
	  //	  scanSpec.addColumnNames(searchKey->getRequiredOutputColumns());
	  listOfRangeRows.insertAt(listOfRangeRows.entries(), scanSpec);
	}
    } // for
  
  if (getSpec.rowIds_.entries() > 0)
    listOfUniqueRows.insert(getSpec);
  
  return 0;
}

short HbaseAccess::processNonSQHbaseKeyPreds(Generator * generator,
				       ValueIdSet &preds,
				       ListOfUniqueRows &listOfUniqueRows,
				       ListOfRangeRows &listOfRangeRows)
{
  ValueId vid;
  ValueId eqRowIdValVid;
  ValueId eqColNameValVid;
  ItemExpr * ie = NULL;
  NABoolean rowIdFound = FALSE;
  NABoolean colNameFound = FALSE;
  NABoolean isConstParam = FALSE;

  ValueIdList newPredList;
  NABoolean addToNewPredList;
 
  HbaseUniqueRows hg;
  HbaseRangeRows hs;
 
  for (vid = preds.init(); 
       (preds.next(vid)); 
       preds.advance(vid))
    {
      ie = vid.getItemExpr();
      
      addToNewPredList = TRUE;
      ConstValue * constVal = NULL;
      if ((NOT rowIdFound) && (isEqGetExpr(ie, eqRowIdValVid, isConstParam, 
					   "ROW_ID")))
	{
	  rowIdFound = TRUE;
	  
	  if (isConstParam)
	    {
	      ConstantParameter*cp = (ConstantParameter*)eqRowIdValVid.getItemExpr();
	      constVal = cp->getConstVal();
	    }
	  else
	    constVal = (ConstValue*)eqRowIdValVid.getItemExpr();
	  NAString rid = *constVal->getRawText();
	  hg.rowIds_.insert(rid); 
	  
	  hg.rowTS_ = -1;
	  
	  addToNewPredList = FALSE;
	}
      
      if (isEqGetExpr(ie, eqColNameValVid, isConstParam, "COL_NAME"))
	{
	  colNameFound = TRUE;
	  
	  if (isConstParam)
	    {
	      ConstantParameter*cp = (ConstantParameter*)eqColNameValVid.getItemExpr();
	      constVal = cp->getConstVal();
	    }
	  else
	    constVal = (ConstValue*)eqColNameValVid.getItemExpr();
	  NAString col = *constVal->getRawText();
	  hg.colNames_.insert(col); 
	  hs.colNames_.insert(col);
	  
	  addToNewPredList = FALSE;
	}
      
      if (addToNewPredList)
	newPredList.insert(vid);
    } // for
  
  if ((rowIdFound) || (colNameFound))
    {
      preds.clear();
      preds.insertList(newPredList);
    }
  
  if (rowIdFound)
    {
      listOfUniqueRows.insert(hg);
    }
  else
    {
      hs.rowTS_ = -1;
      listOfRangeRows.insert(hs);
    }

  //  markAsPreCodeGenned();
  
  // Done.
  return 0;
}

////////////////////////////////////////////////////////////////////////////
// To push down, the predicate must have the following form:
//    <column>  <op>  <value-expr>
//
// and all of the following conditions must be met:
//
//      <column>:       a base table or index column which can be serialized.
//                            serialized: either the column doesn't need encoding, like
//                                            an unsigned integer,  or the column
//                                            was declared with the SERIALIZED option.
//      <op>:              eq, ne, gt, ge, lt, le
//      <value-expr>:  an expression that only contains const or param values, and
//                            <value-expr>'s datatype is not a superset of <column>'s datatype.
//
/////////////////////////////////////////////////////////////////////////////
NABoolean HbaseAccess::isHbaseFilterPred(Generator * generator, ItemExpr * ie,
					 ValueId &colVID, ValueId &valueVID,
					 NAString &op,
					 NABoolean &removeFromOrigList)
{
  NABoolean found = FALSE;
  removeFromOrigList = FALSE;
  NABoolean hbaseLookupPred = FALSE;
  NABoolean flipOp = FALSE;  // set to TRUE when column is child(1)

  if (ie && 
      ((ie->getOperatorType() >= ITM_EQUAL) &&
       (ie->getOperatorType() <= ITM_GREATER_EQ)))
    {
      ItemExpr * child0 = ie->child(0)->castToItemExpr();
      ItemExpr * child1 = ie->child(1)->castToItemExpr();
      
      if ((ie->child(0)->getOperatorType() == ITM_BASECOLUMN) &&
	  (NOT hasColReference(ie->child(1))))
	{
	  found = TRUE;
	  colVID = ie->child(0)->getValueId();
	  valueVID = ie->child(1)->getValueId();
	}
      else if ((ie->child(1)->getOperatorType() == ITM_BASECOLUMN) &&
	       (NOT hasColReference(ie->child(0))))
	{
	  found = TRUE;
          flipOp = TRUE;
	  colVID = ie->child(1)->getValueId();
	  valueVID = ie->child(0)->getValueId();
	}
      else if ((ie->child(0)->getOperatorType() == ITM_INDEXCOLUMN) &&
	       (NOT hasColReference(ie->child(1))))
	{
	  found = TRUE;
	  colVID = ie->child(0)->getValueId();
	  valueVID = ie->child(1)->getValueId();
	}
      else if ((ie->child(1)->getOperatorType() == ITM_INDEXCOLUMN) &&
	       (NOT hasColReference(ie->child(0))))
	{
	  found = TRUE;
          flipOp = TRUE;
	  colVID = ie->child(1)->getValueId();
	  valueVID = ie->child(0)->getValueId();
	}
      else if ((ie->child(0)->getOperatorType() == ITM_REFERENCE) &&
	       (NOT hasColReference(ie->child(1))))
	{
	  found = TRUE;
	  colVID = ie->child(0)->getValueId();
	  valueVID = ie->child(1)->getValueId();
	}
      else if ((ie->child(1)->getOperatorType() == ITM_REFERENCE) &&
	       (NOT hasColReference(ie->child(0))))
	{
	  found = TRUE;
          flipOp = TRUE;
	  colVID = ie->child(1)->getValueId();
	  valueVID = ie->child(0)->getValueId();
	}
      else if ((ie->child(0)->getOperatorType() == ITM_HBASE_COLUMN_LOOKUP) &&
	       (NOT hasColReference(ie->child(1))))
	{
	  HbaseColumnLookup * hcl = (HbaseColumnLookup*)ie->child(0)->castToItemExpr();
	  if (hcl->getValueId().getType().getTypeQualifier() == NA_CHARACTER_TYPE)
	    {
	      hbaseLookupPred = TRUE;

	      ItemExpr * newCV = new(generator->wHeap()) ConstValue(hcl->hbaseCol());
	      newCV = newCV->bindNode(generator->getBindWA());
	      newCV = newCV->preCodeGen(generator);
	      
	      found = TRUE;
	      colVID = newCV->getValueId();
	      valueVID = ie->child(1)->getValueId();
	    }
	}
      else if ((ie->child(1)->getOperatorType() == ITM_HBASE_COLUMN_LOOKUP) &&
	       (NOT hasColReference(ie->child(0))))
	{
	  HbaseColumnLookup * hcl = (HbaseColumnLookup*)ie->child(1)->castToItemExpr();
	  if (hcl->getValueId().getType().getTypeQualifier() == NA_CHARACTER_TYPE)
	    {
	      hbaseLookupPred = TRUE;

	      ItemExpr * newCV = new(generator->wHeap()) ConstValue(hcl->hbaseCol());
	      newCV = newCV->bindNode(generator->getBindWA());
	      newCV = newCV->preCodeGen(generator);
	      
	      found = TRUE;
              flipOp = TRUE;
	      colVID = newCV->getValueId();
	      valueVID = ie->child(0)->getValueId();
	    }
	}
    }

  if (found)
    {
      const NAType &colType = colVID.getType();
      const NAType &valueType = valueVID.getType();

      NABoolean generateNarrow = FALSE;
      if (NOT hbaseLookupPred)
	{
	  generateNarrow = valueType.errorsCanOccur(colType);
	  if ((generateNarrow)  || // value not a superset of column
	      (NOT columnEnabledForSerialization(colVID.getItemExpr())))
	    found = FALSE;
	}

      if (found)
	{
	  if (colType.getTypeQualifier() == NA_CHARACTER_TYPE)
	    {
	      const CharType &charColType = (CharType&)colType;
	      const CharType &charValType = (CharType&)valueType;
	      
	      if ((charColType.isCaseinsensitive() || charValType.isCaseinsensitive()) ||
		  (charColType.isUpshifted() || charValType.isUpshifted()))
		found = FALSE;
	    }
	  else if (colType.getTypeQualifier() == NA_NUMERIC_TYPE)
	    {
	      const NumericType &numType = (NumericType&)colType;
	      const NumericType &valType = (NumericType&)valueType;
	      if (numType.isBigNum() || valType.isBigNum())
		found = FALSE;
	    }
	}

      if (found)
	{
	  if ((ie) && (((BiRelat*)ie)->addedForLikePred()) &&
	      (valueVID.getItemExpr()->getOperatorType() == ITM_CONSTANT))
	    {
	      // remove trailing '\0' characters since this is being pushed down to hbase.
	      ConstValue * cv = (ConstValue*)(valueVID.getItemExpr());
	      char * cvv = (char*)cv->getConstValue();
	      Lng32 len = cv->getStorageSize() - 1;
	      while ((len > 0) && (cvv[len] == '\0'))
		len--;

	      NAString newCVV(cvv, len+1);

	      ItemExpr * newCV = new(generator->wHeap()) ConstValue(newCVV);
	      newCV = newCV->bindNode(generator->getBindWA());
	      newCV = newCV->preCodeGen(generator);
	      valueVID = newCV->getValueId();
	    }

	  ItemExpr * castValue = NULL;
          if (NOT hbaseLookupPred)
            castValue = new(generator->wHeap()) Cast(valueVID.getItemExpr(), &colType);
          else
            {
              castValue = new(generator->wHeap()) Cast(valueVID.getItemExpr(), &valueVID.getType());
            }

	  if ((NOT hbaseLookupPred) &&
	      (isEncodingNeededForSerialization(colVID.getItemExpr())))
	    {
	      castValue = new(generator->wHeap()) CompEncode
		(castValue, FALSE, -1, CollationInfo::Sort, TRUE, FALSE);
	    }

	  castValue = castValue->bindNode(generator->getBindWA());
	  castValue = castValue->preCodeGen(generator);
	  
	  valueVID = castValue->getValueId();

	  // hbase pred evaluation compares the column byte string with the
	  // value byte string. It doesn't have a notion of nullability.
	  // For a nullable value stored in database, the first byte represents
	  // if the value is a null value.
	  // During pred evaluation in hbase, a null value could either get filtered
	  // out due to byte string comparison, or it may get returned back.
	  // For ex,   <col>  <gt>  <value>
	  //      will return TRUE if the first byte of <col> is a null value.
	  //      Similary, <col> <lt> <value> 
	  //      will return FALSE if the first byte of <col> is a null value.
	  // If the a null value gets filtered out, then that is correct semantics.
	  // But if the null value gets returned to executor, then it still need to be
	  // filtered out. To do that, the predicate need to be evaluated in executor
	  // with proper null semantics.
	  //
	  // Long story short, do not remove the original pred if the col or value is
	  // nullable.
	  //   
	  if ((colType.supportsSQLnull()) ||
	      (valueType.supportsSQLnull()))
	    {
	      removeFromOrigList = FALSE;
	    }
	  else
	    {
	      removeFromOrigList = TRUE;
	    }

	  if (ie->getOperatorType() == ITM_EQUAL)
	    op = "EQUAL";
	  else  if (ie->getOperatorType() == ITM_NOT_EQUAL)
	    op = "NOT_EQUAL";
	  else  if (ie->getOperatorType() == ITM_LESS)
            {
            if (flipOp)
              op = "GREATER";
            else
	      op = "LESS";
            }
	  else  if (ie->getOperatorType() == ITM_LESS_EQ)
            {
            if (flipOp)
              op = "GREATER_OR_EQUAL";
            else
	      op = "LESS_OR_EQUAL";
            }
	  else  if (ie->getOperatorType() == ITM_GREATER)
            {
            if (flipOp)
              op = "LESS";
            else
	      op = "GREATER";
            }
	  else  if (ie->getOperatorType() == ITM_GREATER_EQ)
            {
            if (flipOp)
              op = "LESS_OR_EQUAL";
            else
	      op = "GREATER_OR_EQUAL";
            }
	  else
	    op = "NO_OP";
	}
    }

  return found;
}

short HbaseAccess::extractHbaseFilterPreds(Generator * generator, 
					   ValueIdSet &preds, ValueIdSet &newExePreds)
{
   if (CmpCommon::getDefault(HBASE_FILTER_PREDS) == DF_OFF)
       return 0;
   // cannot push preds for aligned format row
   NABoolean isAlignedFormat = getTableDesc()->getNATable()->isAlignedFormat(getIndexDesc());

   if (isAlignedFormat)
     return 0;
  
   for (ValueId vid = preds.init(); 
       (preds.next(vid)); 
       preds.advance(vid))
    {
      ItemExpr * ie = vid.getItemExpr();

      // if it is AND operation, recurse through left and right children
      if (ie->getOperatorType() == ITM_AND)
        {
          ValueIdSet leftPreds;
          ValueIdSet rightPreds;
          leftPreds += ie->child(0)->castToItemExpr()->getValueId();
          rightPreds += ie->child(1)->castToItemExpr()->getValueId();
          extractHbaseFilterPreds(generator, leftPreds, newExePreds);
          extractHbaseFilterPreds(generator, rightPreds, newExePreds);
          continue; 
        }
      
      ValueId colVID;
      ValueId valueVID;
      NABoolean removeFromOrigList = FALSE;
      NAString op;
      NABoolean isHFP =
        isHbaseFilterPred(generator, ie, colVID, valueVID, op, removeFromOrigList);
      
      if (isHFP) 
        {
          hbaseFilterColVIDlist_.insert(colVID);
          hbaseFilterValueVIDlist_.insert(valueVID);
          
          opList_.insert(op);
          
          if (NOT removeFromOrigList)
            newExePreds.insert(vid);
        }
      else 
        {
          newExePreds.insert(vid);
        }
      
    } // end for
  
  return 0;
}

////////////////////////////////////////////////////////////////////////////
// To push down, the predicate must have the following form:
//  xp:=  <column>  <op>  <value-expr>
//  xp:=  <column> is not null (no support for hbase lookup)
//  xp:=  <column> is null (no support for hbase lookup)
//    (xp:=<column> like <value-expr> not yet implemented)
//  xp:=<xp> OR <xp> (not evaluated in isHbaseFilterPredV2, but by extractHbaseFilterPredV2)
//  xp:=<xp> AND <xp>(not evaluated in isHbaseFilterPredV2, but by extractHbaseFilterPredV2)
//
// and all of the following conditions must be met:
//
//      <column>:       a base table or index column which can be serialized and belong to the table being scanned.
//                            serialized: either the column doesn't need encoding, like
//                                            an unsigned integer,  or the column
//                                            was declared with the SERIALIZED option.
//                      it also must not be an added column with default non null.
//      <op>:              eq, ne, gt, ge, lt, le
//      <value-expr>:  an expression that only contains const or param values, and
//                     <value-expr>'s datatype is not a superset of <column>'s datatype.
//
// colVID, valueID and op are output parameters.
/////////////////////////////////////////////////////////////////////////////
NABoolean HbaseAccess::isHbaseFilterPredV2(Generator * generator, ItemExpr * ie,
                     ValueId &colVID, ValueId &valueVID,
                     NAString &op)
{
  NABoolean foundBinary = FALSE;
  NABoolean foundUnary = FALSE;
  NABoolean hbaseLookupPred = FALSE;
  NABoolean flipOp = FALSE;  // set to TRUE when column is child(1)

  if (ie &&
      ((ie->getOperatorType() >= ITM_EQUAL) &&
       (ie->getOperatorType() <= ITM_GREATER_EQ))) //binary operator case
    {//begin expression
      ItemExpr * child0 = ie->child(0)->castToItemExpr();
      ItemExpr * child1 = ie->child(1)->castToItemExpr();

      if ((ie->child(0)->getOperatorType() == ITM_BASECOLUMN) &&
      (NOT hasColReference(ie->child(1))))
    {
      foundBinary = TRUE;
      colVID = ie->child(0)->getValueId();
      valueVID = ie->child(1)->getValueId();
    }
      else if ((ie->child(1)->getOperatorType() == ITM_BASECOLUMN) &&
           (NOT hasColReference(ie->child(0))))
    {
      foundBinary = TRUE;
      flipOp = TRUE;
      colVID = ie->child(1)->getValueId();
      valueVID = ie->child(0)->getValueId();
    }
      else if ((ie->child(0)->getOperatorType() == ITM_INDEXCOLUMN) &&
           (NOT hasColReference(ie->child(1))))
    {
      foundBinary = TRUE;
      colVID = ie->child(0)->getValueId();
      valueVID = ie->child(1)->getValueId();
    }
      else if ((ie->child(1)->getOperatorType() == ITM_INDEXCOLUMN) &&
           (NOT hasColReference(ie->child(0))))
    {
      foundBinary = TRUE;
      flipOp = TRUE;
      colVID = ie->child(1)->getValueId();
      valueVID = ie->child(0)->getValueId();
    }
      else if ((ie->child(0)->getOperatorType() == ITM_HBASE_COLUMN_LOOKUP) &&
           (NOT hasColReference(ie->child(1))))
    {
      HbaseColumnLookup * hcl = (HbaseColumnLookup*)ie->child(0)->castToItemExpr();
      if (hcl->getValueId().getType().getTypeQualifier() == NA_CHARACTER_TYPE)
        {
          hbaseLookupPred = TRUE;

          ItemExpr * newCV = new(generator->wHeap()) ConstValue(hcl->hbaseCol());
          newCV = newCV->bindNode(generator->getBindWA());
          newCV = newCV->preCodeGen(generator);

          foundBinary = TRUE;
          colVID = newCV->getValueId();
          valueVID = ie->child(1)->getValueId();
        }
    }
      else if ((ie->child(1)->getOperatorType() == ITM_HBASE_COLUMN_LOOKUP) &&
           (NOT hasColReference(ie->child(0))))
    {
      HbaseColumnLookup * hcl = (HbaseColumnLookup*)ie->child(1)->castToItemExpr();
      if (hcl->getValueId().getType().getTypeQualifier() == NA_CHARACTER_TYPE)
        {
          hbaseLookupPred = TRUE;

          ItemExpr * newCV = new(generator->wHeap()) ConstValue(hcl->hbaseCol());
          newCV = newCV->bindNode(generator->getBindWA());
          newCV = newCV->preCodeGen(generator);

          foundBinary = TRUE;
          flipOp = TRUE;
          colVID = newCV->getValueId();
          valueVID = ie->child(0)->getValueId();
        }
    }
    }//end binary operators
  else if (ie && ((ie->getOperatorType() == ITM_IS_NULL)||(ie->getOperatorType() == ITM_IS_NOT_NULL))){//check for unary operators
      ItemExpr * child0 = ie->child(0)->castToItemExpr();
      if ((ie->child(0)->getOperatorType() == ITM_BASECOLUMN) ||
          (ie->child(0)->getOperatorType() == ITM_INDEXCOLUMN)){
          foundUnary = TRUE;
          colVID = ie->child(0)->getValueId();
          valueVID = NULL_VALUE_ID;
      }

  }//end unary operators

  //check if found columns belong to table being scanned (so is not an input to the scan node)
  if (foundBinary || foundUnary){
    ValueId dummyValueId;
    if (getGroupAttr()->getCharacteristicInputs().referencesTheGivenValue(colVID,dummyValueId)){
        foundBinary=FALSE;
        foundUnary=FALSE;
    }
  }
  //check if not an added column with default non null
  if ((foundBinary || foundUnary)&& (NOT hbaseLookupPred)){
        if (colVID.isColumnWithNonNullNonCurrentDefault()){
            foundBinary=FALSE;
            foundUnary=FALSE;
        }
  }

  if (foundBinary)
    {
      const NAType &colType = colVID.getType();
      const NAType &valueType = valueVID.getType();

      NABoolean generateNarrow = FALSE;
      if (NOT hbaseLookupPred)
    {
      generateNarrow = valueType.errorsCanOccur(colType);
      if ((generateNarrow)  || // value not a superset of column
          (NOT columnEnabledForSerialization(colVID.getItemExpr())))
          foundBinary = FALSE;
    }

      if (foundBinary)
    {
      if (colType.getTypeQualifier() == NA_CHARACTER_TYPE)
        {
          const CharType &charColType = (CharType&)colType;
          const CharType &charValType = (CharType&)valueType;

          if ((charColType.isCaseinsensitive() || charValType.isCaseinsensitive()) ||
          (charColType.isUpshifted() || charValType.isUpshifted()))
         foundBinary = FALSE;
        }
      else if (colType.getTypeQualifier() == NA_NUMERIC_TYPE)
        {
          const NumericType &numType = (NumericType&)colType;
          const NumericType &valType = (NumericType&)valueType;
          if (numType.isBigNum() || valType.isBigNum())
         foundBinary = FALSE;
        }
    }

      if (foundBinary)
    {
      if ((ie) && (((BiRelat*)ie)->addedForLikePred()) &&
          (valueVID.getItemExpr()->getOperatorType() == ITM_CONSTANT))
        {
          // remove trailing '\0' characters since this is being pushed down to hbase.
          ConstValue * cv = (ConstValue*)(valueVID.getItemExpr());
          char * cvv = (char*)cv->getConstValue();
          Lng32 len = cv->getStorageSize() - 1;
          while ((len > 0) && (cvv[len] == '\0'))
            len--;

          NAString newCVV(cvv, len+1);

          ItemExpr * newCV = new(generator->wHeap()) ConstValue(newCVV);
          newCV = newCV->bindNode(generator->getBindWA());
          newCV = newCV->preCodeGen(generator);
          valueVID = newCV->getValueId();
        }

      ItemExpr * castValue = NULL;
          if (NOT hbaseLookupPred)
            castValue = new(generator->wHeap()) Cast(valueVID.getItemExpr(), &colType);
          else
            {
              castValue = new(generator->wHeap()) Cast(valueVID.getItemExpr(), &valueVID.getType());
            }

      if ((NOT hbaseLookupPred) &&
          (isEncodingNeededForSerialization(colVID.getItemExpr())))
        {
          castValue = new(generator->wHeap()) CompEncode
        (castValue, FALSE, -1, CollationInfo::Sort, TRUE, FALSE);
        }

      castValue = castValue->bindNode(generator->getBindWA());
      castValue = castValue->preCodeGen(generator);

      valueVID = castValue->getValueId();

      NAString nullType;

      if ((colType.supportsSQLnull()) ||
          (valueType.supportsSQLnull()))
        {
          nullType = "_NULL";
        }
      else
        {
          nullType = "";
        }

      // append -NULL to the operator to signify the java code generating pushdown filters to handle NULL semantic logic
      if (ie->getOperatorType() == ITM_EQUAL)
          op = "EQUAL"+nullType;
      else  if (ie->getOperatorType() == ITM_NOT_EQUAL)
        op = "NOT_EQUAL"+nullType;
      else  if (ie->getOperatorType() == ITM_LESS){
          if (flipOp)
              op = "GREATER"+nullType;
          else
              op = "LESS"+nullType;
      }
      else  if (ie->getOperatorType() == ITM_LESS_EQ){
          if (flipOp)
              op = "GREATER_OR_EQUAL"+nullType;
          else
              op = "LESS_OR_EQUAL"+nullType;
      }else  if (ie->getOperatorType() == ITM_GREATER){
          if (flipOp)
              op = "LESS"+nullType;
          else
              op = "GREATER"+nullType;
      }else  if (ie->getOperatorType() == ITM_GREATER_EQ){
          if (flipOp)
              op = "LESS_OR_EQUAL"+nullType;
          else
              op = "GREATER_OR_EQUAL"+nullType;
      }else
        op = "NO_OP"+nullType;
    }
    }
  if (foundUnary){
      const NAType &colType = colVID.getType();
      NAString nullType;

      if (colType.supportsSQLnull())
        {
          nullType = "_NULL";
        }
      else
        {
          nullType = "";
        }
      if (ie->getOperatorType() == ITM_IS_NULL)
              op = "IS_NULL"+nullType;
      else if (ie->getOperatorType() == ITM_IS_NOT_NULL)
              op = "IS_NOT_NULL"+nullType;
  }

  return foundBinary || foundUnary;
}
short HbaseAccess::extractHbaseFilterPredsVX(Generator * generator,
           ValueIdSet &preds, ValueIdSet &newExePreds){
    //separate the code that should not belong in the recursive function
       if (CmpCommon::getDefault(HBASE_FILTER_PREDS) == DF_OFF)
        return 0;
       // check if initial (version 1) implementation
       if (CmpCommon::getDefault(HBASE_FILTER_PREDS) == DF_MINIMUM)
        return extractHbaseFilterPreds(generator,preds,newExePreds);

       // if here, we are DF_MEDIUM
       // cannot push preds for aligned format row
       NABoolean isAlignedFormat = getTableDesc()->getNATable()->isAlignedFormat(getIndexDesc());

       if (isAlignedFormat)
         return 0;
       //recursive function call
       opList_.insert("V2");//to instruct the java side that we are dealing with predicate pushdown V2 semantic, add "V2" marker
       extractHbaseFilterPredsV2(generator,preds,newExePreds,FALSE);
       return 0;

}

// return true if successfull push down of node
NABoolean HbaseAccess::extractHbaseFilterPredsV2(Generator * generator,
                       ValueIdSet &preds, ValueIdSet &newExePreds, NABoolean checkOnly)
{

    // the isFirstAndLayer is used to allow detecting top level predicate that can still be pushed to executor
    int addedNode=0;
    for (ValueId vid = preds.init();
       (preds.next(vid));
       preds.advance(vid))
    {
      ItemExpr * ie = vid.getItemExpr();

      // if it is AND operation, recurse through left and right children
      if (ie->getOperatorType() == ITM_AND){
          ValueIdSet leftPreds;
          ValueIdSet rightPreds;
          leftPreds += ie->child(0)->castToItemExpr()->getValueId();
          rightPreds += ie->child(1)->castToItemExpr()->getValueId();
          //cannot be first AND layer, both left and right must be pushable to get anything pushed
          if(extractHbaseFilterPredsV2(generator, leftPreds, newExePreds, TRUE)&&
             extractHbaseFilterPredsV2(generator, rightPreds, newExePreds, TRUE)){// both left and right child must match
              if(!checkOnly){
                  extractHbaseFilterPredsV2(generator, leftPreds, newExePreds, FALSE);//generate tree
                  extractHbaseFilterPredsV2(generator, rightPreds, newExePreds, FALSE);//generate tree
                  opList_.insert("AND");
              }
            if (preds.entries()==1)
                return TRUE;
          }
          else{
              if(!checkOnly){
                  newExePreds.insert(vid);
              }
              if (preds.entries()==1)
                    return FALSE;
          }
          continue;
          // the OR case is easier, as we don t have the case of top level expression that can still be pushed to executor
      }//end if AND
      else if(ie->getOperatorType() == ITM_OR){
          ValueIdSet leftPreds;
          ValueIdSet rightPreds;
          leftPreds += ie->child(0)->castToItemExpr()->getValueId();
          rightPreds += ie->child(1)->castToItemExpr()->getValueId();
          //both left and right must be pushable to get anything pushed
          if(extractHbaseFilterPredsV2(generator, leftPreds, newExePreds, TRUE)&&
             extractHbaseFilterPredsV2(generator, rightPreds, newExePreds, TRUE)){// both left and right child must match
              if(!checkOnly){
                  extractHbaseFilterPredsV2(generator, leftPreds, newExePreds, FALSE);//generate tree
                  extractHbaseFilterPredsV2(generator, rightPreds, newExePreds, FALSE);//generate tree
                  opList_.insert("OR");
                  if (addedNode>0)opList_.insert("AND"); // if it is not the first node add to the push down, AND it with the rest
                  addedNode++; // we just pushed it down, so increase the node count pushed down.
              }
              if (preds.entries()==1)
               return TRUE;
          }
          else{// if predicate cannot be pushed down
              if(!checkOnly){
                  newExePreds.insert(vid);
              }
              if (preds.entries()==1)
                    return FALSE;
          }
          continue;
      }//end if OR

      ValueId colVID;
      ValueId valueVID;

      NAString op;
      NABoolean isHFP =
        isHbaseFilterPredV2(generator, ie, colVID, valueVID, op);

      if (isHFP && !checkOnly){// if pushable, push it
          hbaseFilterColVIDlist_.insert(colVID);
          if (valueVID != NULL_VALUE_ID) hbaseFilterValueVIDlist_.insert(valueVID);// don't insert valueID for unary operators.
          opList_.insert(op);
          if (addedNode>0)opList_.insert("AND"); // if it is not the first node add to the push down, AND it with the rest
          addedNode++; // we just pushed it down, so increase the node count pushed down.
        }else if (!checkOnly){//if not pushable, pass it for executor evaluation.
            newExePreds.insert(vid);
        }
      if (preds.entries()==1){
          return isHFP; // if we are not on the first call level, where we can have multiple preds, exit returning the pushability
      }

    } // end for

  return TRUE;//don't really care, means we are top level.
}


void HbaseAccess::computeRetrievedCols()
{
  GroupAttributes     fakeGA;
  ValueIdSet          requiredValueIds(getGroupAttr()->
				       getCharacteristicOutputs());
  ValueIdSet          coveredExprs;

  // ---------------------------------------------------------------------
  // Make fake group attributes with all inputs that are available to
  // the file scan node and with no "native" values.
  // Then call the "coverTest" method, offering it all the index columns
  // as additional inputs. "coverTest" will mark those index columns that
  // it actually needs to satisfy the required value ids, and that is
  // what we actually want. The actual cover test should always succeed,
  // otherwise the FileScan node would have been inconsistent.
  // ---------------------------------------------------------------------

  fakeGA.addCharacteristicInputs(getGroupAttr()->getCharacteristicInputs());
  requiredValueIds += selectionPred();
  requiredValueIds += executorPred();

  fakeGA.coverTest(requiredValueIds,              // char outputs + preds
		   getIndexDesc()->getIndexColumns(), // all index columns
		   coveredExprs,                  // dummy parameter
		   retrievedCols());               // needed index cols

  //
  // *** This CMPASSERT goes off sometimes, indicating an actual problem.
  // Hans has agreed to look into it (10/18/96) but I (brass) am
  // commenting it out for now, for sake of my time in doing a checking.
  //
  //  CMPASSERT(coveredExprs == requiredValueIds);

}

RelExpr * HbaseAccess::preCodeGen(Generator * generator,
				  const ValueIdSet & externalInputs,
				  ValueIdSet &pulledNewInputs)
{
  if (nodeIsPreCodeGenned())
    return this;

  const PartitioningFunction* myPartFunc = getPartFunc();

  // use const HBase keys only if we don't have to add
  // partitioning key predicates
  if ( myPartFunc == NULL ||
       !myPartFunc->isPartitioned() ||
       myPartFunc->isAReplicationPartitioningFunction())
    if (!processConstHBaseKeys(
           generator,
           this,
           getSearchKey(),
           getIndexDesc(),
           executorPred(),
           getHbaseSearchKeys(),
           listOfUniqueRows_,
           listOfRangeRows_))
      return NULL;

  if (! FileScan::preCodeGen(generator,externalInputs,pulledNewInputs))
    return NULL;

  //compute isUnique:
  NABoolean isUnique = FALSE;
  if (listOfRangeRows_.entries() == 0)
    {
      if ((searchKey() && searchKey()->isUnique()) &&
    (listOfUniqueRows_.entries() == 0))
  isUnique = TRUE;
      else if ((NOT (searchKey() && searchKey()->isUnique())) &&
         (listOfUniqueRows_.entries() == 1) &&
         (listOfUniqueRows_[0].rowIds_.entries() == 1))
  isUnique = TRUE;
    }

  // executorPred() contains an ANDed list of predicates.
  // if hbase filter preds are enabled, then extracts those preds from executorPred()
  // which could be pushed down to hbase.
  // Do this only for non-unique scan access.
  ValueIdSet newExePreds;
  ValueIdSet* originExePreds = new (generator->wHeap())ValueIdSet(executorPred()) ;//saved for futur nullable column check

  if (CmpCommon::getDefault(HBASE_FILTER_PREDS) != DF_MINIMUM){ // the check for V2 and above is moved up before calculating retrieved columns
      if ((NOT isUnique) &&
          (extractHbaseFilterPredsVX(generator, executorPred(), newExePreds)))
        return this;

      // if some filter preds were found, then initialize executor preds with new exe preds.
      // newExePreds may be empty which means that all predicates were changed into
      // hbase preds. In this case, nuke existing exe preds.
      if (hbaseFilterColVIDlist_.entries() > 0)
        setExecutorPredicates(newExePreds);
  }

  ValueIdSet colRefSet;

  computeRetrievedCols();
  for (ValueId valId = retrievedCols().init();
       retrievedCols().next(valId);
       retrievedCols().advance(valId))
    {
      ValueId dummyValId;
      if ((valId.getItemExpr()->getOperatorType() != ITM_CONSTANT) &&
	  (getGroupAttr()->getCharacteristicOutputs().referencesTheGivenValue(valId, dummyValId)))
	colRefSet.insert(valId);
    }

  if (getTableDesc()->getNATable()->isHbaseCellTable())
    {
      for (Lng32 i = 0; i < getIndexDesc()->getIndexColumns().entries(); i++)
	{
	  //	  retColRefSet_.insert(getIndexDesc()->getIndexColumns()[i]);
	}
    }
  else if (getTableDesc()->getNATable()->isHbaseRowTable())
    {
      NASet<NAString> * hbaseColNameSet = 
	generator->getBindWA()->hbaseColUsageInfo()->hbaseColNameSet
	((QualifiedName*)&getTableDesc()->getNATable()->getTableName());

      NABoolean starFound = FALSE;
      for (Lng32 ij = 0; ij < hbaseColNameSet->entries(); ij++)
	{
	  NAString &colName = (*hbaseColNameSet)[ij];

	  retHbaseColRefSet_.insert(colName);

	  if (colName == "*")
	    starFound = TRUE;
	}

      if (starFound)
	retHbaseColRefSet_.clear();
    }
  else
    {
      // create the list of columns that need to be retrieved from hbase .
      // first add all columns referenced in the executor pred.
      HbaseAccess::addReferenceFromVIDset(executorPred(), TRUE, TRUE, colRefSet);


      HbaseAccess::addReferenceFromVIDset
        (getGroupAttr()->getCharacteristicOutputs(), TRUE, TRUE, colRefSet);

      for (ValueId valId = colRefSet.init();
	   colRefSet.next(valId);
	   colRefSet.advance(valId))
	{
	  ValueId dummyValId;
	  if (NOT getGroupAttr()->getCharacteristicInputs().referencesTheGivenValue(valId, dummyValId))
            {
              retColRefSet_.insert(valId);

              if (valId.getItemExpr()->getOperatorType() == ITM_HBASE_TIMESTAMP)
                {
                  Lng32 colNumber = ((BaseColumn*)((HbaseTimestamp*)valId.getItemExpr())->col())->getColNumber();
                  ValueId colVID = getIndexDesc()->getIndexColumns()[colNumber];
                  retColRefSet_.insert(colVID);
                }

              if (valId.getItemExpr()->getOperatorType() == ITM_HBASE_VERSION)
                {
                  Lng32 colNumber = ((BaseColumn*)((HbaseVersion*)valId.getItemExpr())->col())->getColNumber();
                  ValueId colVID = getIndexDesc()->getIndexColumns()[colNumber];
                  retColRefSet_.insert(colVID);
                }

            }
        }

      // add key columns. If values are missing in hbase, then atleast the key
      // value is needed to retrieve a row.
      //only if needed. If there is already a non nullable non added non nullable with default columns in the set, we should not need to add
      //any other columns.
      if (CmpCommon::getDefault(HBASE_FILTER_PREDS) == DF_MEDIUM && getMdamKeyPtr() == NULL){ //only enable column retrieval optimization with DF_MEDIUM and not for MDAM scan
          bool needAddingNonNullableColumn = true; //assume we need to add one non nullable column
          for (ValueId vid = retColRefSet_.init();// look for each column in th eresult set if one match the criteria non null non added non nullable with default
                  retColRefSet_.next(vid);
                  retColRefSet_.advance(vid))
          {
            if (originExePreds->isNotNullable(vid)){// it is non nullable
                OperatorTypeEnum operatorType = vid.getItemExpr()->getOperatorType();
                if ((operatorType == ITM_BASECOLUMN || operatorType == ITM_INDEXCOLUMN) && !vid.isColumnWithNonNullNonCurrentDefault()){//check if with non null or non current default... notgood
                    needAddingNonNullableColumn = false; // we found one column meeting all criteria
                    break;
                }
            }
          }
          if (needAddingNonNullableColumn){ // ok now we need to add one key column that is not nullable
              bool foundAtLeastOneKeyColumnNotNullable = false;
              for(int i=getIndexDesc()->getIndexKey().entries()-1; i>=0;i--)// doing reverse search is making sure we are trying to avoid to use _SALT_ column
                                                                         // because _SALT_ is physicaly the last column therefore we don't skip columns optimally if using _SALT_ column
              {
                  ValueId vaId = getIndexDesc()->getIndexKey()[i];
                  if ( (vaId.getItemExpr()->getOperatorType() == ITM_BASECOLUMN && !((BaseColumn*)vaId.getItemExpr())->getNAColumn()->getType()->supportsSQLnullPhysical())||
                          (vaId.getItemExpr()->getOperatorType() == ITM_INDEXCOLUMN && !((IndexColumn*)vaId.getItemExpr())->getNAColumn()->getType()->supportsSQLnullPhysical())
                          ){ //found good key column candidate?
                      HbaseAccess::addReferenceFromItemExprTree(vaId.getItemExpr(),TRUE,FALSE,retColRefSet_); // add it
                      foundAtLeastOneKeyColumnNotNullable = true; //tag we found it
                      break; // no need to look further
                  }
              }
              if (!foundAtLeastOneKeyColumnNotNullable){//oh well, did not find any key column non nullable, let s add all key columns
                  HbaseAccess::addColReferenceFromVIDlist(getIndexDesc()->getIndexKey(), retColRefSet_);
              }
          }
      }else //end if DF_MEDIUM
          HbaseAccess::addColReferenceFromVIDlist(getIndexDesc()->getIndexKey(), retColRefSet_);
    }

  if ((getMdamKeyPtr()) &&
      ((listOfRangeRows_.entries() > 0) ||
       (listOfUniqueRows_.entries() > 0)))
    {
      GenAssert(0, "listOfRange/Unique cannot be used if mdam is chosen.");

      return NULL;
    }

  // flag for both hive and hbase tables
  generator->setHdfsAccess(TRUE);

  if (!isUnique)
      generator->oltOptInfo()->setMultipleRowsReturned(TRUE) ;

  // Do not allow cancel of unique queries but allow cancel of queries 
  // that are part of a rowset operation. 
  if ((isUnique) &&
      (NOT generator->oltOptInfo()->multipleRowsReturned()))
    {
      generator->setMayNotCancel(TRUE);
      uniqueHbaseOper() = TRUE;
    }
  else
    {
      generator->oltOptInfo()->setOltCliOpt(FALSE);

      if (isUnique)
	{
	  if ((CmpCommon::getDefault(HBASE_ROWSET_VSBB_OPT) == DF_ON) &&
	      (NOT generator->isRIinliningForTrafIUD()) &&
	      (searchKey() && searchKey()->isUnique()))
	    {
	      uniqueRowsetHbaseOper() = TRUE;
	    }
	}
    }

  // executorPred() contains an ANDed list of predicates.
  // if hbase filter preds are enabled, then extracts those preds from executorPred()
  // which could be pushed down to hbase.
  // Do this only for non-unique scan access.
  if (CmpCommon::getDefault(HBASE_FILTER_PREDS) == DF_MINIMUM){ //keep the check for pushdown after column retrieval for pushdown V1.
    if ((NOT isUnique) &&
        (extractHbaseFilterPreds(generator, executorPred(), newExePreds)))
      return this;

  // if some filter preds were found, then initialize executor preds with new exe preds.
  // newExePreds may be empty which means that all predicates were changed into
  // hbase preds. In this case, nuke existing exe preds.
  if (hbaseFilterColVIDlist_.entries() > 0)
      setExecutorPredicates(newExePreds);
  }//DF_MINIMUM

  snpType_ = SNP_NONE;
  DefaultToken  tok = CmpCommon::getDefault(TRAF_TABLE_SNAPSHOT_SCAN);
  if (tok == DF_LATEST)
    //latest snapshot -- new way used with scan independent from bulk unload
    snpType_= SNP_LATEST;
  else if (tok == DF_SUFFIX)
    //the exsiting where snapshot scan is used with bulk unload
    snpType_ = SNP_SUFFIX;

  markAsPreCodeGenned();
  
  // Done.
  return this;
}

RelExpr * HbaseAccessCoProcAggr::preCodeGen(Generator * generator,
					    const ValueIdSet & externalInputs,
					    ValueIdSet &pulledNewInputs)
{
  if (nodeIsPreCodeGenned())
    return this;

  if (! HbaseAccess::preCodeGen(generator,externalInputs,pulledNewInputs))
    return NULL;

  // Rebuild the aggregate expressions tree
  ValueIdSet availableValues;
  getInputValuesFromParentAndChildren(availableValues);
  aggregateExpr().replaceVEGExpressions
                     (availableValues,
  	 	      getGroupAttr()->getCharacteristicInputs());

  markAsPreCodeGenned();
  
  // Done.
  return this;
}

RelExpr * ExeUtilHbaseCoProcAggr::preCodeGen(Generator * generator,
					    const ValueIdSet & externalInputs,
					    ValueIdSet &pulledNewInputs)
{
  if (nodeIsPreCodeGenned())
    return this;

  if (! ExeUtilExpr::preCodeGen(generator,externalInputs,pulledNewInputs))
    return NULL;

  // Rebuild the aggregate expressions tree
  ValueIdSet availableValues;
  getInputValuesFromParentAndChildren(availableValues);
  aggregateExpr().replaceVEGExpressions
                     (availableValues,
  	 	      getGroupAttr()->getCharacteristicInputs());

  markAsPreCodeGenned();
  
  // Done.
  return this;
}

RelExpr * ExeUtilOrcFastAggr::preCodeGen(Generator * generator,
                                         const ValueIdSet & externalInputs,
                                         ValueIdSet &pulledNewInputs)
{
  if (nodeIsPreCodeGenned())
    return this;

  if (! ExeUtilExpr::preCodeGen(generator,externalInputs,pulledNewInputs))
    return NULL;

  // Rebuild the aggregate expressions tree
  ValueIdSet availableValues;
  getInputValuesFromParentAndChildren(availableValues);
  aggregateExpr().replaceVEGExpressions
                     (availableValues,
  	 	      getGroupAttr()->getCharacteristicInputs());

  markAsPreCodeGenned();
  
  // Done.
  return this;
}

Should there be an assert if we find an AND?