예제 #1
0
Join * MultiJoin::getPreferredJoin()
{
  if(!getGroupAttr()->existsLogExprForSynthesis())
    synthLogProp();

  return (Join*) getGroupAttr()->getLogExprForSynthesis();
}
예제 #2
0
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());
}
예제 #3
0
// --------------------------------------------------------------------
// 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;
}
예제 #4
0
void MultiJoin::synthLogProp(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()) return;

  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()));

  join->synthLogProp(normWAPtr);

  getGroupAttr()->setLogExprForSynthesis(join);

  join->setJoinFromMJSynthLogProp();

  jbbSubset_.setSubsetMJ(this);
  
  CASortedList * synthLogPropPath =        
    new (CmpCommon::statementHeap()) 
    CASortedList(CmpCommon::statementHeap(), jbbcs.entries());
      
  synthLogPropPath->insert((*(left.jbbcsToJBBSubset()->getSynthLogPropPath())));
  synthLogPropPath->insert(right.getFirst());
  jbbSubset_.setSynthLogPropPath(synthLogPropPath);

  CMPASSERT ( getGroupAttr()->getNumJoinedTables() >= getArity());
}
예제 #5
0
CostScalar Scan::computeBaseSelectivity() const
{
    CostScalar scanCardWithoutHint = getGroupAttr()->outputLogProp((*GLOBAL_EMPTY_INPUT_LOGPROP))->\
                                     getColStats().getScanRowCountWithoutHint();

    double cardAfterLocalPreds = scanCardWithoutHint.getValue();
    double baseRowCount = getTableDesc()->tableColStats()[0]->getColStats()->getRowcount().getValue() ;

    // both the minimum and the base row count have to be minimum 1.
    // This is ensured in the called routines. So no need to check here.

    return cardAfterLocalPreds/baseRowCount;
}
예제 #6
0
// -----------------------------------------------------------------------
// MultJoin::recomputeOuterReferences()
// -----------------------------------------------------------------------
void MultiJoin::recomputeOuterReferences()
{
  // ---------------------------------------------------------------------
  // Delete all those input values that are no longer referenced on
  // this operator.
  // ---------------------------------------------------------------------
  if (NOT getGroupAttr()->getCharacteristicInputs().isEmpty())
  {
    ValueIdSet outerRefs = getGroupAttr()->getCharacteristicInputs();

    // Weed out those expressions not needed by my selectionPred and joinPred
    // xxx instead of taking this from getLocalJoinPreds, should I take it
    // from MultiJoin selectionPred??? refer to getLocalJoinPreds definition
    // and consider preds that referencing inputs!!!
    ValueIdSet exprSet = jbbSubset_.getLocalJoinPreds(); // from JbbSubsetAnalysis
    // Need to include LocalDependentPreds later when supported. Ok now for inner MultiJoins

    exprSet.weedOutUnreferenced(outerRefs);

    // Add back those expressiones needed by my children
    Int32 arity = getArity();

    // outputs produced by JBBCs in this MultiJoin
    ValueIdSet jbbcOutputs;
    for (Int32 i = 0; i < arity; i++)
    {
      outerRefs += child(i)->getGroupAttr()->getCharacteristicInputs();
      jbbcOutputs += child(i)->getGroupAttr()->getCharacteristicOutputs();
      // these inputs are provided by jbbcs in this MultiJoin
    }

    // account for TSJs i.e. values flowing from
    // one jbbc to another within this MultiJoin
    outerRefs -= jbbcOutputs;

    getGroupAttr()->setCharacteristicInputs(outerRefs);
  }
  return;
} // MultiJoin::recomputeOuterReferences()
예제 #7
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
예제 #8
0
// change literals of a cacheable query into ConstantParameters 
RelExpr* RelExpr::normalizeForCache(CacheWA& cwa, BindWA& bindWA)
{
  if (nodeIsNormalizedForCache()) { 
    return this; 
  }
  // replace descendants' literals into ConstantParameters
  normalizeKidsForCache(cwa, bindWA);
  if (cwa.getPhase() >= CmpMain::BIND) {
    if (selection_) {
      selection_ = selection_->normalizeForCache(cwa, bindWA);
    }
    else {
      selectionPred().normalizeForCache(cwa, bindWA);
    }
    // RelExpr::bindSelf has done this line during binding; but, we
    // must redo it to recognize any new constantparameters created 
    // by the above normalizeForCache call(s) as RelExpr inputs.
    getGroupAttr()->addCharacteristicInputs
      (bindWA.getCurrentScope()->getOuterRefs());
  }

  markAsNormalizedForCache();
  return this;
}
short ProbeCache::codeGen(Generator *generator)
{
  ExpGenerator * exp_gen = generator->getExpGenerator();
  Space * space = generator->getSpace();

  MapTable * last_map_table = generator->getLastMapTable();

  ex_cri_desc * given_desc
    = generator->getCriDesc(Generator::DOWN);

  ex_cri_desc * returned_desc
    = new(space) ex_cri_desc(given_desc->noTuples() + 1, space);

  // cri descriptor for work atp has 5 entries:
  // entry #0 for const
  // entry #1 for temp
  // entry #2 for hash value of probe input data in Probe Cache Manager
  // entry #3 for encoded probe input data in Probe Cache Manager
  // enrry #4 for inner table row data in this operator's cache buffer
  Int32 work_atp = 1;
  ex_cri_desc * work_cri_desc = new(space) ex_cri_desc(5, space);
  unsigned short hashValIdx          = 2; 
  unsigned short encodedProbeDataIdx = 3;
  unsigned short innerRowDataIdx     = 4;

    // generate code for child tree, and get its tdb and explain tuple.
  child(0)->codeGen(generator);
  ComTdb * child_tdb = (ComTdb *)(generator->getGenObj());
  ExplainTuple *childExplainTuple = generator->getExplainTuple();


  //////////////////////////////////////////////////////
  // Generate up to 4 runtime expressions.
  //////////////////////////////////////////////////////

  // Will use child's char. inputs (+ execution count) for the next
  // two runtime expressions.
  ValueIdList inputsToUse = child(0).getGroupAttr()->getCharacteristicInputs();
  
  inputsToUse.insert(generator->getOrAddStatementExecutionCount());

  // Expression #1 gets the hash value of the probe input data
  ValueIdList hvAsList;

  // Executor has hard-coded assumption that the result is long, 
  // so add a Cast node to convert result to a long.

  ItemExpr *probeHashAsIe = new (generator->wHeap())
    HashDistPartHash(inputsToUse.rebuildExprTree(ITM_ITEM_LIST));

  probeHashAsIe->bindNode(generator->getBindWA());

  NumericType &nTyp = (NumericType &)probeHashAsIe->getValueId().getType();
  GenAssert(nTyp.isSigned() == FALSE,
            "Unexpected signed HashDistPartHash.");

  GenAssert(probeHashAsIe->getValueId().getType().supportsSQLnullLogical()
            == FALSE, "Unexpected nullable HashDistPartHash.");

  ItemExpr *hvAsIe = new (generator->wHeap()) Cast(
       probeHashAsIe, 
       new (generator->wHeap()) 
            SQLInt(FALSE,   // false == unsigned.
                   FALSE    // false == not nullable.
                  ));

  hvAsIe->bindNode(generator->getBindWA());

  hvAsList.insert(hvAsIe->getValueId());

  ex_expr *hvExpr   = NULL;
  ULng32 hvLength;
  exp_gen->generateContiguousMoveExpr(
              hvAsList,
              0, // don't add convert node
              work_atp,
              hashValIdx,
              ExpTupleDesc::SQLARK_EXPLODED_FORMAT,
              hvLength,
              &hvExpr);

  GenAssert(hvLength == sizeof(Lng32),
            "Unexpected length of result of hash function.");

  // Expression #2 encodes the probe input data for storage in 
  // the ProbeCacheManager.

  ValueIdList encodeInputAsList;

  CollIndex inputListIndex;
  for (inputListIndex = 0; 
       inputListIndex < inputsToUse.entries(); 
       inputListIndex++) {   

    ItemExpr *inputIe = 
         (inputsToUse[inputListIndex].getValueDesc())->getItemExpr();

    if (inputIe->getValueId().getType().getVarLenHdrSize() > 0)
      {
        // This logic copied from Sort::codeGen().
        // Explode varchars by moving them to a fixed field
        // whose length is equal to the max length of varchar.
        // 5/8/98: add support for VARNCHAR

        const CharType& char_type =
          (CharType&)(inputIe->getValueId().getType());

	if (!CollationInfo::isSystemCollation(char_type.getCollation()))
	{
	  inputIe = new(generator->wHeap())
              Cast (inputIe,
                    (new(generator->wHeap())
                      SQLChar(
		          CharLenInfo(char_type.getStrCharLimit(), char_type.getDataStorageSize()),
                          char_type.supportsSQLnull(),
                          FALSE, FALSE, FALSE,
                          char_type.getCharSet(),
                          char_type.getCollation(),
                          char_type.getCoercibility()
                              )
                    )
                   );
	}
      }

    CompEncode * enode = new(generator->wHeap()) 
      CompEncode(inputIe, FALSE /* ascend/descend doesn't matter*/);

    enode->bindNode(generator->getBindWA());
    encodeInputAsList.insert(enode->getValueId());
  }

  ex_expr *encodeInputExpr = NULL;
  ULng32 encodedInputLength;
  exp_gen->generateContiguousMoveExpr(encodeInputAsList, 
                              0, //don't add conv nodes
                              work_atp, encodedProbeDataIdx,
                              ExpTupleDesc::SQLARK_EXPLODED_FORMAT,
                              encodedInputLength, &encodeInputExpr);


  // Expression #3 moves the inner table data into a buffer pool.  
  // This is also the tuple returned to ProbeCache's parent. 

  ex_expr * innerRecExpr = NULL;
  ValueIdList innerTableAsList = getGroupAttr()->getCharacteristicOutputs();

  //////////////////////////////////////////////////////
  // Describe the returned row and add the returned 
  // values to the map table.
  //////////////////////////////////////////////////////

  // determine internal format
  NABoolean useCif = FALSE;
  ExpTupleDesc::TupleDataFormat tupleFormat = generator->getInternalFormat();
  //tupleFormat = determineInternalFormat( innerTableAsList, this, useCif,generator);

  ULng32 innerRecLength = 0;
  ExpTupleDesc * innerRecTupleDesc = 0;
  MapTable * returnedMapTable = NULL;

  exp_gen->generateContiguousMoveExpr(innerTableAsList, 
                              -1, // do add conv nodes 
			      work_atp, innerRowDataIdx,
			      tupleFormat,
			      innerRecLength, &innerRecExpr,
			      &innerRecTupleDesc, ExpTupleDesc::SHORT_FORMAT,
                              &returnedMapTable);

  returned_desc->setTupleDescriptor(returned_desc->noTuples() - 1, 
        innerRecTupleDesc);

  // remove all appended map tables and return the returnedMapTable
  generator->removeAll(last_map_table);
  generator->appendAtEnd(returnedMapTable);
  // This returnedMapTable will contain the value ids that are being returned 
  // (the inner table probed).

  // Massage the atp and atp_index of the innerTableAsList.
  for (CollIndex i = 0; i < innerTableAsList.entries(); i++)
    {
      ValueId innerValId = innerTableAsList[i];

      Attributes *attrib =
	generator->getMapInfo(innerValId)->getAttr();

      // All reference to the returned values from this point on
      // will be at atp = 0, atp_index = last entry in returned desc.
      attrib->setAtp(0);
      attrib->setAtpIndex(returned_desc->noTuples() - 1);
    }

  // Expression #4 is a selection predicate, to be applied
  // before returning rows to the parent

  ex_expr * selectPred = NULL;

  if (!selectionPred().isEmpty())
    {
      ItemExpr * selPredTree =
        selectionPred().rebuildExprTree(ITM_AND,TRUE,TRUE);
      exp_gen->generateExpr(selPredTree->getValueId(),
                            ex_expr::exp_SCAN_PRED,
                            &selectPred);
    }

  //////////////////////////////////////////////////////
  // Prepare params for ComTdbProbeCache.
  //////////////////////////////////////////////////////

  queue_index pDownSize = (queue_index)getDefault(GEN_PROBE_CACHE_SIZE_DOWN);
  queue_index pUpSize   = (queue_index)getDefault(GEN_PROBE_CACHE_SIZE_UP);

  // Make sure that the ProbeCache queues can support the childs queues.
  if(pDownSize < child_tdb->getInitialQueueSizeDown()) {
    pDownSize = child_tdb->getInitialQueueSizeDown();
    pDownSize = MINOF(pDownSize, 32768);
  }
  if(pUpSize < child_tdb->getInitialQueueSizeUp()) {
    pUpSize = child_tdb->getInitialQueueSizeUp();
    pUpSize = MINOF(pUpSize, 32768);
  }

  ULng32 pcNumEntries = numCachedProbes_;
  
  // Number of entries in the probe cache cannot be less than 
  // max parent down queue size.  Before testing and adjusting the 
  // max queue size, it is necessary to make sure it is a power of
  // two, rounding up if necessary.  This is to match the logic in
  // ex_queue::resize.

  queue_index pdq2 = 1;
  queue_index bits = pDownSize;
  while (bits && pdq2 < pDownSize) {
    bits = bits  >> 1;
    pdq2 = pdq2 << 1;
  }
  if (pcNumEntries < pdq2)
    pcNumEntries = pdq2;

  numInnerTuples_ = getDefault(GEN_PROBE_CACHE_NUM_INNER);

  if (innerRecExpr == NULL)
    {
      // For semi-join and anti-semi-join, executor need not allocate
      // a buffer.  Set the tdb's buffer size to 0 to be consistent.
      numInnerTuples_ = 0;
    }
  else if (numInnerTuples_ == 0)
    {
      // Handle special value, 0, which tells code gen to 
      // decided on buffer size: i.e., large enough to accomodate
      // all parent up queue entries and all probe cache entries 
      // having a different inner table row.

      // As we did for the down queue, make sure the up queue size 
      // specified is a power of two.

      queue_index puq2 = 1;
      queue_index bits = pUpSize;
      while (bits && puq2 < pUpSize) {
        bits = bits  >> 1;
        puq2 = puq2 << 1;
      }
      numInnerTuples_ = puq2 + pcNumEntries;
    }
예제 #10
0
short RelInternalSP::codeGen(Generator * generator)
{
  Space * space          = generator->getSpace();
  ExpGenerator * exp_gen = generator->getExpGenerator();
  MapTable * last_map_table = generator->getLastMapTable();

  ex_expr * input_expr  = NULL;
  ex_expr * output_expr = NULL;

  ////////////////////////////////////////////////////////////////////////////
  //
  // Returned atp layout:
  //
  // |--------------------------------|
  // | input data  |  stored proc row |
  // | ( I tupps ) |  ( 1 tupp )      |
  // |--------------------------------|
  // <-- returned row to parent ---->
  //
  // input data:        the atp input to this node by its parent. 
  // stored proc row:   tupp where the row read from SP is moved.
  //
  ////////////////////////////////////////////////////////////////////////////

  ex_cri_desc * given_desc 
    = generator->getCriDesc(Generator::DOWN);

  ex_cri_desc * returned_desc 
    = new(space) ex_cri_desc(given_desc->noTuples() + 1, space);
 
  // cri descriptor for work atp has 3 entries:
  // -- the first two entries for consts and temps.
  // -- Entry 3(index #2) is where the input and output rows will be created.
  ex_cri_desc * work_cri_desc = new(space) ex_cri_desc(3, space);
  const Int32 work_atp = 1;
  const Int32 work_atp_index = 2;
 
  ExpTupleDesc * input_tuple_desc = NULL;
  ExpTupleDesc * output_tuple_desc = NULL;

  // Generate expression to create the input row that will be
  // given to the stored proc.
  // The input value is in sp->getProcAllParams() 
  // and has to be converted to sp->procType().
  // Generate Cast node to convert procParam to ProcType.
  // If procType is a varchar, explode it. This is done
  // so that values could be extracted correctly.
  ValueIdList procVIDList;
  for (CollIndex i = 0; i < procTypes().entries(); i++)
    {
      Cast * cn;

      if ((procTypes())[i].getType().getVarLenHdrSize() > 0) 
	{

// 5/9/98: add support for VARNCHAR
          const CharType& char_type =
                (CharType&)((procTypes())[i].getType());

	  // Explode varchars by moving them to a fixed field
	  // whose length is equal to the max length of varchar.
	  cn = new(generator->wHeap()) 
	    Cast ((getProcAllParamsVids())[i].getItemExpr(), 
		  (new(generator->wHeap())
		   SQLChar(generator->wHeap(),
		           CharLenInfo(char_type.getStrCharLimit(), char_type.getDataStorageSize()),
			   char_type.supportsSQLnull(),
			   FALSE, FALSE, FALSE,
			   char_type.getCharSet(),
			   char_type.getCollation(),
			   char_type.getCoercibility()
/*
                           (procTypes())[i].getType().getNominalSize(),
			   (procTypes())[i].getType().supportsSQLnull()
*/
                          )
                  )
                 );
	  
	  // Move the exploded field to a varchar field since 
	  // procType is varchar.
	  // Can optimize by adding an option to convert node to
	  // blankpad. TBD.
	  //
	  cn = new(generator->wHeap())
	    Cast(cn, &((procTypes())[i].getType()));
	} 
      else
 	cn = new(generator->wHeap()) Cast((getProcAllParamsVids())[i].getItemExpr(),
					  &((procTypes())[i].getType()));

      cn->bindNode(generator->getBindWA());
      procVIDList.insert(cn->getValueId());
    }

  ULng32 inputRowlen_ = 0;
  exp_gen->generateContiguousMoveExpr(procVIDList, -1, /*add conv nodes*/
				      work_atp, work_atp_index,
				      ExpTupleDesc::SQLARK_EXPLODED_FORMAT,
				      inputRowlen_,
				      &input_expr,
				      &input_tuple_desc,
				      ExpTupleDesc::LONG_FORMAT);

  // add all columns from this SP to the map table. 
  ULng32 tupleLength;
  exp_gen->processValIdList(getTableDesc()->getColumnList(),
			    ExpTupleDesc::SQLARK_EXPLODED_FORMAT,
			    tupleLength,
			    work_atp, 
			    work_atp_index);
 
  // Generate expression to move the output row returned by the
  // stored proc back to parent.
  ULng32 outputRowlen_ = 0;
  MapTable * returnedMapTable = 0;
  exp_gen->generateContiguousMoveExpr(getTableDesc()->getColumnList(),
				      -1 /*add conv nodes*/,
				      0, returned_desc->noTuples() - 1,
				      ExpTupleDesc::SQLARK_EXPLODED_FORMAT,
				      outputRowlen_,
				      &output_expr,
				      &output_tuple_desc,
				      ExpTupleDesc::LONG_FORMAT,
				      &returnedMapTable);
 
  // Now generate expressions used to extract or move input or
  // output values. See class ExSPInputOutput.
  ExSPInputOutput * extractInputExpr = NULL;
  ExSPInputOutput * moveOutputExpr = NULL;
  
  generateSPIOExpr(this, generator,
		   extractInputExpr,
		   moveOutputExpr);

  // done with expressions at this operator. Remove the appended map tables.
  generator->removeAll(last_map_table);

  // append the map table containing the returned columns
  generator->appendAtEnd(returnedMapTable);

  NAString procNameAsNAString(procName_);
  char * sp_name = 
    space->allocateAndCopyToAlignedSpace(procNameAsNAString,
					 procNameAsNAString.length(), 0);

  ExpGenerator *expGen = generator->getExpGenerator();

  // expression to conditionally return 0 or more rows.
  ex_expr *predExpr = NULL;

  // generate tuple selection expression, if present
  if(NOT selectionPred().isEmpty())
  {
    ItemExpr* pred = selectionPred().rebuildExprTree(ITM_AND,TRUE,TRUE);
    expGen->generateExpr(pred->getValueId(),ex_expr::exp_SCAN_PRED,&predExpr);
  }

  ComTdbStoredProc * sp_tdb = new(space)
    ComTdbStoredProc(sp_name, 
		     input_expr,
		     inputRowlen_,
		     output_expr,
		     outputRowlen_,
		     work_cri_desc,
		     work_atp_index,
		     given_desc,
		     returned_desc,
		     extractInputExpr,
		     moveOutputExpr,
		     2,
		     1024,
		     (Cardinality) getGroupAttr()->
		     getOutputLogPropList()[0]->
		     getResultCardinality().value(),
		     5,
		     64000,  //10240
		     predExpr,
		     (UInt16) arkcmpInfo_);
		      
  generator->initTdbFields(sp_tdb);

  if(!generator->explainDisabled()) 
    {
      generator->setExplainTuple(
				 addExplainInfo(sp_tdb, 0, 0, generator));
    }
  // Do not infer that any transaction started can 
  // be in READ ONLY mode if ISPs are present.
  generator->setNeedsReadWriteTransaction(TRUE);

  generator->setCriDesc(given_desc, Generator::DOWN);
  generator->setCriDesc(returned_desc, Generator::UP);
  generator->setGenObj(this, sp_tdb);

  // Some built-in functions require a TMF transaction
  // because they get their information from catman
  generator->setTransactionFlag(getRequiresTMFTransaction());

  return 0;
}
예제 #11
0
short Join::generateShape(CollHeap * c, char * buf, NAString * shapeStr)
{
  Space * space = (Space *)c;
  char mybuf[100];

  switch (getOperatorType())
    {
    case REL_NESTED_JOIN:
    case REL_LEFT_NESTED_JOIN:
    case REL_NESTED_SEMIJOIN:
    case REL_NESTED_ANTI_SEMIJOIN:
    case REL_NESTED_JOIN_FLOW:
      sprintf(mybuf, "nested_join(");
      break;

    case REL_MERGE_JOIN:
    case REL_LEFT_MERGE_JOIN:
    case REL_MERGE_SEMIJOIN:
    case REL_MERGE_ANTI_SEMIJOIN:
      sprintf(mybuf, "merge_join(");
      break;

    case REL_HASH_SEMIJOIN:
    case REL_HASH_ANTI_SEMIJOIN:
      sprintf(mybuf, "hash_join(");
      break;

    case REL_LEFT_HYBRID_HASH_JOIN:
    case REL_HYBRID_HASH_SEMIJOIN:
    case REL_HYBRID_HASH_ANTI_SEMIJOIN:
    case REL_FULL_HYBRID_HASH_JOIN:
      sprintf(mybuf, "hybrid_hash_join(");
      break;

    case REL_LEFT_ORDERED_HASH_JOIN:
    case REL_ORDERED_HASH_JOIN:
    case REL_ORDERED_HASH_SEMIJOIN:
    case REL_ORDERED_HASH_ANTI_SEMIJOIN:
      sprintf(mybuf, "ordered_hash_join(");
      break;

    case REL_HYBRID_HASH_JOIN:
      if (((HashJoin *)this)->isOrderedCrossProduct())
	sprintf(mybuf, "ordered_cross_product(");
      else
	sprintf(mybuf, "hybrid_hash_join(");
      break;

    default:
      sprintf(mybuf, "add_to_Join::generateShape(");
    }

  outputBuffer(space, buf, mybuf, shapeStr);

  child(0)->generateShape(space, buf, shapeStr);

  sprintf(mybuf, ",");
  outputBuffer(space, buf, mybuf, shapeStr);

  child(1)->generateShape(space, buf, shapeStr);

  // is it IndexJoin? if both children are scans and number of base tables is
  // 1, it is index join
  if (getGroupAttr()->getNumBaseTables() == 1)
  {
     NABoolean child0isScan = FALSE;
     NABoolean child1isScan = FALSE;
     RelExpr *lChild = child(0)->castToRelExpr();

     while (lChild->getArity() == 1)
     {
        lChild=lChild->child(0)->castToRelExpr();
     }

     switch( lChild->castToRelExpr()->getOperatorType())
     {
       case REL_SCAN:
       case REL_FILE_SCAN:
       case REL_HBASE_ACCESS:
       case REL_HDFS_SCAN:
	 child0isScan = TRUE;
     }

     RelExpr *rChild = child(1)->castToRelExpr();

     while (rChild->getArity() == 1)
     {
        rChild = rChild->child(0)->castToRelExpr();
     }
     switch (rChild->castToRelExpr()->getOperatorType())
     {
       case REL_SCAN:
       case REL_FILE_SCAN:
       case REL_HBASE_ACCESS:
       case REL_HDFS_SCAN:
         child1isScan = TRUE;
     }
     if (child0isScan && child1isScan)
     {
       sprintf(mybuf, ",INDEXJOIN)");
     }
     else
     {
       sprintf(mybuf, ")");
     }
  }
  else
  {
    sprintf(mybuf, ")");
  }

  outputBuffer(space, buf, mybuf, shapeStr);

  return 0;
}
// PhysUnPackRows::preCodeGen() -------------------------------------------
// Perform local query rewrites such as for the creation and
// population of intermediate tables, for accessing partitioned
// data. Rewrite the value expressions after minimizing the dataflow
// using the transitive closure of equality predicates.
//
// PhysUnPackRows::preCodeGen() - is basically the same as the RelExpr::
// preCodeGen() except that here we replace the VEG references in the
// unPackExpr() and packingFactor(), as well as the selectionPred().
//
// Parameters:
//
// Generator *generator
//    IN/OUT : A pointer to the generator object which contains the state,
//             and tools (e.g. expression generator) to generate code for
//             this node.
//
// ValueIdSet &externalInputs
//    IN    : The set of external Inputs available to this node.
//
//
RelExpr * PhysUnPackRows::preCodeGen(Generator * generator,
                                     const ValueIdSet & externalInputs,
                                     ValueIdSet &pulledNewInputs)
{
    if (nodeIsPreCodeGenned())
        return this;

    // Resolve the VEGReferences and VEGPredicates, if any, that appear
    // in the Characteristic Inputs, in terms of the externalInputs.
    //
    getGroupAttr()->resolveCharacteristicInputs(externalInputs);

    // My Characteristic Inputs become the external inputs for my children.
    //
    ValueIdSet childPulledInputs;

    child(0) = child(0)->preCodeGen(generator, externalInputs, pulledNewInputs);
    if (! child(0).getPtr())
        return NULL;

    // process additional input value ids the child wants
    getGroupAttr()->addCharacteristicInputs(childPulledInputs);
    pulledNewInputs += childPulledInputs;

    // The VEG expressions in the selection predicates and the characteristic
    // outputs can reference any expression that is either a potential output
    // or a characteristic input for this RelExpr. Supply these values for
    // rewriting the VEG expressions.
    //
    ValueIdSet availableValues;
    getInputValuesFromParentAndChildren(availableValues);

    // The unPackExpr() and packingFactor() expressions have access
    // to only the Input Values. These can come from the parent or be
    // the outputs of the child.
    //
    unPackExpr().
    replaceVEGExpressions(availableValues,
                          getGroupAttr()->getCharacteristicInputs());

    packingFactor().
    replaceVEGExpressions(availableValues,
                          getGroupAttr()->getCharacteristicInputs());

    if (rowwiseRowset())
    {
        if (rwrsInputSizeExpr())
            ((ItemExpr*)rwrsInputSizeExpr())->
            replaceVEGExpressions(availableValues,
                                  getGroupAttr()->getCharacteristicInputs());

        if (rwrsMaxInputRowlenExpr())
            ((ItemExpr*)rwrsMaxInputRowlenExpr())->
            replaceVEGExpressions(availableValues,
                                  getGroupAttr()->getCharacteristicInputs());

        if (rwrsBufferAddrExpr())
            ((ItemExpr*)rwrsBufferAddrExpr())->
            replaceVEGExpressions(availableValues,
                                  getGroupAttr()->getCharacteristicInputs());
    }

    // The selectionPred has access to only the output values generated by
    // UnPackRows and input values from the parent.
    //
    getInputAndPotentialOutputValues(availableValues);

    // Rewrite the selection predicates.
    //
    NABoolean replicatePredicates = TRUE;
    selectionPred().replaceVEGExpressions
    (availableValues,
     getGroupAttr()->getCharacteristicInputs(),
     FALSE, // no key predicates here
     0 /* no need for idempotence here */,
     replicatePredicates
    );

    // Replace VEG references in the outputs and remove redundant
    // outputs.
    //
    getGroupAttr()->resolveCharacteristicOutputs
    (availableValues,
     getGroupAttr()->getCharacteristicInputs());

    generator->oltOptInfo()->setMultipleRowsReturned(TRUE);

    markAsPreCodeGenned();

    return this;
} // PhysUnPackRows::preCodeGen
short
PhysUnPackRows::codeGen(Generator *generator)
{
    // Get handles on expression generator, map table, and heap allocator
    //
    ExpGenerator *expGen = generator->getExpGenerator();
    Space *space = generator->getSpace();

    // Allocate a new map table for this operation
    //
    MapTable *localMapTable = generator->appendAtEnd();

    // Generate the child and capture the task definition block and a description
    // of the reply composite row layout and the explain information.
    //
    child(0)->codeGen(generator);

    ComTdb *childTdb = (ComTdb*)(generator->getGenObj());

    ex_cri_desc *childCriDesc = generator->getCriDesc(Generator::UP);

    ExplainTuple *childExplainTuple = generator->getExplainTuple();

    // Make all of my child's outputs map to ATP 1. Since they are
    // not needed above, they will not be in the work ATP (0).
    // (Later, they will be removed from the map table)
    //
    localMapTable->setAllAtp(1);

    // Generate the given and returned composite row descriptors.
    // unPackRows adds a tupp (for the generated outputs) to the
    // row given by the parent. The workAtp will have the 2 more
    // tupps (1 for the generated outputs and another for the
    // indexValue) than the given.
    //
    ex_cri_desc *givenCriDesc = generator->getCriDesc(Generator::DOWN);

    ex_cri_desc *returnedCriDesc =
#pragma nowarn(1506)   // warning elimination 
        new(space) ex_cri_desc(givenCriDesc->noTuples() + 1, space);
#pragma warn(1506)  // warning elimination 

    ex_cri_desc *workCriDesc =
#pragma nowarn(1506)   // warning elimination 
        new(space) ex_cri_desc(givenCriDesc->noTuples() + 2, space);
#pragma warn(1506)  // warning elimination 


    // unPackCols is the next to the last Tp in Atp 0, the work ATP.
    // and the last Tp in the returned ATP.
    //
    const Int32 unPackColsAtpIndex = workCriDesc->noTuples() - 2;
    const Int32 unPackColsAtp = 0;

    // The length of the new tuple which will contain the columns
    // generated by unPackRows
    //
    ULng32 unPackColsTupleLen;

    // The Tuple Desc describing the tuple containing the new unPacked columns
    // It is generated when the expression is generated.
    //
    ExpTupleDesc *unPackColsTupleDesc = 0;

    // indexValue is the last Tp in Atp 0, the work ATP.
    //
    const Int32 indexValueAtpIndex = workCriDesc->noTuples() - 1;
    const Int32 indexValueAtp = 0;

    // The length of the work tuple which will contain the value
    // of the index.  This should always be sizeof(int).
    //
    ULng32 indexValueTupleLen = 0;

    // The Tuple Desc describing the tuple containing the new unPacked columns
    // It is generated when the expression is generated.
    //
    ExpTupleDesc *indexValueTupleDesc = 0;

    ValueIdList indexValueList;

    if (indexValue() != NULL_VALUE_ID)
    {
        indexValueList.insert(indexValue());

        expGen->processValIdList(indexValueList,
                                 ExpTupleDesc::SQLARK_EXPLODED_FORMAT,
                                 indexValueTupleLen,
                                 indexValueAtp,
                                 indexValueAtpIndex,
                                 &indexValueTupleDesc,
                                 ExpTupleDesc::SHORT_FORMAT);

        GenAssert(indexValueTupleLen == sizeof(Int32),
                  "UnPackRows::codeGen: Internal Error");
    }

    // If a packingFactor exists, generate a move expression for this.
    // It is assumed that the packingFactor expression evaluates to a
    // 4 byte integer.
    //
    ex_expr *packingFactorExpr = 0;
    ULng32 packingFactorTupleLen;

    if(packingFactor().entries() > 0) {
        expGen->generateContiguousMoveExpr(packingFactor(),
                                           -1,
                                           unPackColsAtp,
                                           unPackColsAtpIndex,
                                           ExpTupleDesc::SQLARK_EXPLODED_FORMAT,
                                           packingFactorTupleLen,
                                           &packingFactorExpr);

        GenAssert(packingFactorTupleLen == sizeof(Int32),
                  "UnPackRows::codeGen: Internal Error");
    }

    // Generate the UnPack expressions.
    //
    // characteristicOutputs() - refers to the list of expressions
    // to be move to another tuple.
    //
    // 0 - Do not add conv. nodes.
    //
    // unPackColsAtp - this expression will move data to the
    // unPackColsAtp (0) ATP.
    //
    // unPackColsAtpIndex - within the unPackColsAtp (0) ATP, the destination
    // for this move expression will be the unPackColsAtpIndex TP. This should
    // be the next to the last TP of the work ATP. (The indexValue will be in
    // the last position)
    //
    // SQLARK_EXPLODED_FORMAT - generate the move expression to construct
    // the destination tuple in EXPLODED FORMAT.
    //
    // unPackColsTupleLen - This is an output which will contain the length
    // of the destination Tuple.
    //
    // &unPackColsExpr - The address of the pointer to the expression
    // which will be generated.
    //
    // &unPackColsTupleDesc - The address of the tuple descriptor which is
    // generated.  This describes the destination tuple of the move expression.
    //
    // SHORT_FORMAT - generate the unPackColsTupleDesc in the SHORT FORMAT.
    //
    ex_expr *unPackColsExpr = 0;

    expGen->
    genGuardedContigMoveExpr(selectionPred(),
                             getGroupAttr()->getCharacteristicOutputs(),
                             0, // No Convert Nodes added
                             unPackColsAtp,
                             unPackColsAtpIndex,
                             ExpTupleDesc::SQLARK_EXPLODED_FORMAT,
                             unPackColsTupleLen,
                             &unPackColsExpr,
                             &unPackColsTupleDesc,
                             ExpTupleDesc::SHORT_FORMAT);

#pragma nowarn(1506)   // warning elimination 
    workCriDesc->setTupleDescriptor(unPackColsAtpIndex,
#pragma warn(1506)  // warning elimination 
                                    unPackColsTupleDesc);

#pragma nowarn(1506)   // warning elimination 
    returnedCriDesc->setTupleDescriptor(unPackColsAtpIndex,
#pragma warn(1506)  // warning elimination 
                                        unPackColsTupleDesc);


    // expressions for rowwise rowset implementation.
    ex_expr * rwrsInputSizeExpr = 0;
    ex_expr * rwrsMaxInputRowlenExpr = 0;
    ex_expr * rwrsBufferAddrExpr = 0;
    ULng32 rwrsInputSizeExprLen = 0;
    ULng32 rwrsMaxInputRowlenExprLen = 0;
    ULng32 rwrsBufferAddrExprLen = 0;

    const Int32 rwrsAtp = 1;
    const Int32 rwrsAtpIndex = workCriDesc->noTuples() - 2;
    ExpTupleDesc * rwrsTupleDesc = 0;
    ValueIdList rwrsVidList;
    if (rowwiseRowset())
    {
        rwrsVidList.insert(this->rwrsInputSizeExpr()->getValueId());
        expGen->generateContiguousMoveExpr(rwrsVidList,
                                           0 /*don't add conv nodes*/,
                                           rwrsAtp, rwrsAtpIndex,
                                           ExpTupleDesc::SQLARK_EXPLODED_FORMAT,
                                           rwrsInputSizeExprLen,
                                           &rwrsInputSizeExpr,
                                           &rwrsTupleDesc,ExpTupleDesc::SHORT_FORMAT);

        rwrsVidList.clear();
        rwrsVidList.insert(this->rwrsMaxInputRowlenExpr()->getValueId());
        expGen->generateContiguousMoveExpr(rwrsVidList,
                                           0 /*don't add conv nodes*/,
                                           rwrsAtp, rwrsAtpIndex,
                                           ExpTupleDesc::SQLARK_EXPLODED_FORMAT,
                                           rwrsMaxInputRowlenExprLen,
                                           &rwrsMaxInputRowlenExpr,
                                           &rwrsTupleDesc,ExpTupleDesc::SHORT_FORMAT);

        rwrsVidList.clear();
        rwrsVidList.insert(this->rwrsBufferAddrExpr()->getValueId());
        expGen->generateContiguousMoveExpr(rwrsVidList,
                                           0 /*don't add conv nodes*/,
                                           rwrsAtp, rwrsAtpIndex,
                                           ExpTupleDesc::SQLARK_EXPLODED_FORMAT,
                                           rwrsBufferAddrExprLen,
                                           &rwrsBufferAddrExpr,
                                           &rwrsTupleDesc,ExpTupleDesc::SHORT_FORMAT);

        expGen->assignAtpAndAtpIndex(rwrsOutputVids(),
                                     unPackColsAtp, unPackColsAtpIndex);
    }

    // Move the generated maptable entries, to the localMapTable,
    // so that all other entries can later be removed.
    //
    for(ValueId outputValId = getGroupAttr()->getCharacteristicOutputs().init();
            getGroupAttr()->getCharacteristicOutputs().next(outputValId);
            getGroupAttr()->getCharacteristicOutputs().advance(outputValId)) {

        generator->addMapInfoToThis(localMapTable, outputValId,
                                    generator->getMapInfo(outputValId)->
                                    getAttr());

        // Indicate that code was generated for this map table entry.
        //
        generator->getMapInfoFromThis(localMapTable, outputValId)->codeGenerated();
    }

    NABoolean tolerateNonFatalError = FALSE;

    if (isRowsetIterator() && (generator->getTolerateNonFatalError())) {
        tolerateNonFatalError = TRUE;
        setTolerateNonFatalError(RelExpr::NOT_ATOMIC_);
    }


    // Allocate the UnPack TDB
    //
    ComTdbUnPackRows *unPackTdb = NULL;

    if (rowwiseRowset())
    {
        unPackTdb =
            new (space) ComTdbUnPackRows(NULL, //childTdb,
                                         rwrsInputSizeExpr,
                                         rwrsMaxInputRowlenExpr,
                                         rwrsBufferAddrExpr,
                                         rwrsAtpIndex,
                                         givenCriDesc,
                                         returnedCriDesc,
                                         workCriDesc,
                                         16,
                                         1024,
                                         (Cardinality) getGroupAttr()->
                                         getOutputLogPropList()[0]->
                                         getResultCardinality().value(),
                                         2, 20000);
    }
    else
    {

        // Base the initial queue size on the est. cardinality.
        // UnPackRows does not do dyn queue resize, so passed in
        // queue size values represent initial (and final) queue
        // sizes (not max queue sizes).
        //
        queue_index upQueueSize =
            (queue_index)getGroupAttr()->getOutputLogPropList()[0]->getResultCardinality().value();

        // Make sure it is at least 1024.
        upQueueSize = (upQueueSize < 1024 ? 1024 : upQueueSize);

        // Make sure that it is not more the 64K.
        upQueueSize = (upQueueSize > 65536 ? 65536 : upQueueSize);

        unPackTdb =
            new (space) ComTdbUnPackRows(childTdb,
                                         packingFactorExpr,
                                         unPackColsExpr,
#pragma nowarn(1506)   // warning elimination 
                                         unPackColsTupleLen,
                                         unPackColsAtpIndex,
                                         indexValueAtpIndex,
                                         givenCriDesc,
                                         returnedCriDesc,
                                         workCriDesc,
                                         16,
                                         upQueueSize,
                                         (Cardinality) getGroupAttr()->
                                         getOutputLogPropList()[0]->
                                         getResultCardinality().value(),
                                         isRowsetIterator(),
                                         tolerateNonFatalError);
    }

#pragma warn(1506)  // warning elimination 
    generator->initTdbFields(unPackTdb);

    // Remove child's outputs from mapTable, They are not needed
    // above.
    //
    generator->removeAll(localMapTable);

    // Add the explain Information for this node to the EXPLAIN
    // Fragment.  Set the explainTuple pointer in the generator so
    // the parent of this node can get a handle on this explainTuple.
    //
    if(!generator->explainDisabled()) {
        generator->setExplainTuple(addExplainInfo(unPackTdb,
                                   childExplainTuple,
                                   0,
                                   generator));
    }

    // Restore the Cri Desc's and set the return object.
    //
    generator->setCriDesc(givenCriDesc, Generator::DOWN);
    generator->setCriDesc(returnedCriDesc, Generator::UP);
    generator->setGenObj(this, unPackTdb);


    return 0;
}
예제 #14
0
// PhysSequence::preCodeGen() -------------------------------------------
// Perform local query rewrites such as for the creation and
// population of intermediate tables, for accessing partitioned
// data. Rewrite the value expressions after minimizing the dataflow
// using the transitive closure of equality predicates.
//
// PhysSequence::preCodeGen() - is basically the same as the RelExpr::
// preCodeGen() except that here we replace the VEG references in the
// sortKey() list, as well as the selectionPred().
//
// Parameters:
//
// Generator *generator
//    IN/OUT : A pointer to the generator object which contains the state,
//             and tools (e.g. expression generator) to generate code for
//             this node.
//
// ValueIdSet &externalInputs
//    IN    : The set of external Inputs available to this node.
//
//
RelExpr * PhysSequence::preCodeGen(Generator * generator, 
                                   const ValueIdSet & externalInputs,
                                   ValueIdSet &pulledNewInputs)
{
  if (nodeIsPreCodeGenned())
    return this;

  // Resolve the VEGReferences and VEGPredicates, if any, that appear
  // in the Characteristic Inputs, in terms of the externalInputs.
  //
  getGroupAttr()->resolveCharacteristicInputs(externalInputs);

  // My Characteristic Inputs become the external inputs for my children.
  //
  ValueIdSet childPulledInputs;

  child(0) = child(0)->preCodeGen(generator, externalInputs, pulledNewInputs);
  if (! child(0).getPtr())
    return NULL;

  // process additional input value ids the child wants
  getGroupAttr()->addCharacteristicInputs(childPulledInputs);
  pulledNewInputs += childPulledInputs;

  // The VEG expressions in the selection predicates and the characteristic
  // outputs can reference any expression that is either a potential output
  // or a characteristic input for this RelExpr. Supply these values for
  // rewriting the VEG expressions.
  //
  ValueIdSet availableValues;
  getInputValuesFromParentAndChildren(availableValues);

  // The sequenceFunctions() have access to only the Input
  // Values. These can come from the parent or be the outputs of the
  // child.
  //
  sequenceFunctions().
    replaceVEGExpressions(availableValues,
                          getGroupAttr()->getCharacteristicInputs());

  sequencedColumns().
    replaceVEGExpressions(availableValues,
                          getGroupAttr()->getCharacteristicInputs());

  requiredOrder().
    replaceVEGExpressions(availableValues,
                          getGroupAttr()->getCharacteristicInputs());

  cancelExpr().
    replaceVEGExpressions(availableValues,
                          getGroupAttr()->getCharacteristicInputs());

  partition().
    replaceVEGExpressions(availableValues,
                          getGroupAttr()->getCharacteristicInputs());

  //checkPartitionChangeExpr().
   // replaceVEGExpressions(availableValues,
   //                       getGroupAttr()->getCharacteristicInputs());

  // The selectionPred has access to only the output values generated by
  // Sequence and input values from the parent.
  //
  getInputAndPotentialOutputValues(availableValues);

  // Rewrite the selection predicates.
  //
  NABoolean replicatePredicates = TRUE;
  selectionPred().replaceVEGExpressions
    (availableValues,
     getGroupAttr()->getCharacteristicInputs(),
     FALSE, // no key predicates here
     0 /* no need for idempotence here */,
     replicatePredicates
     ); 

  // Replace VEG references in the outputs and remove redundant
  // outputs.
  //
  getGroupAttr()->resolveCharacteristicOutputs
    (availableValues,
     getGroupAttr()->getCharacteristicInputs());

  
  addCancelExpr(generator->wHeap());

  ///addCheckPartitionChangeExpr(generator->wHeap());

  transformOlapFunctions(generator->wHeap());

  if ( getUnboundedFollowing() ) {
    // Count this Seq as a BMO and add its needed memory to the total needed
    generator->incrNumBMOs();
    
    if ((ActiveSchemaDB()->getDefaults()).
	getAsDouble(EXE_MEMORY_LIMIT_PER_CPU) > 0)
      generator->incrBMOsMemory(getEstimatedRunTimeMemoryUsage(TRUE));
  }
  else
    generator->incrNBMOsMemoryPerCPU(getEstimatedRunTimeMemoryUsage(TRUE));

  markAsPreCodeGenned();

  return this;
} // PhysSequence::preCodeGen
// PhysSample::preCodeGen() -------------------------------------------
// Perform local query rewrites such as for the creation and
// population of intermediate tables, for accessing partitioned
// data. Rewrite the value expressions after minimizing the dataflow
// using the transitive closure of equality predicates.
//
// PhysSample::preCodeGen() - is basically the same as the RelExpr::
// preCodeGen() except that here we replace the VEG references in the
// sortKey() list, as well as the selectionPred().
//
// Parameters:
//
// Generator *generator
//    IN/OUT : A pointer to the generator object which contains the state,
//             and tools (e.g. expression generator) to generate code for
//             this node.
//
// ValueIdSet &externalInputs
//    IN    : The set of external Inputs available to this node.
//
//
RelExpr * PhysSample::preCodeGen(Generator * generator, 
                                 const ValueIdSet & externalInputs,
				 ValueIdSet &pulledNewInputs)
{
  // Do nothing if this node has already been processed.
  //
  if (nodeIsPreCodeGenned())
    return this;

  // Resolve the VEGReferences and VEGPredicates, if any, that appear
  // in the Characteristic Inputs, in terms of the externalInputs.
  //
  getGroupAttr()->resolveCharacteristicInputs(externalInputs);

  // My Characteristics Inputs become the external inputs for my children.
  // preCodeGen my only child.
  //
  ValueIdSet childPulledInputs;
  child(0) = child(0)->preCodeGen(generator, externalInputs, pulledNewInputs);
  if(!child(0).getPtr())
    return NULL;

  // Process additional any additional inputs the child wants.
  //
  getGroupAttr()->addCharacteristicInputs(childPulledInputs);
  pulledNewInputs += childPulledInputs;

  // The sampledCols() only have access to the Input Values.
  // These can come from the parent or be the outputs of the child.
  // Compute the set of available values for the sampledCols() and use 
  // these to resolve any VEG references that the sampledCols() may need.
  //
  ValueIdSet availableValues;
  getInputValuesFromParentAndChildren(availableValues);

  sampledColumns().replaceVEGExpressions
    (availableValues,
     getGroupAttr()->getCharacteristicInputs());

  // Ditto, for the balance expression.
  //
  balanceExpr().replaceVEGExpressions
    (availableValues,
     getGroupAttr()->getCharacteristicInputs());

  requiredOrder().
    replaceVEGExpressions(availableValues,
                          getGroupAttr()->getCharacteristicInputs());

  // The selectionPred has access to only the output values generated by
  // Sequence and input values from the parent. Compute the set of available
  // values for the selectionPred and resolve any VEG references 
  // that the selection predicates may need.
  //
  getInputAndPotentialOutputValues(availableValues);

  NABoolean replicatePredicates = TRUE;
  selectionPred().replaceVEGExpressions
    (availableValues,
     getGroupAttr()->getCharacteristicInputs(),
     FALSE, // no key predicates here
     0 /* no need for idempotence here */,
     replicatePredicates
     ); 

  // Resolve VEG references in the outputs and remove redundant
  // outputs.
  //
  getGroupAttr()->resolveCharacteristicOutputs
    (availableValues,
     getGroupAttr()->getCharacteristicInputs());

  // Mark this node as done and return.
  //
  markAsPreCodeGenned();

  return this;
} // PhysSample::preCodeGen
예제 #16
0
Join* MultiJoin::splitSubset(const JBBSubset & leftSet,
                             const JBBSubset & rightSet,
                             NABoolean reUseMJ) const
{
  // At this point assert that none of the subsets has a group by member
  CMPASSERT ( (jbbSubset_.getGB() == NULL_CA_ID) &&
              (leftSet.getGB() == NULL_CA_ID) &&
              (rightSet.getGB() == NULL_CA_ID) );
#ifndef NDEBUG
  // assert that left + right == subSet_
  // and left intersect right = phi

  CANodeIdSet unionSet(leftSet.getJBBCs());
  CANodeIdSet intersectSet(leftSet.getJBBCs());

  unionSet += rightSet.getJBBCs();
  intersectSet.intersectSet(rightSet.getJBBCs());

  CMPASSERT ( (unionSet == jbbSubset_.getJBBCs()) &&
              (intersectSet.entries() == 0 ));
#endif

  // Note: Joins including left, semi, anti semi are only created when
  // a single jbbc connected via one of them is split as a single right
  // child. InnerNonSemi joins can be created for any split i.e. any
  // number of jbbcs on the left and the right of the join, but special
  // joins (i.e. left, semi and anti semi joins) are only created when
  // there is a single right child i.e. the rightSet contains only one
  // jbbc that is connected via a special join. This is enforced as follows
  //
  // * The leftSet should be legal: This means that for every jbbc in the
  //   leftSet any predecessor jbbcs should be present in the leftSet.
  // * The rightSet is either a single jbbc or if the rightSet has more
  //   than one jbbc then it should be legal, note that a jbbc connected
  //   via a special join is not a legal set by itself but we allow
  //   creation of special joins assuming the predecessors are present
  //   in the leftSet.
  //
  // An implicit assumption here is that 'this' MultiJoin is legal, which
  // is fair since apart from the top level multijoin, rest of the multijoins
  // are produced by splitting the top level multijoin. This method should
  // not produce illegal multijoins, since we check both leftSet and rightSet
  // for legality. Only time we don't check for legality is when the rightChild
  // is a single jbbc, and a single jbbc does not result in a multijoin.

  if(!leftSet.legal())
    return NULL;

  if((rightSet.getJBBCs().entries() > 1) && (!rightSet.legal()))
    return NULL;

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

  RelExpr* child0 = generateSubsetExpr(leftSet, reUseMJ);
  RelExpr* child1 = generateSubsetExpr(rightSet, reUseMJ);

  // Flag to remember to pass on the derivedFromRoutineJoin flag if needed.
  NABoolean derivedFromRoutineJoin(FALSE);

  // now form a JoinExpr with these left and right children.
  Join * result = NULL;

  // if the rightSet is a single jbbc, then it could be connected via
  // a special join. In such a case we have to create the appropriate
  // join operator
  if(rightSet.getJBBCs().entries() == 1){

    JBBC * rightChild = rightSet.getJBBCs().getFirst().getNodeAnalysis()
                         ->getJBBC();

    Join * rightChildParentJoin = rightChild->getOriginalParentJoin();

    // If rightChildParentJoin is NULL, then the child is the left
    // child of the left most join and is considered to be connected
    // via a InnerNonSemi join.
    if(rightChildParentJoin)
    {
      if(rightChildParentJoin->derivedFromRoutineJoin())
        derivedFromRoutineJoin = TRUE;

      if(rightChildParentJoin->isSemiJoin())
        result = new (outHeap) Join(child0, child1, REL_SEMIJOIN, NULL);

      if(rightChildParentJoin->isAntiSemiJoin())
        result = new (outHeap) Join(child0, child1, REL_ANTI_SEMIJOIN, NULL);

      if(rightChildParentJoin->isLeftJoin())
      {

        // left joins can have filter preds, i.e. predicates that
        // are applied as filters after applying the join predicate.
        // We need to set them here.
        result = new (outHeap) Join(child0, child1, REL_LEFT_JOIN, NULL);
        result->setSelectionPredicates(rightChild->getLeftJoinFilterPreds());
      }
      
      if(rightChildParentJoin->isRoutineJoin())
      {
        derivedFromRoutineJoin = TRUE;
        result = new (outHeap) Join(child0, child1, REL_ROUTINE_JOIN, NULL);
        ValueIdSet routineJoinFilterPreds = rightChild->getRoutineJoinFilterPreds();
        ValueIdSet predsToAddToRoutineJoin;
          
        // add covered filter preds
        for (ValueId filterPred= routineJoinFilterPreds.init();
             routineJoinFilterPreds.next(filterPred);
             routineJoinFilterPreds.advance(filterPred) )
        {
          if(jbbSubset_.coversExpr(filterPred))
            predsToAddToRoutineJoin += filterPred;
        } 
 
        result->setSelectionPredicates(predsToAddToRoutineJoin);
      }

      if(result)
      {
        // set the join predicate for special joins, note predicates
        // for regular InnerNonSemi joins are set as selection predicates
        // in the join relexpr.
        result->setJoinPred(rightChild->getPredsWithPredecessors());

        result->nullInstantiatedOutput().insert(rightChild->
                                                  nullInstantiatedOutput());
      }
    }
  }

  // The join to be created is a regular InnerNonSemi join
  if (!result)
    result = new (outHeap) Join(child0, child1, REL_JOIN, NULL);

  // Make sure we carry the derivedFromRoutineJoin flag with us 
  if (derivedFromRoutineJoin)
    result->setDerivedFromRoutineJoin();

  // Share my groupAttr with result
  result->setGroupAttr(getGroupAttr());

  // get inner join predicates
  ValueIdSet selPreds = rightSet.joinPredsWithOther(leftSet);

  // get left join filter preds if any
  selPreds += result->getSelectionPredicates();

  result->setSelectionPredicates(selPreds);

  result->findEquiJoinPredicates();

  // May be I could save a little if i pushdown only to the child(ren)
  // that are not already JBBCs, i.e. multijoins
  result->pushdownCoveredExpr
    (result->getGroupAttr()->getCharacteristicOutputs(),
     result->getGroupAttr()->getCharacteristicInputs(),
     result->selectionPred());

  // We used CutOp as children, to avoid pushing predicates to JBBCs.
  // Now put the actual expression back in case the child is a JBBCs
  if(leftSet.getJBBCs().entries() ==  1)
    result->setChild(0, getJBBCRelExpr(leftSet.getJBBCs().getFirst()));

  // We used CutOp as children, to avoid pushing predicates to JBBCs.
  // Now put the actual expression back in case the child is a JBBCs
  if(rightSet.getJBBCs().entries() ==  1)
    result->setChild(1, getJBBCRelExpr(rightSet.getJBBCs().getFirst()));

  // Temp fixup. We need to take the selectionPred out of MultiJoin
  // for now to prevent that pushed expr from being there. selectionPred
  // is not being used now in MultiJoin xxx.
  if (leftSet.getJBBCs().entries() > 1)
    result->child(0)->selectionPred().clear();
  if (rightSet.getJBBCs().entries() > 1)
    result->child(1)->selectionPred().clear();

  return result;
}