short ex_tcb::handleError(ex_queue_pair *qparent, ComDiagsArea *inDiagsArea) { if (qparent->up->isFull()) return 1; // Return EOF. ex_queue_entry * up_entry = qparent->up->getTailEntry(); ex_queue_entry * pentry_down = qparent->down->getHeadEntry(); up_entry->upState.parentIndex = pentry_down->downState.parentIndex; up_entry->upState.setMatchNo(0); up_entry->upState.status = ex_queue::Q_SQLERROR; ComDiagsArea *diagsArea = up_entry->getDiagsArea(); if (diagsArea == NULL) diagsArea = ComDiagsArea::allocate(this->getGlobals()->getDefaultHeap()); else diagsArea->incrRefCount (); // the setDiagsArea below will decr the ref count if (inDiagsArea) diagsArea->mergeAfter(*inDiagsArea); up_entry->setDiagsArea (diagsArea); // insert into parent qparent->up->insert(); return 0; }
ComDiagsArea *ExExeUtilLongRunningTcb::getDiagAreaFromUpQueueTail() { ex_queue_entry * up_entry = qparent_.up->getTailEntry(); ComDiagsArea *diagsArea = up_entry->getDiagsArea(); if (diagsArea == NULL) diagsArea = ComDiagsArea::allocate(this->getGlobals()->getDefaultHeap()); else diagsArea->incrRefCount (); // setDiagsArea call below will decr ref count // this is the side-effect of this function. Merge in this object's // diagsarea. if (getDiagsArea()) diagsArea->mergeAfter(*getDiagsArea()); up_entry->setDiagsArea (diagsArea); return diagsArea; }
short ex_tcb::handleDone(ex_queue_pair *qparent, ComDiagsArea *inDiagsArea) { if (qparent->up->isFull()) return 1; // Return EOF. ex_queue_entry * up_entry = qparent->up->getTailEntry(); ex_queue_entry * pentry_down = qparent->down->getHeadEntry(); if (inDiagsArea && inDiagsArea->getNumber(DgSqlCode::WARNING_) > 0) { ComDiagsArea *diagsArea = up_entry->getDiagsArea(); if (diagsArea == NULL) diagsArea = ComDiagsArea::allocate(this->getGlobals()->getDefaultHeap()); else diagsArea->incrRefCount (); // the setDiagsArea below will decr the ref count if (inDiagsArea) diagsArea->mergeAfter(*inDiagsArea); up_entry->setDiagsArea (diagsArea); } up_entry->upState.parentIndex = pentry_down->downState.parentIndex; up_entry->upState.setMatchNo(0); up_entry->upState.status = ex_queue::Q_NO_DATA; // insert into parent qparent->up->insert(); // pstate.matches_ = 0; qparent->down->removeHead(); return 0; }
short ExExeUtilPopulateInMemStatsTcb::work() { // short rc = 0; Lng32 cliRC = 0; // if no parent request, return if (qparent_.down->isEmpty()) return WORK_OK; // if no room in up queue, won't be able to return data/status. // Come back later. if (qparent_.up->isFull()) return WORK_OK; ex_queue_entry * pentry_down = qparent_.down->getHeadEntry(); ExExeUtilPrivateState & pstate = *((ExExeUtilPrivateState*) pentry_down->pstate); // Get the globals stucture of the master executor. ExExeStmtGlobals *exeGlob = getGlobals()->castToExExeStmtGlobals(); ExMasterStmtGlobals *masterGlob = exeGlob->castToExMasterStmtGlobals(); ContextCli * currContext = masterGlob->getStatement()->getContext(); while (1) { switch (step_) { case INITIAL_: { if (getDiagsArea()) { getDiagsArea()->clear(); getDiagsArea()->deAllocate(); } setDiagsArea(ComDiagsArea::allocate(getHeap())); step_ = PROLOGUE_; } break; case PROLOGUE_: { if (disableCQS()) { step_ = ERROR_; break; } if (setSchemaVersion(pimsTdb().sourceTableCatName_)) { step_ = ERROR_; break; } // set sqlparserflags to allow use of volatile schema in queries. masterGlob->getStatement()->getContext()-> setSqlParserFlags(0x10000);//ALLOW_VOLATILE_SCHEMA_IN_TABLE_NAME step_ = DELETE_STATS_; } break; case DELETE_STATS_: { Int32 qry_array_size = sizeof(deleteStatsQuery) / sizeof(QueryString); const QueryString * queryString = deleteStatsQuery;; char * gluedQuery; Lng32 gluedQuerySize; glueQueryFragments(qry_array_size, queryString, gluedQuery, gluedQuerySize); Lng32 extraSpace = ComMAX_3_PART_EXTERNAL_UTF8_NAME_LEN_IN_BYTES /* fullyQualTableName */ + 20 /* UID */ + 200 /* overhead */; char * query = new(getHeap()) char[gluedQuerySize + extraSpace]; str_sprintf(query, gluedQuery, (char*)pimsTdb().inMemHistogramsTableName_, pimsTdb().uid_); cliRC = cliInterface()->executeImmediate(query); if (cliRC >= 0) { str_sprintf(query, gluedQuery, (char*)pimsTdb().inMemHistintsTableName_, pimsTdb().uid_); cliRC = cliInterface()->executeImmediate(query); } // Delete new'd string NADELETEBASIC(gluedQuery, getHeap()); gluedQuery = NULL; NADELETEBASIC(query, getHeap()); query = NULL; if (cliRC < 0) { cliInterface()->allocAndRetrieveSQLDiagnostics(diagsArea_); step_ = ERROR_; } else step_ = POPULATE_HISTOGRAMS_STATS_; } break; case POPULATE_HISTOGRAMS_STATS_: { Int32 qry_array_size = sizeof(populateHistogramsStatsQuery) / sizeof(QueryString); const QueryString * queryString = populateHistogramsStatsQuery;; char * gluedQuery; Lng32 gluedQuerySize; glueQueryFragments(qry_array_size, queryString, gluedQuery, gluedQuerySize); Lng32 extraSpace = ComMAX_3_PART_EXTERNAL_UTF8_NAME_LEN_IN_BYTES /* fullyQualInMemHistTableName */ + 20 /* UID */ + ComMAX_3_PART_EXTERNAL_UTF8_NAME_LEN_IN_BYTES /* fullyQualSourceHistTableName */ + 2 * 10 /*segment name*/ + ComMAX_1_PART_EXTERNAL_UTF8_NAME_LEN_IN_BYTES /*cat name*/ + 10 /*version*/ + ComMAX_1_PART_EXTERNAL_UTF8_NAME_LEN_IN_BYTES /*cat name*/ + ComMAX_1_PART_EXTERNAL_UTF8_NAME_LEN_IN_BYTES /*sch name*/ + ComMAX_1_PART_EXTERNAL_UTF8_NAME_LEN_IN_BYTES /*obj name*/ + 200 /* overhead */; char * query = new(getHeap()) char[gluedQuerySize + extraSpace]; str_sprintf(query, gluedQuery, (char*)pimsTdb().inMemHistogramsTableName_, pimsTdb().uid_, (char*)pimsTdb().sourceHistogramsTableName_, (char*)pimsTdb().sourceTableCatName_, (char*)pimsTdb().sourceTableCatName_, (char*)pimsTdb().sourceTableSchName_, (char*)pimsTdb().sourceTableObjName_ ); cliRC = cliInterface()->executeImmediate(query); // Delete new'd string NADELETEBASIC(gluedQuery, getHeap()); gluedQuery = NULL; NADELETEBASIC(query, getHeap()); query = NULL; if (cliRC < 0) { cliInterface()->allocAndRetrieveSQLDiagnostics(diagsArea_); step_ = ERROR_; } else step_ = POPULATE_HISTINTS_STATS_; } break; case POPULATE_HISTINTS_STATS_: { Int32 qry_array_size = sizeof(populateHistintsStatsQuery) / sizeof(QueryString); const QueryString * queryString = populateHistintsStatsQuery;; char * gluedQuery; Lng32 gluedQuerySize; glueQueryFragments(qry_array_size, queryString, gluedQuery, gluedQuerySize); Lng32 extraSpace = ComMAX_3_PART_EXTERNAL_UTF8_NAME_LEN_IN_BYTES /* fullyQualInMemHistTableName */ + 20 /* UID */ + ComMAX_3_PART_EXTERNAL_UTF8_NAME_LEN_IN_BYTES /* fullyQualSourceHistTableName */ + 2 * 10 /*segment name*/ + ComMAX_1_PART_EXTERNAL_UTF8_NAME_LEN_IN_BYTES /*cat name*/ + 10 /*version*/ + ComMAX_1_PART_EXTERNAL_UTF8_NAME_LEN_IN_BYTES /*cat name*/ + ComMAX_1_PART_EXTERNAL_UTF8_NAME_LEN_IN_BYTES /*sch name*/ + ComMAX_1_PART_EXTERNAL_UTF8_NAME_LEN_IN_BYTES /*obj name*/ + 200 /* overhead */; char * query = new(getHeap()) char[gluedQuerySize + extraSpace]; str_sprintf(query, gluedQuery, (char*)pimsTdb().inMemHistintsTableName_, pimsTdb().uid_, (char*)pimsTdb().sourceHistintsTableName_, (char*)pimsTdb().sourceTableCatName_, (char*)pimsTdb().sourceTableCatName_, (char*)pimsTdb().sourceTableSchName_, (char*)pimsTdb().sourceTableObjName_ ); cliRC = cliInterface()->executeImmediate(query); // Delete new'd string NADELETEBASIC(gluedQuery, getHeap()); gluedQuery = NULL; NADELETEBASIC(query, getHeap()); query = NULL; if (cliRC < 0) { cliInterface()->allocAndRetrieveSQLDiagnostics(diagsArea_); step_ = ERROR_; } else step_ = EPILOGUE_; } break; case EPILOGUE_: case EPILOGUE_AND_ERROR_RETURN_: { // reset sqlparserflags masterGlob->getStatement()->getContext()-> resetSqlParserFlags(0x10000);//ALLOW_VOLATILE_SCHEMA_IN_TABLE_NAME restoreCQS(); if (step_ == EPILOGUE_AND_ERROR_RETURN_) step_ = ERROR_RETURN_; else step_ = DONE_; } break; case ERROR_: { step_ = EPILOGUE_AND_ERROR_RETURN_; } break; case ERROR_RETURN_: { if (qparent_.up->isFull()) return WORK_OK; // Return EOF. ex_queue_entry * up_entry = qparent_.up->getTailEntry(); up_entry->upState.parentIndex = pentry_down->downState.parentIndex; up_entry->upState.setMatchNo(0); up_entry->upState.status = ex_queue::Q_SQLERROR; ComDiagsArea *diagsArea = up_entry->getDiagsArea(); if (diagsArea == NULL) diagsArea = ComDiagsArea::allocate(this->getGlobals()->getDefaultHeap()); if (getDiagsArea()) diagsArea->mergeAfter(*getDiagsArea()); up_entry->setDiagsArea (diagsArea); // insert into parent qparent_.up->insert(); step_ = DONE_; } break; case DONE_: { if (qparent_.up->isFull()) return WORK_OK; // Return EOF. ex_queue_entry * up_entry = qparent_.up->getTailEntry(); up_entry->upState.parentIndex = pentry_down->downState.parentIndex; up_entry->upState.setMatchNo(0); up_entry->upState.status = ex_queue::Q_NO_DATA; // insert into parent qparent_.up->insert(); qparent_.down->removeHead(); step_ = INITIAL_; return WORK_OK; } break; default: break; } } return 0; }
////////////////////////////////////////////////////// // work() for ExExeUtilLongRunningTcb ////////////////////////////////////////////////////// short ExExeUtilLongRunningTcb::work() { short rc = 0; Lng32 cliRC = 0; Int64 rowsDeleted = 0; Int64 transactions = 0; // if no parent request, return if (qparent_.down->isEmpty()) return WORK_OK; // if no room in up queue, won't be able to return data/status. // Come back later. if (qparent_.up->isFull()) return WORK_OK; ex_queue_entry * pentry_down = qparent_.down->getHeadEntry(); ExExeUtilPrivateState & pstate = *((ExExeUtilPrivateState*) pentry_down->pstate); // Get the globals stucture of the ESP if this is an ESP ExExeStmtGlobals *exeGlob = getGlobals()->castToExExeStmtGlobals(); ExEspStmtGlobals *espGlob = exeGlob->castToExEspStmtGlobals(); Int32 espNum = 1; // this is an ESP? if (espGlob != NULL) { espNum = (Int32) espGlob->getMyInstanceNumber(); } while (1) { switch (step_) { case INITIAL_: { step_ = LONG_RUNNING_; } break; case LONG_RUNNING_: { rc = doLongRunning(); if ((rc < 0) || (rc == 100)) { finalizeDoLongRunning(); if (rc <0) step_ = ERROR_; else // rc == 100 - done with all the transactions. step_ = DONE_; } // continue in LONG_RUNNING_ state if (rc >= 0) - success and warning. } break; case DONE_: { if (qparent_.up->isFull()) return WORK_OK; // Return EOF. ex_queue_entry * up_entry = qparent_.up->getTailEntry(); up_entry->upState.parentIndex = pentry_down->downState.parentIndex; up_entry->upState.setMatchNo(0); up_entry->upState.status = ex_queue::Q_NO_DATA; // before sending the Q_NO_DATA, send the rowcount as well thro' // the diagsArea. getDiagsArea()->setRowCount(getRowsDeleted()); ComDiagsArea *diagsArea = getDiagAreaFromUpQueueTail(); if (lrTdb().longRunningQueryPlan()) { (*diagsArea) << DgSqlCode(8450) << DgString0((char*)exeUtilTdb().getTableName()) << DgInt0(espNum) << DgInt1((Lng32)getTransactionCount()); } // insert into parent qparent_.up->insert(); //pstate.matches_ = 0; // reset the parameters. step_ = INITIAL_; transactions_ = 0; rowsDeleted_ = 0; initial_ = 1; // clear diags if any if (getDiagsArea()) { getDiagsArea()->clear(); } qparent_.down->removeHead(); return WORK_OK; } break; case ERROR_: { if (qparent_.up->isFull()) return WORK_OK; // Return EOF. ex_queue_entry * up_entry = qparent_.up->getTailEntry(); up_entry->upState.parentIndex = pentry_down->downState.parentIndex; up_entry->upState.setMatchNo(0); up_entry->upState.status = ex_queue::Q_SQLERROR; // get rows deleted so far. getDiagsArea()->setRowCount(getRowsDeleted()); ComDiagsArea *diagsArea = up_entry->getDiagsArea(); if (diagsArea == NULL) diagsArea = ComDiagsArea::allocate(this->getGlobals()->getDefaultHeap()); else diagsArea->incrRefCount (); // setDiagsArea call below will decr ref count if (getDiagsArea()) diagsArea->mergeAfter(*getDiagsArea()); up_entry->setDiagsArea (diagsArea); // insert into parent qparent_.up->insert(); // clear diags if any, since we already sent the information // up and don't want to send it again as part of DONE_ if (getDiagsArea()) { rowsDeleted_ = 0; getDiagsArea()->clear(); } step_ = DONE_; } break; } // switch } // while }
short ExIarTcb::work() { // The work method does the actual extraction, selection, and projection // work. There are 4 possible states: // IAR_NOT_STARTED: This is the initial state before starting the IAR // operation. This is the state that gets set when the // TCB is built and parent queues allocated. // IAR_RETURNING_ROWS: In this state, the operator performs the actual // column extraction from the audit row image, and // projects relevant columns. // IAR_DONE: In this state, Q_NO_DATA is returned in the upqueue to the // parent and state is reinitialized to IAR_NOT_STARTED. // IAR_ERROR: This is the state that is reached if an error occurs in any // other state. The state is changed in this case to IAR_DONE. ex_queue_entry * pentry_down; ExIarPrivateState * pstate; ex_queue::down_request request; while (1) { if (qparent_.down->isEmpty()) return WORK_OK; if (qparent_.up->isFull()) return WORK_OK; pentry_down = qparent_.down->getHeadEntry(); pstate = (ExIarPrivateState *)pentry_down->pstate; request = pentry_down->downState.request; switch (pstate->step_) { case IAR_NOT_STARTED: { if (request == ex_queue::GET_NOMORE) pstate->step_ = IAR_DONE; else pstate->step_ = IAR_RETURNING_ROWS; } break; case IAR_RETURNING_ROWS: { if (qparent_.down->isEmpty()) return WORK_OK; // no more requests - just return. if (qparent_.up->isFull()) return WORK_OK; // parent queue is full. Just return. ex_queue_entry * up_entry = qparent_.up->getTailEntry(); // Copy the input atp into the up queue atp. up_entry->copyAtp(pentry_down); tupp returnedRow; // Allocate space to hold the projected output row to be // returned. #pragma nowarn(1506) if (pool_->get_free_tuple(returnedRow, iarTdb().outputRowLen_)) #pragma warn(1506) return WORK_POOL_BLOCKED; // couldn't allocate, try again later. up_entry->getTupp(iarTdb().criDescUp_->noTuples()-1) = returnedRow; tupp extractedRow; // Allocate space to hold the extracted row. #pragma nowarn(1506) if (pool_->get_free_tuple(extractedRow, iarTdb().extractedRowLen_)) #pragma warn(1506) return WORK_POOL_BLOCKED; // couldn't allocate, try again later. workAtp_->getTupp(2) = extractedRow; ex_expr::exp_return_type retCode; if (iarTdb().getExtractExpr()) { retCode = iarTdb().getExtractExpr()->eval(pentry_down->getAtp(), workAtp_); if (retCode == ex_expr::EXPR_ERROR) { // Set the diagnostics area in the up queue entry. ComDiagsArea *upEntryDiags = up_entry->getDiagsArea(); ComDiagsArea *da = pentry_down->getAtp()->getDiagsArea(); if (!upEntryDiags) { upEntryDiags = ComDiagsArea::allocate(getGlobals()->getDefaultHeap()); up_entry->setDiagsArea(upEntryDiags); } upEntryDiags->mergeAfter(*da); pstate->step_ = IAR_ERROR; break; } } // Evaluate the selection predicate, if any. if (iarTdb().getScanExpr()) { retCode = iarTdb().getScanExpr()->eval(pentry_down->getAtp(), workAtp_); if (retCode == ex_expr::EXPR_FALSE) { pstate->step_ = IAR_DONE; break; } else { if (retCode == ex_expr::EXPR_ERROR) { // Set the diagnostics area in the up queue entry. ComDiagsArea *upEntryDiags = up_entry->getDiagsArea(); ComDiagsArea *da = pentry_down->getAtp()->getDiagsArea(); if (!upEntryDiags) { upEntryDiags = ComDiagsArea::allocate(getGlobals()->getDefaultHeap()); up_entry->setDiagsArea(upEntryDiags); } upEntryDiags->mergeAfter(*da); pstate->step_ = IAR_ERROR; break; } } } // Evaluate the projection expression, if any. if (iarTdb().getProjExpr()) { retCode = iarTdb().getProjExpr()->eval(up_entry->getAtp(), workAtp_); if (retCode == ex_expr::EXPR_ERROR) { pstate->step_ = IAR_ERROR; break; } } up_entry->upState.status = ex_queue::Q_OK_MMORE; up_entry->upState.parentIndex = pentry_down->downState.parentIndex; up_entry->upState.downIndex = qparent_.down->getHeadIndex(); pstate->matchCount_++; up_entry->upState.setMatchNo(pstate->matchCount_); qparent_.up->insert(); pstate->step_ = IAR_DONE; } break; case IAR_DONE: { if (qparent_.up->isFull()) return WORK_OK; // parent queue is full. Just return. ex_queue_entry * up_entry = qparent_.up->getTailEntry(); up_entry->upState.parentIndex = pentry_down->downState.parentIndex; up_entry->upState.setMatchNo(pstate->matchCount_); up_entry->upState.status = ex_queue::Q_NO_DATA; qparent_.up->insert(); workAtp_->release(); qparent_.down->removeHead(); pstate->step_ = IAR_NOT_STARTED; } break; case IAR_ERROR: { if (qparent_.up->isFull()) return WORK_OK; ex_queue_entry * up_entry = qparent_.up->getTailEntry(); up_entry->upState.parentIndex = pentry_down->downState.parentIndex; up_entry->upState.setMatchNo(pstate->matchCount_); up_entry->upState.status = ex_queue::Q_SQLERROR; // insert into parent qparent_.up->insert(); pstate->step_ = IAR_DONE; } break; default: ex_assert(FALSE, "Invalid step in TCB down queue"); break; } } #pragma nowarn(203) return WORK_OK; #pragma warn(203) };
// Insert a single entry into the up queue and optionally // remove the head of the down queue // // Right now this function does not handle data rows, only error // and end-of-data. It could possibly be extended to handle a data // row. I have not looked at that closely enough yet. // void ExFastExtractTcb::insertUpQueueEntry(ex_queue::up_status status, ComDiagsArea *diags, NABoolean popDownQueue) { ex_queue_entry *upEntry = qParent_.up->getTailEntry(); ex_queue_entry *downEntry = qParent_.down->getHeadEntry(); ExFastExtractPrivateState &privateState = *((ExFastExtractPrivateState *) downEntry->pstate); // Initialize the up queue entry. // // copyAtp() will copy all tuple pointers and the diags area from // the down queue entry to the up queue entry. // // When we return Q_NO_DATA if the match count is > 0: // * assume down queue diags were returned with the Q_OK_MMORE entries // * release down queue diags before copyAtp() // if (status == ex_queue::Q_NO_DATA && privateState.matchCount_ > 0) { downEntry->setDiagsArea(NULL); upEntry->copyAtp(downEntry); } else { upEntry->copyAtp(downEntry); downEntry->setDiagsArea(NULL); } upEntry->upState.status = status; upEntry->upState.parentIndex = downEntry->downState.parentIndex; upEntry->upState.downIndex = qParent_.down->getHeadIndex(); upEntry->upState.setMatchNo(privateState.matchCount_); // Move any diags to the up queue entry if (diags != NULL) { ComDiagsArea *atpDiags = upEntry->getDiagsArea(); if (atpDiags == NULL) { // setDiagsArea() does not increment the reference count upEntry->setDiagsArea(diags); diags->incrRefCount(); } else { atpDiags->mergeAfter(*diags); } } // Insert into up queue qParent_.up->insert(); // Optionally remove the head of the down queue if (popDownQueue) { privateState.init(); qParent_.down->removeHead(); } }
short ExTupleFlowTcb::work() { // This is some sort of a hack to fix the problems with the number of rows // inserted returned to the user for packed tables. For these tables, rows // are packed (by the Pack node which is the left child of this tuple flow) // before they are sent off to DP2. DP2 has no idea that it's actually // inserting multiple logical rows (as perceived by the user). However, // there is actually a hidden count of logical rows stored as the first 4 // bytes of the packed row. This counter is supposed to keep track of a sum // of this number in each packed row it gets from the left. When all // insertions are done, this sum is used to override what's stored by the // PA node in the executor global area the number of rows inserted. This is // not a very good place to have this fix, but since this is a low-priority // problem at this time, here we are. // // // NB: The code introduced for this fix // could be safely removed if desired. Also, all changes are within // this file. // if (qParent_.down->isEmpty()) return WORK_OK; ex_queue_entry * pentry_down = qParent_.down->getHeadEntry(); ExTupleFlowPrivateState & pstate = *((ExTupleFlowPrivateState*) pentry_down->pstate); if ((tflowTdb().userSidetreeInsert()) && (pentry_down->downState.request == ex_queue::GET_EOD) && (NOT pstate.parentEOD_)) { pstate.step_ = MOVE_EOD_TO_TGT_; } else if ((pstate.step_ != DONE_) && (pstate.step_ != CANCELLED_) && (pentry_down->downState.request == ex_queue::GET_NOMORE)) { if (pstate.step_ == EMPTY_) pstate.step_ = DONE_; else pstate.step_ = CANCELLED_; } while (1) { switch (pstate.step_) { case EMPTY_: { if (qSrc_.down->isFull()) return WORK_OK; ex_queue_entry * src_entry = qSrc_.down->getTailEntry(); src_entry->downState.request = pentry_down->downState.request; src_entry->downState.requestValue = pentry_down->downState.requestValue; if ((tflowTdb().firstNRows() >= 0) && (pentry_down->downState.request != ex_queue::GET_N)) { src_entry->downState.request = ex_queue::GET_N; src_entry->downState.requestValue = tflowTdb().firstNRows(); } src_entry->downState.parentIndex = qParent_.down->getHeadIndex(); src_entry->passAtp(pentry_down); qSrc_.down->insert(); // just checking to make sure we got a diags area from the CLI if we are // executing a non-tomic insert. This is done now so that we don't have to do it in multiple // places later. if (tflowTdb().isNonFatalErrorTolerated()) { ComDiagsArea *cliDiagsArea = pentry_down->getDiagsArea(); ex_assert(cliDiagsArea, "In Tupleflow : Non-Atomic insert received no diags area from the CLI"); } pstate.parentEOD_ = FALSE; pstate.srcEOD_ = FALSE; pstate.matchCount_ = 0; pstate.tgtRequests_ = 0; pstate.tgtRowsSent_ = FALSE; pstate.noOfUnPackedRows_ = 0; pstate.srcRequestCount_ = -1; pstate.nonFatalErrorSeen_ = FALSE; // Set startRightIndex_ so that CancelReques doesn't do anything. pstate.startRightIndex_ = pstate.srcRequestCount_; pstate.step_ = MOVE_SRC_TO_TGT_; } break; case MOVE_SRC_TO_TGT_: { // if there are some rows in source up queue, move them to target. while ((! qSrc_.up->isEmpty()) && (! qTgt_.down->isFull()) && (pstate.step_ != HANDLE_ERROR_)) { ex_queue_entry * src_entry = qSrc_.up->getHeadEntry(); ex_queue_entry * tgt_entry = qTgt_.down->getTailEntry(); switch (src_entry->upState.status) { case ex_queue::Q_OK_MMORE: { // move this source row to target. // LCOV_EXCL_START // BEGIN: - Read note at beginning of work(). // if (tcbSrc_->getNodeType() == ComTdb::ex_PACKROWS) { char* packTuppPtr = src_entry->getTupp(src_entry->numTuples()-1) .getDataPointer(); Int32 noOfRows = *((Int32 *)packTuppPtr); pstate.noOfUnPackedRows_ += (noOfRows - 1); } // // END:- Read note at beginning of work(). // LCOV_EXCL_STOP pstate.srcRequestCount_++; tgt_entry->downState.request = pentry_down->downState.request; tgt_entry->downState.requestValue = pentry_down->downState.requestValue; tgt_entry->downState.parentIndex = (Lng32) pstate.srcRequestCount_; tgt_entry->copyAtp(src_entry); qTgt_.down->insert(); pstate.tgtRequests_++; pstate.tgtRowsSent_ = TRUE; qSrc_.up->removeHead(); } break; case ex_queue::Q_NO_DATA: { if ((tflowTdb().vsbbInsertOn()) && (pstate.tgtRowsSent_ == TRUE)) { if (tflowTdb().userSidetreeInsert()) { tgt_entry->downState.request = ex_queue::GET_EOD_NO_ST_COMMIT; } else { tgt_entry->downState.request = ex_queue::GET_EOD; } tgt_entry->downState.requestValue = pentry_down->downState.requestValue; tgt_entry->downState.parentIndex = (Lng32) pstate.srcRequestCount_; tgt_entry->copyAtp(src_entry); qTgt_.down->insert(); pstate.tgtRequests_++; } // LCOV_EXCL_START if ((pstate.tgtRowsSent_ == FALSE) && (src_entry->getDiagsArea())) { // a warning is returned with EOD and // nothing else was returned from source. // Move warning to parent's up queue. if (qParent_.up->isFull()) return WORK_OK; ex_queue_entry * up_entry = qParent_.up->getTailEntry(); up_entry->setDiagsArea(src_entry->getDiagsArea()); } // LCOV_EXCL_STOP qSrc_.up->removeHead(); pstate.srcEOD_ = TRUE; // LCOV_EXCL_START if (tflowTdb().sendEODtoTgt()) pstate.step_ = MOVE_EOD_TO_TGT_; // LCOV_EXCL_STOP } break; case ex_queue::Q_SQLERROR: { if (qParent_.up->isFull()) return WORK_OK; ex_queue_entry * pentry = qParent_.up->getTailEntry(); ComDiagsArea * da = src_entry->getDiagsArea(); ex_assert(da, "We have a Q_SQLERROR in Tupleflow but no diags area"); if (tflowTdb().isNonFatalErrorTolerated() && (da->getNextRowNumber(ComCondition::NONFATAL_ERROR) == ComCondition::NONFATAL_ERROR)) { pstate.nonFatalErrorSeen_ = TRUE; } else { pstate.step_ = HANDLE_ERROR_; pstate.nonFatalErrorSeen_ = FALSE; } pstate.srcRequestCount_++; if(tflowTdb().isRowsetIterator()) da->setAllRowNumber((Lng32) pstate.srcRequestCount_); ComDiagsArea *accumulatedDiagsArea = pentry->getDiagsArea(); if (accumulatedDiagsArea) { accumulatedDiagsArea->mergeAfter(*da); if (!(accumulatedDiagsArea->canAcceptMoreErrors()) && tflowTdb().isNonFatalErrorTolerated()) { pstate.nonFatalErrorSeen_ = FALSE; pstate.step_ = HANDLE_ERROR_; } } else { pentry->setDiagsArea(da); da->incrRefCount(); accumulatedDiagsArea = da ; if (tflowTdb().isNonFatalErrorTolerated()) { ComDiagsArea *cliDiagsArea = pentry_down->getDiagsArea(); da->setLengthLimit(cliDiagsArea->getLengthLimit()); } } // For Non-Fatal errors we will remove this Q_SQLERROR reply from the // left child right below as we will continue to stay in this state (MOVE_SRC_TO_TGT_). // For fatal errors this Q_SQLERROR reply is removed in HANDLE_ERROR step to which // we will transition immediately. if (pstate.nonFatalErrorSeen_ == TRUE) qSrc_.up->removeHead(); } break; case ex_queue::Q_REC_SKIPPED: { pstate.srcRequestCount_++; ComDiagsArea * da = src_entry->getDiagsArea(); if (da) pstate.nonFatalErrorSeen_ = TRUE; qSrc_.up->removeHead(); } break; default: { ex_assert(0, "ExTupleFlowTcb::work() Error returned from src"); // LCOV_EXCL_LINE } break; } // switch } // while // if the child reply is not an Q_SQLERROR, then process target if ((pstate.step_ != HANDLE_ERROR_) && (pstate.step_ != MOVE_EOD_TO_TGT_)) pstate.step_ = PROCESS_TGT_; } // MOVE_SRC_TO_TGT break; case MOVE_EOD_TO_TGT_: { pstate.parentEOD_ = TRUE; if (qTgt_.down->isFull()) return WORK_OK; ex_queue_entry * tgt_entry = qTgt_.down->getTailEntry(); tgt_entry->downState.request = ex_queue::GET_EOD; tgt_entry->downState.requestValue = pentry_down->downState.requestValue; tgt_entry->downState.parentIndex = qParent_.down->getHeadIndex(); //tgt_entry->passAtp(pentry_down); qTgt_.down->insert(); pstate.tgtRequests_++; // LCOV_EXCL_START if (tflowTdb().sendEODtoTgt()) pstate.srcEOD_ = TRUE; // LCOV_EXCL_STOP else pstate.srcEOD_ = FALSE; pstate.step_ = PROCESS_TGT_; } break; case PROCESS_TGT_: { while (! qTgt_.up->isEmpty() && pstate.step_ != HANDLE_ERROR_) { ex_queue_entry * tgt_entry = qTgt_.up->getHeadEntry(); switch (tgt_entry->upState.status) { case ex_queue::Q_OK_MMORE: { if (!tflowTdb().isNonFatalErrorTolerated()) { // ex_assert(0, "ExTupleFlowTcb::work() OK_MMORE from tgt"); if (qParent_.up->isFull()) return WORK_OK; ex_queue_entry * pentry = qParent_.up->getTailEntry(); pentry->upState.status = ex_queue::Q_OK_MMORE; pentry->upState.downIndex = qParent_.down->getHeadIndex(); pentry->upState.parentIndex = pentry_down->downState.parentIndex; pentry->upState.setMatchNo(pstate.matchCount_); // copy input tupps from parent request pentry->copyAtp(pentry_down); // copy child's atp to // the output atp (to parent's up queue) pentry->copyAtp(tgt_entry); // insert into parent up queue qParent_.up->insert(); } else { ComDiagsArea * da = tgt_entry->getDiagsArea(); ex_assert(da, "We have a Q_OK_MMORE in Tupleflow but no diags area"); if (da->mainSQLCODE() != 0) { // Non-atomic Rowsets sends OK_MMORE with non-empty diags from child // empty diags (mainsqlcode == 0) implies OK_MMORE sent by ignoreDupKey code // when NAR is on, for -8102 error. Just consume the OK_MMORE. if(tflowTdb().isRowsetIterator()) { da->setAllRowNumber(Lng32 (tgt_entry->upState.parentIndex)); } pstate.nonFatalErrorSeen_ = TRUE; ex_queue_entry * pentry = qParent_.up->getTailEntry(); ComDiagsArea *accumulatedDiagsArea = pentry->getDiagsArea(); if (accumulatedDiagsArea) { accumulatedDiagsArea->mergeAfter(*da); if (!(accumulatedDiagsArea->canAcceptMoreErrors()) && tflowTdb().isNonFatalErrorTolerated()) { pstate.nonFatalErrorSeen_ = FALSE; pstate.step_ = HANDLE_ERROR_; } } else { pentry->setDiagsArea(da); da->incrRefCount(); if (tflowTdb().isNonFatalErrorTolerated()) { ComDiagsArea *cliDiagsArea = pentry_down->getDiagsArea(); da->setLengthLimit(cliDiagsArea->getLengthLimit()); } } } } qTgt_.up->removeHead(); } break; case ex_queue::Q_NO_DATA: { ComDiagsArea * da = tgt_entry->getDiagsArea(); if (da) { ex_queue_entry * pentry = qParent_.up->getTailEntry(); ComDiagsArea *accumulatedDiagsArea = pentry->getDiagsArea(); if (accumulatedDiagsArea) accumulatedDiagsArea->mergeAfter(*da); else { pentry->setDiagsArea(da); da->incrRefCount(); if (tflowTdb().isNonFatalErrorTolerated()) { ComDiagsArea *cliDiagsArea = pentry_down->getDiagsArea(); da->setLengthLimit(cliDiagsArea->getLengthLimit()); } } } pstate.matchCount_ += tgt_entry->upState.getMatchNo(); qTgt_.up->removeHead(); pstate.tgtRequests_--; pstate.startRightIndex_++; } break; case ex_queue::Q_SQLERROR: { if (qParent_.up->isFull()) return WORK_OK; ex_queue_entry * pentry = qParent_.up->getTailEntry(); pentry->copyAtp(tgt_entry); pstate.nonFatalErrorSeen_ = FALSE; pstate.step_ = HANDLE_ERROR_; if(tflowTdb().isRowsetIterator()) { ex_queue_entry * pentry = qParent_.up->getTailEntry(); ComDiagsArea *da = pentry->getDiagsArea(); ex_assert(da, "To set RowNumber, an error condition must be present in the diags area"); da->setAllRowNumber(Lng32 (tgt_entry->upState.parentIndex)); } } break; default: { ex_assert(0, "ExTupleFlowTcb::work() Error returned from tgt"); // LCOV_EXCL_LINE } break; } // switch } // while if (pstate.step_ == HANDLE_ERROR_) break; // if source has returned EOD, // and there are no pending requests in target's down // queue, then we are done with this parent request. if (((pstate.srcEOD_ == TRUE) || (pstate.parentEOD_ == TRUE)) && (qTgt_.down->isEmpty())) pstate.step_ = DONE_; else { if (NOT pstate.parentEOD_) pstate.step_ = MOVE_SRC_TO_TGT_; if (qSrc_.up->isEmpty() || qTgt_.down->isFull()) return WORK_OK; else return WORK_CALL_AGAIN; } } break; case HANDLE_ERROR_: { ex_queue_entry * pentry = qParent_.up->getTailEntry(); pentry->upState.status = ex_queue::Q_SQLERROR; pentry->upState.downIndex = qParent_.down->getHeadIndex(); pentry->upState.parentIndex = pentry_down->downState.parentIndex; pentry->upState.setMatchNo(pstate.matchCount_); ComDiagsArea *da = pentry->getDiagsArea(); if (tflowTdb().isNonFatalErrorTolerated() && !(da->canAcceptMoreErrors())) { ComDiagsArea *cliDiagsArea = pentry_down->getDiagsArea(); da->removeLastErrorCondition(); *da << DgSqlCode(-EXE_NONATOMIC_FAILURE_LIMIT_EXCEEDED) << DgInt0(cliDiagsArea->getLengthLimit()); } // insert into parent up queue qParent_.up->insert(); pstate.step_ = CANCELLED_; } break; case CANCELLED_: { qSrc_.down->cancelRequestWithParentIndex(qParent_.down->getHeadIndex()); // Cancel all the outstanding requests that have been sent to the target. // Cancel all requests within given range (inclusive) qTgt_.down->cancelRequestWithParentIndexRange((queue_index)pstate.startRightIndex_+1, (queue_index)pstate.srcRequestCount_); pstate.startRightIndex_ = pstate.srcRequestCount_; //ignore all rows from source child, till Q_NO_DATA is reached while ((pstate.srcEOD_ != TRUE) && (!qSrc_.up->isEmpty())) { ex_queue_entry * src_entry = qSrc_.up->getHeadEntry(); switch(src_entry->upState.status) { case ex_queue::Q_OK_MMORE: case ex_queue::Q_SQLERROR: case ex_queue::Q_REC_SKIPPED: { qSrc_.up->removeHead(); } break; case ex_queue::Q_NO_DATA: { pstate.srcEOD_ = TRUE; qSrc_.up->removeHead(); } break; default: { ex_assert(0, "ExTupleFlowTcb::work() Error returned from src"); // LCOV_EXCL_LINE } break; } } //ignore all rows from target child, till Q_NO_DATA is reached while (pstate.tgtRequests_ && !qTgt_.up->isEmpty()) { ex_queue_entry * tgt_entry = qTgt_.up->getHeadEntry(); switch(tgt_entry->upState.status) { case ex_queue::Q_OK_MMORE: case ex_queue::Q_SQLERROR: { qTgt_.up->removeHead(); } break; case ex_queue::Q_NO_DATA: { qTgt_.up->removeHead(); pstate.tgtRequests_--; } break; default: { ex_assert(0, "ExTupleFlowTcb::work() Error returned from tgt"); // LCOV_EXCL_LINE } break; } } // if both source and target returned all the rows, // insert Q_SQLERROR into the parent up queue if ((pstate.srcEOD_ == TRUE) && !pstate.tgtRequests_) { pstate.step_ = DONE_; } else return WORK_OK; } break; case DONE_: { if (qParent_.up->isFull()) return WORK_OK; ex_queue_entry * pentry = qParent_.up->getTailEntry(); if (pstate.nonFatalErrorSeen_) { ComDiagsArea *da = pentry->getDiagsArea(); ComDiagsArea *cliDiagsArea = pentry_down->getDiagsArea(); ex_assert((da || cliDiagsArea), "We have non-fatal errors in Tupleflow but no diags area"); if (cliDiagsArea) { if (da) da->mergeAfter(*cliDiagsArea); else { pentry->setDiagsArea(cliDiagsArea); cliDiagsArea->incrRefCount(); } } if (cliDiagsArea->canAcceptMoreErrors()) { ComDiagsArea *mergedDiagsArea = pentry->getDiagsArea(); // used to make mainSQLCODE() return 30022 or 30035. mergedDiagsArea->setNonFatalErrorSeen(TRUE); NABoolean anyRowsAffected = FALSE; // This tupleflow should be in the master for // non-atomic rowsets. ExMasterStmtGlobals *g = getGlobals()-> castToExExeStmtGlobals()->castToExMasterStmtGlobals(); ex_assert(g, "Rowset insert has a flow node that is not in the master executor"); if (g->getRowsAffected() > 0) anyRowsAffected = TRUE; if (anyRowsAffected) *mergedDiagsArea << DgSqlCode(EXE_NONFATAL_ERROR_SEEN); else *mergedDiagsArea << DgSqlCode(EXE_NONFATAL_ERROR_ON_ALL_ROWS); } // we exceeded the Nonfatal error limit when merging with the CLI diags area else { pstate.step_ = HANDLE_ERROR_; // will prevent us from merging the diags areas again pstate.nonFatalErrorSeen_ = FALSE ; break ; } } pentry->upState.status = ex_queue::Q_NO_DATA; pentry->upState.downIndex = qParent_.down->getHeadIndex(); pentry->upState.parentIndex = pentry_down->downState.parentIndex; pentry->upState.setMatchNo(pstate.matchCount_); // LCOV_EXCL_START // BEGIN: Read note at beginning of work(). // if(pstate.noOfUnPackedRows_ != 0) { ComDiagsArea *da = pentry->getDiagsArea(); if (da == NULL) { da = ComDiagsArea::allocate(getGlobals()->getDefaultHeap()); pentry->setDiagsArea(da); } da->addRowCount(pstate.noOfUnPackedRows_); pstate.noOfUnPackedRows_ = 0; } // // END: - Read note at beginning of work(). // LCOV_EXCL_STOP // if stats are to be collected, collect them. if (getStatsEntry()) { // nothing yet returned from right child or returned // to parent. getStatsEntry()->setActualRowsReturned(0); } // insert into parent up queue qParent_.up->insert(); pstate.step_ = EMPTY_; qParent_.down->removeHead(); return WORK_CALL_AGAIN; // check for more down requests } break; } // switch pstate.step_ } // while #pragma nowarn(203) // warning elimination return 0; #pragma warn(203) // warning elimination }
void ExProbeCacheTcb::makeReplyToParentUp(ex_queue_entry *pentry_down, ExProbeCachePrivateState &pstate, ex_queue::up_status reply_status) { ExOperStats *stats; ex_queue_entry * up_entry = qparent_.up->getTailEntry(); Int32 rowQualifies = 1; // Copy the pointers to the input data from parent up_entry->copyAtp(pentry_down); if ((reply_status == ex_queue::Q_OK_MMORE) && (pstate.pcEntry_->innerRowTupp_.isAllocated())) { // Use the pcEntry_ to set the returned tuple from // the pool. up_entry->getAtp()->getTupp(probeCacheTdb().tuppIndex_) = pstate.pcEntry_->innerRowTupp_; if (selectPred()) { ex_expr::exp_return_type evalRetCode = selectPred()->eval(up_entry->getAtp(), 0); if (evalRetCode == ex_expr::EXPR_FALSE) rowQualifies = 0; else if (evalRetCode != ex_expr::EXPR_TRUE) { ex_assert(evalRetCode == ex_expr::EXPR_ERROR, "invalid return code from expr eval"); // diags area should have been generated reply_status = ex_queue::Q_SQLERROR; } } } if (rowQualifies) { // Initialize the upState. up_entry->upState.parentIndex = pentry_down->downState.parentIndex; up_entry->upState.downIndex = qparent_.down->getHeadIndex(); up_entry->upState.setMatchNo(pstate.matchCount_); up_entry->upState.status = reply_status; // Give the reply any diagsArea. Test pcEntry_ before using it // because a request that went from CANCELED_NOT_STARTED to // DONE will never be hooked up with a pcEntry_. if (pstate.pcEntry_ && pstate.pcEntry_->diagsArea_) { ComDiagsArea *accumulatedDiagsArea = up_entry->getDiagsArea(); if (accumulatedDiagsArea) accumulatedDiagsArea->mergeAfter(*pstate.pcEntry_->diagsArea_); else { up_entry->setDiagsArea(pstate.pcEntry_->diagsArea_); pstate.pcEntry_->diagsArea_->incrRefCount(); } } // Insert the reply. qparent_.up->insert(); if ((stats = getStatsEntry()) != NULL && reply_status == ex_queue::Q_OK_MMORE) stats->incActualRowsReturned(); } return; }