// is any literal in this expr safely coercible to its target type? NABoolean Cast::isSafelyCoercible(CacheWA &cwa) const { if (cwa.getPhase() >= CmpMain::BIND) { ItemExpr *opd = child(0); if (!opd->isSafelyCoercible(cwa)) { return FALSE; } if (opd->getOperatorType() == ITM_CONSTANT) { return ((ConstValue*)opd)->canBeSafelyCoercedTo(*type_); } return TRUE; } return FALSE; }
// 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; }
// change literals of a cacheable query into ConstantParameters ItemExpr* UDFunction::normalizeForCache(CacheWA& cwa, BindWA& bindWA) { if (nodeIsNormalizedForCache()) { return this; } // Since the UDFunction::transformNode refers to both the // inputVars_ ValueIdSet and the children array we need to make sure // they are consistent. // The children array may contain cast() of the expressions in inputVars_ // If we have a UUDF function the inputs that were given // at parse time, really do not reflect reality anymore. // So here we will simply reinitialize them with what we find in the // inputVars_. CMPASSERT(udfDesc_); // we better have one after binding. NABoolean isUUDF(udfDesc_->isUUDFRoutine()); // Save off a copy of the original inputVars_ set. ValueIdSet origInputVars(inputVars_); // Loop through the given inputs for (Int32 x = 0; x < getArity(); x++) { NABoolean origInputIsChildOfCast(FALSE); ItemExpr * origIe = child(x); ItemExpr * newIe = NULL; ValueId vid = origIe->getValueId(); if (cwa.getPhase() == CmpMain::BIND) { if (origIe->isSafelyCoercible(cwa)) { // fix CR 10-010726-4109: make sure queries with constants that // cannot be safely backpatched such as // select case smallintcol when 4294967393 then 'max' end from t // are not parameterized newIe = origIe->normalizeForCache(cwa, bindWA); if (newIe != origIe ) { // normalizeForCache returned a new ItemExpr. We have to update // the UDFunction inputVars_ set, as this is used to determine // characteristic inputs for IsolatedScalarUDF at transform time. child(x) = newIe; // Is it a input that UDFunction::bindNode put a cast around? if ((origIe->getOperatorType() == ITM_CAST) && (origInputVars.contains(origIe->child(0)->getValueId()))) { // Since the original child was a CAST that UDFunction::bindNode // created, check to see if that CAST's child is part of the new // expression, if it is, we don't have to do anything, since the // CASTED value is part of the inputVars set, otherwise, we have // to update the inputVars set to keep the characteristic inputs // consistent. if (! newIe->referencesTheGivenValue( origIe->child(0)->getValueId()), TRUE) { // remove the original input from inputVars. It is the child // of origIe because origIe is a cast that UDFunction::bindNode // introduced. inputVars_ -= origIe->child(0)->getValueId(); if (newIe->getOperatorType() == ITM_CAST) { // If the new expression is a CAST, we assume the child is the // real input. We don't expect CAST(CAST(CAST(expr))) type // expressions only simple CAST(expr) ones. inputVars_ += newIe->child(0)->getValueId(); } else { // add the newIe itself if it was not a CAST. inputVars_ += newIe->getValueId(); } } } else { // If the newIe doesn't contain the original one, we need to update // the inputVars set. if (! newIe->referencesTheGivenValue( origIe->getValueId()), TRUE) { // the origIe was not a CAST introduced by UDFunction::bindNode() if (newIe->getOperatorType() == ITM_CAST) { if (!origInputVars.contains(newIe->child(0)->getValueId())) { inputVars_ -= origIe->getValueId(); // If the new expression is a CAST, we assume the child is the // real input. We don't expect CAST(CAST(CAST(expr))) type // expressions only simple CAST(expr) ones. inputVars_ += newIe->child(0)->getValueId(); } // we don't need to update inputVars_ if the origInputVars // contains the valueId of the newIe child already. } else { // This is an entirely new input. Remove the old one, and // add in the new. inputVars_ -= origIe->getValueId(); inputVars_ += newIe->getValueId(); } } } } } } } markAsNormalizedForCache(); return this; }
// 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 }