// is this entire expression cacheable after this phase? NABoolean Tuple::isCacheableExpr(CacheWA& cwa) { // we do not call RelExpr::isCacheableExpr here because it's redundant // -- Tuple is a leaf node and has no predicates. ItemExpr *tExpr = tupleExprTree() ? tupleExprTree() : tupleExpr_.rebuildExprTree(); return tExpr->isCacheableExpr(cwa); }
// 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 GroupByAgg::isCacheableExpr(CacheWA& cwa) { // descend to scans early to get cwa.numberOfScans_ if (!RelExpr::isCacheableExpr(cwa)) { return FALSE; } // is the group by col/expr cacheable? ItemExpr *grpExpr = groupExprTree_ ? groupExprTree_ : groupExpr_.rebuildExprTree(ITM_ITEM_LIST); if (grpExpr && !grpExpr->isCacheableExpr(cwa)) { return FALSE; } return TRUE; // may be cacheable }
// is any literal in this expr safely coercible to its target type? NABoolean Assign::isSafelyCoercible(CacheWA &cwa) const { if (cwa.getPhase() >= CmpMain::BIND) { // we have to disallow caching of the following types of updates: // update t set col = overlylongliteral ItemExpr *src = getSource().getItemExpr(); if (src->getOperatorType() == ITM_CONSTANT) { // source is a literal; make sure this update is cacheable only if // literal can be safely coerced into its target type. return ((ConstValue*)src)->canBeSafelyCoercedTo(getTarget().getType()); } else { // source is not a literal // we need to descend into this expr to verify that no // errors can occur during backpatching. For example, // update t set i = i + 123456789012345678901234567890 // should not be cacheable if i is a smallint. // reject "update t set c=(subquery)" as noncacheable // as part of a fix to CR 10-020108-8401. return src->isSafelyCoercible(cwa) && src->isCacheableExpr(cwa); } } 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 }