// --------------------------------------------------------------------
// Create a MultiJoin that is joining a subset of this MultiJoin children.
// Note: We assume JBBCs are already primed before calling this method.
// THis is a fine assumption at the analysis and post analysis stage.
// --------------------------------------------------------------------
MultiJoin* MultiJoin::createSubsetMultiJoin(const JBBSubset & subset, NABoolean reUseMJ) const
{
  MultiJoin * result = NULL;

  if(reUseMJ)
    result = subset.getSubsetMJ();

  if(result)
    return result;

  CMPASSERT (subset.getGB() == NULL_CA_ID); // no GBs for now
  CMPASSERT (subset.getJBBCs().entries() > 1);

  // everything here goes to statement heap
  CollHeap* outHeap = CmpCommon::statementHeap();

  result = new (outHeap) MultiJoin(subset, outHeap);
  result->setChildren(childrenMap_);

  result->setGroupAttr(new (outHeap) GroupAttributes());

  // Assign my Characteristic Inputs to the newly created subset multi-join.
  result->getGroupAttr()->addCharacteristicInputs
    (getGroupAttr()->getCharacteristicInputs());

  // The following call primes the result Characteristic Outputs.
  // It ensures that the inputs are minimal and outputs are maximal.
  result->primeGroupAttributes();
  // Now compute the GroupAnalysis fields
  result->primeGroupAnalysis();

  return result;
}
// 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
void
TriggerDB::clearAndDestroy()
{
  NAHashDictionaryIterator<TableOp,BeforeAndAfterTriggers> iter(*this);
  
  TableOp * key = NULL;
  BeforeAndAfterTriggers* value = NULL;
  // iterate over all entries and destroy them
#pragma warning (disable : 4018)   //warning elimination
  for (Int32 i=0; i < iter.entries(); i++) 
#pragma warning (default : 4018)   //warning elimination
  {
    iter.getNext(key, value);
    CMPASSERT(key != NULL);
    CMPASSERT(value != NULL);
    value->clearAndDestroy();
    delete value;
    value = NULL;
    delete key;
    key = NULL;
  }
  this->clear(FALSE);

  // now, TriggerDB should be empty
  CMPASSERT(this->entries() == 0);
}
// -----------------------------------------------------------------------
// Given a column list providing identifiers for columns of this table,
// this method returns a list of VEG expressions and/or base columns that
// show the equivalence of base columns with index columns.
// -----------------------------------------------------------------------
void TableDesc::getEquivVEGCols (const ValueIdList& columnList,
                                 ValueIdList &VEGColumnList) const
{
    for (CollIndex i=0; i < columnList.entries(); i++)
    {
        ItemExpr   *ie = columnList[i].getItemExpr();
        BaseColumn *bc = NULL;

        switch (ie->getOperatorType())
        {
        case ITM_BASECOLUMN:
            bc = (BaseColumn *) ie;
            break;
        case ITM_INDEXCOLUMN:
            bc = (BaseColumn *) ((IndexColumn *) ie)->getDefinition().
                 getItemExpr();
            CMPASSERT(bc->getOperatorType() == ITM_BASECOLUMN);

            break;
        default:
            ABORT("Invalid argument to TableDesc::getEquivVEGCols()\n");
        }

        CMPASSERT(bc->getTableDesc() == this);
        VEGColumnList.insert(getColumnVEGList()[bc->getColNumber()]);
    }
}
// ---------------------------------------------------------------
// Compute the Group Analysis for this multi join based on its
// children. Verify its consistent with its jbbSubset_
// ---------------------------------------------------------------
void MultiJoin::primeGroupAnalysis()
{
  // Analysis must have passed now that we have a MultiJoin. Otherwise
  // we must have cleanup problem.
  CMPASSERT (QueryAnalysis::Instance()->isAnalysisON());

  // no GB in multi-joins for now
  CMPASSERT (jbbSubset_.getGB() == NULL_CA_ID);

  GroupAnalysis* groupAnalysis = getGroupAnalysis();

  // recursively call the children appending their subtreeTables
  // and parentJBBViews
  JBBSubset* localView =
    new (groupAnalysis->outHeap()) JBBSubset(groupAnalysis->outHeap());
  CANodeIdSet allSubtreeTables;
  Int32 arity = getArity();
  for (Lng32 i = 0; i < arity; i++)
  {
    GroupAnalysis* childAnalysis = child(i).getPtr()->getGroupAnalysis();
	// use children parentViews to build this join local view
    localView->addSubset(*(childAnalysis->getParentJBBView()));
    allSubtreeTables += childAnalysis->getAllSubtreeTables();
  }
  groupAnalysis->setLocalJBBView(localView);
  groupAnalysis->setSubtreeTables(allSubtreeTables);

  // The computed localJBBView should be the same as the MultiJoin subset.
  CMPASSERT (jbbSubset_ == *localView);

  return;
}
static NABoolean ISPFetchPut(CmpInternalSP* storedProc, // to fetch data
                                    CmpISPDataObject* ispData) // to put data
{
  NABoolean bufferFull = FALSE;    
  // fetch until there is no more data
#pragma nowarn(770)   // warning elimination 
  CmpStoredProc::ExecStatus execStatus;
  short putStatus;
  while ( !bufferFull &&
    (execStatus=storedProc->fetch(*ispData)) == CmpStoredProc::MOREDATA )
  {
    if ( (putStatus = ispData->output()->AddARow()) == 1 )
      bufferFull = TRUE;
    CMPASSERT(putStatus != -1);
  }
  // close the ISP
  if ( !bufferFull )
  {
    storedProc->close(*ispData);
    if ( (putStatus = ispData->output()->AddEOR() ) == 1 )
      bufferFull = TRUE;
    CMPASSERT(putStatus != -1);
  }
  return bufferFull;
}
CmpStatement::ReturnStatus
CmpStatementISP::process (CmpMessageISPRequest& isp)
{
#pragma nowarn(262)   // warning elimination 
  ReturnStatus ret = CmpStatement_ERROR;

#ifdef _DEBUG
  if (getenv("DEBUG_SP2"))  DebugBreak();
#endif
  CmpCommon::context()->sqlSession()->setParentQid(isp.getParentQid()); 

  // Instantiate a CmpInternalSP
  CmpInternalSP* storedProc = new(heap_) CmpInternalSP(isp.procName(), context_);
  CMPASSERT(storedProc);
  setStoredProc(storedProc);
  reply_ = new(outHeap_) CmpMessageReplyISP(outHeap_, isp.id(), 0, 0, outHeap_);
  
  // prepare the data for execution
  // Make sure the pointer that ispData owns won't be deleted until ispData is
  // out of scope. Because of the performance reason, the pointers are copied, 
  // not the contents. 
  // The procedure flow is : 
  // .CmpContext contains CmpStatements
  // .one CmpStatementISP is created per CmpMessageISPRequest, there might be many CmpMessageGetNext to fetch more data, 
  // but they all share the same CmpStatementISP. This CmpStatementISP will be deleted when the execution of ISP is finished. 
  // .CmpStatementISP owns a CmpInternalSP, the interface to stored procedure execution. CmpInternalSP will be deleted in
  // CmpStatement::~CmpStatement
  // . CmpInternalSP owns a CmpISPDataObject which contains data passed from executor for ISP execution. this 
  // CmpISPDataObject will only be deleted when CmpInternalSP is out of scope.
  // .CmpISPDataObject is constructed from the CmpMessageISPRequest, for better performance
  // the data pointers are copied instead of duplicating the data, so it should own the
  // data member and only delete them when CmpISPDataObject is out of scope.

  // storedProc_ owns this ispData, it should be deleted in storedProc is out of scope.
  CmpISPDataObject* ispData = new(heap_) 
    CmpISPDataObject(&isp, storedProc, context_->heap(), context_);
  ISPReqId_ = isp.id();

  // open ISP
  short inputStatus = 0;
  NABoolean bufferFull = FALSE;
  for (; !bufferFull && (inputStatus = ispData->input()->next() ) == 0; )
  {
    if (storedProc->open(*ispData) == CmpStoredProc::SUCCESS)
      bufferFull = ISPFetchPut(storedProc, ispData);
    else
    {
      if ( ispData->output()->AddEOR() == 1 )
        bufferFull = TRUE;
    }
   }

  CMPASSERT(inputStatus != -1); // fail for retrieving input data

  // prepare to send the data back to executor
  ISPPrepareReply(ispData, reply_, bufferFull);

  return CmpStatement_SUCCESS;
}
//////////////////////////////////////////////////////////////////////////////
// Get all the ref constraints from this NATable, filter the ones that are to
// tables in this graph, and mark them on both tables. For example, use the
// RI on Orderes and Customers: O->C ( O is referencing C ). Because of the 
// semantics of the order of the tables in the join graph, in order for RI
// optimization to be utilized, C must appear in the graph solution AFTER O.
// The result is that C has an incoming bit for table O, and O has an 
// outgoing bit for table C.
// Other conditions that must be met for the RI to be usable:
// 1. C must have non-empty, insert only delta.
// 2. O must not be inner tables of left joins.
// 3. Each of the columns of the RI constraint must be covered by a predicate.
//    So if O(a,b) is referencing C(x,y) the join should use these two equal 
//    predicates: (O.a = C.x) AND (O.b = C.y).
// In this method, this table is O, and otherTable is C.
Lng32 MVJoinTable::markRiConstraints(BindWA *bindWA, MVInfo *mvInfo)
{
  LIST (MVUsedObjectInfo*)& usedObjects = mvInfo->getUsedObjectsList();
  if (usedObjects[tableIndex_]->isInnerTableOfLeftJoin())
    return 0;	// O must not be inner table of a left join.

  Lng32 howManyRIs=0;
  const AbstractRIConstraintList& refConstraints = 
    naTable_->getRefConstraints();

  for (CollIndex i=0; i<refConstraints.entries(); i++)
  {
    RefConstraint *const ref = (RefConstraint *const)(refConstraints[i]);
    CMPASSERT(ref->getOperatorType() == ITM_REF_CONSTRAINT);
    // Ignore self referencing RIs.
    if (ref->selfRef())
      continue;

    // Find the table the RI is referencing.
    const NAString& otherTableName = 
      ref->getOtherTableName().getQualifiedNameAsString();
    MVJoinTable *otherTable =
      mvInfo->getJoinGraph()->getTableObjectFor(&otherTableName);
    if (otherTable == NULL)
      continue;	 // The other table must be on the graph.

    if (otherTable->deltaType_ != INSERTONLY_DELTA)
      continue;  // C must be insert only.

    Lng32 otherTableIndex = otherTable->getTableIndex();

    // The RI must be covered by equal predicates on the same columns
    LIST(Lng32) myCols;
    LIST(Lng32) otherCols;
    ref->getMyKeyColumns(myCols);
    ref->getOtherTableKeyColumns(bindWA, otherCols);
    CMPASSERT(myCols.entries() == otherCols.entries());

    NABoolean matchingPredicatesExist=TRUE;
    for (CollIndex currentCol=0; currentCol<myCols.entries(); currentCol++)
    {
      if (!mvInfo->isEqPredicateBetween(naTable_->getTableName(),
					myCols[currentCol],
					ref->getOtherTableName(),
					otherCols[currentCol]))
	matchingPredicatesExist = FALSE;
    }
    if (!matchingPredicatesExist)
      continue;

    // OK - we found a qualifying RI that we can use for optimization.
    // Now mark the bits.
    markRiTo(otherTableIndex);
    otherTable->markRiFrom(getTableIndex());
    howManyRIs++;
  }
  return howManyRIs;
}	
void MultiJoin::synthLogPropWithMJReuse(NormWA * normWAPtr)
{
  // Check to see whether this GA has already been associated
  // with a logExpr for synthesis.  If so, no need to resynthesize
  // for this equivalent log. expression.
  if (getGroupAttr()->existsLogExprForSynthesis())
  {
    Join * joinExprForSynth = 
      (Join *) getGroupAttr()->getLogExprForSynthesis();
      
    if(joinExprForSynth->isJoinFromMJSynthLogProp())
      return;
  }

  NABoolean reUseMJ = TRUE;

  CMPASSERT ( (jbbSubset_.getGB() == NULL_CA_ID));

  const CANodeIdSet & jbbcs = jbbSubset_.getJBBCs();

  // Instead of always picking the first JBBC as the right child
  // pick the one with minimum JBBC connections. This will avoid
  // all unnecessary crossproducts

  CANodeId jbbcRight;

  jbbcRight = jbbcs.getJBBCwithMinConnectionsToThisJBBSubset();

  CANodeIdSet right(jbbcRight);
  CANodeIdSet left(jbbcs);
  left -= jbbcRight;

  Join* join = splitSubset(*(left.jbbcsToJBBSubset()),
                             *(right.jbbcsToJBBSubset()),
                           reUseMJ);

  //if the left is a MultiJoin, synthesize it using reUse
  //this has to be done before join->synthLogProp to avoid
  //calling MultiJoin::synthLogProp on the left MultiJoin
  //because that does not reUse
  if(left.entries() > 1)
  {
    RelExpr * leftRelExpr = join->child(0)->castToRelExpr();
    if(leftRelExpr &&
       leftRelExpr->getOperator() == REL_MULTI_JOIN)
      ((MultiJoin *) leftRelExpr)->synthLogPropWithMJReuse(normWAPtr);
  }

  join->synthLogProp(normWAPtr);

  join->setJoinFromMJSynthLogProp();

  getGroupAttr()->setLogExprForSynthesis(join);

  jbbSubset_.setSubsetMJ(this);

  CMPASSERT ( getGroupAttr()->getNumJoinedTables() >= getArity());
}
//////////////////////////////////////////////////////////////////////////////
// Determine the correct MvRefreshBuilder sub-class to handle the refresh job,
// construct, and return it.
// This method is called from two places in the code:
//   1) From Refresh::bindNode() with isPipelined = FALSE, for a non-pipelined
//      refresh job.
//   2) From PipelinedMavBuilder::buildRefreshTree() with isPipelined = TRUE,
//      for the lowest level of a pipelined refresh job.
//////////////////////////////////////////////////////////////////////////////
MvRefreshBuilder *Refresh::constructRefreshBuilder(BindWA       *bindWA,
        MVInfoForDML *mvInfo)
{
    CollHeap *heap = bindWA->wHeap();

    CorrName  mvCorrName(mvName_);
    mvCorrName.setSpecialType(ExtendedQualName::MV_TABLE);

    MvRefreshBuilder *treeBuilder = NULL;
    switch (refreshType_)
    {
    case RECOMPUTE:
    {
        treeBuilder = new(heap)
        MvRecomputeBuilder(mvCorrName, mvInfo, noDeleteOnRecompute_, bindWA);
        break;
    }

    case SINGLEDELTA:
        // Verify no Multidelta in SINGLEDELTA definition.
        CMPASSERT(deltaDefList_->entries() == 1);
    // Fall through to multidelta.

    case MULTIDELTA:
        CMPASSERT(mvInfo->getRefreshType() == COM_ON_REQUEST);

        switch (mvInfo->getMVType())
        {
        case COM_MAV:
        case COM_MAJV:
        {
            treeBuilder =
                constructMavSpecifichBuilder(bindWA, mvCorrName, mvInfo);
            break;
        }

        case COM_MJV:
        {
            treeBuilder =
                constructMjvSpecifichBuilder(bindWA, mvCorrName, mvInfo);
            break;
        }

        default:
            CMPASSERT(FALSE);
        }
        break;

    default:
        // Unknown refresh type
        CMPASSERT(FALSE);
    }

    CMPASSERT(treeBuilder!=NULL);
    return treeBuilder;
}  // Refresh::constructRefreshBuilder()
short CmpSeabaseDDL::buildViewColInfo(StmtDDLCreateView * createViewParseNode,
				       ElemDDLColDefArray *colDefArray)
{
  // Builds the list of ElemDDLColDef parse nodes from the list of
  // NAType parse nodes derived from the query expression parse sub-tree
  // and the list of ElemDDLColViewDef parse nodes from the parse tree.
  // This extra step is needed to invoke (reuse) global func CatBuildColumnList.

  CMPASSERT(createViewParseNode->getQueryExpression()->
             getOperatorType() EQU REL_ROOT);

  RelRoot * pQueryExpr = (RelRoot *)createViewParseNode->getQueryExpression();

  const ValueIdList &valIdList = pQueryExpr->compExpr();        // select-list
  CMPASSERT(valIdList.entries() > 0);

  CollIndex numOfCols(createViewParseNode->getViewColDefArray().entries());
  if (numOfCols NEQ valIdList.entries())
    {
      *CmpCommon::diags() << DgSqlCode(-1108) //CAT_NUM_OF_VIEW_COLS_NOT_MATCHED
			  << DgInt0(numOfCols)
			  << DgInt1(valIdList.entries());
      return -1;
  }

  const ElemDDLColViewDefArray &viewColDefArray = createViewParseNode->
    getViewColDefArray();
  for (CollIndex i = 0; i < numOfCols; i++)
    {
      // ANSI 11.19 SR8
      if (viewColDefArray[i]->getColumnName().isNull())
	{
	  *CmpCommon::diags() << DgSqlCode(-1099) //CAT_VIEW_COLUMN_UNNAMED
			      << DgInt0(i+1);
	  return -1;
	}
      
      colDefArray->insert(new (STMTHEAP) ElemDDLColDef
			  ( viewColDefArray[i]->getColumnName()
			    , (NAType *)&valIdList[i].getType()
			    , NULL    // default value (n/a for view def)
			    , NULL    // col attr list (not needed)
			    , STMTHEAP));
      
      if (viewColDefArray[i]->isHeadingSpecified())
	{
	  (*colDefArray)[i]->setIsHeadingSpecified(TRUE);
	  (*colDefArray)[i]->setHeading(viewColDefArray[i]->getHeading());
	}
    }
  
  return 0;
}
Beispiel #11
0
// LCOV_EXCL_START 
// Used for other RelExpr but not MultiJoin
void MultiJoin::synthEstLogProp(const EstLogPropSharedPtr& inputEstLogProp)
{
  CMPASSERT(inputEstLogProp->getNodeSet());

  Join * preferredJoin = jbbSubset_.getPreferredJoin();
  
  CMPASSERT(preferredJoin->isJoinFromMJSynthLogProp());
  
  EstLogPropSharedPtr myEstLogProp = 
    preferredJoin->getGroupAttr()->outputLogProp(inputEstLogProp);
  
  getGroupAttr()->addInputOutputLogProp (inputEstLogProp, myEstLogProp, NULL);
} // MultiJoin::synthEstLogProp
// Constructor that parses a 1-, 2-, or 3-part external (Ansi) name string
// and optionally applies default catalog and schema to it.
// Use this on a string gotten from a trusted source (Sql Catalog), because
// if it doesn't parse, the ctor cannot return an error so it CMPASSERTs.
//
// This code cloned for CorrName::applyPrototype below.
//
QualifiedName::QualifiedName(const NAString &ansiString, 
                             Int32 minNameParts,
                             CollHeap * h, 
                             BindWA *bindWA) :
     SchemaName(h),
     objectName_(h),
     objectNameSpace_(COM_UNKNOWN_NAME),
     flagbits_(0)
{
  if (HasMPLocPrefix(ansiString.data())) {
    ComMPLoc loc(ansiString);
    catalogName_ = loc.getSysDotVol();
    schemaName_ = loc.getSubvolName();
    objectName_ = loc.getFileName();
  }
  else
  {
    CmpContext *cmpContext = bindWA ? bindWA->currentCmpContext() : NULL;
    Parser parser(cmpContext);
    NAString ns("TABLE " + ansiString + ";", CmpCommon::statementHeap());
#pragma nowarn(1506)   // warning elimination 
    // save the current parserflags setting
    ULng32 savedParserFlags = Get_SqlParser_Flags (0xFFFFFFFF);
    StmtQuery *stmt = (StmtQuery *)parser.parseDML(ns, ns.length(), GetAnsiNameCharSet());
    // Restore parser flags settings 
    Set_SqlParser_Flags (savedParserFlags);
#pragma warn(1506)  // warning elimination 
    if (stmt) {
      CMPASSERT(stmt->getOperatorType() == STM_QUERY);
      *this = stmt->getQueryExpression()->getScanNode()->getTableName().getQualifiedNameObj();
      delete stmt;
    } else {
      // It is possible for the parser to get errors when parsing SQL/MP
      // stored text.  The caller is expected to check the contents of
      // this QualifiedName.
      //
      return;
    }
  }

  Int32 nameParts = 0;
  if (minNameParts > 0) {
    nameParts = getCatalogName() != "" ? 3 :
		getSchemaName()  != "" ? 2 :
		getObjectName()  != "" ? 1 : 0;
    CMPASSERT(nameParts >= minNameParts);
  }

  if (bindWA && nameParts < 3)
    applyDefaults(bindWA->getDefaultSchema());
} // end of QualifiedName::QualifiedName 
CmpStatement::ReturnStatus
CmpStatementISP::process (const CmpMessageISPGetNext& getNext)
{
  // This routine is to process the getNext request

  // 1. It first allocate the output data with size specified.
  // 2. it then fetched the remaining data from previous ISP execution.
  // 3. continue open/fetch/close for ISP execution.

  CmpCommon::context()->sqlSession()->setParentQid(getNext.getParentQid());
  CmpInternalSP& internalSP= *((CmpInternalSP*)storedProc_);
  CmpISPDataObject& ispData = *(CmpISPDataObject*)(internalSP.ispData());
  ispData.output()->allocateData(getNext.bufSize());

  NABoolean bufferFull = FALSE;
  short putStatus;
  if (ispData.output()->rowExist())
  {
    if ( (putStatus = ispData.output()->AddARow()) == 1 )
      bufferFull = TRUE;
    CMPASSERT(putStatus != -1);
    if ( !bufferFull)
      bufferFull = ISPFetchPut(&internalSP, &ispData);
  }

  else if (ispData.output()->EORExist())
  {
    if ( (putStatus = ispData.output()->AddEOR()) == 1 )
      bufferFull = TRUE;
    CMPASSERT(putStatus != -1);
  }

  // open ISP again for remaining input.
  short inputStatus = 0;
  for (; !bufferFull && (inputStatus = ispData.input()->next() ) == 0; )
  {
    if (internalSP.open(ispData) == CmpStoredProc::SUCCESS)
      bufferFull = ISPFetchPut(&internalSP, &ispData);
    else
    {
      if ( ispData.output()->AddEOR() == 1 )
        bufferFull = TRUE;
    }
  }

  CMPASSERT(inputStatus != -1); // fail for retrieving input data

  ISPPrepareReply(&ispData, reply_, bufferFull);
  return CmpStatement_SUCCESS;
}
Beispiel #14
0
CmpSPExecDataItemInput::CmpSPExecDataItemInput(ULng32 exprSize,
                                               void* expr,
                                               ULng32 dataSize,
                                               void* data,
                                               CmpContext* context)
                                               : CmpSPExecDataItem(exprSize, expr, 
                                               dataSize, data, context)
{
  CMPASSERT(ExSPPrepareInputBuffer(data_) == 0);
  CMPASSERT(ExSPPosition(data_) == 0);
  currentRow_ = 0;
  rowLength_  = 0;
  control_ = 0; 
}
//////////////////////////////////////////////////////////////////////////////
// This is the MDL version of the algorithm, used during a multi-delta refresh.
//   - RIs are used to determine the BEST order of the tables.
//   - We compute a solution from each and every table in the graph, and use
//     the number of usable RIs on the solution to determine which one wins.
void MVJoinGraph::findBestOrder()
{
  CMPASSERT(nofTables_>1);

#ifndef NDEBUG
    display();
#endif

  // start with one group of all tables.
  for (Lng32 i=0; i<nofTables_; i++)
    reorderGroupSet_.insert(i);
  notStartedSet_ = reorderGroupSet_;
  MVJoinGraphState state(nofTables_, nofRI_, reorderGroupSet_, heap_);

  NABoolean done = FALSE;
  while (!done && notStartedSet_.entries()>0)
  {
    // Choose a table to start from
    Lng32 firstTable = state.pickNextTable(*this, TRUE);
    CMPASSERT(firstTable != -1);
    state.nextTableIs(firstTable, FALSE);
    notStartedSet_.remove(firstTable);

    // Find a solution from this table.
    if (findSolutionFrom(state))
    {
      state.chooseBestSolution();
      if (state.getBestRoute().getScore() == nofRI_)
	done = TRUE;  // This is as good as it gets.
    }
    else
    {
      // If we get here the graph is not fully connected!
      CMPASSERT(FALSE);
    }

    if (!done)
      state.reset(reorderGroupSet_);
  } 

  CMPASSERT(!state.getBestRoute().isEmpty());

  // The state object will be gone when we exit this method, so save
  // the solution for later.
  theSolution_ = state.getBestRoute();

#ifndef NDEBUG
  theSolution_.display();
#endif
}
Int32 UniqueConstraint::getRefConstraints(BindWA *bindWA, 
					const ColSignature &updateCols,
					RefConstraintList &resultList)
{
  if (!constraintOverlapsUpdateCols(bindWA, updateCols))
    return 0;

  CollIndex constraintCnt = refConstraintsReferencingMe_.entries();
  
  //   Loop over FKs referencing this UC.
  //   Find one FK
  //   Tell it that it is the "other table" relative to me
  //   Set the FK's UC's column list pointer to my list of cols
  //   Append the FK to the result list
  for (CollIndex i = 0; i < constraintCnt; i++)
  {
      RefConstraint *rc = (RefConstraint *)findConstraint(bindWA, 
      					    *refConstraintsReferencingMe_[i]);
      if (!rc) return 0;

      // If Binder fails because of preivilege error, QI logic removes 
      // NATable marked for deletion and retries the same query. If the deleted 
      // NATable (T1) had RefConstraint on other table T2, then T2's NATable 
      // RefConstraint contains the address of T1 UniqueConstraint keyColumn_.
      // Since T1 has been removed from the cache, T2's 
      // RefConstraint->uniqueConstraintReferencedByMe_.keyColumns_ could contain 
      // invalid address. If this situation occurs, keyColumns_ will be reset 
      // instead of asserting.
      if ( bindWA->shouldLogAccessViolations() )
        rc->uniqueConstraintReferencedByMe_.resetAfterStatement();

	  rc->setOtherTableName();	     
	  CMPASSERT((rc->getOtherTableName() == rc->getDefiningTableName()) || (rc->getOtherTableName() == getDefiningTableName()));

      
    if (!rc->uniqueConstraintReferencedByMe_.keyColumns_)
		rc->uniqueConstraintReferencedByMe_.keyColumns_ = &keyColumns(); // assignment
    else 
	{
 		CMPASSERT(rc->uniqueConstraintReferencedByMe_.keyColumns_ == &keyColumns()); // equality operator
	}
    
	resultList.insert(rc);
  
  }

  return (Int32)constraintCnt;

} // UniqueConstraint::getRefConstraints
CharInfo::Collation CollationDB::insert(QualifiedName &qn,
					const SchemaName *defaultSchema,
					CollationInfo::CollationFlags flags)
{
  Int32 defaultMatchCount = 0;
  if (defaultSchema)
    defaultMatchCount = qn.applyDefaults(*defaultSchema);

  CMPASSERT(!qn.getCatalogName().isNull()); // fully qualified w/ all defaults

  size_t siz[CollationInfo::SIZEARRAY_SIZE];
  NAString nam(qn.getQualifiedNameAsAnsiString(siz));
  CMPASSERT(siz[0] == 3);		    // fully qualified w/ all defaults

  return insert(nam, siz, flags, defaultMatchCount);
}
Beispiel #18
0
CostScalar IndexDesc::getEstimatedRecordsPerBlock() const
{

  // We don't have "spanning rows" so the fractional part
  // is "garbage" and wasted space, therefore 
  // we take the floor of the following measure since
  // a fractional "rows per block" does not make sense:

  const CostScalar blockSize = getNAFileSet()->getBlockSize();

  const CostScalar recordLength = getNAFileSet()->getRecordLength();

  const CostScalar recordsPerBlock = (blockSize / recordLength).getFloor();

  if ((CmpCommon::getDefault(MODE_SEABASE) != DF_ON) ||
      (NOT getPrimaryTableDesc()->getNATable()->isHbaseTable()))
    {
      // A row can never be larger than a block:
      CMPASSERT( recordsPerBlock > csZero );
    }
  else
    {
      // For an hbase table, there is no concept of a SQ like blocksize and
      // the record size can be very large.
      // For now, make recordsPerBlock as 1 if it becomes 0 or less.
      // TBD TBD
      if (recordsPerBlock <= csZero)
	return (CostScalar)1;
    }

  return recordsPerBlock;  

}
UInt32 ValidateCollationList::insertIntoCDB(SchemaDB *sdb,
					      CollationDB *cdb,
					      const char *value,
					      NABoolean nsk)
{
  NABoolean savformatNSK = formatNSK_;
  formatNSK_ = nsk;

  lastCoInserted_ = CharInfo::UNKNOWN_COLLATION;
  cntCoParsed_ = 0;

  CMPASSERT(!cdb_ && !sdb_);	// our kludgy/dodgy passing mechanism...
  cdb_ = cdb;
  sdb_ = sdb;
  validate(value, NULL, 0, 0/*silent*/);
  cdb_ = NULL;
  sdb_ = NULL;

  formatNSK_ = savformatNSK;

  #ifndef NDEBUG
    if (getenv("NCHAR_DEBUG")) CollationDB::Display();
  #endif

  return cntCoParsed_;
}
Beispiel #20
0
short CmpSPExecDataItemInput::next() 
{
  short status = 0;
  status = ExSPGetInputRow(data_, control_, currentRow_, rowLength_);
  CMPASSERT(status != -1);
  return status;
}
CharInfo::Collation CollationDB::insert(ComMPLoc &loc,
					const ComMPLoc *defaultMPLoc,
					CollationInfo::CollationFlags flags)
{
  Int32 defaultMatchCount = 0;
  if (defaultMPLoc)
    defaultMatchCount = loc.applyDefaults(*defaultMPLoc);

  CMPASSERT(loc.isValid(ComMPLoc::FILE));

  size_t siz[CollationInfo::SIZEARRAY_SIZE];
  NAString nam(loc.getMPName(siz));
  CMPASSERT(siz[0] == 3 || siz[0] == 4);    // was defaulted out to $vol or \sys

  return insert(nam, siz, flags, defaultMatchCount);
}
/************************************************************************
method CompilerTrackingInfo::hCacheLookups

The current histogram cache lookups counter is calculated by
 subtracting the total from the last time we marked an interval
 (see CompilerTrackingInfo::resetInterval and resetMetadataCacheCounters
   for interval marking)

************************************************************************/
inline 
ULng32 
CompilerTrackingInfo::hCacheLookups()
{ 
  CMPASSERT(NULL!=CURRCONTEXT_HISTCACHE);
  return CURRCONTEXT_HISTCACHE->lookups() - hCacheLookups_; 
}
Beispiel #23
0
//CmpStoredProc::Status CmpInternalSP::open(CmpISPDataObject& data)
CmpStoredProc::ExecStatus CmpInternalSP::open(CmpISPDataObject& data)
{
  CMPASSERT(state_ == NONE);
  procFuncs_ = procFuncsLookupTable_[procName()];
  if (!procFuncsLookupTable_.ValidPFuncs(procFuncs_))
  {
    *(cmpContext()->diags()) << DgSqlCode(arkcmpErrorISPNotFound) 
      << DgString0(procName().data());
    return FAIL;       
  }

  initSP_ERROR_STRUCT();
  SP_STATUS spStatus =
      (*(procFuncs_.procFunc_))( SP_PROC_OPEN, 
				(SP_ROW_DATA)data.input(),
				CmpSPExtractFunc,
				(SP_ROW_DATA)data.output(), 
				CmpSPFormatFunc,
				(SP_KEY_VALUE)data.key(), 
				CmpSPKeyValueFunc,
				&procHandle_, 
				procFuncs_.spHandle_, 
				&spError_[0]);

  if (spStatus == SP_FAIL || spStatus == SP_SUCCESS_WARNING)
  {
    // Errors or warnings, go get them
    data.output()->MoveDiags(spError_, spStatus);
    if (spStatus == SP_FAIL)
      return FAIL;
  }
  state_ = PROCESS;
  return SUCCESS; 
}
Beispiel #24
0
NABoolean HHDFSTableStats::connectHDFS(const NAString &host, Int32 port)
{
  NABoolean result = TRUE;

  // establish connection to HDFS if needed
  if (fs_ == NULL ||
      currHdfsHost_ != host ||
      currHdfsPort_ != port)
    {
      if (fs_)
        {
          hdfsDisconnect(fs_);
          fs_ = NULL;
        }
      fs_ = hdfsConnect(host, port);
      
      if (fs_ == NULL)
        {
          CMPASSERT(fs_);
          // TBD:DIAGS
          result = FALSE;
        }
      currHdfsHost_ = host;
      currHdfsPort_ = port;
    }
  return result;
}
Beispiel #25
0
MultiJoin::MultiJoin(const JBBSubset & jbbSubset,
                     CollHeap *oHeap)
  : RelExpr(REL_MULTI_JOIN, NULL, NULL, oHeap)
  , jbbSubset_(jbbSubset)
  , childrenMap_(oHeap)
  , scheduledLSRs_(oHeap)
{
  // Need to initialize the childrenMap
  // This will set all children to NULL
  CANodeIdSet jbbcs = jbbSubset_.getJBBCs();
  Lng32 index = 0;

  for (CANodeId x= jbbcs.init();
       jbbcs.next(x);
       jbbcs.advance(x) )
  {
    JBBCExprGroupEntry* entry = new (oHeap)
      JBBCExprGroupEntry(x, (RelExpr*)NULL, oHeap);

    childrenMap_.insertAt(index, entry);
	index++;
  }

  lsrC_ = new (oHeap) LSRConfidence(oHeap);
#pragma warning (disable : 4018)  //warning elimination
  CMPASSERT (getArity() == jbbcs.entries());
#pragma warning (default : 4018)  //warning elimination
}
void PhysSequence::transformOlapFunctions(CollHeap *wHeap)
{

 
  for(ValueId valId = sequenceFunctions().init();
      sequenceFunctions().next(valId);
      sequenceFunctions().advance(valId)) 
  {
    
    ItemExpr * itmExpr = valId.getItemExpr();

    //NAType *itmType = itmExpr->getValueId().getType().newCopy(wHeap);

    if (itmExpr->isOlapFunction())
    {
      NAType *itmType = itmExpr->getValueId().getType().newCopy(wHeap);

      itmExpr = ((ItmSeqOlapFunction*)itmExpr)->transformOlapFunction(wHeap);

      CMPASSERT(itmExpr);
      if(itmExpr->getValueId() != valId)
      {
	itmExpr = new (wHeap) Cast(itmExpr, itmType);
	itmExpr->synthTypeAndValueId(TRUE);
	valId.replaceItemExpr(itmExpr);
	itmExpr->getValueId().changeType(itmType);//????
      }
    }
      itmExpr->transformOlapFunctions(wHeap);
  }
}
// First, always calls applyPrototype -- so may fill in one or more of 
// this's name parts -- hence this method is not const.
//
// Second, delegates to QualifiedName::extractAndDefaultNameParts 
// to fill in the return name parts --
// *EXCEPT* in the case that this CorrName contains a correlation name,
// masking a qualified name like "c.s.t", -- then we always return 0
// and the name parts are *not* filled in with defaults (they're meaningless).
//
Int32 CorrName::extractAndDefaultNameParts(BindWA *bindWA,
					 const SchemaName& defCatSch,
					 NAString& catName,	// OUT
					 NAString& schName,	// OUT
					 NAString& objName)	// OUT
{
  // For performance, avoid redoing work if we've done it before
  if (defaultMatchCount_ < 0) {		// initially -1
  
    applyPrototype(bindWA);
    // if (!nodeIsBound()) return -1;	// caller will check bindWA-errStatus()

    if (getCorrNameAsString() == "") {	// CorrName is "qual", not "corr"
      CMPASSERT(NOT isFabricated());  	// only corr names can be fabricated
      defaultMatchCount_ = getQualifiedNameObj().applyDefaults(defCatSch);
      // override schema, if default schema is "from" schema
      // increase count so columns like t.a will be valid
      if ( bindWA->overrideSchemaEnabled()
        && (bindWA->getOsFromSchema() == defCatSch.getSchemaName()) 
        && (bindWA->getOsToSchema() == getQualifiedNameObj().getSchemaName()) )
        defaultMatchCount_++;
    } else
      defaultMatchCount_ = 0;		// "corr" masks "qual", always return 0
  }

  catName = getQualifiedNameObj().getCatalogName();		// OUT
  schName = getQualifiedNameObj().getSchemaName();		// OUT
  objName = getQualifiedNameObj().getObjectName();		// OUT
  
  return defaultMatchCount_;
}
//
// --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;
}
const NAString SchemaName::getSchemaNameAsAnsiString() const
{
  QualifiedName q("X", getSchemaName(), getCatalogName());
  NAString result(q.getQualifiedNameAsAnsiString(), CmpCommon::statementHeap());
  CMPASSERT(result[result.length()-1] == 'X');
  result.remove(result.length()-2);		// remove the '.X'
  return result;
}
Beispiel #30
0
RelExpr *Refresh::buildCompleteRefreshTree(BindWA *bindWA, MVInfoForDML *mvInfo)
{
    CollHeap *heap = bindWA->wHeap();

    MvRefreshBuilder *firstBuilder = constructRefreshBuilder(bindWA, mvInfo);
    if (bindWA->errStatus())
        return NULL;

    RelExpr *topTree = firstBuilder->buildRefreshTree();

    // For recompute the refresh tree does not scan the log.
    // For MJV, it sometimes does, and when it does, it handles it itself.
    // So, for these types, the refresh tree is ready.
    if (refreshType_        == RECOMPUTE ||
            mvInfo->getMVType() == COM_MJV)
    {
        delete firstBuilder;
        return topTree;
    }

    MvBindContext *bindContext = new(heap) MvBindContext(heap);
    bindContext->setRefreshBuilder(firstBuilder);

    // In multi-delta, this is done inside the refresh tree.
    if (refreshType_ == SINGLEDELTA)
    {
        CMPASSERT(deltaDefList_->entries() == 1);
        DeltaDefinition *deltaDef = deltaDefList_->at(0);
        const QualifiedName *baseTableName = deltaDef->getTableName();

        RelExpr *scanLogBlock =
            firstBuilder->buildLogsScanningBlock(*baseTableName);
        if (bindWA->errStatus() || scanLogBlock == NULL)
            return NULL;

        bindContext->setReplacementFor(baseTableName, scanLogBlock);
    }

    if (pipelineClause_ != NULL)
        topTree = constructPipelinedBuilders(bindWA, bindContext, topTree);
    if (topTree == NULL)
        return NULL;

    // Make sure no data is projected out.
    RelRoot *rootNode = new(heap) RelRoot(topTree);
#ifndef NDEBUG
    if (!getenv("DEBUG_DCB"))
#endif
        rootNode->setEmptySelectList();

    rootNode->setMvBindContext(bindContext);
    RelExpr *topNode = rootNode;

    // Save the bind context for cleanup.
    bindContext_ = bindContext;

    return topNode;
}  // Refresh::buildCompleteRefreshTree()