Пример #1
0
// ExSampleTcb constructor
//
// 1. Allocate buffer pool.
// 2. Allocate parent queues and initialize private state.
// 3. Fixup expressions.
//
ExSampleTcb::ExSampleTcb
(const ExSampleTdb &  myTdb, 
 const ex_tcb &    child_tcb,
 ex_globals * glob
 ) : 
  ex_tcb(myTdb, 1, glob)
{
  Space * space = (glob ? glob->getSpace() : 0);
  CollHeap * heap = (glob ? glob->getDefaultHeap() : 0);
  
  childTcb_ = &child_tcb;

   // get the queue that child use to communicate with me
  qchild_  = child_tcb.getParentQueue(); 

  // Allocate the queue to communicate with parent
  qparent_.down = new(space) ex_queue(ex_queue::DOWN_QUEUE,
							myTdb.queueSizeDown_,
				     myTdb.criDescDown_,
				     space);
  
  // Allocate the private state in each entry of the down queue
  ExSamplePrivateState *p 
    = new(space) ExSamplePrivateState(this);
  qparent_.down->allocatePstate(p, this);
  delete p;


  qparent_.up = new(space) ex_queue(ex_queue::UP_QUEUE,
				    myTdb.queueSizeUp_,
				    myTdb.criDescUp_,
				    space);

  // Intialized processedInputs_ to the next request to process
  processedInputs_ = qparent_.down->getTailIndex();

  // Fixup the sample expression
  //
  if (initExpr())
    initExpr()->fixup(0, getExpressionMode(), this, space, heap, FALSE, glob);

  if (balanceExpr())
    balanceExpr()->fixup(0, getExpressionMode(), this, space, heap, FALSE, glob);

  if (postPred())
    postPred()->fixup(0, getExpressionMode(), this, space, heap, FALSE, glob);
}
// 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
Пример #3
0
// work - doit...
//
//
short ExSampleTcb::work()
{
  // If there are no parent requests on the queue, then there cannot
  // be anything to do here.
  //
  if (qparent_.down->isEmpty())
    return WORK_OK;

  ex_queue_entry * pentry_down;
  ExSamplePrivateState * pstate;
  ex_queue::down_request request;

  // Take any new parent requests and pass them on to the child as long
  // as the child's queue is not full. processedInputs_ maintains the 
  // Queue index of the last request that was passed on.
  // 
  for(queue_index tail = qparent_.down->getTailIndex(); 
      (processedInputs_ != tail) && (!qchild_.down->isFull());
      processedInputs_++ )
    {
      pentry_down = qparent_.down->getQueueEntry(processedInputs_);
      pstate = (ExSamplePrivateState*) pentry_down->pstate;
      request = pentry_down->downState.request;

      // If the request has already been cancelled don't pass it to the
      // child. Instead, just mark the request as done. This will trigger
      // a EOD reply when this request gets worked on.
      //
      if (request == ex_queue::GET_NOMORE)
        {
          pstate->step_ = ExSamp_DONE;
        }
      else
        {
          pstate->step_ = ExSamp_PREWORK;

	  // Pass the request to the child
	  //
          ex_queue_entry * centry = qchild_.down->getTailEntry();
          centry->downState.request = ex_queue::GET_ALL;
          centry->downState.requestValue = 11;
          centry->downState.parentIndex = processedInputs_;
          centry->passAtp(pentry_down);
          qchild_.down->insert();

          // Copy the input atp to the work atp for this request
	  //
          pstate->workAtp_->copyAtp(pentry_down->getAtp());
        }
    } // end for processedInputs_

  pentry_down = qparent_.down->getHeadEntry();
  pstate = (ExSamplePrivateState*) pentry_down->pstate;
  request = pentry_down->downState.request;

  // If the request has not been worked on yet, then
  // initialize the presistent expression variable data and
  // switch to the WORKING state.
  //
  if(pstate->step_ == ExSamp_PREWORK)
    {
      pstate->step_ = ExSamp_WORKING;
      if(balanceExpr()) balanceExpr()->initializePersistentData();
    }
  
  ExOperStats *statsEntry = getStatsEntry(); 
  // Take any child replies and process them. Return the processed
  // rows as long the parent queue has room.
  //
  while (1)
    {
      // If we have satisfied the parent request (or it was cancelled),
      // then stop processing rows, cancel any outstanding child
      // requests, and set this request to the CANCELLED state.
      //
      if((pstate->step_ == ExSamp_WORKING) ||
	 (pstate->step_ == ExSamp_RETURNINGROWS))
	{
	  if ((request == ex_queue::GET_NOMORE) ||
	      ((request == ex_queue::GET_N) &&
	       (pentry_down->downState.requestValue 
		<= (Lng32)pstate->matchCount_)))
	    {
	      qchild_.down->cancelRequestWithParentIndex
		(qparent_.down->getHeadIndex());
	      pstate->step_ = ExSamp_CANCELLED;
	    }
	}

      switch (pstate->step_)
	{
	  // ExSamp_CANCELLED
	  //
	  // Transition to this state from ...
	  // 1. ExSamp_Error - After the error has been processed.
	  // 2. ExSamp_Working - If enough rows have been returned.
	  // 3. ExSamp_Working - If the request was cancelled.
	  //
	  // Remain in this state until ..
	  // 1. All rows from the child including EOD are consumed
	  //
	  // Transition from this state to ...
	  // 1. ExSamp_DONE - In all cases.
	  //
	case ExSamp_CANCELLED:
	  {
	    // There are no extra rows to process from the child yet,
	    // so try again later.
	    //
	    if (qchild_.up->isEmpty())
	      {
		return WORK_OK;
	      }

	    ex_queue_entry * centry = qchild_.up->getHeadEntry();
	    ex_queue::up_status child_status = centry->upState.status;

	    // If this is the EOD, transition to the ExSamp_DONE state.
	    //
	    if (child_status == ex_queue::Q_NO_DATA)
		  pstate->step_ = ExSamp_DONE;

	    // Discard the child row.
	    qchild_.up->removeHead();	    
	    break;
	  }

	// ExSamp_ERROR
	//
	// Transition to this state from ...
	// 1. ExSamp_WORKING - a child reply with the type SQLERROR.
	//
	// Remain in this state until ..
	// 1. The error row has been returned to the parent.
	//
	// Transition from this state to ...
	// 1. ExSamp_CANCELLED - In all cases.
	//
	case ExSamp_ERROR:
	  {
            // If there is no room in the parent queue for the reply,
	    // try again later.
	    //
	    if (qparent_.up->isFull())
	      return WORK_OK;

	    ex_queue_entry *pentry_up = qparent_.up->getTailEntry();
	    ex_queue_entry * centry = qchild_.up->getHeadEntry();

	    // Cancel the child request - there must be a child request in
	    // progress to get to the ExSamp_ERROR state.
	    //
	    qchild_.down->cancelRequestWithParentIndex
	      (qparent_.down->getHeadIndex());

	    // Construct and return the error row.
	    //
            pentry_up->copyAtp(centry);
	    pentry_up->upState.status = ex_queue::Q_SQLERROR;
	    pentry_up->upState.parentIndex 
	      = pentry_down->downState.parentIndex;
	    pentry_up->upState.downIndex = qparent_.down->getHeadIndex();
            pentry_up->upState.setMatchNo(pstate->matchCount_);
            qparent_.up->insert();

	    // Transition to the ExSamp_CANCELLED state.
	    //
	    pstate->step_ = ExSamp_CANCELLED;
	    break;
	  }

	// ExSamp_WORKING
	//
	// Transition to this state from ...
	// 1. ExSamp_EMPTY - If a request is started.
	//
	// Remain in this state until ...
	// 1. All child replies including EOD have been processed.
	// 2. A SQLERROR row is received.
	// 3. Enough rows have been returned.
	// 4. The request is cancelled.
	//
	// Transition from this state to ...
	// 1. ExSamp_DONE - If all the child rows including EOD have 
	//    been processed.
	// 2. ExSamp_ERROR - If an SQLERROR rows is received.
	// 3. ExSamp_CANCELLED - If enough rows have been returned.
	// 3. ExSamp_CANCELLED - If the request is cancelled.
	//
	case ExSamp_WORKING:
	  {
	    // If there is not room in the parent Queue for the reply,
	    // try again later.
	    //
	    if (qparent_.up->isFull())
	      return WORK_OK;

	    // If there are no replies, try again later.
	    //
	    if (qchild_.up->isEmpty())
	      return WORK_OK;

	    ex_queue_entry * centry = qchild_.up->getHeadEntry();
	    switch (centry->upState.status)
	      {
		
		// A data row from the child.
		//
	      case ex_queue::Q_OK_MMORE:
		{
		  // Apply the sampling predicate if it exists and extract
		  // the sampling factor.
		  //
		  ex_expr::exp_return_type retCode = ex_expr::EXPR_TRUE;
		  Int32 samplingFactor = 1;
		  if(balanceExpr())
		    {
		      retCode = balanceExpr()->eval
			(centry->getAtp(), centry->getAtp());
		      
		      if(retCode == ex_expr::EXPR_OK)
			{
			  samplingFactor = 
			    *(Lng32*)balanceExpr()->getPersistentData
			    (returnFactorOffset());
		      
			  // If the sampling factor is less than 0, then
			  // we are done with this request. Mark the
			  // request as get-no-more. Forces the child to be
                          // cancelled
			  //
			  if(samplingFactor < 0)
			    {
                              // Cancel the rest of this
                              // request.
			      pentry_down->downState.request 
				= ex_queue::GET_NOMORE;
			      request = ex_queue::GET_NOMORE;
                              
                              // Return no rows
			      retCode = ex_expr::EXPR_FALSE;
			    }
			}
		    }
		  
		  // If the row passed the sampling predicate, apply the 
		  // selection predicate if it exists.
		  //
		  if ((samplingFactor > 0) && 
		      (retCode == ex_expr::EXPR_OK) && 
		      postPred()) 
		    retCode = postPred()->eval
		      (centry->getAtp(), centry->getAtp());

		  // Act on the result of the selection predicate.
		  //
		  switch(retCode) {
		    // If the selection predicate returns TRUE,
		    // return the row to the parent the number
		    // of times indicated by the sampling factor as long
		    // as there is room in the parent queue.
		    //
		  case ex_expr::EXPR_TRUE:
		  case ex_expr::EXPR_OK:
		    while(!qparent_.up->isFull() && (samplingFactor > 0))
		      {
			// Copy the child ATP to the parent ATP -- the 
			// row images are exactly the same.
			//
			ex_queue_entry * pentry_up 
			  = qparent_.up->getTailEntry();
			pentry_up->copyAtp(centry);

			// Fixup the up state.
			//
			pentry_up->upState.status = ex_queue::Q_OK_MMORE;
			pentry_up->upState.parentIndex 
			  = pentry_down->downState.parentIndex;
			pentry_up->upState.downIndex 
			  = qparent_.down->getHeadIndex();
			pstate->matchCount_++;
			pentry_up->upState.setMatchNo(pstate->matchCount_);

			// Commit the entry.
			//
			qparent_.up->insert();
                        if (statsEntry)
                           statsEntry->incActualRowsReturned();
			samplingFactor--;

			// If we have satisfied a GET_N request, then
			// break out of here so we can stop processing.
			//
			if((request == ex_queue::GET_N) &&
			   (pentry_down->downState.requestValue 
			    <= (Lng32)pstate->matchCount_))
			  {
			    samplingFactor = 0;
			    break;
			  }
		      }

		    // If all of the rows are returned, then we are done
		    // with this entry and can proceed. 
		    //
		    if(samplingFactor == 0)
		      {
			qchild_.up->removeHead();
		      }
		    // Otherwise, the queue must have become full so we 
		    // have to switch to the RETURNINGROWS state to finish 
		    // the job.
		    else
		      {
			pstate->rowsToReturn_ = samplingFactor;
			pstate->step_ = ExSamp_RETURNINGROWS;
			return WORK_OK;
		      }
		      
		    break;
		    
		    // If the selection predicate returns FALSE,
		    // do not return the child row.
		    //
		  case ex_expr::EXPR_FALSE:
		    qchild_.up->removeHead();
		    break;

		    // If the selection predicate returns an ERROR,
		    // go to the error processing state.
		    //
		  case ex_expr::EXPR_ERROR:
		    pstate->step_ = ExSamp_ERROR;
		    break;
		  }
		}
		break;

		// The EOD from the child. Transition to ExSamp_DONE.
		//
	      case ex_queue::Q_NO_DATA:
		pstate->step_ = ExSamp_DONE;
		qchild_.up->removeHead();
		break;

		// An SQLERROR from the child. Transition to ExSamp_ERROR.
		//
	      case ex_queue::Q_SQLERROR:
		pstate->step_ = ExSamp_ERROR;
		break;
	      }
	  }
	break;

	// ExSamp_RETURNINGROWS
	//
	// Transistion to this state from ...
	// 1. ExSamp_WORKING - if up queue becomes full when returning 
	//                    multiple rows from oversampling.
	//
	// Remain in this state until ...
	// 1. the multiple oversampled rows have been returned.
	//
	case ExSamp_RETURNINGROWS:
	  {
	    ex_queue_entry * centry = qchild_.up->getHeadEntry();
	    while(!qparent_.up->isFull() && (pstate->rowsToReturn_ > 0))
	      {
		// Copy the child ATP to the parent ATP -- the row
		// images are exactly the same.
		//
		ex_queue_entry * pentry_up = qparent_.up->getTailEntry();
		pentry_up->copyAtp(centry);
		
		// Fixup the up state.
		//
		pentry_up->upState.status = ex_queue::Q_OK_MMORE;
		pentry_up->upState.parentIndex 
		  = pentry_down->downState.parentIndex;
		pentry_up->upState.downIndex = qparent_.down->getHeadIndex();
		pstate->matchCount_++;
		pentry_up->upState.setMatchNo(pstate->matchCount_);
		
		// Commit the entry.
		//
		qparent_.up->insert();
                if (statsEntry)
                   statsEntry->incActualRowsReturned();

		pstate->rowsToReturn_--;

		// If we have satisfied a GET_N request, then
		// break out of here so we can stop processing.
		//
		if((request == ex_queue::GET_N) &&
		   (pentry_down->downState.requestValue 
		    <= (Lng32)pstate->matchCount_))
		  {
		    pstate->rowsToReturn_ = 0;
		    break;
		  }
	      }

	    // If all of the rows were returned, remove the child's reply
	    // and go back to the WORKING state.
	    //
	    if(pstate->rowsToReturn_ == 0)
	      {
		qchild_.up->removeHead();
		pstate->step_ = ExSamp_WORKING;
	      }
	    // Otherwise, we need to come back later to finish up.
	    //
	    else
	      {
		return WORK_OK;
	      }
	  }
	break;

	// ExSamp_DONE
	//
	// Transition to the state from ...
	// 1. ExSamp_WORKING - if all child rows have been processed.
	// 2. ExSamp_CANCELLED - if all child rows have been consumed.
	// 3. ExSamp_EMPTY - if the request was DOA.
	//
	// Remain in this state until ...
	// 1. The EOD is returned to the parent.
	//
	// Transition from this state to ...
	// 1. ExSamp_EMPTY - In all cases.
	//
	case ExSamp_DONE:
	  {
	    // If there is not any room in the parent's queue, 
	    // try again later.
	    //
	    if (qparent_.up->isFull())
	      return WORK_OK;
	    
	    ex_queue_entry * pentry_up = qparent_.up->getTailEntry();
	    pentry_up->upState.status = ex_queue::Q_NO_DATA;
	    pentry_up->upState.parentIndex 
	      = pentry_down->downState.parentIndex;
	    pentry_up->upState.downIndex = qparent_.down->getHeadIndex();
	    pentry_up->upState.setMatchNo(pstate->matchCount_);
	    
	    qparent_.down->removeHead();
	    qparent_.up->insert();

            // Re-initialize pstate
	    //
	    pstate->step_ = ExSamp_EMPTY;
            pstate->matchCount_ = 0;
	    pstate->rowsToReturn_ = 0;
            pstate->workAtp_->release();

	    // If there are no more requests, simply return.
	    //
            if (qparent_.down->isEmpty())
              return WORK_OK;

            // If we haven't given to our child the new head
            // index return and ask to be called again.
	    //
            if (qparent_.down->getHeadIndex() == processedInputs_)
	      return WORK_CALL_AGAIN;

            // Postion at the new head of the request queue.
	    //
            pentry_down = qparent_.down->getHeadEntry();
            pstate = (ExSamplePrivateState*) pentry_down->pstate;
            request = pentry_down->downState.request;

	    // If the request has not been worked on yet, then initialize the
	    // presistent expression variable data and switch to the 
	    // WORKING state.
	    //
	    if(pstate->step_ == ExSamp_PREWORK)
	      {
		pstate->step_ = ExSamp_WORKING;
		if(balanceExpr()) balanceExpr()->initializePersistentData();
	      }
	  }
	break;
	} // switch pstate->step_
    } // while
}
short
PhysSample::codeGen(Generator *generator) 
{  
  // Get a local handle on some of the generator objects.
  //
  CollHeap *wHeap = generator->wHeap();
  Space *space = generator->getSpace();
  MapTable *mapTable = generator->getMapTable();
  ExpGenerator *expGen = generator->getExpGenerator();

  // Allocate a new map table for this node. This must be done
  // before generating the code for my child so that this local
  // map table will be sandwiched between the map tables already
  // generated and the map tables generated by my offspring.
  //
  // Only the items available as output from this node will
  // be put in the local map table. Before exiting this function, all of
  // my offsprings map tables will be removed. Thus, none of the outputs 
  // from nodes below this node will be visible to nodes above it except 
  // those placed in the local map table and those that already exist in
  // my ancestors map tables. This is the standard mechanism used in the
  // generator for managing the access to item expressions.
  //
  MapTable *localMapTable = generator->appendAtEnd();

  // Since this operation doesn't modify the row on the way down the tree,
  // go ahead and generate the child subtree. Capture the given composite row
  // descriptor and the child's returned TDB and composite row descriptor.
  //
  ex_cri_desc * givenCriDesc = generator->getCriDesc(Generator::DOWN);
  child(0)->codeGen(generator);
  ComTdb *childTdb = (ComTdb*)generator->getGenObj();
  ex_cri_desc * childCriDesc = generator->getCriDesc(Generator::UP);
  ExplainTuple *childExplainTuple = generator->getExplainTuple();

  // Geneate the sampling expression.
  //
  ex_expr *balExpr = NULL;
  Int32 returnFactorOffset = 0;
  ValueId val;
  val = balanceExpr().init();
  if(balanceExpr().next(val))
    expGen->generateSamplingExpr(val, &balExpr, returnFactorOffset);

  // Alias the sampleColumns() so that they reference the underlying
  // expressions directly. This is done to avoid having to generate and
  // execute a project expression that simply moves the columns from
  // one tupp to another to reflect the application of the sampledCol
  // function.
  //
//   ValueId valId;
//   for(valId = sampledColumns().init();
//       sampledColumns().next(valId);
//       sampledColumns().advance(valId))
//     {
//       MapInfo *mapInfoChild = localMapTable->getMapInfoAsIs
// 	(valId.getItemExpr()->child(0)->castToItemExpr()->getValueId());
//       GenAssert(mapInfoChild, "Sample::codeGen -- no child map info.");
//       Attributes *attr = mapInfoChild->getAttr();
//       MapInfo *mapInfo = localMapTable->addMapInfoToThis(valId, attr);
//       mapInfo->codeGenerated();
//     }
// check if any of the columns inthe sampled columns are lob columns. If so, return an error.
  ValueId valId;
  for(valId = sampledColumns().init();
      sampledColumns().next(valId);
      sampledColumns().advance(valId))
    {
      const NAType &colType = valId.getType();
      if ((colType.getFSDatatype() == REC_BLOB) ||
	  (colType.getFSDatatype() == REC_CLOB))
	{
	   *CmpCommon::diags() << DgSqlCode(-4322);
	   GenExit();
	}
    }
  // Now, remove all attributes from the map table except the 
  // the stuff in the local map table -- the result of this node.
  //
//  localMapTable->removeAll();

  // Generate the expression to evaluate predicate on the sampled row.
  //
  ex_expr *postPred = 0;
  if (!selectionPred().isEmpty()) {
    ItemExpr * newPredTree 
      = selectionPred().rebuildExprTree(ITM_AND,TRUE,TRUE);

    expGen->generateExpr(newPredTree->getValueId(), ex_expr::exp_SCAN_PRED,
			 &postPred);
  }

  // Construct the Sample TDB.
  //
  ComTdbSample *sampleTdb
    = new(space) ComTdbSample(NULL,
			      balExpr,
			      returnFactorOffset,
			      postPred,
			      childTdb,
			      givenCriDesc,
			      childCriDesc,
			      (queue_index)getDefault(GEN_SAMPLE_SIZE_DOWN),
			      (queue_index)getDefault(GEN_SAMPLE_SIZE_UP));
  generator->initTdbFields(sampleTdb);

  if(!generator->explainDisabled()) {
    generator->
      setExplainTuple(addExplainInfo(sampleTdb,
                                     childExplainTuple,
                                     0,
                                     generator));
  }

  generator->setCriDesc(givenCriDesc, Generator::DOWN);
  generator->setCriDesc(childCriDesc, Generator::UP);
  generator->setGenObj(this, sampleTdb);

  return 0;
}