// index access (both reference and value)
ItemExpr * ItemExprTreeAsList::operator [] (CollIndex i)
{
  
  //     think of three different cases:
  // 
  //     a) i is out of range (< 0 or >= #entries)
  // 
  //     b) the node we are looking for is neither the only nor the last
  //        node in the backbone
  // 
  //     c) we are looking for the last element in the backbone (which
  //        may be the only element)
  // 

  ItemExpr *aNodePtr = *treePtr_;
  Int32 j = (Int32) i; // j may become negative, i may be unsigned

  if (j < 0)
    return NULL; // case a

  if (aNodePtr->getOperatorType() != operator_ AND
      j == 0)
    return aNodePtr; // case b

  while (aNodePtr != NULL AND j >= 0)
    {
      if (aNodePtr->getOperatorType() == operator_ AND
	  aNodePtr->getArity() >= 2)
	{
	  if (shape_ == LEFT_LINEAR_TREE)
	    {
	      if (j == 0)
		aNodePtr = aNodePtr->child(1); // case b
	      else
		aNodePtr = aNodePtr->child(0);
	    }
	  else if (shape_ == RIGHT_LINEAR_TREE)
	    {
	      if (j == 0)
		aNodePtr = aNodePtr->child(0); // case b
	      else
		aNodePtr = aNodePtr->child(1);
	    }
	  else
	    ABORT("can't do bushy trees");
	}
      j--;
    }

  // if we are looking for the only element, the while loop
  // is not executed at all

  return aNodePtr;

}
// check whether an element is in the collection
NABoolean ItemExprTreeAsList::contains(const ItemExpr *treeToCheck)
{
  
  ItemExpr *aNodePtr = *treePtr_;

  while (aNodePtr != NULL)
    {
      if (aNodePtr == treeToCheck)
	return TRUE;

      if (aNodePtr->getOperatorType() == operator_ AND
	  aNodePtr->getArity() >= 2)
	{
	  if (shape_ == RIGHT_LINEAR_TREE)
	    aNodePtr = aNodePtr->child(1);
	  else
	    ABORT("can't do other than right-linear trees");
	}
      else
	aNodePtr = NULL;
    }
  return FALSE;
}
// return number of entries
Lng32 ItemExprTreeAsList::entries() const
{
  ItemExpr *aNode = *treePtr_;
  Lng32 result = 0;

  while (aNode != NULL)
    {
      result++;
      if (aNode->getOperatorType() == operator_ AND
	  aNode->getArity() >= 2)
	{
	  if (shape_ == LEFT_LINEAR_TREE)
	    aNode = aNode->child(0);
	  else
	    if (shape_ == RIGHT_LINEAR_TREE)
	      aNode = aNode->child(1);
	    else
	      ABORT("can't do other than right-linear trees");
	}
      else
	aNode = NULL;
    }
  return result;
}
// computeHistoryBuffer
//
// Helper function that traverses the set of root sequence functions
// supplied by the compiler and dynamically determines the size
// of the history buffer.
// 
void PhysSequence::computeHistoryRows(const ValueIdSet &sequenceFunctions,//historyIds
                                      Lng32 &computedHistoryRows,
                                      Lng32 &unableToCalculate,
                                      NABoolean &unboundedFollowing, 
                                      Lng32 &minFollowingRows,
                                      const ValueIdSet &outputFromChild) 
{
  ValueIdSet children;
  ValueIdSet historyAttributes;
  Lng32 value = 0;

  for(ValueId valId = sequenceFunctions.init();
      sequenceFunctions.next(valId);
      sequenceFunctions.advance(valId)) 
  {
    if(valId.getItemExpr()->isASequenceFunction()) 
    {
      ItemExpr *itmExpr = valId.getItemExpr();

      switch(itmExpr->getOperatorType())
        {

        // THIS and NOT THIS are not dynamically computed
        //
        case ITM_THIS:
        case ITM_NOT_THIS:
          break;

        // The RUNNING functions and LastNotNull all need to go back just one row.
        //
        case ITM_RUNNING_SUM:
        case ITM_RUNNING_COUNT:
        case ITM_RUNNING_MIN:
        case ITM_RUNNING_MAX:
        case ITM_RUNNING_CHANGE:   
        case ITM_LAST_NOT_NULL:
          computedHistoryRows = MAXOF(computedHistoryRows, 2);
          break;
        ///set to unable to compute for now-- will change later to compte values from frameStart_ and frameEnd_
        case ITM_OLAP_SUM:
        case ITM_OLAP_COUNT:
        case ITM_OLAP_MIN:
        case ITM_OLAP_MAX:
        case ITM_OLAP_RANK:
        case ITM_OLAP_DRANK:
        {
          if ( !outputFromChild.contains(itmExpr->getValueId()))
          {
            ItmSeqOlapFunction * olap = (ItmSeqOlapFunction*)itmExpr;

            if (olap->isFrameStartUnboundedPreceding()) //(olap->getframeStart() == - INT_MAX)
            {
              computedHistoryRows = MAXOF(computedHistoryRows, 2);
            }
            else
            {
              computedHistoryRows = MAXOF(computedHistoryRows, ABS(olap->getframeStart()) + 2);
            }
            if (!olap->isFrameEndUnboundedFollowing()) //(olap->getframeEnd() != INT_MAX)
            {
              computedHistoryRows = MAXOF(computedHistoryRows, ABS(olap->getframeEnd()) + 1);
            }

            if (olap->isFrameEndUnboundedFollowing()) //(olap->getframeEnd() == INT_MAX)
            {
              unboundedFollowing = TRUE;
              if (olap->getframeStart() > 0) 
              {
                minFollowingRows = ((minFollowingRows > olap->getframeStart()) ?  
                                    minFollowingRows : olap->getframeStart());
              }
            } else  if (olap->getframeEnd() > 0)
            {
              minFollowingRows = ((minFollowingRows > olap->getframeEnd()) ?  
                                  minFollowingRows : olap->getframeEnd());
            }
          }
        }

        break;

        // If 'rows since', we cannot determine how much history is needed.  
        case ITM_ROWS_SINCE:
          unableToCalculate = 1;
          break;

        // The MOVING and OFFSET functions need to go back as far as the value
        // of their second child.
        //
        //  The second argument can be:
        //    Constant: for these, we can use the constant value to set the upper bound
        //              for the history buffer.
        //    ItmScalarMinMax(child0, child1) (with operType = ITM_SCALAR_MIN)  
        //      - if child0 or child1 is a constant, then we can use either one
        //        to set the upper bound.
        
        case ITM_MOVING_MIN:
        case ITM_MOVING_MAX:
        case ITM_OFFSET:
         
          for(Lng32 i = 1; i < itmExpr->getArity(); i++)
          {
            if (itmExpr->child(i)->getOperatorType() != ITM_NOTCOVERED)
            {
              ItemExpr * exprPtr = itmExpr->child(i);
              NABoolean negate;
              ConstValue *cv = exprPtr->castToConstValue(negate);
              if (cv AND cv->canGetExactNumericValue())
                {
                  Lng32 scale;
                  Int64 value64 = cv->getExactNumericValue(scale);

                  if(scale == 0 && value64 >= 0 && value64 < INT_MAX) 
                    {
                      value64 = (negate ? -value64 : value64);
                      value = MAXOF((Lng32)value64, value);
                    }
                 }
              else
                {
                  if (exprPtr->getOperatorType() == ITM_SCALAR_MIN)
                    {
                      for(Lng32 j = 0; j < exprPtr->getArity(); j++)
                        {
                          if (exprPtr->child(j)->getOperatorType()
                            != ITM_NOTCOVERED)
                            {
                               ItemExpr * exprPtr1 = exprPtr->child(j);
                               NABoolean negate1;
                               ConstValue *cv1 = exprPtr1->castToConstValue(negate1);
                               if (cv1 AND cv1->canGetExactNumericValue())
                                 {
                                   Lng32 scale1;
                                   Int64 value64_1 = cv1->getExactNumericValue(scale1);

                                   if(scale1 == 0 && value64_1 >= 0 && value64_1 < INT_MAX) 
                                     {
                                       value64_1 = (negate1 ? -value64_1 : value64_1);
                                       value = MAXOF((Lng32)value64_1, value);
                                     }
                                  }
                              }
                          }   
                     }   
                }  // end of inner else
            }// end of if

          }// end of for

          // Check if the value is greater than zero.
          // If it is, then save the value, but first
          // increment the returned ConstValue by one.
          // Otherwise, the offset or moving value was unable
          // to be calculated.

          if (value > 0)
          {
            value++;
            computedHistoryRows = MAXOF(computedHistoryRows, value);
            value = 0;
          }
          else
            unableToCalculate = 1;

          break;

        default:
          CMPASSERT(0);
        }
    }
   
    // Gather all the children, and if not empty, recurse down to the
    // next level of the tree.
    //

    for(Lng32 i = 0; i < valId.getItemExpr()->getArity(); i++) {
      if (//valId.getItemExpr()->child(i)->getOperatorType() != ITM_NOTCOVERED //old stuff
          !outputFromChild.contains(valId.getItemExpr()->child(i)->getValueId()))
      {
        children += valId.getItemExpr()->child(i)->getValueId();
      }
    }
  }
  
  if (NOT children.isEmpty())
  {
    computeHistoryRows(children, 
                       computedHistoryRows, 
                       unableToCalculate, 
                       unboundedFollowing, 
                       minFollowingRows,
                       outputFromChild);  
  }
} // PhysSequence::computeHistoryRows
void PhysSequence::computeReadNReturnItems( ValueId topSeqVid,
                                            ValueId vid,
                                            const ValueIdSet &outputFromChild,
                                            CollHeap *wHeap)
{
  ItemExpr * itmExpr = vid.getItemExpr();


  if (outputFromChild.contains(vid)) 
  {
    return;
  }
  //test if itm_minus and then if negative offset ....
  if ( itmExpr->getOperatorType() == ITM_OFFSET &&
      ((ItmSeqOffset *)itmExpr)->getOffsetConstantValue() < 0)
  {
    readSeqFunctions() -= topSeqVid;
    returnSeqFunctions() += topSeqVid;

    readSeqFunctions() += itmExpr->child(0)->castToItemExpr()->getValueId();
    return;
  }
  
  if (itmExpr->getOperatorType() == ITM_MINUS)
  {
    ItemExpr * chld0  = itmExpr->child(0)->castToItemExpr();
    if ( chld0->getOperatorType() == ITM_OFFSET &&
        ((ItmSeqOffset *)chld0)->getOffsetConstantValue() <0)
    {
      readSeqFunctions() -= topSeqVid;
      returnSeqFunctions() += topSeqVid;

      readSeqFunctions() += chld0->child(0)->castToItemExpr()->getValueId();

      ItemExpr * chld1  = itmExpr->child(1)->castToItemExpr();
      if (chld1->getOperatorType() == ITM_OFFSET &&
          ((ItmSeqOffset *)chld1)->getOffsetConstantValue() < 0)
      {
        readSeqFunctions() += chld1->child(0)->castToItemExpr()->getValueId();
      }
      else
      {
        readSeqFunctions() += chld1->getValueId();
      }
      return;
    }
    
  }
  
  
  if (itmExpr->getOperatorType() == ITM_OLAP_MIN || 
           itmExpr->getOperatorType() == ITM_OLAP_MAX) 
  { 
    ItmSeqOlapFunction * olap = (ItmSeqOlapFunction *)itmExpr;
    if (olap->getframeEnd()>0)
    {
      readSeqFunctions() -= topSeqVid;
      returnSeqFunctions() += topSeqVid;

      ItemExpr *newChild = new(wHeap) Convert (itmExpr->child(0)->castToItemExpr());
      newChild->synthTypeAndValueId(TRUE);

      itmExpr->child(0) = newChild;

      readSeqFunctions() += newChild->getValueId();
      return;
    }
  }
  
  if (itmExpr->getOperatorType() == ITM_SCALAR_MIN || 
           itmExpr->getOperatorType() == ITM_SCALAR_MAX) 
  {
    ItemExpr * chld0  = itmExpr->child(0)->castToItemExpr();
    ItemExpr * chld1  = itmExpr->child(1)->castToItemExpr();
    if ((chld0->getOperatorType() == ITM_OLAP_MIN && chld1->getOperatorType() == ITM_OLAP_MIN )|| 
        (chld0->getOperatorType() == ITM_OLAP_MAX && chld1->getOperatorType() == ITM_OLAP_MAX ))
    {
      ItmSeqOlapFunction * olap0 = (ItmSeqOlapFunction *)chld0;
      ItmSeqOlapFunction * olap1 = (ItmSeqOlapFunction *)chld1;
      if ( olap1->getframeEnd()>0)
      { 
        CMPASSERT(olap0->getframeEnd()==0);

        readSeqFunctions() -= topSeqVid;
        returnSeqFunctions() += topSeqVid;
        readSeqFunctions() += olap0->getValueId();
        
        ItemExpr *newChild = new(wHeap) Convert (olap1->child(0)->castToItemExpr());
        newChild->synthTypeAndValueId(TRUE);

        olap1->child(0) = newChild;

        readSeqFunctions() += newChild->getValueId();
      }
      else
      {
        CMPASSERT(olap1->getframeEnd()==0);

        readSeqFunctions() -= topSeqVid;
        returnSeqFunctions() += topSeqVid;
        readSeqFunctions() += olap1->getValueId();

        ItemExpr *newChild = new(wHeap) Convert (olap0->child(0)->castToItemExpr());
        newChild->synthTypeAndValueId(TRUE);

        olap0->child(0) = newChild;

        readSeqFunctions() += newChild->getValueId();
      }
      return;
    }
  }

  for (Int32 i= 0 ; i < itmExpr->getArity(); i++)
  {
    ItemExpr * chld= itmExpr->child(i);
    computeReadNReturnItems(topSeqVid,
                            chld->getValueId(),
                            outputFromChild,
                            wHeap);
  }
}//void PhysSequence::computeReadNReturnItems(ItemExpr * other)
// remove an element that is given by its value
ItemExpr * ItemExprTreeAsList::remove(ItemExpr *treeToRemove)
{
  ItemExpr *andNodePtr  = treePtr_->getPtr();
  ItemExpr *predecessor = NULL;
  NABoolean found       = FALSE;

  // assume the predicate is represented in right-linear
  // form:
  //
  //         op
  //        /   \
  //	   A    op
  //	       /   \
  //	      B     ...
  //
  // and search for the <op> node that is directly above the
  // predicate that we want to remove.

  if (shape_ != RIGHT_LINEAR_TREE)
    ABORT("delete is supported for right linear trees only");

  // is the node to delete the only node?
  if (treeToRemove == andNodePtr)
    {
      found = TRUE;
      delete andNodePtr;
      *treePtr_ = NULL;
    }
  else
    // traverse the backbone looking for "treeToRemove"
    while (andNodePtr != NULL AND
	   andNodePtr->getOperatorType() == operator_ AND
	   andNodePtr->getArity() == 2 AND
	   NOT found)
      {
	// did we find the right node?
	if (andNodePtr->child(0).getPtr() == treeToRemove)
	  {
	    found = TRUE;
	    
	    // take "andNode" out of the original tree
	    if (predecessor != NULL)
	      {
		predecessor->child(1) = andNodePtr->child(1);
	      }
	    else
	      *treePtr_ = andNodePtr->child(1);
	    
	    // set all children of "andNode" to NULL, then delete it
	    andNodePtr->child(0) = NULL;
	    andNodePtr->child(1) = NULL;
	    delete andNodePtr;
	    andNodePtr = NULL;
	  }
	else
	  {
	    predecessor = andNodePtr;
	    andNodePtr = andNodePtr->child(1);
	  }
      }
  
  if (found)
    return treeToRemove;
  else
    return NULL;

}
// insert a new entry.
// The new entry is created at the end of the current tree.
void ItemExprTreeAsList::insert(ItemExpr *treeToInsert)
{
  if (treePtr_->getPtr() == NULL)
    {
      *treePtr_ = treeToInsert;
    }
  else
    {
      if (shape_ == RIGHT_LINEAR_TREE)
	{
	  switch (operator_)
	    {
	    case ITM_AND:
	      *treePtr_ = new(CmpCommon::statementHeap()) 
		BiLogic(operator_,
			treeToInsert,
			treePtr_->getPtr());
	      break;

	    case ITM_ITEM_LIST:
	      {
		ItemExpr *aNode = treePtr_->getPtr();
		ItemExpr *pNode = treePtr_->getPtr();
		if (aNode->getOperatorType() != operator_ AND
		    aNode->getArity() < 2)
		  {
		    // case of current number of entries equal to 1.
		    *treePtr_ = new(CmpCommon::statementHeap())
		      ItemList(treePtr_->getPtr(),
			       treeToInsert);
		  }
		else
		  {
		    // current number of entries > 1
		    while (aNode != NULL)
		      {
			if (aNode->getOperatorType() == operator_ AND
			    aNode->getArity() >= 2)
			  {
			    if (shape_ == RIGHT_LINEAR_TREE)
			      {
				pNode = aNode;
				aNode = aNode->child(1);
			      }
			    else
			      ABORT("can't do other than right-linear trees");
			  }
			else
			  aNode = NULL;
		      }
		    
		    pNode->child(1) = new(CmpCommon::statementHeap())
		      ItemList(pNode->child(1),
			       treeToInsert);
		    
		  }
	      }
	      
	      break;

	    default:
	      ABORT("Can't do backbones with this node type");
	    }
	}
      else
	ABORT("can only insert into right-linear trees");
    }
}