예제 #1
0
// ***************************************************************************
// Is this column from a table that has an LOJ parent?
// ***************************************************************************
NABoolean DescriptorDetails::isColumnFromLojTable(const QRColumnPtr col)
{
  const NAString& tableID = col->getTableID();
  const QRElementPtr tableElem = getElementForID(tableID);
  assertLogAndThrow(CAT_MATCHTST_MVDETAILS, LL_MVQR_FAIL,
                    tableElem, QRLogicException, 
		    "Table not found in JBB.");
  const QRTablePtr table = tableElem->downCastToQRTable();
  return table->hasLOJParent();
}
void QRGroupLattice::insert(QRJoinSubGraphMapPtr map, const QRJBBPtr jbb)
{
  QRTRACER("QRGroupLattice::insert()");
  LatticeKeyList keyList;
  NABoolean ok = getGroupingLatticeKeys(keyList, map, map->getMVDetails(), jbb, FALSE, TRUE);
  assertLogAndThrow(CAT_GRP_LATTCE_INDX, LL_ERROR,
                    ok, QRLogicException, 
		    "getGroupingLatticeKeys() failed in Insert mode (Inserting a multi-JBB MV?).");
  lattice_->addMV(keyList, map);

  dumpLattice("1");
}
예제 #3
0
Visitor::VisitResult RefFinderVisitor::visit(QRElementPtr caller)
{
  // Elements that don't reference other elements, should reference 
  // themselves (the default value).
  if (caller->getRef() == "")
    return VR_Continue;

  QRElementPtr elem = descDetails_->getElementForID(caller->getRef());
  assertLogAndThrow(CAT_MATCHTST_MVDETAILS, LL_MVQR_FAIL, 
                    elem != NULL, QRLogicException, 
		    "Element is referencing a non-existing element.");
  caller->setReferencedElement(elem);

  return VR_Continue;
}
예제 #4
0
// ***************************************************************************
// Initialize internal data structures.
// ***************************************************************************
void MVDetails::init(CollHeap* heap)
{
  // Init the superclass
  DescriptorDetails::init(heap);

  const NAPtrList<QRJBBPtr>& jbbs = descriptor_->getJbbList();
  assertLogAndThrow(CAT_MATCHTST_MVDETAILS, LL_MVQR_FAIL,
                    jbbs.entries() == 1, QRLogicException, 
		    "Support single JBB MVs only for now.");
  // Init the shortcut to the first (and only) JBB in MV descriptors.
  jbbDetails_ = jbbDetailsList_[0];
  // TBD - When we support multi-JBB MVs, we need to loop over the jbb list.
  const QRJBBPtr jbb = jbbs[0];

  // Initialize the several hash tables that map output list elements.
  initOutputs(jbb, heap);

  // Initialize the hash of tables in the descriptor.
  initTables(jbb, heap);
}
예제 #5
0
// *************************************************************** 
// * Prepare the object name to handle any double quotes
// * within the delimited name
// *************************************************************** 
void QRQueriesImpl::fixupDelimitedName(const char * inName, char * outName)
{
  // Prepare the object name to handle any double quotes
  // within the delimited name

  assertLogAndThrow(CAT_SQL_COMP_QR_COMMON, LL_ERROR,
                    inName!=NULL && outName!=NULL, QRLogicException, 
		    "Bad input parameters to fixupDelimitedName()."); 
  
  Int32 j = 0;
  short len = strlen(inName);

  for (Int32 i = 0; i < len; i++)
  {
    if (inName[i] == '"')
      outName[j++] = '"';

    outName[j++] = inName[i];
  }

  outName[j] = '\0';
}  // End of fixupDelimitedName
예제 #6
0
// *************************************************************** 
// * Obtain a catalog name for the catalog UID specified.
// *
// * A static SQL query is used to obtain the
// * CATALOG name from the system metadata. 
// *************************************************************** 
const NAString* QRQueriesImpl::getCatalogName(Int64 catalogUID)
{
  NAString* catalogName = new(heap_) NAString(heap_);
  Lng32 sqlCode = queries_->openCatalogName(catalogUID);
  assertLogAndThrow1(CAT_SQL_COMP_QR_COMMON, LL_ERROR,
                    sqlCode==SQL_Success, QRDatabaseException, 
		    "Error %d performing get catalog name.", sqlCode); 

  sqlCode = queries_->fetchCatalogName(*catalogName);
  // SQL_Eof means the catalog UID is wrong.
  assertLogAndThrow(CAT_SQL_COMP_QR_COMMON, LL_ERROR,
                    sqlCode != SQL_Eof, QRDatabaseException, 
		    "Unable to obtain catalog name for UID."); 
  // Otherwise its an SQL error.
  assertLogAndThrow1(CAT_SQL_COMP_QR_COMMON, LL_ERROR,
                    sqlCode==SQL_Success, QRDatabaseException, 
		    "Error %d performing get catalog name.", sqlCode); 

  // Always close to free up resources
  queries_->closeCatalogName();

  return catalogName;
}  // End of getCatalogName
//*****************************************************************************
// Implement the end of the state machine algorithm, closing the last segment.
//*****************************************************************************
void SelfJoinHandler::doneAddingTables()
{
  // Which state in the state machine are we in?
  switch (state_)
  {
    case ST_SINGLE:
    case ST_UNIQUE:
      addSegment(SelfJoinSegment::UNIQUE_TABLE_SEGMENT);
      break;

    case ST_SELFJOIN:
      addSegment(SelfJoinSegment::SELF_JOIN_SEGMENT);
      break;

    case ST_START:
    case ST_END:
      assertLogAndThrow(CAT_MVMEMO_JOINGRAPH, LL_MVQR_FAIL,
                        FALSE, QRLogicException, 
                        "calling SelfJoinHandler::end() in ST_START or ST_END state.");
      break;
  }

  state_ = ST_END;
}
예제 #8
0
// ***************************************************************************
// Initialize the several hash tables that map output list elements:
//    outputByIDHash_	      - Using the ID of the output item as the key.
//    outputByColumnName_     - Using the "ID Qualified" column name as the key.
//    outputByExprText_	      - Using the expression text as the key.
//    outputByInputColumns_   - Using the name of expression input column as the key.
// ***************************************************************************
void MVDetails::initOutputs(const QRJBBPtr jbb, CollHeap* heap)
{
  // Match the output elements with their names.
  const QROutputListPtr outputList = jbb->getOutputList();

  assertLogAndThrow(CAT_MATCHTST_MVDETAILS, LL_MVQR_FAIL,
                    outputList != NULL, QRLogicException,
                    "Output list is null.");

  // For each output list element
  for (CollIndex i=0; i<outputList->entries(); i++)
  {
    QROutputPtr output = (*outputList)[i];
    // Set the ordinal number of the output element.
    output->setColPos(i+1);

    // Get the output item (column or expression).
    QRElementPtr outputItem = output->getOutputItem()->getReferencedElement();
    const NAString& id = outputItem->getID();
    // Insert the ID of the output item (whatever it is) into the ID hash.
    outputByIDHash_.insert(&id, output);

    // OK, now lets check what type of output item it is.
    switch (outputItem->getElementType())
    {
      case ET_Column:
      {
	// If its an output column, add it to the output column by name hash.
	const QRColumnPtr col = outputItem->downCastToQRColumn();

        const QRElementPtr tableElem = getElementForID(col->getTableID());
        NABoolean hasLOJParent = tableElem->downCastToQRTable()->hasLOJParent();

        if (!isFromJoin(col) || hasLOJParent)
        {
	  // Compute the "ID Qualified" column name as the key.
	  const NAString* idQualifiedColName = 
	    calcIDQualifiedColumnName(col->getTableID(),  col->getColumnName(), heap);

	  // Insert into the hash table.
	  outputByColumnName_.insert(idQualifiedColName, output);
        }
        else
        {
	  // If its an equality set, insert all the participating columns
	  // as pointing to the same MV output column.
          const QRJoinPredPtr jp = getJoinPred(col);
	  const QRJoinPredPtr joinPredElement = jp->downCastToQRJoinPred();
          addEqualitySet(joinPredElement, FALSE, output, heap);
        }
	break;
      }

      case ET_JoinPred:
      {
        assertLogAndThrow(CAT_MATCHTST_MVDETAILS, LL_MVQR_FAIL,
                          (outputItem->getElementType() == ET_JoinPred), QRLogicException, 
			  "Unexpected JoinPred element.");

	// If its an equality set, insert all the participating columns
	// as pointing to the same MV output column.
	const QRJoinPredPtr joinPredElement = outputItem->downCastToQRJoinPred();
        addEqualitySet(joinPredElement, FALSE, output, heap);
	break;
      }

      case ET_Expr:
      {
	// This is an expression. Insert the expression text into the expression hash.
	const QRExprPtr expr = outputItem->downCastToQRExpr();
        const NAString& exprText = expr->getExprText(); 
	outputByExprText_.insert(&exprText, output);
        QRLogger::log(CAT_MATCHTST_MVDETAILS, LL_DEBUG,
          "Adding output expression: %s.", exprText.data());

	// Also map the expressions's input columns to it.
	// This call to getInitColumns() also inits the input list using the 
	// right heap.
	const ElementPtrList& inputs = expr->getInputColumns(heap);
	if (inputs.entries() > 0)
	{
	  for (CollIndex j=0; j<inputs.entries(); j++)
	  {
            QRElementPtr inputElem = inputs[j]->getReferencedElement();
            if (inputElem->getElementType() == ET_Column)
            {
	      QRColumnPtr inputCol = inputElem->downCastToQRColumn();

	      // Compute the "ID Qualified" column name as the key.
	      const NAString* idQualifiedColName = 
	        calcIDQualifiedColumnName(inputCol->getTableID(),  inputCol->getColumnName(), heap);

	      outputByInputColumns_.insert(idQualifiedColName, output);
	    }
            else
            {
              QRJoinPredPtr inputJoinPred = inputElem->downCastToQRJoinPred();
              addEqualitySet(inputJoinPred, TRUE, output, heap);
            }
          }
	}

        // Check if this is the COUNT(*) function.
        QRExplicitExprPtr rootExpr = expr->getExprRoot();
        if (rootExpr->getElementType() == ET_Function)
        {
          QRFunctionPtr func = rootExpr->downCastToQRFunction();
          if (func->getAggregateFunc() == QRFunction::AFT_COUNTSTAR)
          {
            // Found it, now remember it for later use.
            // If a COUNT(*) equivalent function has already been found 
            // (see below) - overwrite it.
            countStar_ = output;
          }
          else if (countStar_ == NULL &&
                   func->isCountStarEquivalent(heap) )
          {
            // Well, we didn't find a COUNT(*) yet, but we found a COUNT(a)
            // and the input column is NOT NOLL, we can use it as a COUNT(*) column.
            countStar_ = output;
          }
        }
      } // end of case ET_Expr
      break;
    }  // switch on element type
  }  // for on output list elements
}  //  MVDetails::initOutputs()
예제 #9
0
// ***************************************************************************
// ***************************************************************************
void JBBDetails::initRangePreds(CollHeap* heap)
{
  // Initialize the Range predicates.
  const QRRangePredListPtr rangePreds = jbbDesc_->getHub()->getRangePredList();
  if (rangePreds==NULL || rangePreds->entries() == 0)
  {
    hasNoRangePredicates_ = TRUE;
    return;
  }

  for (CollIndex k=0; k<rangePreds->entries(); k++)
  {
    const QRRangePredPtr rangePred = (*rangePreds)[k];
    const QRElementPtr rangeElem = rangePred->getRangeItem()->getReferencedElement();

    if (rangeElem->getElementType() == ET_Column && rangePred->isSingleValue())
    {
      constColumns_.insert(&rangeElem->getID());
    }

    // For query descriptors, only check for const columns.
    if (!isAnMV_)
      continue;

    if (rangeElem->getElementType() == ET_Column)
    {
      const QRColumnPtr rangeColumn = rangeElem->downCastToQRColumn();

      if (!descDetails_->isFromJoin(rangeColumn))
      {
        // This column is NOT part of a join predicate.
        BaseTableDetailsPtr rangeTable = getBaseTableByID(rangeColumn->getTableID());
        rangeTable->addRangePredicateOnColumn(rangePred, rangeColumn);
      }
      else
      {
        // This column IS part of a join predicate.
        // Insert the range pred for all the participating columns.
        const QRJoinPredPtr jp = descDetails_->getJoinPred(rangeColumn);
        const ElementPtrList& equalitySet = jp->getEqualityList();
        for (CollIndex i=0; i<equalitySet.entries(); i++)
        {
	  const QRElementPtr halfPred = equalitySet[i];

	  // Now lets look at the equality set members
	  // Ignore members that are not simple columns.
	  if (halfPred->getElementType() != ET_Column)
	    continue;

	  const QRColumnPtr eqSetColumn = halfPred->getReferencedElement()->downCastToQRColumn();
          BaseTableDetailsPtr rangeTable = getBaseTableByID(eqSetColumn->getTableID());
          rangeTable->addRangePredicateOnColumn(rangePred, eqSetColumn);
        }
      }
    }
    else if (rangeElem->getElementType() == ET_JoinPred)
    {
      assertLogAndThrow(CAT_MATCHTST_MVDETAILS, LL_MVQR_FAIL,
                        (rangeElem->getElementType() == ET_JoinPred), QRLogicException, 
			"Unexpected JoinPred element.");

      // If its an equality set, insert the range pred for all the participating columns.
      const QRJoinPredPtr joinPredElement = rangeElem->downCastToQRJoinPred();
      const ElementPtrList& equalitySet = joinPredElement->getEqualityList();
  
      for (CollIndex i=0; i<equalitySet.entries(); i++)
      {
	const QRElementPtr halfPred = equalitySet[i];

	// Now lets look at the equality set members
	// Ignore members that are not simple columns.
	if (halfPred->getElementType() != ET_Column)
	  continue;

	const QRColumnPtr eqSetColumn = halfPred->getReferencedElement()->downCastToQRColumn();
        BaseTableDetailsPtr rangeTable = getBaseTableByID(eqSetColumn->getTableID());
        rangeTable->addRangePredicateOnColumn(rangePred, eqSetColumn);
      }
    }
    else
    {
      // The range pred is on an expression. Insert it for all the expression's input columns.
      const QRExprPtr rangeExpr = rangeElem->downCastToQRExpr();

      if (rangeExpr->getExprRoot()->containsAnAggregate(heap))
      {
        hasHavingPredicates_ = TRUE;
      }

      // Verify we have a single input column
      // No input columns mean its a COUNT(*), which is OK too.
      const ElementPtrList& inputs = rangeExpr->getInputColumns(heap);
      assertLogAndThrow(CAT_MATCHTST_MVDETAILS, LL_MVQR_FAIL,
                        (inputs.entries() <= 1), QRLogicException, 
			"Range predicate expression must have a single input at most.");

      const NAString& predText = rangeExpr->getExprText();

      // Look it up in the hash table: do we already have a range pred with this text?
      RangePredPtrList* predList = getRangePredsOnExpression(predText);

      if (predList == NULL)
	{
	  // No, its the first one. Create a new list.
	  predList = new(heap) RangePredPtrList(heap);
	  // And insert it into the hash table.
	  rangePredicates_.insert(&predText, predList);
	}

      // Insert the predicate into the pred list.
      predList->insert(rangePred);
    }
  }
}  // JBBDetails::init()
LatticeIndexablePtr QRGroupLattice::elementToKey(const QRElementPtr      element, 
                                                 QRJoinSubGraphMapPtr    map,
						 DescriptorDetailsPtr    queryDetails, 
                                                 NABoolean               insertMode,
                                                 NABoolean               isRecursive)
{
  QRElementPtr elem = element->getReferencedElement();
  QRColumnPtr col = NULL;
  if (elem->getElementType() == ET_Column)
  {
    col = elem->downCastToQRColumn();
    if (queryDetails->isFromJoin(col) && !isRecursive)
    {
    // This groupby element is a join pred.
    // During insert, this loop inserts the first column.
    // During search, try each equality set element until we find one that 
    // appears in our array.
      const QRJoinPredPtr eqSet = queryDetails->getJoinPred(col);
      const ElementPtrList& equalityList = eqSet->getEqualityList();

      if (insertMode)
      {
        // Insert mode - pick the first column of the equality set.
        col = equalityList[0]->downCastToQRColumn();
      }
      else
      {
        // Search mode - pick the first equality set entry that is found in this LatticeIndex.
        for (CollIndex i=0; i<equalityList.entries(); i++)
        {
          QRElementPtr entry = equalityList[i]->getReferencedElement();
          // Call recursively for each join pred column.
          LatticeIndexablePtr entryKey = elementToKey(entry, map, queryDetails, insertMode, TRUE);
          if (entryKey == NULL)
            continue;

          if (lattice_->contains(entryKey))
          {
            // Found it in the lattice index.
            col = entry->downCastToQRColumn();
            break;
          }
        } // for ( )

        // If none of the entries was found - give up now.
        if (col == NULL)
          return NULL;

      }  // if insert mode
    }  // if JoinPred
  } // if Column

  NAString* key = NULL;
  if (col != NULL)
  {
    col = col->getReferencedElement()->downCastToQRColumn();
    const NAString& tableID = col->getTableID();
    Int32 Inx = map->getIndexForTable(tableID);
    if (Inx == -1)
    {
      assertLogAndThrow(CAT_GRP_LATTCE_INDX, LL_ERROR,
                        !insertMode, QRLogicException, 
		        "Table index not found in Insert mode (Inserting a multi-JBB MV?).");
      return NULL;
    }

    char buffer[4096+5];
    sprintf(buffer, "%d.%s", Inx, col->getColumnName().data() );

    key = new(heap_) NAString(buffer, heap_);
  }
  else
  {
    // This is an expression.
    // TBD We still do not handle expressions using columns from self-join tables.
    key = new(heap_) NAString(element->getSortName(), heap_);
  }

  // The reverseKeyHash should always use the most recent MV inserted.
  if (insertMode)
  {
    reverseKeyHash_.remove(key);
    reverseKeyHash_.insert(key, element);
  }
  return key;
}
//*****************************************************************************
// Add a table to the Self-Join analysis.
// This method, together with doneAddingTables(), implement a state machine
// with the following states:
//   ST_START:    The start state. No open segments.
//   ST_SINGLE:   Got the first table of a new segment, don't know segment type yet.
//   ST_UNIQUE:   Last two tables were different.
//   ST_SELFJOIN: Last two tables were the same.
//   ST_END:      We are done.
// The full state machine diagram is in the MVQR IS document.
//*****************************************************************************
void SelfJoinHandler::addTable(JoinGraphTablePtr table)
{
  const NAString& newTable = table->getName(); 
  // This is the current table index.
  UInt32 currentIndex = table->getTempNumber();
  if (currentIndex == -1)
  {
    // This subgraph generation was not yet started, 
    // This must be the initial self-join check.
    currentIndex = table->getOrdinalNumber();
  }

  // Is this table the same as the last one?
  // Skip the string comparison if the table is unique in the full join graph.
  NABoolean isDifferent = !table->isSelfJoinTable() || newTable != *lastTable_;

  // Which state in the state machine are we in?
  switch (state_)
  {
    case ST_START:
      segmentStart_ = currentIndex;
      state_ = ST_SINGLE;
      break;

    case ST_SINGLE:
      if (isDifferent)
        state_ = ST_UNIQUE;
      else
        state_ = ST_SELFJOIN;
      break;

    case ST_SELFJOIN:
      if (isDifferent)
      {
        // We have an open selfjoin segment and got a different table.
        // The selfjoin segment ends with the previous table, and the next
        // segment (which can be either type) starts with this table.
        addSegment(SelfJoinSegment::SELF_JOIN_SEGMENT);
        segmentStart_ = currentIndex;
        state_ = ST_SINGLE;
      }
      else
      {
        // do nothing.
      }
      break;

    case ST_UNIQUE:
      if (isDifferent)
      {
        // do nothing.
      }
      else
      {
        // OK, we have an open unique segment, and the new table is the same 
        // as the last one. So actually, the open unique segment ended with the
        // table before the prevous one, and the new self-join segment started 
        // with the previous table.
        segmentEnd_--;
        addSegment(SelfJoinSegment::UNIQUE_TABLE_SEGMENT);
        segmentStart_ = currentIndex-1;
        state_ = ST_SELFJOIN;
      }
      break;

    case ST_END:
      assertLogAndThrow(CAT_MVMEMO_JOINGRAPH, LL_MVQR_FAIL,
                        FALSE, QRLogicException, 
		        "Adding a table to SelfJoinHandler in ST_END state.");
      break;
  }

  lastTable_ = &table->getName();
  segmentEnd_ = currentIndex;
}