TEST_F(OneSubOptimizerTests, EqOpAndXorOpSecOpOfXorIsTenNotOptimized) { // return (a == b) ^ 10; // // Not optimized. // ShPtr<Variable> varA(Variable::create("a", IntType::create(16, true))); ShPtr<Variable> varB(Variable::create("b", IntType::create(16, true))); ShPtr<ConstInt> constInt(ConstInt::create(10, 64)); ShPtr<EqOpExpr> eqOpExpr( EqOpExpr::create( varA, varB )); ShPtr<BitXorOpExpr> returnExpr( BitXorOpExpr::create( eqOpExpr, constInt )); ShPtr<ReturnStmt> returnStmt(ReturnStmt::create(returnExpr)); optimizer->tryOptimize(returnStmt->getRetVal()); ShPtr<BitXorOpExpr> outBitXorOpExpr(cast<BitXorOpExpr>(returnStmt->getRetVal())); ASSERT_TRUE(outBitXorOpExpr) << "expected `BitXorOpExpr`, " "got `" << returnStmt->getRetVal() << "`"; ShPtr<EqOpExpr> outEqOpExpr(cast<EqOpExpr>(outBitXorOpExpr->getFirstOperand())); ASSERT_TRUE(outEqOpExpr) << "expected `EqOpExpr`, " "got `" << outBitXorOpExpr->getFirstOperand() << "`"; ShPtr<Variable> outOp1(cast<Variable>(outEqOpExpr->getFirstOperand())); ASSERT_TRUE(outOp1) << "expected `Variable`, " "got `" << outEqOpExpr->getFirstOperand() << "`"; EXPECT_EQ(varA, outOp1) << "expected `" << varA << "`, " "got `" << outOp1 << "`"; ShPtr<Variable> outOp2(cast<Variable>(outEqOpExpr->getSecondOperand())); ASSERT_TRUE(outOp2) << "expected `Variable`, " "got `" << outEqOpExpr->getSecondOperand() << "`"; EXPECT_EQ(varB, outOp2) << "expected `" << varB << "`, " "got `" << outOp2 << "`"; ShPtr<ConstInt> outConstInt(cast<ConstInt>(outBitXorOpExpr->getSecondOperand())); ASSERT_TRUE(outConstInt) << "expected `ConstInt`, " "got `" << outBitXorOpExpr->getSecondOperand() << "`"; EXPECT_EQ(constInt, outConstInt) << "expected `" << constInt << "`, " "got `" << outConstInt << "`"; }
TEST_F(OneSubOptimizerTests, EqOpWithCastsAndXorOpSecOpOfXorIsOneOptimized) { // return IntToPtr(IntToPtr((a == b))) ^ 1; // // Optimized to retun a != b. // ShPtr<Variable> varA(Variable::create("a", IntType::create(16, true))); ShPtr<Variable> varB(Variable::create("b", IntType::create(16, true))); ShPtr<EqOpExpr> eqOpExpr( EqOpExpr::create( varA, varB )); ShPtr<IntToPtrCastExpr> intToPtrCastExprInner( IntToPtrCastExpr::create( eqOpExpr, IntType::create(16) )); ShPtr<IntToPtrCastExpr> intToPtrCastExprOuter( IntToPtrCastExpr::create( intToPtrCastExprInner, IntType::create(16) )); ShPtr<BitXorOpExpr> returnExpr( BitXorOpExpr::create( intToPtrCastExprOuter, ConstInt::create(1, 64) )); ShPtr<ReturnStmt> returnStmt(ReturnStmt::create(returnExpr)); optimizer->tryOptimize(returnStmt->getRetVal()); ShPtr<NeqOpExpr> outNeqOpExpr(cast<NeqOpExpr>(returnStmt->getRetVal())); ASSERT_TRUE(outNeqOpExpr) << "expected `NegOpExpr`, " "got `" << returnStmt->getRetVal() << "`"; ShPtr<Variable> outOp1(cast<Variable>(outNeqOpExpr->getFirstOperand())); ASSERT_TRUE(outOp1) << "expected `Variable`, " "got `" << outNeqOpExpr->getFirstOperand() << "`"; EXPECT_EQ(varA, outOp1) << "expected `" << varA << "`, " "got `" << outOp1 << "`"; ShPtr<Variable> outOp2(cast<Variable>(outNeqOpExpr->getSecondOperand())); ASSERT_TRUE(outOp2) << "expected `Variable`, " "got `" << outNeqOpExpr->getSecondOperand() << "`"; EXPECT_EQ(varB, outOp2) << "expected `" << varB << "`, " "got `" << outOp2 << "`"; }
TEST_F(OneSubOptimizerTests, FirstOpIsOneConstFloatMulOptimized) { // return 1.0 * a; // // Optimized to return a. // ShPtr<Variable> varA(Variable::create("a", IntType::create(16))); ShPtr<MulOpExpr> returnExpr( MulOpExpr::create( ConstFloat::create(llvm::APFloat(1.0)), varA )); ShPtr<ReturnStmt> returnStmt(ReturnStmt::create(returnExpr)); optimizer->tryOptimize(returnStmt->getRetVal()); EXPECT_EQ(varA, returnStmt->getRetVal()) << "expected `" << varA << "`, " "got `" << returnStmt << "`"; }
TEST_F(OneSubOptimizerTests, SecOpIsOneConstIntMulOptimized) { // return a * 1; // // Optimized to return a. // ShPtr<Variable> varA(Variable::create("a", IntType::create(16))); ShPtr<MulOpExpr> returnExpr( MulOpExpr::create( varA, ConstInt::create(1, 64) )); ShPtr<ReturnStmt> returnStmt(ReturnStmt::create(returnExpr)); optimizer->tryOptimize(returnStmt->getRetVal()); EXPECT_EQ(varA, returnStmt->getRetVal()) << "expected `" << varA << "`, " "got `" << returnStmt << "`"; }
// work - doit... // // short ExSequenceTcb::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; ExSequencePrivateState * 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 = (ExSequencePrivateState*) 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) { // LCOV_EXCL_START pstate->step_ = ExSeq_DONE; // LCOV_EXCL_STOP } else { pstate->step_ = ExSeq_WORKING_READ; // 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(); } } // end for processedInputs_ pentry_down = qparent_.down->getHeadEntry(); pstate = (ExSequencePrivateState*) pentry_down->pstate; request = pentry_down->downState.request; // 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_ == ExSeq_WORKING_READ) || (pstate->step_ == ExSeq_WORKING_RETURN)) { 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_ = ExSeq_CANCELLED; } } switch (pstate->step_) { // ExSeq_CANCELLED // // Transition to this state from ... // 1. ExSeq_Error - After the error has been processed. // 2. ExSeq_Working - If enough rows have been returned. // 3. ExSeq_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. ExSeq_DONE - In all cases. // case ExSeq_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 ExSeq_DONE state. // if (child_status == ex_queue::Q_NO_DATA) pstate->step_ = ExSeq_DONE; // Discard the child row. qchild_.up->removeHead(); break; } // ExSeq_ERROR // // Transition to this state from ... // 1. ExSeq_WORKING_READ - a child reply with the type SQLERROR. // 2. ExSeq_WORKING_RETURN // 3. ExSeq_OVERFLOW_READ // 4. ExSeq_OVERFLOW_WRITE // Remain in this state until .. // 1. The error row has been returned to the parent. // // Transition from this state to ... // 1. ExSeq_CANCELLED - In all cases. // case ExSeq_ERROR: { // If there is no room in the parent queue for the reply, // try again later. // if (qparent_.up->isFull()) // LCOV_EXCL_START return WORK_OK; // LCOV_EXCL_STOP ex_queue_entry *pentry_up = qparent_.up->getTailEntry(); // Cancel the child request - there must be a child request in // progress to get to the ExSeq_ERROR state. // qchild_.down->cancelRequestWithParentIndex (qparent_.down->getHeadIndex()); // Construct and return the error row. // if (workAtp_->getDiagsArea()) { ComDiagsArea * da = workAtp_->getDiagsArea(); pentry_up->setDiagsArea(da); da->incrRefCount(); workAtp_->setDiagsArea(0); } 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 ExSeq_CANCELLED state. // pstate->step_ = ExSeq_CANCELLED; break; } // ExSeq_WORKING_READ // // Transition to this state from ... // 1. ExSeq_EMPTY - If a request is started. // 2. ExSeq_WORKING_RETURN - // 3. ExSeq_OVERFLOW_WRITE - // 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. // 5. End of partition is reached // Transition from this state to ... // 2. ExSeq_ERROR - If an SQLERROR rows is received. // 3. ExSeq_CANCELLED - If the request is cancelled. // 4. ExSeq_WORKING_RETURN // 5. ExSeq_OVERFLOW_WRITE - case ExSeq_WORKING_READ: { if(!isUnboundedFollowing() && isHistoryFull()) { pstate->step_ = ExSeq_WORKING_RETURN; break; } // 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: { tupp_descriptor histTupp; workAtp_->copyAtp(pentry_down->getAtp()); workAtp_->getTupp(myTdb().tuppIndex_) = &histTupp; if ( checkPartitionChangeExpr() && currentHistRowPtr_) { workAtp_->getTupp (myTdb().tuppIndex_).setDataPointer(currentHistRowPtr_); // Check whether the partition changed ex_expr::exp_return_type retCode = checkPartitionChangeExpr()->eval(workAtp_, centry->getAtp()); if (retCode == ex_expr::EXPR_ERROR) { // LCOV_EXCL_START updateDiagsArea(centry); pstate->step_ = ExSeq_ERROR; break; // LCOV_EXCL_STOP } if ( retCode == ex_expr::EXPR_FALSE) { setPartitionEnd(TRUE); pstate->step_ = ExSeq_END_OF_PARTITION; break; } } if (isUnboundedFollowing() ) { if (OLAPBuffersFlushed_) { OLAPBuffersFlushed_ = FALSE;// current row is the first one in first buffer already } else { NABoolean noMemory = advanceHistoryRow( TRUE /* checkMemoryPressure */); if (noMemory) { pstate->step_ = ExSeq_OVERFLOW_WRITE; cluster_->nextBufferToFlush_ = firstOLAPBuffer_; cluster_->afterLastBufferToFlush_ = NULL;//flush them all // If it is the first overflow, for this partition if ( ! memoryPressureDetected_ ) { memoryPressureDetected_ = TRUE; } // memory pressure detected break; } } } else { advanceHistoryRow(); } workAtp_->getTupp (myTdb().tuppIndex_).setDataPointer(currentHistRowPtr_); ex_expr::exp_return_type retCode = ex_expr::EXPR_OK; // Apply the read phase sequence function expression to compute // the values of the sequence functions. if (sequenceExpr()) { retCode = sequenceExpr()->eval(workAtp_, centry->getAtp()); if (retCode == ex_expr::EXPR_ERROR) { updateDiagsArea(centry); pstate->step_ = ExSeq_ERROR; break; } } // merge the child's diags area into the work atp updateDiagsArea(centry); qchild_.up->removeHead(); break; } // The EOD from the child. Transition to ExSeq_DONE. // case ex_queue::Q_NO_DATA: { setPartitionEnd(TRUE); if (isHistoryEmpty()) { pstate->step_ = ExSeq_DONE; qchild_.up->removeHead(); } else { pstate->step_ = ExSeq_END_OF_PARTITION; } } break; // An SQLERROR from the child. Transition to ExSeq_ERROR. // case ex_queue::Q_SQLERROR: updateDiagsArea(centry); pstate->step_ = ExSeq_ERROR; break; } } break; // ExSeq_WORKING_RETURN // // Transition to this state from ... // 1. ExSeq_WORKING_READ - // 2. ExSeq_OVERFLOW_READ - // 3. ExSeq_END_OF_PARTITION - // Remain in this state until ... // 1. All rows are returned. // 2. A SQLERROR row is received. // 3. Enough rows have been returned. // // Transition from this state to ... // 1. ExSeq_DONE - If all the child rows including EOD have // been processed. // 2. ExSeq_ERROR - If an SQLERROR rows is received. // 3. ExSeq_CANCELLED - If enough rows have been returned. // 4. ExSeq_CANCELLED - If the request is cancelled. // 5. ExSeq_WORKING_RETURN // 6. ExSeq_DONE // 7. ExSeq_OVERFLOW_READ case ExSeq_WORKING_RETURN: { // If there is not room in the parent Queue for the reply, // try again later. // if (qparent_.up->isFull()) return WORK_OK; if(isHistoryEmpty()) { ex_queue_entry * centry = NULL; if(!qchild_.up->isEmpty()) { centry = qchild_.up->getHeadEntry(); } if(centry && (centry->upState.status == ex_queue::Q_NO_DATA)) { pstate->step_ = ExSeq_DONE; qchild_.up->removeHead(); } else { pstate->step_ = ExSeq_WORKING_READ; if (getPartitionEnd()) { initializeHistory(); } } break; } if(!canReturnRows() && !getPartitionEnd() && !isUnboundedFollowing() && !isOverflowStarted()) // redundant? because not unbounded ... { pstate->step_ = ExSeq_WORKING_READ; break; } ex_queue_entry * pentry_up = qparent_.up->getTailEntry(); pentry_up->copyAtp(pentry_down); // Try to allocate a tupp. // if (pool_->get_free_tuple(pentry_up->getTupp(myTdb().tuppIndex_), recLen())) // LCOV_EXCL_START return WORK_POOL_BLOCKED; // LCOV_EXCL_STOP char *tuppData = pentry_up->getTupp (myTdb().tuppIndex_).getDataPointer(); advanceReturnHistoryRow(); char *histData = currentRetHistRowPtr_; pentry_up->getTupp (myTdb().tuppIndex_).setDataPointer(histData); ex_expr::exp_return_type retCode = ex_expr::EXPR_OK; // Apply the return phase expression if(returnExpr()) { retCode = returnExpr()->eval(pentry_up->getAtp(),workAtp_); if (retCode == ex_expr::EXPR_ERROR) { // LCOV_EXCL_START pstate->step_ = ExSeq_ERROR; break; // LCOV_EXCL_STOP } } retCode = ex_expr::EXPR_OK; //Apply post predicate expression if (postPred()) { retCode = postPred()->eval(pentry_up->getAtp(),pentry_up->getAtp()); if (retCode == ex_expr::EXPR_ERROR) { // LCOV_EXCL_START pstate->step_ = ExSeq_ERROR; break; // LCOV_EXCL_STOP } } //pentry_up->getAtp()->display("return eval result", myTdb().getCriDescUp()); // // Case-10-030724-7963: we are done pointing the tupp at the // history buffer, so point it back to the SQL buffer. // pentry_up->getTupp (myTdb().tuppIndex_).setDataPointer(tuppData); switch(retCode) { case ex_expr::EXPR_OK: case ex_expr::EXPR_TRUE: case ex_expr::EXPR_NULL: // Copy the row that was computed in the history buffer, // to the space previously allocated in the SQL buffer. str_cpy_all(tuppData, histData, recLen()); // Return the processed row. // // Finalize the queue entry, then insert it // 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_); qparent_.up->insert(); break; // If the selection predicate returns FALSE, // do not return the child row. // case ex_expr::EXPR_FALSE: break; // If the selection predicate returns an ERROR, // go to the error processing state. // case ex_expr::EXPR_ERROR: // LCOV_EXCL_START pstate->step_ = ExSeq_ERROR; // LCOV_EXCL_STOP break; } // MV -- // Now, if there are no errors so far, evaluate the // cancel expression if ((pstate->step_ != ExSeq_ERROR) && cancelExpr()) { // Temporarily point the tupp to the tail of the // history buffer for evaluating the // expressions. // pentry_up->getTupp (myTdb().tuppIndex_).setDataPointer(histData); retCode = cancelExpr()->eval(pentry_up->getAtp(),pentry_up->getAtp()); // We are done pointing the tupp at the history // buffer, so point it back to the SQL buffer. // pentry_up->getTupp (myTdb().tuppIndex_).setDataPointer(tuppData); if (retCode == ex_expr::EXPR_TRUE) { qchild_.down->cancelRequestWithParentIndex (qparent_.down->getHeadIndex()); pstate->step_ = ExSeq_CANCELLED; } } updateHistRowsToReturn(); if ( isOverflowStarted() ) { numberOfRowsReturnedBeforeReadOF_ ++; if (numberOfRowsReturnedBeforeReadOF_ == maxNumberOfRowsReturnedBeforeReadOF_) { firstOLAPBufferFromOF_ = currentRetOLAPBuffer_->getNext(); if (firstOLAPBufferFromOF_ == NULL) { firstOLAPBufferFromOF_ = firstOLAPBuffer_; } for( Int32 i = 0; i < numberOfWinOLAPBuffers_; i++) { firstOLAPBufferFromOF_ = firstOLAPBufferFromOF_->getNext(); if (firstOLAPBufferFromOF_ == NULL) { firstOLAPBufferFromOF_ = firstOLAPBuffer_; } } numberOfOLAPBuffersFromOF_ = numberOfOLAPBuffers_ - numberOfWinOLAPBuffers_; cluster_->nextBufferToRead_ = firstOLAPBufferFromOF_; HashBuffer * afterLast = firstOLAPBufferFromOF_; // last buffer to read into is the current buffer - maybe ? for ( Lng32 bufcount = numberOfOLAPBuffersFromOF_ ; bufcount ; bufcount-- ) { afterLast = afterLast->getNext() ; // Don't cycle back if bufcount == 1 because the logic in // Cluster::read relies on the NULL ptr to stop reading if ( bufcount > 1 && ! afterLast ) afterLast = firstOLAPBuffer_; // cycle back } // The last buffer to read to is always the current buffer // ex_assert ( afterLast == currentRetOLAPBuffer_->getNext(), // "Miscalculated the last buffer to read into"); cluster_->afterLastBufferToRead_ = afterLast; pstate->step_ = ExSeq_OVERFLOW_READ; } } } break; // ExSeq_END_OF_PARTITION // // Transition to this state from ... // 1. ExSeq_WORKING_READ - // Transition from this state to ... // 1. ExSeq_OVERFLOW_WRITE // 2. ExSeq_WORKING_RETURN case ExSeq_END_OF_PARTITION: { setPartitionEnd(TRUE); if (lastRow_ && isUnboundedFollowing()) { ex_assert(currentHistRowPtr_ != NULL, "ExSequenceTcb::work() - currentHistRowPtr_ is a NULL pointer"); str_cpy_all(lastRow_, currentHistRowPtr_, recLen()); } if ( isOverflowStarted() ) // we are overflowing { cluster_->nextBufferToFlush_ = firstOLAPBuffer_; // do not flush beyond the current buffer cluster_->afterLastBufferToFlush_ = currentOLAPBuffer_->getNext(); pstate->step_ = ExSeq_OVERFLOW_WRITE; } else { pstate->step_ = ExSeq_WORKING_RETURN; } } break; // ExSeq_OVERFLOW_WRITE // // Transition to this state from ... // 1. ExSeq_WORKING_READ - // 2. ExSeq_END_OF_PARTITION - // Remain in this state until ... // 1. OLAPbuffers are written to oveflow space. // 2. An error occurs // // Transition from this state to ... // 1. ExSeq_OVERFLOW_READ // 2. ExSeq_ERROR - If an error occurs case ExSeq_OVERFLOW_WRITE: { if (!overflowEnabled_) { // LCOV_EXCL_START // used for debugging when CmpCommon::getDefault(EXE_BMO_DISABLE_OVERFLOW)is set to off ; updateDiagsArea(EXE_OLAP_OVERFLOW_NOT_SUPPORTED); pstate->step_ = ExSeq_ERROR; break; // LCOV_EXCL_STOP } ex_assert(isUnboundedFollowing(),""); if ( ! cluster_->flush(&rc_) ) { // flush the buffers // LCOV_EXCL_START // if no errors this code path is not visited if ( rc_ ) { // some error updateDiagsArea( rc_); pstate->step_ = ExSeq_ERROR; break; } // LCOV_EXCL_STOP // not all the buffers are completely flushed. An I/O is pending // LCOV_EXCL_START // maybe we cane remove in the future return WORK_OK; // LCOV_EXCL_STOP } // At this point -- all the buffers were completely flushed OLAPBuffersFlushed_ = TRUE; if (getPartitionEnd()) { firstOLAPBufferFromOF_ = firstOLAPBuffer_; numberOfOLAPBuffersFromOF_ = numberOfOLAPBuffers_; cluster_->nextBufferToRead_ = firstOLAPBufferFromOF_; // First time we read and fill all the buffers cluster_->afterLastBufferToRead_ = NULL; pstate->step_ = ExSeq_OVERFLOW_READ; } else { pstate->step_ = ExSeq_WORKING_READ; } } break; // ExSeq_OVERFLOW_READ // // Transition to this state from ... // 1. ExSeq_OVERFLOW_WRITE // 2. ExSeq_WORKING_RETURN // Remain in this state until ... // 1. OLAPbuffers are read from oveflow space. // 2. An error occurs // // Transition from this state to ... // 1. ExSeq_WORKING_RETURN // 2. ExSeq_ERROR - If an error occurs case ExSeq_OVERFLOW_READ: { assert(firstOLAPBufferFromOF_ && isUnboundedFollowing() ); if ( ! cluster_->read(&rc_) ) { // LCOV_EXCL_START if ( rc_ ) { // some error updateDiagsArea( rc_); pstate->step_ = ExSeq_ERROR; break; } // LCOV_EXCL_STOP // not all the buffers are completely read. An I/O is pending // LCOV_EXCL_START return WORK_OK; // LCOV_EXCL_STOP } numberOfRowsReturnedBeforeReadOF_ = 0; pstate->step_ = ExSeq_WORKING_RETURN; } break; // ExSeq_DONE // // Transition to the state from ... // 1. ExSeq_WORKING_RETURN - if all child rows have been processed. // 2. ExSeq_CANCELLED - if all child rows have been consumed. // 3. ExSeq_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. ExSeq_EMPTY - In all cases. // case ExSeq_DONE: { // If there is not any room in the parent's queue, // try again later. // if (qparent_.up->isFull()) // LCOV_EXCL_START return WORK_OK; // LCOV_EXCL_STOP 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_ = ExSeq_EMPTY; pstate->matchCount_ = 0; workAtp_->release(); // Initialize the history buffer in preparation for the // next request. // initializeHistory(); // If there are no more requests, simply return. // if (qparent_.down->isEmpty()) return WORK_OK; // LCOV_EXCL_START // 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; // Position at the new head of the request queue. // pentry_down = qparent_.down->getHeadEntry(); pstate = (ExSequencePrivateState*) pentry_down->pstate; request = pentry_down->downState.request; // LCOV_EXCL_STOP } break; } // switch pstate->step_ } // while }
// ExSequenceTcb constructor // // 1. Allocate buffer pool. // 2. Allocate parent queues and initialize private state. // 3. Fixup expressions. // ExSequenceTcb::ExSequenceTcb (const ExSequenceTdb & myTdb, const ex_tcb & child_tcb, ex_globals * glob) : ex_tcb(myTdb, 1, glob), lastRow_(NULL), clusterDb_(NULL), cluster_(NULL), ioEventHandler_(NULL), OLAPBuffersFlushed_(FALSE), firstOLAPBuffer_(NULL), lastOLAPBuffer_(NULL), rc_(EXE_OK), olapBufferSize_(0), maxNumberOfOLAPBuffers_(0), numberOfOLAPBuffers_(0), minNumberOfOLAPBuffers_(0), memoryPressureDetected_(FALSE) { Space * space = (glob ? glob->getSpace() : 0); CollHeap * heap = (glob ? glob->getDefaultHeap() : 0); heap_ = heap; childTcb_ = &child_tcb; // Allocate the buffer pool #pragma nowarn(1506) // warning elimination pool_ = new(space) sql_buffer_pool(myTdb.numBuffers_, myTdb.bufferSize_, space); allocRowLength_ = ROUND8(myTdb.recLen_); #pragma warn(1506) // warning elimination // Initialize the machinery for maintaining the row history for // computing sequence functions. // maxNumberHistoryRows_ = myTdb.maxHistoryRows_; minFollowing_ = myTdb.minFollowing_; unboundedFollowing_ = myTdb.isUnboundedFollowing(); maxNumberOfOLAPBuffers_ = myTdb.maxNumberOfOLAPBuffers_;//testing olapBufferSize_ = myTdb.OLAPBufferSize_ ; maxRowsInOLAPBuffer_ = myTdb.maxRowsInOLAPBuffer_; minNumberOfOLAPBuffers_ = myTdb.minNumberOfOLAPBuffers_; numberOfWinOLAPBuffers_ = myTdb.numberOfWinOLAPBuffers_; overflowEnabled_ = ! myTdb.isNoOverflow(); ex_assert( maxNumberOfOLAPBuffers_ >= minNumberOfOLAPBuffers_ , "maxNumberOfOLAPBuffers is too small"); // Initialize history parameters // For unbounded following -- also create/initialize clusterDb, cluster initializeHistory(); // 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.initialQueueSizeDown_, myTdb.criDescDown_, space); // Allocate the private state in each entry of the down queue ExSequencePrivateState *p = new(space) ExSequencePrivateState(this); qparent_.down->allocatePstate(p, this); delete p; qparent_.up = new(space) ex_queue(ex_queue::UP_QUEUE, myTdb.initialQueueSizeUp_, myTdb.criDescUp_, space); // Intialized processedInputs_ to the next request to process processedInputs_ = qparent_.down->getTailIndex(); workAtp_ = allocateAtp(myTdb.criDescUp_, space); // Fixup the sequence function expression. This requires the standard // expression fixup plus initializing the GetRow method for the sequence // clauses. // if (sequenceExpr()) { ((ExpSequenceExpression*)sequenceExpr())->seqFixup ((void*)this, GetHistoryRow, GetHistoryRowOLAP); sequenceExpr()->fixup(0, getExpressionMode(), this, space, heap_, FALSE, glob); } if (returnExpr()) { ((ExpSequenceExpression*)returnExpr())->seqFixup ((void*)this, GetHistoryRow, GetHistoryRowFollowingOLAP); returnExpr()->fixup(0, getExpressionMode(), this, space, heap_, FALSE, glob); } if (postPred()) postPred()->fixup(0, getExpressionMode(), this, space, heap_, FALSE, glob); if (cancelExpr()) cancelExpr()->fixup(0, getExpressionMode(), this, space, heap_, FALSE, glob); if (checkPartitionChangeExpr()) { ((ExpSequenceExpression*)checkPartitionChangeExpr())->seqFixup ((void*)this, GetHistoryRow, GetHistoryRowOLAP); checkPartitionChangeExpr()->fixup(0, getExpressionMode(), this, space, heap_, FALSE, glob); } }