Ejemplo n.º 1
0
// 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
Ejemplo n.º 2
0
//
// --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;
}
Ejemplo n.º 3
0
// 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;
}
Ejemplo n.º 4
0
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()
Ejemplo n.º 5
0
//////////////////////////////////////////////////////////////////////////////
// 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;
}
Ejemplo n.º 6
0
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;
  }
Ejemplo n.º 7
0
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;

}