// append an ascii-version of RelRoot into cachewa.qryText_ void RelRoot::generateCacheKey(CacheWA &cwa) const { RelExpr::generateCacheKey(cwa); ItemExpr *cExpr = compExprTree_ ? compExprTree_ : compExpr_.rebuildExprTree(); if (cExpr) { // append any select list into cache key cwa += " cExpr:"; cExpr->generateCacheKey(cwa); // reflect any "[first n]" cwa += ((RelRoot*)this)->needFirstSortedRows() ? " 1stN" : " "; // Should the select_list aliases be a part of the cache key? // Their not affecting the compiled plan argues for their exclusion. // Their affecting sqlci's expected output argues for their inclusion. RETDesc *rDesc = getRETDesc(); CollIndex degree, x; if (rDesc && (degree=rDesc->getDegree()) > 0) { cwa += " sla:"; for (x = 0; x < degree; x++){ cwa += rDesc->getColRefNameObj(x).getColName().data(); cwa += " "; } // fix 0-061115-0532 (query cache didn't handle select with embedded // update correctly). New/Old corr. names are recorded for embedded // updates here for exact match. This is important because otherwise // a reuse of a query returning the old/new version of values for // a query requesting new/old version is totally possible and // unacceptable. // // Sample embedded update queries // select * from (update tab1 set x = x + 1 where x > 1 return new.*) y; // select * from (update tab1 set x = x + 1 where x > 1 return new.x, old.y) y; // if ( cwa.isUpdate() && isTrueRoot() == FALSE ) { cwa += " corrNamTok:"; cwa += rDesc->getBindWA()->getCorrNameTokens(); } } } // order by clause is important ItemExpr *orderBy = orderByTree_ ? orderByTree_ : reqdOrder_.rebuildExprTree(); if (orderBy) { cwa += " order:"; orderBy->generateCacheKey(cwa); } // statement-level access type & lock mode are important for multiuser // applications. both are reflected in the stmt-level and/or context-wide // TransMode. So, we mimic RelRoot::codeGen logic here: "copy the current // context-wide TransMode, then overlay with this stmt's 'FOR xxx ACCESS' // setting, if any". TransMode tmode; tmode.updateTransMode(CmpCommon::transMode()); StmtLevelAccessOptions &opts = ((RelRoot*)this)->accessOptions(); if (opts.accessType() != ACCESS_TYPE_NOT_SPECIFIED_) { tmode.updateAccessModeFromIsolationLevel (TransMode::ATtoIL(opts.accessType())); tmode.setStmtLevelAccessOptions(); } if (isTrueRoot()) { // these are needed by Javier's qc stats virtual tbl interface cwa.setIsoLvl(tmode.getIsolationLevel()); cwa.setAccessMode(tmode.getAccessMode()); cwa.setAutoCommit(tmode.getAutoCommit()); cwa.setFlags(tmode.getFlags()); cwa.setRollbackMode(tmode.getRollbackMode()); cwa.setAutoabortInterval(tmode.getAutoAbortIntervalInSeconds()); cwa.setMultiCommit(tmode.getMultiCommit()); } // needed to distinguish these queries and avoid a false hit // select * from (delete from t where a=2) as t; // select * from (delete from t where a=2 for SKIP CONFLICT ACCESS) as t; char mode[40]; str_itoa(tmode.getIsolationLevel(), mode); cwa += " il:"; cwa += mode; str_itoa(tmode.getAccessMode(), mode); cwa += " am:"; cwa += mode; // Solution: 10-060418-5903 str_itoa(cwa.getIsoLvlForUpdates(), mode); cwa += " ilu:"; cwa += mode; str_itoa(tmode.getAutoCommit(), mode); cwa += " ac:"; cwa += mode; str_itoa(tmode.getFlags(), mode); cwa += " fl:"; cwa += mode; str_itoa(tmode.getRollbackMode(), mode); cwa += " rm:"; cwa += mode; str_itoa(tmode.getAutoAbortIntervalInSeconds(), mode); cwa += " ai:"; cwa += mode; str_itoa(tmode.getMultiCommit(), mode); cwa += " mc:"; cwa += mode; if (opts.lockMode() != LOCK_MODE_NOT_SPECIFIED_) { // need to distinguish these queries and avoid a false hit // select * from t in share mode; // select * from t in exclusive mode; str_itoa(opts.lockMode(), mode); cwa += " lm:"; cwa += mode; } // updatableSelect_ is essential. Otherwise, queries like // "select * from t" and "select * from t for update" can confuse // query caching into a false hit, causing fullstack/test051 to fail. if (updatableSelect_) { cwa += " 4updt "; } // for update of col [,col]... clause is important ItemExpr *updCol = updateColTree_ ? updateColTree_ : updateCol_.rebuildExprTree(); if (updCol) { cwa += " updCol:"; updCol->generateCacheKey(cwa); } // making the CQS part of the key is more efficient than calling // CompilerEnv::changeEnv() in ControlDB::setRequiredShape() if (reqdShape_) { reqdShape_->unparse(cwa.reqdShape_); } }