blob: b74447b02b6a2310b5f1ca5099e3d118ce161576 [file] [log] [blame]
/**********************************************************************
// @@@ 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: ItemCache.cpp
* Description: All the ItemExpr methods introduced by query caching
* Created: 2/23/2001
* Language: C++
*
*
******************************************************************************
*/
#include "AllItemExpr.h"
#include "CacheWA.h"
#include "CmpMain.h"
#include "NumericType.h"
#include "SchemaDB.h"
#include "ItemFuncUDF.h"
void computeAndAddSelParamIfPossible(
CacheWA& cwa, BindWA& bindWA, ExprValueId& child,
BaseColumn *base, ConstValue *val)
{
ColStatsSharedPtr cStatsPtr = (base->getTableDesc()->tableColStats()).
getColStatsPtrForColumn(base->getValueId());
if (cStatsPtr == NULL )
return;
HistogramSharedPtr hist = cStatsPtr->getHistogram();
if ( hist == NULL )
return;
CostScalar sel;
NABoolean canComputeSelectivity = hist -> computeSelectivityForEquality(
val, cStatsPtr->getRowcount(), cStatsPtr->getTotalUec(),
sel);
if ( canComputeSelectivity == TRUE ) {
const NAType * newType = base->getNAColumn()->getType();
// for char datatypes, assign the caseinsensitive attribute from
// the const node.
if (newType->getTypeQualifier() == NA_CHARACTER_TYPE)
{
newType =
base->getNAColumn()->getType()->newCopy(cwa.wHeap());
((CharType*)newType)->setCaseinsensitive(((CharType*)val->getType())->isCaseinsensitive());
}
cwa.replaceWithNewOrOldSelParam(val, newType, Selectivity(sel),
child, bindWA);
}
}
ConstValue * SelParameter::castToConstValue(NABoolean & negate_it)
{
negate_it = FALSE;
return getConstVal();
}
// append an ascii-version of aggregate into cachewa.qryText_
void Aggregate::generateCacheKey(CacheWA& cwa) const
{
ItemExpr::generateCacheKey(cwa);
cwa += " all:";
cwa += isDistinct_ ? "a0" : "a1";
}
// 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* Assign::normalizeForCache(CacheWA& cwa, BindWA& bindWA)
{
if (nodeIsNormalizedForCache()) {
return this;
}
if (cwa.getPhase() == CmpMain::PARSE) {
child(1) = child(1)->normalizeForCache(cwa, bindWA);
}
else if (cwa.getPhase() >= CmpMain::BIND) {
ItemExpr *leftC=child(0), *rightC=child(1);
OperatorTypeEnum leftO = leftC->getOperatorType();
OperatorTypeEnum rightO = rightC->getOperatorType();
ConstantParameter *cParam;
if (leftO == ITM_BASECOLUMN && rightO == ITM_CONSTANT
// normalizeForCache only constants that can be safely backpatched.
// part of fix to CR 10-010726-4109.
&& isSafelyCoercible(cwa)
// normalizeForCache only constants that are contained in the original
// SQL query so that each parameter can be backpatched by the
// corresponding constant from the query. This is to fix regression
// failure MP core/test055 where a SystemLiteral was inserted when the
// Keytag for a MP table column is not zero. see LeafInsert::bindNode().
// The offending query in MP core/test055 is
// update t055t9v set b = b + 1 where current of c10;
&& NOT ((ConstValue*)rightC)->isSystemProvided() ) {
ConstValue *val = (ConstValue*)rightC;
if (!val->isNull()) {
cParam = new (cwa.wHeap()) ConstantParameter
((ConstValue*)rightC, cwa.wHeap(),
((BaseColumn*)leftC)->getNAColumn()->getType());
cwa.addConstParam(cParam, bindWA);
child(1) = cParam;
}
// else val is null; keep null as is.
// this is part of a fix to genesis case: 10-010618-3484.
}
else {
child(1) = child(1)->normalizeForCache(cwa, bindWA);
}
}
markAsNormalizedForCache();
return this;
}
// is val a constant that can be safely coerced to BaseColumn's type?
NABoolean BaseColumn::canSafelyCoerce(ItemExpr& val) const
{
NAColumn *baseCol = getNAColumn();
OperatorTypeEnum valTyp = val.getOperatorType();
return
(baseCol != NULL &&
((valTyp == ITM_CONSTANT &&
((ConstValue*)&val)->canBeSafelyCoercedTo(*baseCol->getType()))
// we don't need to check the types of param & hostvar here because we
// are called after ItemExpr::bindNode has successfully type-checked
// the current search predicate that is being tested for cacheability
|| valTyp == ITM_HOSTVAR
|| valTyp == ITM_DYN_PARAM
|| valTyp == ITM_CACHE_PARAM
));
}
// append an ascii-version of ItemExpr into cachewa.qryText_
void BaseColumn::generateCacheKey(CacheWA& cwa) const
{
if (getTableDesc()->getCorrNameObj().getPrototype() == NULL) {
// return the table in the format "table.col"
ColRefName name
(getTableDesc()->getNATable()->getNAColumnArray()[colNumber_]->
getColName(),
getTableDesc()->getCorrNameObj(), CmpCommon::statementHeap());
cwa += name.getColRefAsAnsiString();
}
else {
ColRefName name
(getTableDesc()->getNATable()->getNAColumnArray()[colNumber_]->
getColName(), CmpCommon::statementHeap());
cwa += name.getColRefAsAnsiString();
}
}
// is this BaseColumn a primary or partitioning key and is val a single
// value or a constant that can be safely coerced to BaseColumn's type?
NABoolean BaseColumn::isKeyColumnValue(ItemExpr& val) const
{
NAColumn *baseCol = getNAColumn();
return
(baseCol != NULL &&
(baseCol->isPrimaryKey() || baseCol->isPartitioningKey()) &&
canSafelyCoerce(val));
}
// append an ascii-version of BETWEEN into cachewa.qryText_
void Between::generateCacheKey(CacheWA& cwa) const
{
cwa += leftBoundryIncluded_ ? "L1" : "L0";
cwa += rightBoundryIncluded_ ? "R1" : "R0";
if (pDirectionVector_) {
cwa += "dV";
Int32 x, limit=pDirectionVector_->entries();
for (x = 0; x<limit; x++) {
cwa += ((pDirectionVector_->at(x) == -1) ? "d" : "a");
}
}
BuiltinFunction::generateCacheKey(cwa);
}
// append an ascii-version of biarith
void BiArith::generateCacheKey(CacheWA& cwa) const
{
ItemExpr::generateCacheKey(cwa);
// append an indication of rounding mode for datetime arithmetic functions
if ( isKeepLastDay() ) cwa += "r1";
else if ( isStandardNormalization() ) cwa += "r0";
if (getOperatorType() == ITM_DIVIDE)
{
cwa += " arm:"; // arith rounding mode
char dFmt[20];
str_itoa(roundingMode_, dFmt);
cwa += dFmt;
}
}
// change literals of a cacheable query into ConstantParameters
ItemExpr* BiArith::normalizeForCache(CacheWA& cwa, BindWA& bindWA)
{
if (nodeIsNormalizedForCache()) {
return this;
}
if (!isUnaryNegate()) { // set in sqlparser.y which transforms "-i" into
// "0 - i" because apparently the executor does not have a unary negate.
// so, we must avoid replacing this system-introduced "0".
child(0) = child(0)->normalizeForCache(cwa, bindWA);
}
child(1) = child(1)->normalizeForCache(cwa, bindWA);
markAsNormalizedForCache();
return this;
}
// we want BiLogic to be cacheable
NABoolean BiLogic::isCacheableExpr(CacheWA& cwa)
{
if (cwa.getPhase() >= CmpMain::BIND && getArity() == 2) {
if (getOperatorType() == ITM_AND) {
ItemExpr *leftC=child(0), *rightC=child(1);
// we want to descend to both left & right
// so cwa.usedKeys & cwa.keyCols get updated
NABoolean leftOK = leftC->isCacheableExpr(cwa);
NABoolean rightOK = rightC->isCacheableExpr(cwa);
// return FALSE if both left & right are not cacheable.
if (!leftOK && !rightOK)
return FALSE;
// allow "select * from t where k1=1 and k2=2" as potentially cacheable
return TRUE;
// the definitive check whether a query's predicate covers
// all referenced tables' key columns can be (and is) done
// only in RelRoot::isCacheableExpr() when cwa.usedKeys &
// cwa.keyCols are fully defined. Otherwise, queries like
// "select * from t1 join t2 on a=x and a=7 where x=7"
// may be incorrectly rejected as non-cacheable if t1 has
// primary key(a) and t2 has primary key(x).
}
else if (getOperatorType() == ITM_OR) {
return TRUE;
// ORs can be cacheable but are not necessarily
// parameterizable, see Bilogic::normalizeForCache below.
}
}
return FALSE;
}
// selectively change literals of a cacheable query into input parameters
ItemExpr* BiLogic::normalizeForCache(CacheWA& cwa, BindWA& bindWA)
{
if (nodeIsNormalizedForCache()) {
return this;
}
if (getOperatorType() == ITM_AND) {
return ItemExpr::normalizeForCache(cwa, bindWA);
}
else {
// do not replace literals in OR predicates
markAsNormalizedForCache();
return this;
}
}
// append an ascii-version of ItemExpr into cachewa.qryText_
void BiRelat::generateCacheKey(CacheWA& cwa) const
{
cwa += specialNulls_ ? "s1" : "s0";
cwa += specialMultiValuePredicateTransformation_ ? "m1" : "m0";
cwa += isaPartKeyPred_ ? "p1" : "p0";
if (directionVector_) {
cwa += "Dv";
Int32 x, limit=directionVector_->entries();
for (x = 0; x<limit; x++) {
cwa += ((directionVector_->at(x) == -1) ? "d" : "a");
}
}
// we are deliberately excluding from the cachekey the following BiRelat
// data members: likeSelectivity_, originalLikeExprId_
// because we believe they are "internal" variables, ie, they are not
// essential to distinguishing between two different queries.
ItemExpr::generateCacheKey(cwa);
}
// we want BiRelat to be cacheable
NABoolean BiRelat::isCacheableExpr(CacheWA& cwa)
{
if (cwa.getPhase() >= CmpMain::BIND && getArity() == 2) {
if (getOperatorType() == ITM_EQUAL) {
ItemExpr *leftC=child(0), *rightC=child(1);
OperatorTypeEnum leftO = leftC->getOperatorType();
OperatorTypeEnum rightO = rightC->getOperatorType();
BaseColumn *base;
if (leftO == ITM_BASECOLUMN) {
base = (BaseColumn*)leftC;
if (base->isKeyColumnValue(*rightC)) {
cwa.addToUsedKeys(base);
}
return TRUE;
}
else if (rightO == ITM_BASECOLUMN) {
base = (BaseColumn*)rightC;
if (base->isKeyColumnValue(*leftC)) {
cwa.addToUsedKeys(base);
}
return TRUE;
}
else if (leftO == ITM_ITEM_LIST && rightO == ITM_ITEM_LIST &&
((ItemList*)leftC)->isListOfCacheableSelPred
(cwa, (ItemList*)rightC)) {
return TRUE;
}
else {
// we want all other equality comparisons to be cacheable, eg,
// retail_div_cd||acct_type_cd||substring(acct_id,1,8)='20V43085193'
return TRUE;
}
}
else {
return TRUE;
// other binary comparison predicates can be cacheable, but are
// not necessarily parameterizable, see BiRelat::normalizeForCache
}
}
return FALSE;
}
// is it safe to parameterize this selection predicate term?
// change literals of a cacheable query into input parameters
ItemExpr* BiRelat::normalizeForCache(CacheWA& cwa, BindWA& bindWA)
{
if (cwa.getPhase() >= CmpMain::BIND) {
// NB: we assume here that when a query is cacheable because it has a key
// equi-predicate, then its key equi-predicates can be parameterized
if (getArity() == 2) {
if (getOperatorType() == ITM_EQUAL) {
// normalizeForCache only constants that can be safely backpatched.
// part of fix to CR 10-010726-4109.
ItemExpr *leftC=child(0), *rightC=child(1);
OperatorTypeEnum leftO = leftC->getOperatorType();
// fix case 10-061027-0129: discover the potential base column
// below the InstantiateNull node
if ( leftO == ITM_INSTANTIATE_NULL ) {
leftC = leftC->child(0);
leftO = leftC->getOperatorType();
}
OperatorTypeEnum rightO = rightC->getOperatorType();
// fix case 10-061027-0129.
if ( rightO == ITM_INSTANTIATE_NULL ) {
rightC = rightC->child(0);
rightO = rightC->getOperatorType();
}
if (leftO == ITM_BASECOLUMN && rightO == ITM_CONSTANT) {
parameterizeMe(cwa, bindWA, child(1),
(BaseColumn*)leftC, (ConstValue*)rightC);
//HQC collect histogram for column
ItemExpr * cParameter = child(1);
cwa.bindConstant2SQC((BaseColumn*)leftC, (ConstantParameter*)cParameter);
}
else if (rightO == ITM_BASECOLUMN && leftO == ITM_CONSTANT) {
parameterizeMe(cwa, bindWA, child(0),
(BaseColumn*)rightC, (ConstValue*)leftC);
//HQC collect histogram for column
ItemExpr * cParameter = child(0);
cwa.bindConstant2SQC((BaseColumn*)rightC, (ConstantParameter*)cParameter);
}
else if (leftO == ITM_ITEM_LIST && rightO == ITM_ITEM_LIST) {
child(0) = ((ItemList*)leftC)->normalizeListForCache
(cwa, bindWA, (ItemList*)rightC);
}
}
// FIXME: ie, parameterize other binary comparison predicates
// if we can guarantee the correctness of such parameterizations
}
}
markAsNormalizedForCache();
return this;
}
// helper to change literals of a cacheable query into input parameters
void BiRelat::parameterizeMe(CacheWA& cwa, BindWA& bindWA, ExprValueId& child,
BaseColumn *base, ConstValue *val)
{
NABoolean parameterizableMVQRplan = cwa.hasRewriteEnabledMV() &&
CmpCommon::getDefault(MVQR_PARAMETERIZE_EQ_PRED) == DF_ON;
NABoolean parameterizablePlan = parameterizableMVQRplan ||
!cwa.hasRewriteEnabledMV();
if (val->isNull()) {
// val is null; keep null as is.
// this is part of a fix to genesis case: 10-010618-3484.
}
else if (base->isKeyColumnValue(*val) // keyCol = constant
&& cwa.isParameterizable(base) && parameterizablePlan) {
cwa.replaceWithNewOrOldConstParam(val, base->getNAColumn()->getType(),
child, bindWA);
if (parameterizableMVQRplan)
cwa.setParameterizedPred(TRUE);
}
else if (!base->canSafelyCoerce(*val)) {
// term is not parameterizable, keep it as is.
}
else { // nonKeyCol = constant
if (parameterizablePlan) {
computeAndAddSelParamIfPossible(cwa, bindWA, child, base, val);
if (parameterizableMVQRplan)
cwa.setParameterizedPred(TRUE);
}
}
}
// append an ascii-version of ItemExpr into cachewa.qryText_
void Case::generateCacheKey(CacheWA& cwa) const
{
// print any caseOperand before the case itself. That's out-of-order,
// but, we must differentiate 2 case exprs that differ only in their
// caseOperands. Otherwise, we will fail on a test, ie,
// we'll cache this insert
// insert into t values(case 3 when 4 then 0 when 3 then 1 end)
// and then later incorrectly consider this insert as a hit
// insert into t values(case 4 when 4 then 0 when 3 then 1 end)
// because their cache keys are identical
if (caseOperand_) {
cwa += " caseOpd:";
caseOperand_->generateCacheKey(cwa);
cwa += caseOperandWasNullable_ ? " 1" : " 0";
}
cwa += " builtinFunc:";
BuiltinFunction::generateCacheKey(cwa);
}
// does this entire ItemExpr qualify query to be cacheable after this phase?
NABoolean Case::isCacheableExpr(CacheWA& cwa)
{
if (caseOperand_ && !caseOperand_->isCacheableExpr(cwa)) {
return FALSE;
}
return ItemExpr::isCacheableExpr(cwa);
}
// change literals of a cacheable query into input parameters
ItemExpr* Case::normalizeForCache(CacheWA& cwa, BindWA& bindWA)
{
if (caseOperand_) {
caseOperand_ = caseOperand_->normalizeForCache(cwa, bindWA);
}
return BuiltinFunction::normalizeForCache(cwa, bindWA);
}
// append an ascii-version of Cast into cachewa.qryText_
void Cast::generateCacheKey(CacheWA& cwa) const
{
BuiltinFunction::generateCacheKey(cwa);
if (type_) {
cwa += " ";
cwa += type_->getTypeSQLname().data();
}
}
// 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;
}
// append an ascii-version of ConstantParameter into cachewa.qryText_
void ConstantParameter::generateCacheKey(CacheWA& cwa) const
{
cwa += "%";
}
// return our size in bytes
Lng32 ConstantParameter::getSize() const
{
return (Lng32)(sizeof(*this) + type_->getSize() + val_->getSize());
}
// can this ConstValue be safely coerced into this target type?
NABoolean ConstValue::canBeSafelyCoercedTo(const NAType& target)
{
// if errorsCanOccur says it's safe then it is
if (!type_->errorsCanOccur(target)) {
if ((target.getTypeQualifier() == NA_CHARACTER_TYPE) &&
(type_->getTypeQualifier() == NA_CHARACTER_TYPE)) {
if (((CharType&)target).isCaseinsensitive() !=
(((CharType*)type_)->isCaseinsensitive()))
return FALSE;
else {
// fix bugzilla 2764 by skipping parameterization of long
// char literals because backpatching those does not work.
// not yet.
return target.getNominalSize() <
CmpCommon::getDefaultNumeric(QUERY_CACHE_MAX_CHAR_LEN);
}
}
return TRUE;
}
// a NULL can be safely coerced to any nullable type
if (isNull()) {
return target.supportsSQLnullLogical();
}
// If the ConstValue type and the target type are both numeric
// and if the ConstValue can fit in the target type,
// it should be ok.
if ( target.getTypeQualifier() == NA_NUMERIC_TYPE &&
type_->getTypeQualifier() == NA_NUMERIC_TYPE ) {
NumericType *srcType = (NumericType*)type_;
NumericType *tgtType = (NumericType*)(&target);
if (tgtType->shouldCheckValueFitInType()) {
double val = srcType->getNormalizedValue(value_);
if ((val >= 0) && (val <= (tgtType->getMaxValue())) ) {
if ( srcType->isExact() && tgtType->isExact() &&
(srcType->getScale() > tgtType->getScale() ) )
return FALSE;
else
return TRUE;
}
if ((val < 0) && (val >= (tgtType->getMinValue())) ) {
if ( srcType->isExact() && tgtType->isExact() &&
(srcType->getScale() > tgtType->getScale() ) )
return FALSE;
else
return TRUE;
}
}
// NUMERIC and DECIMAL should be (but are not always) covered in
// errorsCanOccur.
if (srcType->isExact() && tgtType->isExact()) {
// Source and target are exact.
if (srcType->isUnsigned() || tgtType->isSigned()) {
// If the magnitude and scale of the target are greater
// than or equal to the source, then no conversion
// error can occur
if ((srcType->getMagnitude() <= tgtType->getMagnitude()) &&
(srcType->getScale() <= tgtType->getScale())
)
return TRUE;
}
else { // source literal is signed and target is unsigned
// errors can NOT occur if source literal >= 0 and the
// magnitude and scale of the target are >= those of source
if (type_->encode(value_) >= 0.0 &&
(srcType->getMagnitude() <= tgtType->getMagnitude()) &&
(srcType->getScale() <= tgtType->getScale()))
return TRUE;
}
}
}
// except if target is unsigned exact numeric and
// our type is signed exact numeric and our value is non-negative
// in which case we morph our type into signed
// and then retry the errorsCanOccur test
if (target.getTypeQualifier() == NA_NUMERIC_TYPE &&
((const NumericType&)target).isExact() &&
((const NumericType&)target).isUnsigned() &&
isExactNumeric() && ((NumericType*)type_)->isSigned() &&
type_->encode(value_) >= 0.0) {
((NumericType*)type_)->makeUnsigned();
NABoolean result = !type_->errorsCanOccur(target);
((NumericType*)type_)->makeSigned();
return result;
}
// except if source & target types are INTERVALs and
// our constant's SQLnullFlag_ == NOT_NULL_NOT_DROPPABLE
// and target's SQLnullFlag_ == ALLOWS_NULLS
if (target.getTypeQualifier() == NA_INTERVAL_TYPE &&
type_->getTypeQualifier() == NA_INTERVAL_TYPE &&
target.supportsSQLnullLogical() && !type_->supportsSQLnullPhysical()) {
// in which case, we morph our constant's SQLnullFlag_ to ALLOWS_NULLS
// and then retry the errorsCanOccur test
((NAType*)type_)->setSQLnullFlag();
NABoolean result = !type_->errorsCanOccur(target);
((NAType*)type_)->resetSQLnullFlag();
return result;
}
return FALSE; // we can't guarantee a safe coercion into target
}
// return our size in bytes
Lng32 ConstValue::getSize() const
{
return (Lng32)(sizeof(*this) + getStorageSize() +
(text_ ? text_->length() : 0) +
(locale_strval ? locale_strval->length() : 0) +
(locale_wstrval ? locale_wstrval->length() : 0));
}
// return true iff I am a string literal with unknown character set
NABoolean ConstValue::hasUnknownCharSet()
{
return type_->getTypeQualifier() == NA_CHARACTER_TYPE &&
((CharType*)type_)->getCharSet() == CharInfo::UnknownCharSet;
}
// does this ItemExpr (dis)qualify query to be cacheable after this phase?
NABoolean ConstValue::isCacheableExpr(CacheWA& cwa)
{
if (cwa.getPhase() <= CmpMain::PARSE && hasUnknownCharSet()) {
// string literal with unknown character set cannot be considered
// cacheable by pre-binder stages because the information needed
// to determine their character set is not known until bind-time.
// This fixes genesis case 10-041215-6141, soln 10-041215-2826.
return FALSE;
}
// string of length zero causes a problem during backpatching in method
// CacheData::backpatchParams.
// For now, do not cache it.
if ((NOT isNull()) &&
(isEmptyString()))
return FALSE;
return ItemExpr::isCacheableExpr(cwa);
}
// change literal of a cacheable query into ConstantParameter
ItemExpr* ConstValue::normalizeForCache(CacheWA& cwa, BindWA& bindWA)
{
// skip system supplied or empty string literals
if (isSystemSupplied_ || isEmptyString()) {
return this;
}
if (nodeIsNormalizedForCache()) {
return this;
}
// for now, do not parameterize NULLs because they can cause false
// constraint violations, eg, fullstack/TEST005
// create table t005t2(a int, b int not null, c char(10) not null,
// d int, primary key (c) );
// insert into t005t2 values (NULL,7,'?-7-?',NULL);
// gets "ERROR[8421] NULL cannot be assigned to a NOT NULL column."
if (isNull()) {
return this;
}
NAHeap* heap = cwa.wHeap();
// quantize length of strings only in after parse case
ConstantParameter* result = new(heap) ConstantParameter
(*this, heap, cwa.getPhase() == CmpMain::PARSE);
if (result) {
// "after-parser" ConstantParameters will undergo complete binding, so
// addConstParam does not have to bind "after-parser" ConstantParameters
cwa.addConstParam(result, bindWA);
cwa.bindConstant2SQC((BaseColumn*)NULL, result);
result->markAsNormalizedForCache();
}
// do not mark this ConstValue as normalizedForCache because it may
// be "shared" and may need to be replaced into a ConstantParameter
// again in another referencing expression context. For example, the
// binder visits the case operand "3" more than once in
// insert into t values(case 3 when 4 then 0 when 3 then 1 end)
return result;
}
// append an ascii-version of DateFormat into cachewa.qryText_
void DateFormat::generateCacheKey(CacheWA& cwa) const
{
BuiltinFunction::generateCacheKey(cwa);
cwa += " fmt:";
char dFmt[20];
str_itoa(dateFormat_, dFmt);
cwa += dFmt;
str_itoa(frmt_, dFmt);
cwa += dFmt;
}
// does this entire ItemExpr qualify query to be cacheable after this phase?
NABoolean DynamicParam::isCacheableExpr(CacheWA& cwa)
{
// a dynamic parameter is not cacheable after parse
return (cwa.getPhase() <= CmpMain::PARSE) ? FALSE : TRUE;
}
// append an ascii-version of Cast into cachewa.qryText_
void Extract::generateCacheKey(CacheWA& cwa) const
{
BuiltinFunction::generateCacheKey(cwa);
cwa += " xFld:";
char xFld[20]; str_itoa(extractField_, xFld);
cwa += xFld;
cwa += " fldFun:";
cwa += fieldFunction_ ? "1" : "0";
}
// append an ascii-version of HbaseTimestamp into cachewa.qryText_
void HbaseTimestamp::generateCacheKey(CacheWA& cwa) const
{
BuiltinFunction::generateCacheKey(cwa);
col()->generateCacheKey(cwa);
}
// append an ascii-version of HbaseVersion into cachewa.qryText_
void HbaseVersion::generateCacheKey(CacheWA& cwa) const
{
BuiltinFunction::generateCacheKey(cwa);
col()->generateCacheKey(cwa);
}
// does this entire ItemExpr qualify query to be cacheable after this phase?
NABoolean HostVar::isCacheableExpr(CacheWA& cwa)
{
// a HostVar is always cacheable
return TRUE;
}
// append an ascii-version of PivotGroup into cachewa.qryText_
void PivotGroup::generateCacheKey(CacheWA& cwa) const
{
Aggregate::generateCacheKey(cwa);
cwa += delim_;
char xFld[20]; str_itoa(maxLen_, xFld);
cwa += xFld;
cwa += orderBy_ ? "1" : "0";
}
// append an ascii-version of ItemExpr into cachewa.qryText_
void ItemExpr::generateCacheKey(CacheWA& cwa) const
{
Int32 arity = getArity();
switch (arity) {
case 0:
// simply print the text out for a leaf operator
cwa += getText4CacheKey();
break;
case 2:
if (getOperatorType() == ITM_ITEM_LIST || getOperatorType() == ITM_AND) {
if (child(0)) {
child(0)->generateCacheKey(cwa);
}
else {
cwa += "NULL";
}
if (getOperatorType() != ITM_ITEM_LIST) {
cwa += " ";
}
cwa += getText4CacheKey();
cwa += " ";
if (child(1)) {
child(1)->generateCacheKey(cwa);
}
else {
cwa += "NULL";
}
}
else {
// assume this is an infix operator (<child0>) op (<child1>)
cwa += "(";
NABoolean list0 = FALSE, list1 = FALSE;
if (getOperatorType() != ITM_ITEM_LIST) {
list0 = child(0)->getOperatorType() == ITM_ITEM_LIST;
list1 = child(1)->getOperatorType() == ITM_ITEM_LIST;
}
if (list0) {
cwa += "(";
}
child(0)->generateCacheKey(cwa);
if (list0) {
cwa += ")";
}
cwa += " ";
cwa += getText4CacheKey();
cwa += " ";
if (list1) {
cwa += "(";
}
child(1)->generateCacheKey(cwa);
if (list1) {
cwa += ")";
}
cwa += ")";
}
break;
default:
if (arity == 1 && isAPredicate() && getOperatorType() != ITM_NOT) {
child(0)->generateCacheKey(cwa);
cwa += " ";
cwa += getText4CacheKey();
}
else {
// any other arity: assume a function op(<child>,<child>,...)
cwa += getText4CacheKey();
cwa += "(";
for (Lng32 i = 0; i < (Lng32)arity; i++) {
if (i > 0) {
cwa += ", ";
}
child(i)->generateCacheKey(cwa);
}
cwa += ")";
break;
}
}
addSelectivityFactor( cwa ) ;
}
//
// addSelectivityFactor() - a helper routine for ItemExpr::generateCacheKey()
//
// NOTE: The code in this routine came from the previous version of
// ItemExpr::generateCacheKey(). 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::generateCacheKey() routine.
//
void ItemExpr::addSelectivityFactor( CacheWA& cwa ) const
{
if(((ItemExpr *)this)->isSelectivitySetUsingHint())
{
char str[100];
sprintf(str, " sel:%g", getSelectivityFactor());
cwa += str;
}
}
// return true if ItemExpr & its descendants have no constants & noncacheables
NABoolean ItemExpr::hasNoLiterals(CacheWA& cwa)
{
if (isNonCacheable()) {
return FALSE;
}
OperatorTypeEnum opTyp = getOperatorType();
switch (opTyp) {
case ITM_CONSTANT:
case ITM_HOSTVAR:
case ITM_DYN_PARAM:
case ITM_CACHE_PARAM:
return FALSE;
default: // fall thru
break;
}
NABoolean result = TRUE;
Int32 arity = getArity();
for (Int32 x = 0; x < arity && result; x++) {
if (child(x)) {
result = child(x)->hasNoLiterals(cwa);
}
}
return result;
}
// does this entire ItemExpr qualify query to be cacheable after this phase?
NABoolean ItemExpr::isCacheableExpr(CacheWA& cwa)
{
switch (cwa.getPhase()) {
default: { const NABoolean notYetImplemented = FALSE;
CMPASSERT(notYetImplemented);
break;
}
case CmpMain::PARSE:
// ItemExpr::isCacheableExpr is used by Tuple::isCacheable to
// determine whether a tuple-insert or a tuplelist-insert is
// cacheable after parse. It traverses a tuple's values list
// looking for non-cacheable ItemExprs such as HostVar,
// DynamicParam, Subquery, etc.
// determine cacheability of tuple INSERT's itemexprs here
if (isNonCacheable() || !cwa.isConditionallyCacheable()) {
return FALSE;
}
else { // we're either cacheable or maybecacheable
Int32 arity = getArity();
if (arity <= 0) { // we have no kids & we're conditionally cacheable
return TRUE; // we're cacheable
}
// cacheability of child(ren) determine our cacheability
for (Int32 x = 0; x < arity; x++) {
if (!child(x) || child(x)->isNonCacheable()) {
// the 1st noncacheable child makes us noncacheable
setNonCacheable();
return FALSE;
}
else if (!child(x)->isCacheableExpr(cwa)) {
// noncacheable child
return FALSE;
}
else { // cacheable child
continue; // look at next child
}
}
// all children are cacheable, so we're cacheable too
setCacheableNode(cwa.getPhase());
return TRUE;
}
break;
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;
}
// ItemExpr::isCacheableExpr is used in "after BIND" cases to
// visit all operands of an ItemExpr looking for noncacheable
// expressions. For example, it discovers that
// SELECT (SELECT a FROM t2 WHERE MAX(o.c)>1) FROM t1 o;
// is noncacheable only after it visits the outer query's select list.
if (isNonCacheable()) {
return FALSE;
}
else if (isCacheableNode(cwa.getPhase())) {
return TRUE;
}
else { // we're either cacheable or maybecacheable
// Assume this ItemExpr is an operand of a function or a list. In
// this case, a single noncacheable child renders us noncacheable.
Int32 arity = getArity();
for (Int32 x = 0; x < arity; x++) {
if (!child(x) || !child(x)->isCacheableExpr(cwa)) {
// noncacheable child
return FALSE;
}
else { // cacheable child
continue; // look at next child
}
}
// all children are cacheable, so we're cacheable too
setCacheableNode(cwa.getPhase());
return TRUE;
}
break;
}
return FALSE;
}
// is this ExprNode cacheable after this phase?
NABoolean ItemExpr::isCacheableNode(CmpPhase phase) const
{
switch (phase) {
case CmpMain::PARSE:
return cacheable_ == ExprNode::CACHEABLE_PARSE;
case CmpMain::BIND:
return cacheable_ == ExprNode::CACHEABLE_BIND ||
cacheable_ == ExprNode::CACHEABLE_PARSE;
default:
break;
}
return FALSE;
}
// is any literal in this expr safely coercible to its target type?
NABoolean ItemExpr::isSafelyCoercible(CacheWA &cwa) const
{
if (cwa.getPhase() >= CmpMain::BIND) {
Int32 arity = getArity();
for (Int32 x = 0; x < arity; x++) {
if (!child(x)->isSafelyCoercible(cwa)) {
return FALSE;
}
}
if (arity == 2) {
// we have to disallow caching of the following types of exprs:
// expr + 123456789012345678901234567890
// expr || 'overlylongstringthatwouldoverflow'
ItemExpr *left = child(0), *right = child(1);
if (left->getOperatorType() == ITM_CONSTANT) {
if (right->getOperatorType() == ITM_CONSTANT) {
// "10 + 1" should be safely coercible
return TRUE;
} else {
return ((ConstValue*)left)->canBeSafelyCoercedTo
(right->getValueId().getType());
}
}
else if (right->getOperatorType() == ITM_CONSTANT) {
return ((ConstValue*)right)->canBeSafelyCoercedTo
(left->getValueId().getType());
}
// else both are nonliterals; fall thru
}
// else nondyadic expr; fall thru
return TRUE;
}
return FALSE;
}
// change literals of a cacheable query into ConstantParameters
ItemExpr* ItemExpr::normalizeForCache(CacheWA& cwa, BindWA& bindWA)
{
if (nodeIsNormalizedForCache()) {
return this;
}
Int32 arity = getArity();
for (Int32 x = 0; x < arity; x++) {
if (cwa.getPhase() == CmpMain::PARSE) {
// we want to parameterize tuple inserts
child(x) = child(x)->normalizeForCache(cwa, bindWA);
}
else if (cwa.getPhase() == CmpMain::BIND) {
if (child(x)->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
child(x) = child(x)->normalizeForCache(cwa, bindWA);
}
}
}
markAsNormalizedForCache();
return this;
}
// mark this ExprNode as cacheable after this phase
void ItemExpr::setCacheableNode(CmpPhase phase)
{
switch (phase) {
case CmpMain::PARSE:
cacheable_ = ExprNode::CACHEABLE_PARSE;
break;
case CmpMain::BIND:
cacheable_ = ExprNode::CACHEABLE_BIND;
break;
default:
break;
}
}
// does this query's selection predicate list qualify query
// to be cacheable after this phase?
NABoolean ItemList::isListOfCacheableSelPred
(CacheWA& cwa, ItemList *other) const
{
Int32 arity = getArity();
NABoolean result = FALSE;
if (cwa.getPhase() >= CmpMain::BIND &&
other && arity == other->getArity()) {
// assume this is an AND list, so, we need only one
// cacheable conjunct to consider the list cacheable.
for (Int32 x = 0; x < arity; x++) {
ItemExpr *leftC = child(x), *rightC = other->child(x);
OperatorTypeEnum leftO = leftC->getOperatorType();
OperatorTypeEnum rightO = rightC->getOperatorType();
BaseColumn *base;
if (leftO == ITM_BASECOLUMN) {
base = (BaseColumn*)leftC;
if (base->isKeyColumnValue(*rightC)) {
cwa.addToUsedKeys(base);
}
result = TRUE;
continue;
}
else if (rightO == ITM_BASECOLUMN) {
base = (BaseColumn*)rightC;
if (base->isKeyColumnValue(*leftC)) {
cwa.addToUsedKeys(base);
}
result = TRUE;
continue;
}
else if (leftO == ITM_ITEM_LIST && rightO == ITM_ITEM_LIST &&
((ItemList*)leftC)->isListOfCacheableSelPred
(cwa, (ItemList*)rightC)) {
result = TRUE;
continue;
}
}
}
return result;
}
// is any literal in this expr safely coercible to its target type?
NABoolean ItemList::isSafelyCoercible(CacheWA& cwa) const
{
if (cwa.getPhase() >= CmpMain::BIND) {
Int32 arity = getArity();
for (Int32 x = 0; x < arity; x++) {
if (!child(x)->isSafelyCoercible(cwa)) {
return FALSE;
}
}
return TRUE;
}
return FALSE;
}
// change literals of a cacheable query into input parameters
ItemExpr* ItemList::normalizeListForCache
(CacheWA& cwa, BindWA& bindWA, ItemList *other)
{
Int32 arity = getArity();
if (cwa.getPhase() >= CmpMain::BIND &&
other && arity == other->getArity()) {
for (Int32 x = 0; x < arity; x++) {
ItemExpr *leftC = child(x), *rightC = other->child(x);
OperatorTypeEnum leftO = leftC->getOperatorType();
OperatorTypeEnum rightO = rightC->getOperatorType();
if (leftO == ITM_BASECOLUMN && rightO == ITM_CONSTANT) {
parameterizeMe(cwa, bindWA, other->child(x), (BaseColumn*)leftC,
(ConstValue*)rightC);
//HQC collect histogram for column
ItemExpr * cParameter = other->child(x);
cwa.bindConstant2SQC((BaseColumn*)leftC, (ConstantParameter*)cParameter);
}
else if (rightO == ITM_BASECOLUMN && leftO == ITM_CONSTANT) {
parameterizeMe(cwa, bindWA, child(x), (BaseColumn*)rightC,
(ConstValue*)leftC);
//HQC collect histogram for column
ItemExpr * cParameter = child(x);
cwa.bindConstant2SQC((BaseColumn*)rightC, (ConstantParameter*)cParameter);
}
else if (leftO == ITM_ITEM_LIST && rightO == ITM_ITEM_LIST) {
child(x) = ((ItemList*)leftC)->normalizeListForCache
(cwa, bindWA, (ItemList*)rightC);
}
}
}
return this;
}
// helper to change literals of a cacheable query into input parameters
void ItemList::parameterizeMe(CacheWA& cwa, BindWA& bindWA, ExprValueId& child,
BaseColumn *base, ConstValue *val)
{
NABoolean parameterizableMVQRplan = cwa.hasRewriteEnabledMV() &&
CmpCommon::getDefault(MVQR_PARAMETERIZE_EQ_PRED) == DF_ON;
NABoolean parameterizablePlan = parameterizableMVQRplan ||
!cwa.hasRewriteEnabledMV();
if (val->isNull()) {
// val is null; keep null as is.
// this is part of a fix to genesis case: 10-010618-3484.
}
else if (base->isKeyColumnValue(*val) // keyCol = constant
&& cwa.isParameterizable(base) && parameterizablePlan) {
cwa.replaceWithNewOrOldConstParam(val, base->getNAColumn()->getType(),
child, bindWA);
if (parameterizableMVQRplan)
cwa.setParameterizedPred(TRUE);
}
else if (!base->canSafelyCoerce(*val)) {
// term is not parameterizable, keep it as is.
}
else { // nonKeyCol = constant
if (parameterizablePlan) {
computeAndAddSelParamIfPossible(cwa, bindWA, child, base, val);
if (parameterizableMVQRplan)
cwa.setParameterizedPred(TRUE);
}
}
}
// append an ascii-version of LIKE into cachewa.qryText_
void PatternMatchingFunction::generateCacheKey(CacheWA& cwa) const
{
// we are deliberately excluding from cachekey the data members:
// numberOfNonWildcardChars_, patternAStringLiteral_,
// oldDefaultSelForLikeWildCardUsed_
// because we believe they are "internal" variables, ie, they are
// not essential to distinguishing two different LIKEs.
BuiltinFunction::generateCacheKey(cwa);
}
// change literals of a cacheable query into ConstantParameters
ItemExpr* PatternMatchingFunction::normalizeForCache(CacheWA& cwa, BindWA& bindWA)
{
if (nodeIsNormalizedForCache()) {
return this;
}
// replace only the matchValue
child(0) = child(0)->normalizeForCache(cwa, bindWA);
// but, don't touch the pattern or the escapeChar.
markAsNormalizedForCache();
return this;
}
// Note: When this method is used during query cache lookup (actually the
// verification step), this belongs to the item in the bucket that matches
// the key, and other is the selectivity computed for an equal-predicate
// constant in the query to be looked up.
//
// This method is called to verify that this and other are not different
// very much.
//
// We return TRUE iff
// this.val_ / (1+delta) <= other.val_ <= this.val_ * (1 + delta)
//
// where delta is
// the value stored in QUERY_CACHE_SELECTIVITY_TOLERANCE
//
NABoolean Selectivity::operator==(const Selectivity& other) const
{
CostScalar delta =
CostScalar((ActiveSchemaDB()->getDefaults()).getAsDouble(QUERY_CACHE_SELECTIVITY_TOLERANCE)) + 1;
return (val_ / delta <= other.val_) && (other.val_ <= val_ * delta);
}
// append an ascii-version of SelParameter into cachewa.qryText_
void SelParameter::generateCacheKey(CacheWA& cwa) const
{
cwa += "#";
}
// append an ascii-version of SequenceValue into cachewa.qryText_
void SequenceValue::generateCacheKey(CacheWA& cwa) const
{
BuiltinFunction::generateCacheKey(cwa);
cwa += seqCorrName_.getQualifiedNameAsString();
if (currVal_)
cwa += "currVal";
else if (nextVal_)
cwa += "nextVal";
}
// append an ascii-version of Subquery into cachewa.qryText_
void Subquery::generateCacheKey(CacheWA& cwa) const
{
ItemExpr::generateCacheKey(cwa);
cwa += " tExp:";
getSubquery()->generateCacheKey(cwa);
}
// return true if ItemExpr & its descendants have no constants
// and no noncacheable nodes
NABoolean Subquery::hasNoLiterals(CacheWA& cwa)
{
return ItemExpr::hasNoLiterals(cwa) && getSubquery()->isCacheableExpr(cwa);
}
// we want Subquery to be cacheable
NABoolean Subquery::isCacheableExpr(CacheWA& cwa)
{
if (!getSubquery()->isCacheableExpr(cwa)) {
return FALSE;
}
return ItemExpr::isCacheableExpr(cwa);
}
// change literals of a cacheable query into ConstantParameters
ItemExpr* Substring::normalizeForCache(CacheWA& cwa, BindWA& bindWA)
{
if (nodeIsNormalizedForCache()) {
return this;
}
// parameterize S in "substring(S from B for L)" but skip B & L
child(0) = child(0)->normalizeForCache(cwa, bindWA);
markAsNormalizedForCache();
return this;
}
// append an ascii-version of Translate into cachewa.qryText_
void Translate::generateCacheKey(CacheWA& cwa) const
{
BuiltinFunction::generateCacheKey(cwa);
cwa += " map:";
char map[20]; str_itoa(map_table_id_, map);
cwa += map;
}
// append an ascii-version of Trim into cachewa.qryText_
void Trim::generateCacheKey(CacheWA& cwa) const
{
BuiltinFunction::generateCacheKey(cwa);
cwa += " tlb:";
char mode[20]; str_itoa(mode_, mode);
cwa += mode;
}
// Only alow UDFunctions to be cached after BIND time.
NABoolean UDFunction::isCacheableExpr(CacheWA& cwa)
{
if (cwa.getPhase() >= CmpMain::BIND)
return TRUE;
else
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;
}
// append an ascii-version of UDFunction into cachewa.qryText_
void UDFunction::generateCacheKey(CacheWA& cwa) const
{
NARoutine *routine = NULL;
NARoutine *action = NULL;
cwa += " nam:";
cwa += functionName_.getExternalName().data();
if (cwa.getPhase() >= CmpMain::BIND &&
getRoutineDesc() &&
(routine=getRoutineDesc()->getNARoutine()) != NULL)
{
char redefTime[40];
convertInt64ToAscii(routine->getRedefTime(), redefTime);
cwa += " redef:";
cwa += redefTime;
}
if (getRoutineDesc() &&
getRoutineDesc()->getActionNameAsGiven().length() != 0)
{
cwa += " actnam:";
cwa += getRoutineDesc()->getActionNameAsGiven();
if (cwa.getPhase() >= CmpMain::BIND &&
getRoutineDesc() &&
(action=getRoutineDesc()->getActionNARoutine()) != NULL)
{
char redefTime[40];
convertInt64ToAscii(action->getRedefTime(), redefTime);
cwa += " actredef:";
cwa += redefTime;
}
}
cwa += "(";
Lng32 arity = (Lng32) getArity();
for (Lng32 i = 0; i < arity; i++) {
if (i > 0) {
cwa += ", ";
}
child(i)->generateCacheKey(cwa);
}
if (getRoutineDesc()->getLocale() != 0 )
{
cwa += ", LOCALE: ";
char dFmt[20];
str_itoa(getRoutineDesc()->getLocale(), dFmt);
cwa += dFmt;
}
cwa += ")";
}
// is any literal in this expr safely coercible to its target type?
NABoolean UDFunction::isSafelyCoercible(CacheWA& cwa) const
{
if (cwa.getPhase() >= CmpMain::BIND) {
Int32 arity = getArity();
for (Int32 x = 0; x < arity; x++) {
if (!child(x)->isSafelyCoercible(cwa)) {
return FALSE;
}
}
return TRUE;
}
return FALSE;
}
// append an ascii-version of Subquery into cachewa.qryText_
void ValueIdProxy::generateCacheKey(CacheWA& cwa) const
{
ItemExpr::generateCacheKey(cwa);
cwa += " tExp:";
derivedFrom_.getItemExpr()->generateCacheKey(cwa);
}
// return true if ItemExpr & its descendants have no constants
// and no noncacheable nodes
NABoolean ValueIdProxy::hasNoLiterals(CacheWA& cwa)
{
return derivedFrom_.getItemExpr()->hasNoLiterals(cwa) &&
derivedFrom_.getItemExpr()->isCacheableExpr(cwa);
}
// is any literal in this expr safely coercible to its target type?
NABoolean ValueIdProxy::isSafelyCoercible(CacheWA& cwa) const
{
if (cwa.getPhase() >= CmpMain::BIND) {
if (!derivedFrom_.getItemExpr()->isSafelyCoercible(cwa))
return FALSE;
else
return TRUE;
}
return FALSE;
}
// change literals of a cacheable query into ConstantParameters
ItemExpr* ValueIdProxy::normalizeForCache(CacheWA& cwa, BindWA& bindWA)
{
if (nodeIsNormalizedForCache()) {
return this;
}
if (cwa.getPhase() == CmpMain::PARSE) {
// we want to parameterize tuple inserts
derivedFrom_ = derivedFrom_.getItemExpr()->normalizeForCache(cwa, bindWA)->getValueId();
}
else if (cwa.getPhase() == CmpMain::BIND) {
if (derivedFrom_.getItemExpr()->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
derivedFrom_ = derivedFrom_.getItemExpr()->normalizeForCache(cwa, bindWA)->getValueId();
}
}
markAsNormalizedForCache();
return this;
}