// Cleanup NARoutine cache after the statement completes. Remove entries // using LRU policy, if the cache has grown too large. The approach here is // somewhat different from NATableDB caching, which deletes entries from the // NATable cache if the statement was DDL that may have affected the table // definition. NATable caching also deletes tables from the cache at this // time for performance reasons. void NARoutineDB::resetAfterStatement() { // Delete 'dirty' NARoutine objects that were not deleted earlier // to save compile-time performance. if (routinesToDeleteAfterStatement_.entries()) { // Clear the list of tables to delete after statement routinesToDeleteAfterStatement_.clear(); } if (entries()) { // Reduce size of cache if it has grown too large. if (!enforceMemorySpaceConstraints()) cacheMetaData_ = FALSE; // Disable cache if there is a problem. // Reset statement level flags refreshCacheInThisStatement_=FALSE; // Clear 'accessed in current statement' flag for all cached NARoutines. NAHashDictionaryIterator<NARoutineDBKey,NARoutine> iter (*this); NARoutineDBKey *key; NARoutine *routine; iter.getNext(key,routine); while(key) { routine->getAccessedInCurStmt() = FALSE; iter.getNext(key,routine); } } }
// ---------------------------------------------------------------------------- // method: removeNARoutine // // The method is called when DDL is performed against a routine making its // definition incorrect. // It has a side affect of generating query invalidation keys that are // propagate to all the other processes that could have the routine stored // in cache. // ---------------------------------------------------------------------------- void NARoutineDB::removeNARoutine2(QualifiedName &routineName, ComQiScope qiScope, Int64 objUID) { NAHashDictionaryIterator<NARoutineDBKey,NARoutine> iter (*this); NARoutineDBKey *key = NULL; NARoutine *cachedNARoutine = NULL; NASet<Int64> objectUIDs(CmpCommon::statementHeap(), 1); // If there are no items in cache, skip if (entries() > 0) { NASet<Int64> objectUIDs(CmpCommon::statementHeap(), 1); // iterate over all entries and remove the ones that match the name iter.reset(); iter.getNext(key,cachedNARoutine); while(key && cachedNARoutine) { if (cachedNARoutine->getSqlName() == routineName) { objectUIDs.insert(cachedNARoutine->getRoutineID()); moveRoutineToDeleteList(cachedNARoutine,key); } iter.getNext(key,cachedNARoutine); } } // clear out the other users' caches too. if (qiScope == REMOVE_FROM_ALL_USERS) { // There are some scenarios where the affected object does not have an // NARoutine cache entry. However, other processes may have this routine // in their caches. Go ahead and create an invalidation key if (0 == objectUIDs.entries()) objectUIDs.insert(objUID); Int32 numKeys = objectUIDs.entries(); SQL_QIKEY qiKeys[numKeys]; for (CollIndex i = 0; i < numKeys; i++) { qiKeys[i].ddlObjectUID = objectUIDs[i]; qiKeys[i].operation[0] = 'O'; qiKeys[i].operation[1] = 'R'; } long retcode = SQL_EXEC_SetSecInvalidKeys(numKeys, qiKeys); } }
// ---------------------------------------------------------------------------- // method: free_entries_with_QI_key // // This method is sent a list of query invalidation keys. // It looks through the list of routines to see if any of them need to be // removed from cache because their definitions are no longer valid. // // numKeys - number of existing invalidation keys // qiKeyArray - actual keys // ---------------------------------------------------------------------------- void NARoutineDB::free_entries_with_QI_key(Int32 numKeys, SQL_QIKEY* qiKeyArray) { NAHashDictionaryIterator<NARoutineDBKey,NARoutine> iter (*this); NARoutineDBKey *key; NARoutine *routine; iter.getNext(key,routine); while(key && routine) { // See if item should be removed if (qiCheckForInvalidObject(numKeys, qiKeyArray, routine->getRoutineID(), routine->getSecKeySet())) moveRoutineToDeleteList(routine, key); iter.getNext(key,routine); } }
// 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 ((routine->getSchemaLabelFileName()) && (str_len(routine->getSchemaLabelFileName()) > 0)) { char schRedefTime[40]; convertInt64ToAscii(routine->getSchemaRedefTime(), schRedefTime); cwa += " schredef:"; cwa += schRedefTime; } } 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 += ")"; }
// append an ascii-version of IsolatedScalarUDF into cachewa.qryText_ void IsolatedScalarUDF::generateCacheKey(CacheWA &cwa) const { NARoutine *routine = NULL; NARoutine *action = NULL; RelExpr::generateCacheKey(cwa); cwa += " UDFname:"; cwa += getRoutineName().getQualifiedNameAsAnsiString().data(); if (cwa.getPhase() >= CmpMain::BIND && getRoutineDesc() && (routine=getRoutineDesc()->getNARoutine()) != NULL) { char redefTime[40]; convertInt64ToAscii(routine->getRedefTime(), redefTime); cwa += " redef:"; cwa += redefTime; } if (getRoutineDesc() != NULL && getRoutineDesc()->isUUDFRoutine()) { cwa += " action:"; cwa += getRoutineDesc()->getActionNameAsGiven(); if (cwa.getPhase() >= CmpMain::BIND && getRoutineDesc() && (action=getRoutineDesc()->getActionNARoutine()) != NULL) { char redefTime[40]; convertInt64ToAscii(action->getRedefTime(), redefTime); cwa += " actredef:"; cwa += redefTime; } } const ItemExpr *paramExpr = (getProcAllParamsTree() == NULL) ? getProcInputParamsVids().rebuildExprTree(ITM_ITEM_LIST) : getProcAllParamsTree(); if (paramExpr) { cwa += " arg:("; paramExpr->generateCacheKey(cwa); cwa += ")"; } }
// Find the NARoutine entry in the cache for 'key' or create it if not found. // 1. Check for entry in cache. // 2. If it doesn't exist, return. // 3. If it does exist, check to see if this is first time entry accessed. // 4. If so, check to see if entry is dirty (obsolete). // 5. If dirty, remove key and add to list to remove entry after statement // completes. // Note that BindWA is needed to be passed to this function so that we can // use it with getRedefTime() is necessary. NARoutine *NARoutineDB::get(BindWA *bindWA, const NARoutineDBKey *key) { // Check cache to see if a cached NARoutine object exists NARoutine *cachedNARoutine = NAKeyLookup<NARoutineDBKey,NARoutine>::get(key); /* 1 */ totalLookupsCount_++; // Statistics counter: number of lookups if (!cachedNARoutine || !cacheMetaData_) return NULL; /* 2 */ totalCacheHits_++; // Statistics counter: number of cache hits. // Record time that this NARoutine was obtained from cache for LRU. cachedNARoutine->setLastUsedTime(hs_getEpochTime()); cachedNARoutine->getAccessedInCurStmt() = TRUE; return cachedNARoutine; }
NARoutine::NARoutine (const NARoutine &old, CollHeap *h) : name_ (old.name_, h) , hashKey_ (old.hashKey_, h) , language_ (old.language_) , UDRType_ (old.UDRType_) , sqlAccess_ (old.sqlAccess_) , transactionAttributes_ (old.transactionAttributes_) , maxResults_ (old.maxResults_) , externalFile_ (old.externalFile_, h) , externalPath_ (old.externalPath_, h) , externalName_ (old.externalName_, h) , signature_ (old.signature_, h) , librarySqlName_ (old.librarySqlName_, h) , paramStyle_ (old.paramStyle_) , paramStyleVersion_ (old.paramStyleVersion_) , isDeterministic_ (old.isDeterministic_) , isCallOnNull_ (old.isCallOnNull_) , isIsolate_ (old.isIsolate_) , externalSecurity_ (old.externalSecurity_) , isExtraCall_ (old.isExtraCall_) , hasOutParams_ (old.hasOutParams_) , redefTime_ (old.redefTime_) , lastUsedTime_ (old.lastUsedTime_) , routineSecKeySet_ (h) , isUniversal_ (old.isUniversal_) , executionMode_ (old.getExecutionMode()) , objectUID_ (old.objectUID_) , stateAreaSize_ (old.stateAreaSize_) , dllName_ (old.dllName_, h) , dllEntryPoint_ (old.dllEntryPoint_, h) , comRoutineParallelism_ (old.comRoutineParallelism_) , sasFormatWidth_ (old.sasFormatWidth_, h) , systemName_ (old.systemName_, h) , dataSource_ (old.dataSource_, h) , fileSuffix_ (old.fileSuffix_, h) , initialRowCost_ (old.initialRowCost_) , normalRowCost_ (old.normalRowCost_) , udfFanOut_ (old.udfFanOut_) , passThruDataNumEntries_ (old.passThruDataNumEntries_) , uecValues_ (old.uecValues_, h) , actionPosition_ (old.actionPosition_) , schemaVersionOfRoutine_ (old.schemaVersionOfRoutine_) , objectOwner_ (0) , schemaOwner_ (0) , privInfo_ (NULL) , heap_ (h) { extRoutineName_ = new (h) ExtendedQualName(*old.extRoutineName_, h); extActionName_ = new (h) NAString(*old.extActionName_, h); intActionName_ = new (h) ComObjectName(*old.intActionName_, h); inParams_ = new (h) NAColumnArray(*old.inParams_, h); outParams_ = new (h) NAColumnArray(*old.outParams_, h); params_ = new (h) NAColumnArray(*old.params_, h); if (old.passThruDataNumEntries_ EQU 0) { passThruDataNumEntries_ = 0; passThruData_ = NULL; passThruDataSize_ = NULL; } else { passThruData_ = new (h) char*[(UInt32) passThruDataNumEntries_]; passThruDataSize_ = new (h) Int64[(UInt32) passThruDataNumEntries_]; for (Int32 i=0; i<passThruDataNumEntries_; i++) { passThruDataSize_[i]=old.passThruDataSize_[i]; passThruData_[i] = new (h) char[(UInt32)passThruDataSize_[i]+1]; memcpy(passThruData_[i], old.passThruData_[i], (size_t)passThruDataSize_[i]); passThruData_[i][(size_t)passThruDataSize_[i]]=0; // make sure to Null terminate the string } } routineSecKeySet_ = old.routineSecKeySet_; heapSize_ = (h ? h->getTotalSize() : 0); }
void CmpSeabaseDDL::dropSeabaseRoutine(StmtDDLDropRoutine * dropRoutineNode, NAString &currCatName, NAString &currSchName) { Lng32 retcode = 0; ComObjectName routineName(dropRoutineNode->getRoutineName()); ComAnsiNamePart currCatAnsiName(currCatName); ComAnsiNamePart currSchAnsiName(currSchName); routineName.applyDefaults(currCatAnsiName, currSchAnsiName); const NAString catalogNamePart = routineName.getCatalogNamePartAsAnsiString(); const NAString schemaNamePart = routineName.getSchemaNamePartAsAnsiString(TRUE); const NAString objectNamePart = routineName.getObjectNamePartAsAnsiString(TRUE); const NAString extRoutineName = routineName.getExternalName(TRUE); ExpHbaseInterface * ehi = NULL; ExeCliInterface cliInterface(STMTHEAP, NULL, NULL, CmpCommon::context()->sqlSession()->getParentQid()); ehi = allocEHI(); if (ehi == NULL) { processReturn(); return; } retcode = existsInSeabaseMDTable(&cliInterface, catalogNamePart, schemaNamePart, objectNamePart, COM_USER_DEFINED_ROUTINE_OBJECT, TRUE, FALSE); if (retcode < 0) { deallocEHI(ehi); processReturn(); return; } if (retcode == 0) // does not exist { *CmpCommon::diags() << DgSqlCode(-1389) << DgString0(extRoutineName); deallocEHI(ehi); processReturn(); return; } // get objectOwner Int64 objUID = 0; Int32 objectOwnerID = 0; Int32 schemaOwnerID = 0; Int64 objectFlags = 0; // see if routine is cached BindWA bindWA(ActiveSchemaDB(), CmpCommon::context(), FALSE/*inDDL*/); NARoutineDB *pRoutineDBCache = ActiveSchemaDB()->getNARoutineDB(); QualifiedName qualRoutineName(routineName, STMTHEAP); NARoutineDBKey key(qualRoutineName, STMTHEAP); NARoutine *cachedNARoutine = pRoutineDBCache->get(&bindWA, &key); if (cachedNARoutine) { objUID = cachedNARoutine->getRoutineID(); objectOwnerID = cachedNARoutine->getObjectOwner(); schemaOwnerID = cachedNARoutine->getSchemaOwner(); } else { objUID = getObjectInfo(&cliInterface, catalogNamePart.data(), schemaNamePart.data(), objectNamePart.data(), COM_USER_DEFINED_ROUTINE_OBJECT, objectOwnerID,schemaOwnerID,objectFlags); if (objUID < 0 || objectOwnerID == 0 || schemaOwnerID == 0) { deallocEHI(ehi); processReturn(); return; } } // Verify user has privilege to drop routine if (!isDDLOperationAuthorized(SQLOperation::DROP_ROUTINE,objectOwnerID,schemaOwnerID)) { *CmpCommon::diags() << DgSqlCode(-CAT_NOT_AUTHORIZED); deallocEHI(ehi); processReturn (); return; } // Determine if this function is referenced by any other objects. Lng32 cliRC = 0; Queue * usingViewsQueue = NULL; if (dropRoutineNode->getDropBehavior() == COM_RESTRICT_DROP_BEHAVIOR) { NAString usingObjName; cliRC = getUsingObject(&cliInterface, objUID, usingObjName); if (cliRC < 0) { deallocEHI(ehi); processReturn(); return; } if (cliRC != 100) // found an object { *CmpCommon::diags() << DgSqlCode(-CAT_DEPENDENT_VIEW_EXISTS) << DgTableName(usingObjName); deallocEHI(ehi); processReturn(); return; } } else if (dropRoutineNode->getDropBehavior() == COM_CASCADE_DROP_BEHAVIOR) { cliRC = getUsingViews(&cliInterface, objUID, usingViewsQueue); if (cliRC < 0) { deallocEHI(ehi); processReturn(); return; } } if (usingViewsQueue) { usingViewsQueue->position(); for (int idx = 0; idx < usingViewsQueue->numEntries(); idx++) { OutputInfo * vi = (OutputInfo*)usingViewsQueue->getNext(); char * viewName = vi->get(0); if (dropOneTableorView(cliInterface,viewName,COM_VIEW_OBJECT,false)) { deallocEHI(ehi); processReturn(); return; } } } // Removed routine from metadata if (dropSeabaseObject(ehi, dropRoutineNode->getRoutineName(), currCatName, currSchName, COM_USER_DEFINED_ROUTINE_OBJECT, TRUE, FALSE)) { deallocEHI(ehi); processReturn(); return; } // Remove cached entries in other processes pRoutineDBCache->removeNARoutine(qualRoutineName, NARoutineDB::REMOVE_FROM_ALL_USERS, objUID); deallocEHI(ehi); processReturn(); return; }