| /********************************************************************** |
| // @@@ 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 @@@ |
| **********************************************************************/ |
| #ifndef CacheWA__H |
| #define CacheWA__H |
| /* -*-C++-*- |
| ************************************************************************* |
| * |
| * File: CacheWA.h |
| * Description: The workarea used by {Rel|Item}Expr::normalizeForCache. |
| * It holds contextual information needed and generated by |
| * isCacheableExpr and normalizeForCache as the compiler |
| * decides whether a query is cacheable. For a cacheable |
| * query, normalizeForCache replaces query constants into |
| * ConstantParameters. ConstantParameters act like wildcards |
| * matching all constants that can be safely coerced into |
| * that constant's formal type. We cache only queries that |
| * have been normalizedForCache. The goal is to maximize the |
| * cache hit rate of every cached query plan. |
| * |
| * A query is cacheable after parse iff it is a tuple or |
| * tuplelist insert whose tuple values' types are known at |
| * parse-time. Thus, tuple inserts that have hostvars, dynamic |
| * parameters, subqueries, nulls are not cacheable after parse. |
| * "insert into t values(1),(2),(3)" is cacheable after parse. |
| * "insert into t values(?p1),(:hv2),(select a from s)" is not. |
| * A query is cacheable after bind iff it is an insert, delete, |
| * update, select whose compiled plan is insensitive to actual |
| * values of literals in that query. Thus, "delete from t where |
| * pk = 1" is cacheable after bind iff pk is a primary key or a |
| * column with a unique constraint because its compiled plan does |
| * not depend on the value "1". "delete from t where pk > 1" |
| * is not cacheable because its compiled plan may depend on the |
| * value "1". |
| * Determining query cacheability is implemented by {Rel|Item} |
| * Expr::isCacheableExpr(). Every ExprNode (the base class of |
| * RelExpr and ItemExpr) has a protected cacheable_ attribute |
| * that specifies that node's cacheability (returned by the |
| * isCacheableNode() method). |
| * Most ExprNodes start in the MAYBECAHEABLE state. |
| * Certain ExprNodes (such as ControlAbstractClass, Describe, |
| * StmtNode, ElemDDLNode, RelLock, RelTransaction) that |
| * represent non-DML queries are always NONCACHEABLE. |
| * (Tuple and tuplelist) Insert nodes (a class derived from |
| * RelExpr) become CACHEABLE_PARSE (ie, cacheable after parse) |
| * during their isCacheableExpr (top-down) query tree traversal. |
| * Some Insert, Delete, Update, Scan nodes (classes derived from |
| * RelExpr) become CACHEABLE_BIND (cacheable after bind) during |
| * their isCacheableExpr traversal. |
| * A query tree that has only MAYBECACHEABLE ExprNodes is not |
| * cacheable (ie, its isCacheableExpr() traversal returns FALSE). |
| * For a query tree to be cacheable after parse, its |
| * isCacheableExpr traversal must encounter a CACHEABLE_PARSE |
| * node which causes that query to be marked as |
| * cachewa.conditionallyCacheable_ and its descendant nodes are |
| * MAYBECACHEABLE or conditionallyCacheable_. No descendant's |
| * isCacheableExpr() call must return FALSE. Note that hostvars' |
| * and dynamic parameters' isCacheableExpr() return FALSE after |
| * parse but return TRUE after bind. |
| * For a query tree to be cacheable after bind, its |
| * isCacheableExpr traversal must encounter a CACHEABLE_BIND node |
| * (an insert, delete, update, scan) and its selection predicate, |
| * if present, must have at least one conjunctive equality of a |
| * literal against a primary key or a column with a unique |
| * constraint. |
| * To avoid an unnecessary isCacheableExpr traversal, say, after |
| * parse and then after bind, we set a node's cacheable_ |
| * attribute to become NONCACHEABLE if that query has been |
| * determined not to be cacheable after any phase. For example, |
| * "select a from t intersect select b from s where c >= 1" |
| * is not cacheable after any phase. |
| * Created: August 3, 2000 |
| * Language: C++ |
| * |
| * |
| * |
| * |
| ************************************************************************* |
| */ |
| |
| #include "ItemColRef.h" |
| #include "exp_attrs.h" |
| #include "NAString.h" |
| #include "RelMisc.h" |
| #include "QCache.h" |
| |
| // contents of this file |
| class CacheWA; |
| class ConstantParameters; |
| class SelParameters; |
| |
| // Forward declarations |
| |
| // ConstantParameters is used to represent a query's list of actual |
| // constant parameters after query has undergone normalizeForCache. |
| class ConstantParameters : public LIST(ConstantParameter*) |
| { |
| public: |
| // create an empty list |
| ConstantParameters(NAHeap *h); |
| |
| // copy constructor |
| ConstantParameters(const ConstantParameters &s, NAHeap* h) |
| : NAList<ConstantParameter*>(s, h) {} |
| |
| // free our allocated memory |
| virtual ~ConstantParameters(); |
| |
| // return our elements' total size in bytes |
| Lng32 getSize() const; |
| |
| // return true & matching element if val is in this list |
| NABoolean find(ConstValue *val, ConstantParameter **match); |
| }; |
| |
| // SelParameters is used to represent a query's list of actual SelParameters |
| // after query has undergone normalizeForCache. |
| class SelParameters : public LIST(SelParameter*) |
| { |
| public: |
| // create an empty list |
| SelParameters(NAHeap *h); |
| |
| // copy constructor |
| SelParameters(const SelParameters &s, NAHeap* h) |
| : NAList<SelParameter*>(s, h) {} |
| |
| // free our allocated memory |
| virtual ~SelParameters(); |
| |
| // return our elements' total size in bytes |
| Lng32 getSize() const; |
| |
| // return true & matching element if val is in this list |
| NABoolean find(ConstValue *val, SelParameter **match); |
| }; |
| |
| |
| // CacheWA is the contextual work area for {Rel|Item}Expr::isCacheableExpr |
| // and {Rel|Item}Expr::normalizeForCache query tree traversals. It holds |
| // contextual information (such as the current phase of compilation, |
| // the cacheability of the current query, the |
| // parameterized query text, the query's cache key, the query root, etc) |
| // which is needed and generated by {Rel|Item}Expr::isCacheableExpr and |
| // {Rel|Item}Expr::normalizeForCache traversals of the query tree. |
| class CacheWA : public NABasicObject |
| { |
| public: |
| // Constructor |
| CacheWA(NAHeap *h); |
| |
| private: |
| // copy constructor |
| CacheWA(const CacheWA &s); // not written and not used but is here |
| // nevertheless because code inspectors say it should. |
| // This will cause a link error if it's ever called. |
| |
| public: |
| // Destructor function |
| virtual ~CacheWA(); |
| |
| // Dear code reader/inspector: Please do not (nit)pick on the following |
| // accessors as violations of coding guideline 7.3 (a function must never |
| // return a pointer to local data). The only purpose in life of cachewa |
| // is to hold "global" state for {Rel|Item}Expr::isCacheableExpr and |
| // {Rel|Item}Expr::normalizeForCache. Without these accessors, cachewa |
| // is useless. |
| |
| // replace constant with new or existing ConstantParameter |
| void replaceWithNewOrOldConstParam(ConstValue *val, const NAType *typ, |
| ExprValueId& tgt, BindWA &bindWA); |
| |
| // replace constant with new or existing SelParameter |
| void replaceWithNewOrOldSelParam(ConstValue *val, const NAType *typ, |
| const Selectivity sel, ExprValueId& tgt, |
| BindWA &bindWA); |
| |
| // add ConstantParameter to current query's actual parameters |
| void addConstParam(ConstantParameter* p, BindWA& bindwa); |
| |
| // add SelParameter to current query's selection parameters |
| void addSelParam(SelParameter* p, BindWA& bindwa); |
| |
| // add referenced table |
| void addTable( NATable *t ) { tables_.insert(t); } |
| |
| // get referenced tables |
| LIST(NATable*) &getTables() { return tables_; } |
| |
| // return current query's actual parameters for backpatching cached plan |
| ConstantParameters &getConstParams() { return actuals_; } |
| |
| // return current query's selection parameters for backpatching cached plan |
| SelParameters &getSelParams() { return sels_; } |
| |
| LIST(Int32) &getConstParamPositionsInSql() { return sqlStmtConstParamPos_; } |
| LIST(Int32) &getSelParamPositionsInSql() { return sqlStmtSelParamPos_; } |
| LIST(Int32) &getHQCConstPositionsInSql() { return hqcSqlConstPos_; } |
| |
| void bindConstant2SQC(BaseColumn* base, ConstantParameter* cParameter) |
| { |
| if (HQCKey_&& HQCKey_->isCacheable()) |
| HQCKey_->bindConstant2SQC(base, cParameter, hqcSqlConstPos_); |
| } |
| |
| void setHQCKey(HQCParseKey * key) { HQCKey_ = key;} |
| |
| // return current query's formal parameter types |
| const ParameterTypeList* getFormalParamTypes(); |
| |
| // return current query's formal SelParamTypes |
| const SelParamTypeList* getFormalSelParamTypes(); |
| |
| // compose and return TextKey of current query |
| TextKey *getTextKey(const char *sText, Lng32 charset, |
| const QryStmtAttributeSet& attrs); |
| |
| // traverse queryExpr and put together its cacheKey |
| void generateCacheKey(RelExpr *queryExpr, const char *sText, Lng32 charset, |
| const NAString& viewsUsed); |
| |
| // caller wants us to remember an occurrence of a view join |
| void foundViewJoin(); |
| |
| // compose and return CacheKey of current query |
| CacheKey *getCacheKey(const QryStmtAttributeSet& attrs); |
| |
| // return current phase of compilation |
| CmpPhase getPhase() const { return phase_; } |
| |
| // used by subsequent phases to check if query is definitely cacheable |
| NABoolean isCacheable() const { return cacheable_; } |
| |
| // is current query conditionally cacheable? |
| NABoolean isConditionallyCacheable() const |
| { return conditionallyCacheable_; } |
| |
| // mark current query as definitely cacheable |
| void setCacheable() { cacheable_ = TRUE; } |
| |
| // mark current query as definitely not cacheable |
| void resetCacheable() { cacheable_ = FALSE; } |
| |
| // tilt current query towards cacheability |
| void setConditionallyCacheable() { conditionallyCacheable_ = TRUE; } |
| |
| // record current phase of compilation |
| void setPhase(CmpPhase p) { phase_ = p; } |
| |
| // remember current query's true root |
| void setTopRoot(RelRoot* root) { topRoot_ = root; } |
| |
| // return compiler's statementHeap |
| NAHeap *wHeap() const { return heap_; } |
| |
| // append string s to current query's parameterized sql text |
| void operator+=(const char* s); |
| |
| // add referenced column's valueid to usedKeys |
| void addToUsedKeys(BaseColumn *base); |
| |
| // is this column parameterizable? |
| NABoolean isParameterizable(BaseColumn *base); |
| |
| void setHasPredicate() { hasPredicate_ = TRUE; } |
| void setPredHasNoLit(NABoolean v) { predHasNoLit_ = v; } |
| |
| NABoolean inc_N_check_still_cacheable(); |
| void resetNofExprs() { numberOfExprs_ = 0; } |
| |
| void incNofScans(TableDesc* td); |
| |
| TransMode::IsolationLevel getIsoLvl() { return isoLvl_; } |
| TransMode::AccessMode getAccessMode() { return accMode_; } |
| |
| TransMode::IsolationLevel getIsoLvlForUpdates() { return isoLvlIDU_; } |
| |
| void setIsoLvl(TransMode::IsolationLevel l) { isoLvl_ = l; } |
| void setAccessMode(TransMode::AccessMode m) { accMode_ = m; } |
| |
| void setIsoLvlForUpdates(TransMode::IsolationLevel l) { isoLvlIDU_ = l; } |
| |
| Int16 getFlags() { return flags_ ; } |
| void setFlags(Int16 f) { flags_ = f; } |
| |
| void setAutoCommit(TransMode::AutoCommit a) { autoCmt_ = a; } |
| void setRollbackMode(TransMode::RollbackMode r) { rbackMode_ = r; } |
| void setAutoabortInterval(Lng32 val) {autoabortInterval_ = val ; } |
| void setMultiCommit(TransMode::MultiCommit a) { multiCmt_ = a; } |
| |
| NABoolean hasRewriteEnabledMV() { return hasRewriteEnabledMV_; } |
| void setRewriteEnabledMV(NABoolean x = TRUE) { hasRewriteEnabledMV_ = x; } |
| |
| NABoolean hasParameterizedPred() { return hasParameterizedPred_; } |
| void setParameterizedPred(NABoolean x = TRUE) { hasParameterizedPred_ = x; } |
| |
| NABoolean isUpdate() { return isUpdate_; } ; |
| void setIsUpdate(NABoolean x = TRUE) { isUpdate_ = x; } ; |
| |
| NAString reqdShape_; // control query shape or empty string |
| |
| private: |
| typedef TableDesc* TableDescPtr; |
| |
| HQCParseKey* HQCKey_; //collect histogram info for a Hybrid Cache Key during NormalizeForCache. |
| |
| Int32 numberOfExprs_; // number of ExprNodes in current query |
| // a query with more than N ExprNodes is not cacheable |
| |
| Int32 numberOfScans_; // number of Scan nodes in current query |
| |
| TableDescPtr *tabDescPtr_; // array of TableDesc pointers |
| ValueIdSet **usedKyPtr_; // array of ValueIdSet pointers |
| Int32 tabArraySize_; // size of the tabDescPtr_ and usedKyPtr_ arrays |
| |
| Int32 requiredPrefixKeys_; |
| |
| NABoolean hasPredicate_; // TRUE if query has a WHERE clause |
| NABoolean predHasNoLit_; // TRUE if predicate has no constants |
| |
| NAHeap *heap_; // compiler's statementHeap |
| NAString qryText_; // parameterized sql statement text |
| TextKey *tkey_; // text key of current query |
| CacheKey *ckey_; // cache key of current query |
| |
| TransMode::IsolationLevel isoLvl_; // tx isolation level |
| TransMode::AccessMode accMode_; // tx access mode |
| TransMode::IsolationLevel isoLvlIDU_; // tx isolation level for updates |
| |
| TransMode::AutoCommit autoCmt_; // tx auto-commit |
| TransMode::MultiCommit multiCmt_; // tx multi-commit |
| Int16 flags_; // tx flags |
| TransMode::RollbackMode rbackMode_; // tx rollback mode |
| Lng32 autoabortInterval_ ; //tx autoabortInterval |
| |
| SelParameters sels_; // list of actual selection parameters |
| LIST(Int32) sqlStmtConstParamPos_; |
| // list of positions in sql stmt |
| // that each constant occurs. Each is replaced |
| // by a const parameter |
| LIST(Int32) sqlStmtSelParamPos_; |
| // list of positions in sql stmt |
| // that each constant occurs. Each is replaced |
| // by a selParameter |
| LIST(Int32) hqcSqlConstPos_; |
| // used by the HQC logic to keep track of the correct |
| // order of the query constants |
| UInt32 posCounter_; |
| // used for keeping track of positions of aliased SelParams & ParamTypes |
| // valid positions are 1 up to count of SelParams & ConstantParameters |
| |
| SelParamTypeList *selTypes_; // types & selectivities of sel parameters |
| // selTypes_ is always derived from sels_; it's only purpose in life |
| // is to allow ~CacheWA() to deallocate selTypes_. |
| |
| ConstantParameters actuals_; // list of actual constant parameters |
| ParameterTypeList *parmTypes_; // types of actual constant parameters |
| // parmTypes_ is always derived from actuals_; it's only purpose in life |
| // is to allow ~CacheWA() to deallocate parmTypes_. |
| |
| CmpPhase phase_; // compiler cache phase (PARSE or BIND) |
| RelRoot *topRoot_; // has inputVarTree |
| NABoolean cacheable_; // true iff current query is cacheable |
| |
| // conditionallyCacheable_ is used by RelExpr::isCacheableExpr & its cohorts. |
| // It is set to true iff a RelExpr::isCacheableExpr() traversal has found |
| // a query node, such as a tuple insert that we definitely want to be |
| // cacheable at this phase subject only to the condition that it does |
| // not have any non-cacheable components. For example, we want all |
| // tuple inserts whose constants' types are reasonably-defined such as |
| // insert into t values(1, 3.14); |
| // to be cacheable after parse. However, dynamic-parameter-bearing |
| // tuple inserts such as |
| // insert into t values(?p1, ?p2); |
| // should be cacheable only after bind. |
| NABoolean conditionallyCacheable_; |
| |
| NABoolean useView_; |
| // must be set to true for cacheable query that references a view. |
| // used to suppress text caching of such a query to avoid subverting |
| // revocation of privilege on referenced view(s). |
| |
| NABoolean isViewJoin_; // true iff current query is a view join |
| // we want to safely cache view joins. But, there are view joins such as |
| // these two joins from regress/qatdml07 |
| // select avg(firstt.large_int) from pvsel01 firstt, pvsel01 secondd |
| // group by firstt.medium_int; |
| // select avg(secondd.large_int) from pvsel01 firstt, pvsel01 secondd |
| // group by firstt.medium_int; |
| // whose only difference is in their "avg(<basecolref>)". Unfortunately, |
| // after view expansion, both "firstt.large_int" and "secondd.large_int" |
| // resolve to the same fully qualified <basecolref> name |
| // "cat.sch.btsel01.large_int". The end result can be a false cache hit. |
| // To avoid this problem, isViewJoin_ is set true when such a view join |
| // is detected by RelCache.cpp's Join::isCacheableExpr() and later used |
| // to prepend the query's original text into its cachekey. |
| |
| NABoolean isUpdate_; // true iff the current query contains an update |
| |
| // list of referenced tables for getting to their histograms' timestamps. |
| // used for "passive invalidation" of oached plans. |
| LIST(NATable*) tables_; |
| |
| NABoolean hasRewriteEnabledMV_; |
| // true iff query references table that has rewrite enabled MV |
| |
| NABoolean hasParameterizedPred_; |
| // true iff query has a parameterized equality predicate |
| }; // class CacheWA |
| |
| #endif /* CacheWA__H */ |