// is this entire expression cacheable after this phase?
NABoolean Join::isCacheableExpr(CacheWA& cwa)
{
  if (cwa.getPhase() >= CmpMain::BIND) {
    // must first descend to scans to get cwa.numberOfScans_ 
    if (!RelExpr::isCacheableExpr(cwa)) {
      return FALSE;
    }
    if (isCacheableNode(cwa.getPhase())) { 
      cwa.setConditionallyCacheable();
    }
    // if we allow joins of views to be cached, query caching cannot 
    // distinguish between (see note at bottom of cachewa.h)
    //   select avg(f.a) from v f, v s group by f.b;
    //   select avg(s.a) from v f, v s group by f.b;
    //   select avg(t.a) from v f, t   group by f.b;
    // assuming v is "create view v from select * from t". We avoid
    // false cache hits by detecting the possible occurrence of such 
    // view joins here and later using cwa.isViewJoin_ to include
    // their query texts into their cache keys.
    //
    // A view is repsented by a renamed table with isView() returnning 
    // TRUE.

    RelExpr *c0 = child(0);
    RelExpr *c1 = child(1);
    if ((c0->getOperatorType() == REL_RENAME_TABLE &&
        ((RenameTable *)c0)->isView() == TRUE)
        ||
        (c1->getOperatorType() == REL_RENAME_TABLE &&
        ((RenameTable *)c1)->isView() == TRUE)) {
      cwa.foundViewJoin();
    }
    // check its join predicate
    ItemExpr *pred = joinPredTree_ ? joinPredTree_ :
      joinPred_.rebuildExprTree();
    if (pred) {
      cwa.setHasPredicate();
      // is join predicate cacheable?
      if (pred->hasNoLiterals(cwa)) {
        // predicate with no literals is cacheable
      }
      else {
        cwa.setPredHasNoLit(FALSE);
        if (!pred->isCacheableExpr(cwa)) {
          // a non-cacheable predicate renders Join non-cacheable.
          setNonCacheable();
          return FALSE;
        }
      }
    }
    return TRUE; // join may be cacheable
  }
  return FALSE;
}
// is this entire expression cacheable after this phase?
NABoolean RelExpr::isCacheableExpr(CacheWA& cwa)
{
  switch (cwa.getPhase()) {
  case CmpMain::PARSE:
  case CmpMain::BIND: {
    // does query have too many ExprNodes?
    if (cwa.inc_N_check_still_cacheable() == FALSE) {
      // yes. query with too many ExprNodes is not cacheable.
      return FALSE;
    }
    if (isNonCacheable()) { // this node is not cacheable
      return FALSE; // so the entire expression is not cacheable
      // don't mark this node non-cacheable because this
      // RelExpr may be cacheable after the next phase.
    }
    if (isCacheableNode(cwa.getPhase())) { 
      // must be an INSERT, UPDATE, DELETE, or SELECT node;
      // so, mark this expression as conditionally cacheable.
      cwa.setConditionallyCacheable();
    }
    // must descend to scans to get cwa.numberOfScans_ 
    if (!cacheableKids(cwa)) {
      return FALSE;
    }
    // this node is either cacheable or maybecacheable
    // check its selection predicate
    ItemExpr *pred = selPredTree() ? selPredTree() :
      getSelectionPred().rebuildExprTree();
    if (pred) {
      cwa.setHasPredicate();
      // is selection predicate cacheable?
      if (pred->hasNoLiterals(cwa)) {
        // predicate with no literals is cacheable
      }
      else {
        cwa.setPredHasNoLit(FALSE);
        if (!pred->isCacheableExpr(cwa)) {
          // a non-cacheable selection predicate 
          // renders entire RelExpr non-cacheable.
          setNonCacheable();
          return FALSE;
        }
      }
    }
    return TRUE; // RelExpr may be cacheable
  }
  default: { const NABoolean notYetImplemented = FALSE; 
  CMPASSERT(notYetImplemented);
  return FALSE;
    }
  }
}
// is this entire expression cacheable after this phase?
NABoolean GenericUpdate::isCacheableExpr(CacheWA& cwa)
{
  // descend to scans early to get cwa.numberOfScans_ 
  if (!RelExpr::isCacheableExpr(cwa)) {
    return FALSE;
  }

  // Make "{update|delete} ... where current of cursor" non-cacheable
  // so that stale cache will not lead to timestamp mismatch error at
  // runtime.  AQR attempts to handle this error, but only after the 
  // referenced cursor is closed due to transaction rollback.  This is
  // Solution 10-100425-9755.
  if (currOfCursorName()) { 
    return FALSE; 
  }

  if (cwa.getPhase() >= CmpMain::BIND) {
    // make sure any literals in the assignment clause can be safely
    // cast and assigned to their target types at plan-backpatch-time
    ItemExpr *newExpr = newRecExprTree_ ? newRecExprTree_ :
      newRecExpr_.rebuildExprTree(ITM_ITEM_LIST);
    if (newExpr && !newExpr->isSafelyCoercible(cwa)) { 
      return FALSE; 
    }
    // reject as non-cacheable queries such as
    //   prepare s from select * from (update t042qT8 set b=7 
    //   set on rollback c=12345678901234567890 where a=2) as t;
    ItemExpr *setOnRollback;
    if (newRecBeforeExpr_.entries() > 0 &&
        (setOnRollback=newRecBeforeExpr_.rebuildExprTree(ITM_ITEM_LIST)) 
        && !setOnRollback->isSafelyCoercible(cwa)) {
      return FALSE; 
    }
    // make sure any executor predicate is cacheable
    ItemExpr *execPred = executorPredTree_ ? executorPredTree_ :
      executorPred_.rebuildExprTree();
    if (execPred) {
      cwa.setHasPredicate();
      if (execPred->hasNoLiterals(cwa)) {
        // predicate with no literals is cacheable
      }
      else {
        cwa.setPredHasNoLit(FALSE);
        return execPred->isCacheableExpr(cwa);
      }
    }

    // at this time, not cacheable if subquery is specified in 
    // UPDATE SET clause.
    // This could be enabled later.
    if (subqInUpdateAssign()) {
      return FALSE;
    }
  }
  else {
    if ((getTableName().isPartitionNameSpecified()) ||
	(getTableName().isLocationNameSpecified()) ||
	(getTableName().isPartitionRangeSpecified()))
      return FALSE; // If PartnClause is used no cache hit before bind stage.
  }
  return TRUE; // may be cacheable
}