void ExSequenceTcb::registerSubtasks() { ExScheduler *sched = getGlobals()->getScheduler(); ex_tcb :: registerSubtasks(); // Regsiter the I/O event, if overflow is possible if ( isUnboundedFollowing() ) { ioEventHandler_ = sched->registerNonQueueSubtask(sWork,this); // work around: The handler was just created, while clusterDb was created // earlier (in the TCB ctor), so update clusterDb now with the handler ex_assert( clusterDb_ , "Unlimited following and no clusterDb_") ; clusterDb_->ioEventHandler_ = ioEventHandler_ ; } };
// Return FALSE if memory allocation failed. NABoolean ExSequenceTcb::addNewOLAPBuffer(NABoolean checkMemoryPressure) { if ( checkMemoryPressure && ! clusterDb_->enoughMemory(olapBufferSize_) ) return FALSE; // not enought memory (e.g., memory pressure) HashBuffer *tmpBuf; if ( cluster_ ) { tmpBuf = new(heap_) HashBuffer(cluster_); } else { tmpBuf = new(heap_) HashBuffer(olapBufferSize_, allocRowLength_, false, heap_, clusterDb_, &rc_); } if ( tmpBuf == NULL || tmpBuf->getDataPointer() == NULL ) { // LCOV_EXCL_START return FALSE; // no memory // LCOV_EXCL_STOP } if (firstOLAPBuffer_== NULL) { firstOLAPBuffer_ = tmpBuf; lastOLAPBuffer_ = firstOLAPBuffer_; } else { lastOLAPBuffer_->setNext(tmpBuf); tmpBuf->setPrev(lastOLAPBuffer_) ; lastOLAPBuffer_ = tmpBuf; } numberOfOLAPBuffers_++; maxNumberHistoryRows_ = numberOfOLAPBuffers_ * maxRowsInOLAPBuffer_; if(isUnboundedFollowing()) { maxNumberOfRowsReturnedBeforeReadOF_ = (numberOfOLAPBuffers_ - numberOfWinOLAPBuffers_) * maxRowsInOLAPBuffer_; } return TRUE; // no memory problems }
void ComTdbSequence::displayContents(Space * space,ULng32 flag) { ComTdb::displayContents(space,flag & 0xFFFFFFFE); if(flag & 0x00000008) { char buf[100]; str_sprintf(buf, "\nFor ComTdbSequence :"); space->allocateAndCopyToAlignedSpace(buf, str_len(buf), sizeof(short)); str_sprintf(buf,"recLen_ = %d, maxHistoryRows_ = %d, OLAPFlags_ = %b %s", recLen_, maxHistoryRows_, OLAPFlags_, isUnboundedFollowing() ? ", UNBOUNDED_FOLLOWING" : ""); space->allocateAndCopyToAlignedSpace(buf, str_len(buf), sizeof(short)); str_sprintf(buf,"minFollowing_ = %d, OLAPBufferSize_ = %d, maxNumberOfOLAPBuffers_ = %d", minFollowing_,OLAPBufferSize_,maxNumberOfOLAPBuffers_); space->allocateAndCopyToAlignedSpace(buf, str_len(buf), sizeof(short)); str_sprintf(buf,"maxRowsInOLAPBuffer_ = %d, minNumberOfOLAPBuffers_ = %d", maxRowsInOLAPBuffer_, minNumberOfOLAPBuffers_); space->allocateAndCopyToAlignedSpace(buf, str_len(buf), sizeof(short)); str_sprintf(buf, "numberOfWinOLAPBuffers_ = %d, %s memoryQuotaMB = %d", numberOfWinOLAPBuffers_, logDiagnostics() ? "LOG_DIAGNOSTICS," : "", memoryQuotaMB()); space->allocateAndCopyToAlignedSpace(buf, str_len(buf), sizeof(short)); str_sprintf(buf,"%s memUsagePercent = %d, pressureThreshold = %d", isNoOverflow() ? "NO_OVERFLOW," : "", memUsagePercent_,pressureThreshold_); space->allocateAndCopyToAlignedSpace(buf, str_len(buf), sizeof(short)); } if(flag & 0x00000001) { displayExpression(space,flag); displayChildren(space,flag); } }
// 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 }
void ExSequenceTcb::initializeHistory() { currentOLAPBuffer_ = NULL; currentHistRowInOLAPBuffer_ = 0; currentHistRowPtr_ = NULL; currentRetOLAPBuffer_ = NULL; currentRetHistRowInOLAPBuffer_ = 0; currentRetHistRowPtr_ = NULL; numberHistoryRows_ = 0; histRowsToReturn_ = 0; partitionEnd_ = FALSE; // allocate the minimum number of olap buffers if (firstOLAPBuffer_ == NULL) { for (Int32 i = 0 ; i < minNumberOfOLAPBuffers_; i++) { if ( ! addNewOLAPBuffer( FALSE /* No Memory Pressure Check */ ) ) // LCOV_EXCL_START ex_assert(0, "No memory for minimal OLAP window!"); // LCOV_EXCL_STOP } } else { if (!shrinkOLAPBufferList()) // LCOV_EXCL_START ex_assert(0,"initializeHistory-- can not shrink buffer list"); // LCOV_EXCL_STOP } // Initialize all the settings needed for unbounded following (and overflow) if ( isUnboundedFollowing() ) { //last row in partition if (lastRow_ == NULL) { lastRow_ = new(heap_) char[recLen()]; ex_assert( lastRow_ , "No memory available for OLAP Operator"); } // initialize parameters needed for overflow handling OLAPBuffersFlushed_ = FALSE; firstOLAPBufferFromOF_ = NULL; numberOfOLAPBuffersFromOF_ = 0; memoryPressureDetected_ = FALSE; numberOfRowsReturnedBeforeReadOF_ = 0; createCluster(); // Cluster needs to know the first buffer in the OLAP list of buffers // (Currently only used when reading buffers from overflow for // "bounded following", where Cluster::read() may need to jump back to // first buffer in the list.) cluster_->firstBufferInList_ = firstOLAPBuffer_ ; } // if ( isUnboundedFollowing() ) }