// Lookup the other table involved in this RI relationship, // and find the other constraint in the other NATable constraint list. // I.e., if called by a UniqueConstraint, this looks in the referencing table's // refConstraints to find the FK constraint passed in riInfo; // if called by a RefConstraint, this looks in the referenced table's // uniqueConstraints to find the UC constraint passed in riInfo. // AbstractRIConstraint *AbstractRIConstraint::findConstraint( BindWA *bindWA, const ComplementaryRIConstraint &riInfo) const { // Lookup errors should be impossible, due to Ansi transaction semantics // during compilation of a query, so no need for fancy diags, just assert // (should only happen if catalog corrupt or txn seriously haywire) CorrName tempName(riInfo.tableName_); NATable *naTable = bindWA->getNATable(tempName, FALSE); if (!naTable) return NULL; const AbstractRIConstraintList otherConstraints = (getOperatorType() == ITM_UNIQUE_CONSTRAINT) ? naTable->getRefConstraints() : naTable->getUniqueConstraints(); // The find() from Collections template doesn't work for us, so roll our own AbstractRIConstraint *c; for (CollIndex i = 0; i < otherConstraints.entries(); i++) { c = otherConstraints[i]; if (c->getConstraintName() == riInfo.constraintName_) return c; } *CmpCommon::diags() << DgSqlCode(-4353) << DgTableName(naTable->getTableName().getQualifiedNameAsAnsiString()) ; bindWA->setErrStatus(); return NULL; } // AbstractRIConstraint::findConstraint
// // --TriggerDB::getValidEntry // // return the BeforeAndAfterTriggers (ptr) given the key. // NULL is returned if no entry was found. In case of working across statements // (Trigger::heap() == CmpCommon::contextHeap()) then this method // VALIDATES (timestamp check) the return value before returning. // Note: a non-valid entry is first removed from the DB and a NULL is returned. // BeforeAndAfterTriggers* TriggerDB::getValidEntry(const TableOp * key, BindWA * bindWA) { BeforeAndAfterTriggers* result = NAHashDictionary<TableOp, BeforeAndAfterTriggers>::getFirstValue(key); if ((result != NULL) && (Trigger::Heap() == CmpCommon::contextHeap())) { // only used when triggers are allocated from the cntext heap. // Currently triggers are allocated from the statement heap. // See method Trigger::Heap() in file Triggers.h for more details // LCOV_EXCL_START // entry exist in TriggerDB and we work ACROSS statements => // validate the entry: compare the entry's subject table timestamp // against the actual subject table's timestamp // convert to ExtendedQualName ExtendedQualName exSubjectTable = ExtendedQualName(key->subjectTable_, CmpCommon::statementHeap()); // fetch the subject table from the NATableDB NATable *subjectTable = bindWA->getSchemaDB()->getNATableDB()->get(&exSubjectTable); // the subject table MUST appear in the TableTB because it must have // been fetched earlier by the binder (also in the case of cascaded // triggers) CMPASSERT(subjectTable != NULL); ComTimestamp trigsTS = result->getSubjectTableTimeStamp(); CMPASSERT(trigsTS != 0); // must have been initialized by the catman if (subjectTable->getRedefTime() != trigsTS) { // no match => invalidate this->remove((TableOp*) key); result->clearAndDestroy(); delete result; // destroy the entry return NULL; } // LCOV_EXCL_STOP } // end of validation // at this point, if result != NULL, then it is valid. Otherwise it is // not in the TriggerDB return result; }
// Look for groups that constitute a leading prefix of the primary key, possibly // excluding the "_SALT_" column. For each such group that omits "_SALT_", add // another group consisting of that group plus "_SALT_", with the columns in index // order. For each such group that already includes "_SALT_", replace it with a // group containing the same set of columns, but in index order. This function // should only be called for a salted table. Lng32 AddSaltToIndexPrefixes() { Lng32 retcode = 0; HSGlobalsClass *hs_globals = GetHSContext(); NATable* naTbl = hs_globals->objDef->getNATable(); NAFileSet* clusteringIndex = naTbl->getClusteringIndex(); NABoolean groupHasSalt; HSColGroupStruct* nextGroup; NABoolean doingSingles = TRUE; HSColGroupStruct* group = hs_globals->singleGroup; if (!group) { group = hs_globals->multiGroup; doingSingles = FALSE; } while (group) { // AddSaltedIndexPrefix may remove the group it is passed from the group // list and deallocate it, so we grab the link to the next one from it first. nextGroup = group->next; // See if the group matches a prefix of the key, allowing _SALT_ to not // be present. groupHasSalt will indicate whether it was present. If it // matches, add the appropriate group. if (MatchesIndexPrefix(group, clusteringIndex, groupHasSalt)) retcode = AddSaltedIndexPrefix(clusteringIndex, group, groupHasSalt); group = nextGroup; if (!group && doingSingles) { doingSingles = FALSE; group = hs_globals->multiGroup; } } return retcode; }
MVInfoForDML *Refresh::getMvInfo(BindWA *bindWA, CorrName& mvToRefresh) const { // Get the NATable for the MV. NATable *mavNaTable = bindWA->getNATable(mvToRefresh); if (bindWA->errStatus()) return NULL; CMPASSERT(mavNaTable!=NULL); CMPASSERT(mavNaTable->isAnMV()); // If this is an incremental refresh, verify that the MV is initialized. // Recompute can be done on un-initialized. // Don't check if the MV is unavailable - the utility may have set it to // unavailable during the refresh operation. const ComMvAttributeBitmap& bitmap = mavNaTable->getMvAttributeBitmap(); if (!bitmap.getIsMvUnAvailable() && bitmap.getIsMvUnInitialized()) CMPASSERT(refreshType_ == RECOMPUTE); // Now get the MVInfo. MVInfoForDML *mvInfo = mavNaTable->getMVInfo(bindWA); CMPASSERT(mvInfo != NULL); mvInfo->initUsedObjectsHash(); return mvInfo; } // Refresh::getMvInfo()
////////////////////////////////////////////////////////////////////////////// // Does this base table have a supporting index on the MAV GroupBy columns? // (Supporting index means that the MAV GroupBy columns must be a prefix // of the index columns). ////////////////////////////////////////////////////////////////////////////// NABoolean Refresh::doesBaseTableHaveSupportingIndex(BindWA *bindWA, MVInfoForDML *mvInfo) const { CollIndex i; LIST (MVUsedObjectInfo*)& UsedObjList = mvInfo->getUsedObjectsList(); MVUsedObjectInfo* pUsedTable = UsedObjList[0]; // Extract GroupBy columns const MVColumns& pMvInfoColumnList = mvInfo->getMVColumns(); LIST (MVColumnInfo *) mvGroupByColumns(bindWA->wHeap()); for ( i = 0 ; i < pMvInfoColumnList.entries() ; i++) { #pragma nowarn(1506) // warning elimination MVColumnInfo *currentMvColInfo = pMvInfoColumnList[i]; #pragma warn(1506) // warning elimination if (COM_MVCOL_GROUPBY == currentMvColInfo->getColType()) { mvGroupByColumns.insert(currentMvColInfo); } } // If the MAV does not have any group by columns - than there is // no supporting index. if (mvGroupByColumns.entries() == 0) return FALSE; // Get the NATable QualifiedName underlyingTableName = pUsedTable->getObjectName(); CorrName corrTableName(underlyingTableName); NATable * pNaTable = bindWA->getNATable(corrTableName, FALSE); // Construct table GroupBy NAColumnArray tableGroupByArray; const NAColumnArray & columnArray = pNaTable->getNAColumnArray(); for ( i = 0 ; i < mvGroupByColumns.entries() ; i++) { Int32 tableColNum = (mvGroupByColumns)[i]->getOrigColNumber(); NAColumn * pColumn = columnArray.getColumn(tableColNum); tableGroupByArray.insert(pColumn); } // Check the clustering Index. const NAFileSet *pClusteringIndexFileSet = pNaTable->getClusteringIndex(); const NAColumnArray& ciColumns = pClusteringIndexFileSet->getIndexKeyColumns(); if (TRUE == areGroupByColsAnIndexPrefix(tableGroupByArray, ciColumns)) { return TRUE; } // Check any secondary indices. const NAFileSetList & indexFileSetList = pNaTable->getIndexList(); for ( i = 0 ; i < indexFileSetList.entries() ; i++) { const NAFileSet *pSecondaryIndexFileSet = indexFileSetList[i]; const NAColumnArray& siColumns = pSecondaryIndexFileSet->getIndexKeyColumns(); if (TRUE == areGroupByColsAnIndexPrefix(tableGroupByArray, siColumns)) { return TRUE; } } return FALSE; }
Lng32 AddKeyGroups() { HSGlobalsClass *hs_globals = GetHSContext(); if (HSGlobalsClass::isHiveCat(hs_globals->objDef->getCatName())) { // HSHiveTableDef::getKeyList()/getIndexArray() not yet implemented. *CmpCommon::diags() << DgSqlCode(-UERR_NO_ONEVERYKEY) << DgString0("hive"); return -1; } Lng32 retcode = 0; Lng32 numColsInGroup = 0; HSColumnStruct col; NAString tempColList = ""; NAString tempCol; NAString autoGroup; ULng32 numKeys; ULng32 i, j; NATable* naTbl = hs_globals->objDef->getNATable(); HSLogMan *LM = HSLogMan::Instance(); // ---------------------------------------------------------- // Generate histograms for KEY // ---------------------------------------------------------- // The clustering index is included in the list of indices returned by // NATable::getIndexList(), so we store its pointer so we can skip it // when the other indexes are processed below. NAFileSet* clusteringIndex = naTbl->getClusteringIndex(); const NAColumnArray& keyCols = clusteringIndex->getIndexKeyColumns(); Lng32 colPos; numKeys = keyCols.entries(); if (numKeys == 1) // SINGLE-COLUMN KEY { colPos = keyCols[0]->getPosition(); if (LM->LogNeeded()) { sprintf(LM->msg, "\t\tKEY:\t\t(%s)", hs_globals->objDef->getColName(colPos)); LM->Log(LM->msg); } if (ColumnExists(colPos)) // avoid duplicates { LM->Log("\t\t** duplicate column group has been ignored."); } else // add to single-column group list { retcode = AddSingleColumn(colPos); } } else if (numKeys > 1) // MULTI-COLUMN KEY { // Create multiple MC group(s) if numkeys > 1. Subset MC groups will // also be created if numkeys > 2, E.g. If numkeys = 5, then // MC groups with 5, 4, 3, and 2 columns will be created using // the key columns. Note that if numkeys is larger than CQD // USTAT_NUM_MC_GROUPS_FOR_KEYS (default = 5), then the number // of groups created will be limited by this value. So, e.g. if // numkeys = 10, then MC groups with 5, 4, 3, and 2 columns will // be created (that is, 5 groups will be created - incl the single). ULng32 minMCGroupSz = 2; ULng32 maxMCGroups = (ULng32) CmpCommon::getDefaultNumeric(USTAT_NUM_MC_GROUPS_FOR_KEYS); // Generate no MCs with more cols than specified by the cqd. if (numKeys > maxMCGroups) numKeys = maxMCGroups; // For salted table, generate only the longest MC for the key (subject // to max cols determined above) unless a cqd is set to gen all MCs of // allowable sizes. if (CmpCommon::getDefault(USTAT_ADD_SALTED_KEY_PREFIXES_FOR_MC) == DF_OFF && hs_globals->objDef->getColNum("_SALT_", FALSE) >= 0) minMCGroupSz = numKeys; while (numKeys >= minMCGroupSz) // Create only MC groups not single cols { HSColSet colSet; autoGroup = "("; for (j = 0; j < numKeys; j++) { colPos = keyCols[j]->getPosition(); col = hs_globals->objDef->getColInfo(colPos); col.colnum = colPos; colSet.insert(col); autoGroup += col.colname->data(); autoGroup += ","; } if (LM->LogNeeded()) { autoGroup.replace(autoGroup.length()-1,1,")"); // replace comma with close parenthesis sprintf(LM->msg, "\t\tKEY:\t\t%s", autoGroup.data()); LM->Log(LM->msg); } if (retcode = AddColumnSet(colSet)) { HSHandleError(retcode); } numKeys--; } } // ---------------------------------------------------------- // Generate histograms for all INDEXES // ---------------------------------------------------------- const NAFileSetList& indexes = naTbl->getIndexList(); NAFileSet* index; for (i = 0; i < indexes.entries(); i++ ) { index = indexes[i]; if (index == clusteringIndex) continue; // clustering index processed above already const NAColumnArray& keyCols = index->getIndexKeyColumns(); numKeys = keyCols.entries(); if (numKeys == 1) // SINGLE-COLUMN INDEX { colPos = keyCols[0]->getPosition(); if (LM->LogNeeded()) { sprintf(LM->msg, "\t\tINDEX[%d]\t(%s)", i, hs_globals->objDef->getColName(colPos)); LM->Log(LM->msg); } if (ColumnExists(colPos)) // avoid duplicates { LM->Log("\t\t*** duplicate column group has been ignored."); } else // add to single-column group list { retcode = AddSingleColumn(colPos); } } else // MULTI-COLUMN INDEX { // Create multiple MC group(s) if numkeys > 1. Subset MC groups will // also be created if numkeys > 2, E.g. If numkeys = 5, then // MC groups with 5, 4, 3, and 2 columns will be created using // the key columns. Note that if numkeys is larger than CQD // USTAT_NUM_MC_GROUPS_FOR_KEYS (default = 5), then the number // of groups created will be limited by this value. So, e.g. if // numkeys = 10, then MC groups with 10, 9, 8, 7, 6 columns will // be created (that is, 5 groups will be created). ULng32 minMCGroupSz = 2; ULng32 maxMCGroups = (ULng32) CmpCommon::getDefaultNumeric(USTAT_NUM_MC_GROUPS_FOR_KEYS); if (numKeys > maxMCGroups) minMCGroupSz = numKeys - maxMCGroups + 1; while (numKeys >= minMCGroupSz) // MinMCGroupSz is greater than 1. { HSColSet colSet; tempColList = ""; autoGroup = "("; for (j = 0; j < numKeys; j++) { colPos = keyCols[j]->getPosition(); tempCol = "."; tempCol += LongToNAString(colPos); tempCol += "."; // Eliminate duplicate columns in the index; // They may have been introduced by appending the key to the specified index. if (!tempColList.contains(tempCol)) { col = hs_globals->objDef->getColInfo(colPos); col.colnum = colPos; colSet.insert((const struct HSColumnStruct) col); tempColList += tempCol.data(); numColsInGroup++; autoGroup += col.colname->data(); autoGroup += ","; } } if (colSet.entries()) { if (numColsInGroup > 1) { if (LM->LogNeeded()) { autoGroup.replace(autoGroup.length()-1,1,")"); // replace comma with close parenthesis sprintf(LM->msg, "\t\tINDEX[%d]\t%s", i, autoGroup.data()); LM->Log(LM->msg); } if (retcode = AddColumnSet(colSet)) { HSHandleError(retcode); } } numColsInGroup = 0; } numKeys--; } } } return retcode; }
EstLogPropSharedPtr AppliedStatMan::getStatsForCANodeId( CANodeId jbbc, const EstLogPropSharedPtr &inLP, const ValueIdSet * predIdSet) { EstLogPropSharedPtr inputLP = inLP; if(inputLP == (*GLOBAL_EMPTY_INPUT_LOGPROP)) inputLP = jbbc.getJBBInput(); EstLogPropSharedPtr outputEstLogProp = NULL; // 1. Try to find Logical Properties from cache if cacheable. // The estimate Logical Properties can be cacheable if all local // predicates are to be applied and if inNodeSet is provided, // or the inLP are cacheable if ((inputLP->isCacheable()) && (predIdSet == NULL) ) { CANodeIdSet combinedSet = jbbc; // get the nodeIdSet of the outer child, if not already given. This // along with the present jbbc is used as a key in the cache CANodeIdSet * inputNodeSet; inputNodeSet = inputLP->getNodeSet(); // if inLP are cacheable these should have a nodeSet attached CCMPASSERT(inputNodeSet != NULL); if (inputNodeSet) { combinedSet.insert(*inputNodeSet); // if estLogProp for all local predicates is required, // then it might already exist in the cache outputEstLogProp = getCachedStatistics(&combinedSet); } } if (outputEstLogProp == NULL) { // 2. properties do not exist in the cache, so synthesize them. //if specified by the user apply those predicates, // else apply predicates in the original expr NodeAnalysis * jbbcNode = jbbc.getNodeAnalysis(); TableAnalysis * tableAnalysis = jbbcNode->getTableAnalysis(); if (tableAnalysis && predIdSet) { TableDesc * tableDesc = tableAnalysis->getTableDesc(); const QualifiedName& qualName = tableDesc->getNATable()->getTableName(); CorrName name(qualName, STMTHEAP); Scan *scanExpr = new STMTHEAP Scan(name, tableDesc, REL_SCAN, STMTHEAP); Cardinality rc = tableDesc->getNATable()->getEstRowCount(); const CardinalityHint* cardHint = tableDesc->getCardinalityHint(); if ( cardHint ) rc = (cardHint->getScanCardinality()).getValue(); if ( !cardHint && tableDesc->getNATable()->isHbaseTable() ) { NATable* nt = (NATable*)(tableDesc->getNATable()); StatsList* statsList = nt->getColStats(); if ( statsList && statsList->entries() > 0 ) { ColStatsSharedPtr cStatsPtr = statsList->getSingleColumnColStats(0); if ( cStatsPtr ) rc = (cStatsPtr->getRowcount()).getValue(); } } scanExpr->setBaseCardinality(MIN_ONE (rc)); GroupAttributes * gaExpr = new STMTHEAP GroupAttributes(); scanExpr->setSelectionPredicates(*predIdSet); ValueIdSet requiredOutputs = jbbc.getNodeAnalysis()->\ getOriginalExpr()->getGroupAttr()->getCharacteristicOutputs(); gaExpr->setCharacteristicOutputs(requiredOutputs); scanExpr->setGroupAttr(gaExpr); gaExpr->setLogExprForSynthesis(scanExpr); EstLogPropSharedPtr nonCacheableInLP(new (HISTHEAP) EstLogProp (*inputLP)); nonCacheableInLP->setCacheableFlag(FALSE); scanExpr->synthLogProp(); outputEstLogProp = scanExpr->getGroupAttr()->outputLogProp(nonCacheableInLP); } else { NodeAnalysis * nodeAnalysis = jbbc.getNodeAnalysis(); RelExpr * relExpr = nodeAnalysis->getModifiedExpr(); if (relExpr == NULL) relExpr = nodeAnalysis->getOriginalExpr(); // synthesize and cache estLogProp for the given inLP. outputEstLogProp = relExpr->getGroupAttr()->outputLogProp(inputLP); } } return outputEstLogProp; } // getStatsForCANodeId
// ***************************************************************************** // * * // * Function: checkAccessPrivileges * // * * // * This function determines if a user has the requesite privileges to * // * access the referenced objects that comprise the view. * // * * // ***************************************************************************** // * * // * Parameters: * // * * // * <vtul> const ParTableUsageList & In * // * is a reference to a list of objects used by the view. * // * * // * <vctcul> const ParViewColTableColsUsageList & In * // * is a reference to the list of columns used by the view. * // * * // * <privilegesBitmap> PrivMgrBitmap & Out * // * passes back the union of privileges the user has on the referenced * // * objects. * // * * // * <grantableBitmap> PrivMgrBitmap & Out * // * passes back the union of the with grant option authority the user has * // * on the referenced objects. * // * * // ***************************************************************************** // * * // * Returns: bool * // * * // * true: User has requisite privileges; bitmap unions returned. * // * false: Could not retrieve privileges or user does not have requesite * // * privileges; see diags area for error details. * // * * // ***************************************************************************** static bool checkAccessPrivileges( const ParTableUsageList & vtul, const ParViewColTableColsUsageList & vctcul, PrivMgrBitmap & privilegesBitmap, PrivMgrBitmap & grantableBitmap) { BindWA bindWA(ActiveSchemaDB(),CmpCommon::context(),FALSE/*inDDL*/); bool missingPrivilege = false; NAString extUsedObjName; // generate the lists of privileges and grantable privileges // a side effect is to return an error if basic privileges are not granted for (CollIndex i = 0; i < vtul.entries(); i++) { if (vtul[i].getSpecialType() == ExtendedQualName::SG_TABLE) continue; ComObjectName usedObjName(vtul[i].getQualifiedNameObj().getQualifiedNameAsAnsiString(), vtul[i].getAnsiNameSpace()); const NAString catalogNamePart = usedObjName.getCatalogNamePartAsAnsiString(); const NAString schemaNamePart = usedObjName.getSchemaNamePartAsAnsiString(TRUE); const NAString objectNamePart = usedObjName.getObjectNamePartAsAnsiString(TRUE); const NAString extUsedObjName = usedObjName.getExternalName(TRUE); CorrName cn(objectNamePart,STMTHEAP, schemaNamePart,catalogNamePart); NATable *naTable = bindWA.getNATable(cn); if (naTable == NULL) { SEABASEDDL_INTERNAL_ERROR("Bad NATable pointer in checkAccessPrivileges"); return false; } // Grab privileges from the NATable structure PrivMgrUserPrivs *privs = naTable->getPrivInfo(); if (privs == NULL) { *CmpCommon::diags() << DgSqlCode(-CAT_UNABLE_TO_RETRIEVE_PRIVS); return false; } // Requester must have at least select privilege if ( !privs->hasSelectPriv() ) missingPrivilege = true; // Summarize privileges privilegesBitmap &= privs->getObjectBitmap(); grantableBitmap &= privs->getGrantableBitmap(); } if (!missingPrivilege) return true; missingPrivilege = false; PrivColumnBitmap colPrivBitmap; PrivColumnBitmap colGrantableBitmap; PrivMgrPrivileges::setColumnPrivs(colPrivBitmap); PrivMgrPrivileges::setColumnPrivs(colGrantableBitmap); for (size_t i = 0; i < vctcul.entries(); i++) { const ParViewColTableColsUsage &vctcu = vctcul[i]; int32_t usingColNum = vctcu.getUsingViewColumnNumber(); const ColRefName &usedColRef = vctcu.getUsedObjectColumnName(); ComObjectName usedObjName; usedObjName = usedColRef.getCorrNameObj().getQualifiedNameObj(). getQualifiedNameAsAnsiString(); const NAString catalogNamePart = usedObjName.getCatalogNamePartAsAnsiString(); const NAString schemaNamePart = usedObjName.getSchemaNamePartAsAnsiString(TRUE); const NAString objectNamePart = usedObjName.getObjectNamePartAsAnsiString(TRUE); extUsedObjName = usedObjName.getExternalName(TRUE); CorrName cn(objectNamePart,STMTHEAP,schemaNamePart,catalogNamePart); NATable *naTable = bindWA.getNATable(cn); if (naTable == NULL) { SEABASEDDL_INTERNAL_ERROR("Bad NATable pointer in checkAccessPrivileges"); return -1; } const NAColumnArray &nacolArr = naTable->getNAColumnArray(); ComString usedObjColName(usedColRef.getColName()); const NAColumn * naCol = nacolArr.getColumn(usedObjColName); if (naCol == NULL) { *CmpCommon::diags() << DgSqlCode(-CAT_COLUMN_DOES_NOT_EXIST_ERROR) << DgColumnName(usedObjColName); return false; } int32_t usedColNumber = naCol->getPosition(); // Grab privileges from the NATable structure PrivMgrUserPrivs *privs = naTable->getPrivInfo(); if (privs == NULL) { *CmpCommon::diags() << DgSqlCode(-CAT_UNABLE_TO_RETRIEVE_PRIVS); return false; } // If the user is missing SELECT on at least one column-level privilege, // view cannot be created. No need to proceed. if (!privs->hasColSelectPriv(usedColNumber)) { missingPrivilege = true; break; } colPrivBitmap &= privs->getColumnPrivBitmap(usedColNumber); colGrantableBitmap &= privs->getColumnGrantableBitmap(usedColNumber); } if (missingPrivilege || vctcul.entries() == 0) { *CmpCommon::diags() << DgSqlCode(-4481) << DgString0("SELECT") << DgString1(extUsedObjName.data()); return false; } for (size_t i = FIRST_DML_COL_PRIV; i <= LAST_DML_COL_PRIV; i++ ) { if (colPrivBitmap.test(PrivType(i))) privilegesBitmap.set(PrivType(i)); if (colGrantableBitmap.test(PrivType(i))) grantableBitmap.set(PrivType(i)); } return true; }