@@ -4368,14 +4368,6 @@ RelExpr * GenericUpdate::preCodeGen(Generator * generator,
 	  identityCol = valId.getNAColumn();
 	}
 
-      if ((getOperatorType() != REL_HBASE_UPDATE) &&
-	  (mergeInsertRecExpr().entries() > 0))
-	{
-	  *CmpCommon::diags() << DgSqlCode(-3241)
-			      << DgString0(" Non-unique ON clause not allowed with INSERT.");
-	  GenExit();
-	}
-
       if (((getOperatorType() == REL_HBASE_DELETE) ||
            (getOperatorType() == REL_HBASE_UPDATE)) &&
           (getTableDesc()->getNATable()->getClusteringIndex()->hasSyskey()))
/**********************************************************************
// @@@ 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 "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;
}

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);
    }
  
  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_UPDATE) &&
	  (mergeInsertRecExpr().entries() > 0))
	{
	  *CmpCommon::diags() << DgSqlCode(-3241)
			      << DgString0(" Non-unique ON clause not allowed with INSERT.");
	  GenExit();
	}

      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_DELETE) &&
          (mergeInsertRecExpr().entries() > 0) &&
          (CmpCommon::getDefault(COMP_BOOL_175) == DF_OFF))
	{
	  *CmpCommon::diags() << DgSqlCode(-3241)
			      << DgString0(" MERGE delete 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();

      if (isMerge())
	{
	  // column being updated must be from the same table that is being
	  // updated.
	  if (((BaseColumn *)(item_expr->child(0)->castToItemExpr()))->getTableDesc() !=
	      getTableDesc())
	    {
	      *CmpCommon::diags() << DgSqlCode(-3241)
				  << DgString0("Invalid column being updated.");
	      GenExit();
	    }
	}

      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_);
        }
    }

  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()))
	 uniqueRowsetHbaseOper() = TRUE;
  }
  else
  if (isUnique)
    {
      // do not cancel unique queries.
      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()))
	    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;
	    }
	}
    }
  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 (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)
    {
      // do not cancel unique queries.
      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->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->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() = srcValueId.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->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");

	      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());
	    } // 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)
{
  if (!ie)
    return NULL;

  if ((ie->getOperatorType() == ITM_BASECOLUMN) ||
      (ie->getOperatorType() == ITM_INDEXCOLUMN))
    {
      if (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));
      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());

  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;

  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;
	  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;
	  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;
	  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;
	      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)
	    op = "LESS";
	  else  if (ie->getOperatorType() == ITM_LESS_EQ)
	    op = "LESS_OR_EQUAL";
	  else  if (ie->getOperatorType() == ITM_GREATER)
	    op = "GREATER";
	  else  if (ie->getOperatorType() == ITM_GREATER_EQ)
	    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;
}

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;

  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 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 ((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);

  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;
    }

  if (!isUnique)
      generator->oltOptInfo()->setMultipleRowsReturned(TRUE) ;

  if ((isUnique) &&
      (NOT generator->oltOptInfo()->multipleRowsReturned()))
    {
      // do not cancel unique queries.
      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.
  ValueIdSet newExePreds;

  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);

  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;
}

I am glad that this check was removed. Can you please tell me if we ever see any of the other 3241 errors being triggered from the generator? To me this indicates that the binder "let one get through". I would like to eventually raise all these 3241 errors in thebinder.