ExWorkProcRetcode ExCancelTcb::work() { ExMasterStmtGlobals *masterGlobals = getGlobals()->castToExExeStmtGlobals()->castToExMasterStmtGlobals(); CliGlobals *cliGlobals = masterGlobals->getCliGlobals(); while ((qparent_.down->isEmpty() == FALSE) && (qparent_.up->isFull() == FALSE)) { ex_queue_entry *pentry_down = qparent_.down->getHeadEntry(); switch (step_) { case NOT_STARTED: { if (pentry_down->downState.request == ex_queue::GET_NOMORE) step_ = DONE; else { retryCount_ = 0; // Priv checking is done during compilation. To support // REVOKE, prevent a prepared CANCEL/SUSPEND/ACTIVATE // that was compiled more than 1 second ago from executing // by raising the 8734 error to force an AQR. Int64 microSecondsSinceCompile = NA_JulianTimestamp() - masterGlobals->getStatement()->getCompileEndTime(); if (microSecondsSinceCompile > 1000*1000) { ComDiagsArea *diagsArea = ComDiagsArea::allocate(getGlobals()->getDefaultHeap()); *diagsArea << DgSqlCode(-CLI_INVALID_QUERY_PRIVS); reportError(diagsArea); step_ = DONE; break; } // Figure out which MXSSMP broker to use. if (cancelTdb().getAction() == ComTdbCancel::CancelByPname) { int nid = -1; int rc = msg_mon_get_process_info(cancelTdb().getCancelPname(), &nid, &pid_); switch (rc) { case XZFIL_ERR_OK: cpu_ = (short) nid; break; case XZFIL_ERR_NOTFOUND: case XZFIL_ERR_BADNAME: case XZFIL_ERR_NOSUCHDEV: { ComDiagsArea *diagsArea = ComDiagsArea::allocate(getGlobals()->getDefaultHeap()); *diagsArea << DgSqlCode(-EXE_CANCEL_PROCESS_NOT_FOUND); *diagsArea << DgString0(cancelTdb().getCancelPname()); reportError(diagsArea); step_ = DONE; break; } default: { char buf[200]; str_sprintf(buf, "Unexpected error %d returned from " "msg_mon_get_process_info", rc); ex_assert(0, buf); } } if (step_ != NOT_STARTED) break; } else if (cancelTdb().getAction() == ComTdbCancel::CancelByNidPid) { cpu_ = (short) cancelTdb().getCancelNid(); pid_ = cancelTdb().getCancelPid(); // check that process exists, if not report error. char processName[MS_MON_MAX_PROCESS_NAME]; int rc = msg_mon_get_process_name(cpu_, pid_, processName); if (XZFIL_ERR_OK == rc) ; // good. nid & pid are valid. else { if ((XZFIL_ERR_NOTFOUND != rc) && (XZFIL_ERR_BADNAME != rc) && (XZFIL_ERR_NOSUCHDEV != rc)) { // Log rc in case it needs investigation later. char buf[200]; str_sprintf(buf, "Unexpected error %d returned from " "msg_mon_get_process_name", rc); SQLMXLoggingArea::logExecRtInfo(__FILE__, __LINE__, buf, 0); } char nid_pid_str[32]; str_sprintf(nid_pid_str, "%d, %d", cpu_, pid_); ComDiagsArea *diagsArea = ComDiagsArea::allocate(getGlobals()->getDefaultHeap()); *diagsArea << DgSqlCode(-EXE_CANCEL_PROCESS_NOT_FOUND); *diagsArea << DgString0(nid_pid_str); reportError(diagsArea); step_ = DONE; break; } } else { char * qid = cancelTdb().qid_; Lng32 qid_len = str_len(qid); // This static method is defined in SqlStats.cpp. It side-effects // the nodeName and cpu_ according to the input qid. if (getMasterCpu( qid, qid_len, nodeName_, sizeof(nodeName_) - 1, cpu_) == -1) { ComDiagsArea *diagsArea = ComDiagsArea::allocate(getGlobals()->getDefaultHeap()); *diagsArea << DgSqlCode(-EXE_RTS_INVALID_QID); reportError(diagsArea); step_ = DONE; break; } } // Testpoints for hard to reproduce problems: bool fakeError8028 = false; fakeError8028 = (getenv("HP_FAKE_ERROR_8028") != NULL); if ((cliGlobals->getCbServerClass() == NULL) || fakeError8028) { ComDiagsArea *diagsArea = ComDiagsArea::allocate(getGlobals()->getDefaultHeap()); *diagsArea << DgSqlCode(-EXE_CANCEL_PROCESS_NOT_FOUND); *diagsArea << DgString0("$ZSM000"); reportError(diagsArea); step_ = DONE; break; } ComDiagsArea *diagsArea = NULL; bool fakeError2024 = false; fakeError2024 = (getenv("HP_FAKE_ERROR_2024") != NULL); if (fakeError2024) { cbServer_ = NULL; diagsArea = ComDiagsArea::allocate(getGlobals()->getDefaultHeap()); if (getenv("HP_FAKE_ERROR_8142")) { *diagsArea << DgSqlCode(-8142); *diagsArea << DgString0(__FILE__); *diagsArea << DgString1("cbServer_ is NULL"); } else *diagsArea << DgSqlCode(-2024); } else cbServer_ = cliGlobals->getCbServerClass()->allocateServerProcess( &diagsArea, cliGlobals->getEnvironment()->getHeap(), nodeName_, cpu_, IPC_PRIORITY_DONT_CARE, FALSE, // usesTransactions TRUE, // waitedCreation 2 // maxNowaitRequests -- cancel+(1 extra). ); if (cbServer_ == NULL || cbServer_->getControlConnection() == NULL) { ex_assert(diagsArea != NULL, "allocateServerProcess failed, but no diags"); // look for SQLCode 2024 // "*** ERROR[2024] Server Process $0~string0 // is not running or could not be created. Operating System // Error $1~int0 was returned." // Remap to cancel-specfic error 8028. if (diagsArea->contains(-2024) && cancelTdb().actionIsCancel()) { diagsArea->deleteError(diagsArea->returnIndex(-2024)); reportError(diagsArea, true, EXE_CANCEL_PROCESS_NOT_FOUND, nodeName_, cpu_); } else reportError(diagsArea); step_ = DONE; break; } // the reportError method was not called -- see break above. if (diagsArea != NULL) diagsArea->decrRefCount(); //Create the stream on the IpcHeap, since we don't dispose // of it immediately. We just add it to the list of completed // messages in the IpcEnv, and it is disposed of later. cancelStream_ = new (cliGlobals->getIpcHeap()) CancelMsgStream(cliGlobals->getEnvironment(), this); cancelStream_->addRecipient(cbServer_->getControlConnection()); } step_ = SEND_MESSAGE; break; } // end case NOT_STARTED #pragma warning (disable : 4291) case SEND_MESSAGE: { RtsHandle rtsHandle = (RtsHandle) this; if (cancelTdb().actionIsCancel()) { Int64 cancelStartTime = JULIANTIMESTAMP(); Lng32 firstEscalationInterval = cliGlobals->currContext()-> getSessionDefaults()->getCancelEscalationInterval(); Lng32 secondEscalationInterval = cliGlobals->currContext()-> getSessionDefaults()->getCancelEscalationMxosrvrInterval(); NABoolean cancelEscalationSaveabend = cliGlobals->currContext()-> getSessionDefaults()->getCancelEscalationSaveabend(); bool cancelLogging = (TRUE == cliGlobals->currContext()-> getSessionDefaults()->getCancelLogging()); CancelQueryRequest *cancelMsg = new (cliGlobals->getIpcHeap()) CancelQueryRequest(rtsHandle, cliGlobals->getIpcHeap(), cancelStartTime, firstEscalationInterval, secondEscalationInterval, cancelEscalationSaveabend, cancelTdb().getCommentText(), str_len(cancelTdb().getCommentText()), cancelLogging, cancelTdb().action_ != ComTdbCancel::CancelByQid, pid_, cancelTdb().getCancelPidBlockThreshold()); #pragma warning (default : 4291) *cancelStream_ << *cancelMsg; cancelMsg->decrRefCount(); } else if (ComTdbCancel::Suspend == cancelTdb().action_) { bool suspendLogging = (TRUE == cliGlobals->currContext()-> getSessionDefaults()->getSuspendLogging()); #pragma warning (disable : 4291) SuspendQueryRequest * suspendMsg = new (cliGlobals->getIpcHeap()) SuspendQueryRequest(rtsHandle, cliGlobals->getIpcHeap(), ComTdbCancel::Force == cancelTdb().forced_, suspendLogging); #pragma warning (default : 4291) *cancelStream_ << *suspendMsg; suspendMsg->decrRefCount(); } else { ex_assert( ComTdbCancel::Activate == cancelTdb().action_, "invalid action for ExCancelTcb"); bool suspendLogging = (TRUE == cliGlobals->currContext()-> getSessionDefaults()->getSuspendLogging()); #pragma warning (disable : 4291) ActivateQueryRequest * activateMsg = new (cliGlobals->getIpcHeap()) ActivateQueryRequest(rtsHandle, cliGlobals->getIpcHeap(), suspendLogging); #pragma warning (default : 4291) *cancelStream_ << *activateMsg; activateMsg->decrRefCount(); } if ((cancelTdb().getAction() != ComTdbCancel::CancelByPname) && (cancelTdb().getAction() != ComTdbCancel::CancelByNidPid)) { char * qid = cancelTdb().qid_; Lng32 qid_len = str_len(qid); #pragma warning (disable : 4291) RtsQueryId *rtsQueryId = new (cliGlobals->getIpcHeap()) RtsQueryId( cliGlobals->getIpcHeap(), qid, qid_len); #pragma warning (default : 4291) *cancelStream_ << *rtsQueryId; rtsQueryId->decrRefCount(); } // send a no-wait request to the cancel broker. cancelStream_->send(FALSE); step_ = GET_REPLY; // Come back when I/O completes. return WORK_OK; break; } // end case SEND_MESSAGE case GET_REPLY: { // Handle general IPC error. bool fakeError201 = false; fakeError201 = (getenv("HP_FAKE_ERROR_201") != NULL); if ((cbServer_->getControlConnection()->getErrorInfo() != 0) || fakeError201) { ComDiagsArea *diagsArea = ComDiagsArea::allocate(getGlobals()->getDefaultHeap()); cbServer_->getControlConnection()-> populateDiagsArea( diagsArea, getGlobals()->getDefaultHeap()); if (fakeError201) { *diagsArea << DgSqlCode(-2034) << DgInt0(201) << DgString0("I say") << DgString1("control broker"); } if (diagsArea->contains(-8921)) { // Should not get timeout error 8921. Get a core-file // of the SSMP and this process too so that this can be // debugged. cbServer_->getControlConnection()-> dumpAndStopOtherEnd(true, false); genLinuxCorefile("Unexpected timeout error"); } reportError(diagsArea); step_ = DONE; break; } // See if stream has the reply yet. if (!cancelStream_->moreObjects()) return WORK_OK; #pragma warning (disable : 4291) ControlQueryReply *reply = new (cliGlobals->getIpcHeap()) ControlQueryReply(INVALID_RTS_HANDLE, cliGlobals->getIpcHeap()); #pragma warning (default : 4291) *cancelStream_ >> *reply; if (reply->didAttemptControl()) { // yeaah! cancelStream_->clearAllObjects(); } else { if (cancelStream_->moreObjects() && cancelStream_->getNextObjType() == IPC_SQL_DIAG_AREA) { ComDiagsArea *diagsArea = ComDiagsArea::allocate(getGlobals()->getDefaultHeap()); *cancelStream_ >> *diagsArea; cancelStream_->clearAllObjects(); if ( retryQidNotActive_ && (diagsArea->mainSQLCODE() == -EXE_SUSPEND_QID_NOT_ACTIVE) && (++retryCount_ <= 60)) { SQLMXLoggingArea::logExecRtInfo(__FILE__, __LINE__, "Retrying error 8672.", 0); DELAY(500); diagsArea->decrRefCount(); step_ = SEND_MESSAGE; break; } reportError(diagsArea); } else ex_assert(0, "Control failed, but no diagnostics."); } step_ = DONE; break; } case DONE: { if (cancelStream_) { cancelStream_->addToCompletedList(); cancelStream_ = NULL; } if (cbServer_) { cbServer_->release(); cbServer_ = NULL; } ex_queue_entry * up_entry = qparent_.up->getTailEntry(); up_entry->copyAtp(pentry_down); up_entry->upState.parentIndex = pentry_down->downState.parentIndex; up_entry->upState.downIndex = qparent_.down->getHeadIndex(); up_entry->upState.setMatchNo(1); up_entry->upState.status = ex_queue::Q_NO_DATA; qparent_.up->insert(); qparent_.down->removeHead(); step_ = NOT_STARTED; break; } default: ex_assert( 0, "Unknown step_."); }
short ExExeUtilTcb::executeQuery(char * task, char * object, char * query, NABoolean displayStartTime, NABoolean displayEndTime, short &rc, short * warning, Lng32 * ec, NABoolean moveErrorRow, NABoolean continueOnError, NABoolean monitorThis) { short retcode = 0; char buf[BUFFER_SIZE]; while (1) { switch (pqStep_) { case PROLOGUE_: { warning_ = 0; startTime_ = NA_JulianTimestamp(); elapsedTime_ = 0; if (displayStartTime) { getStatusString(task, "Started", object, buf); if (moveRowToUpQueue(buf, 0, &rc)) return 1; } pqStep_ = EXECUTE_; rc = WORK_RESCHEDULE_AND_RETURN; return 1; } break; case EXECUTE_: { retcode = cliInterface()->fetchRowsPrologue(query,FALSE,monitorThis); if (retcode < 0) { pqStep_ = ERROR_RETURN_; break; } pqStep_ = FETCH_ROW_; } break; case FETCH_ROW_: { retcode = (short)cliInterface()->fetch(); if (retcode < 0) { pqStep_ = ERROR_RETURN_; break; } if ((retcode > 0) && (retcode != 100)) warning_ = retcode; if ((retcode != 100) && (cliInterface()->outputBuf())) pqStep_ = RETURN_ROW_; else pqStep_ = CLOSE_; } break; case RETURN_ROW_: { char * ptr; Lng32 len; cliInterface()->getPtrAndLen(1, ptr, len); retcode = moveRowToUpQueue(ptr, len, &rc); if (retcode) return 1; pqStep_ = FETCH_ROW_; } break; case CLOSE_: { retcode = cliInterface()->fetchRowsEpilogue(""); if (retcode < 0) { pqStep_ = ERROR_RETURN_; break; } pqStep_ = EPILOGUE_; } break; case EPILOGUE_: { endTime_ = NA_JulianTimestamp(); elapsedTime_ = endTime_ - startTime_; if (displayEndTime) { char timeBuf[200]; getTimeAsString(elapsedTime_, timeBuf); getStatusString(task, "Ended", object, buf, timeBuf); if (moveRowToUpQueue(buf, 0, &rc)) return 1; } pqStep_ = ALL_DONE_; rc = WORK_RESCHEDULE_AND_RETURN; return 1; } break; case ERROR_RETURN_: { Lng32 sqlcode = 0; char * stringParam1 = NULL; Lng32 intParam1 = ComDiags_UnInitialized_Int; retcode = (short)cliInterface()->retrieveSQLDiagnostics(getDiagsArea()); if (moveErrorRow) { if (retcode == 0) { ComDiagsArea * da = getDiagsArea(); sqlcode = (short)da->mainSQLCODE(); ComCondition * cc; if (sqlcode < 0) cc = da->getErrorEntry(1); else cc = da->getWarningEntry(1); if (sqlcode < 0 && ec != NULL) *ec = sqlcode; if (cc->getOptionalStringCharSet(0) == CharInfo::ISO88591 || cc->getOptionalStringCharSet(0) == CharInfo::UTF8) stringParam1 = (char*)cc->getOptionalString(0); else stringParam1 = NULL; intParam1 = cc->getOptionalInteger(0); } else { sqlcode = retcode; } Lng32 errorBufLen = 200 + (stringParam1 ? strlen(stringParam1) : 0); char * errorBuf = new(getHeap()) char[errorBufLen]; str_sprintf(errorBuf, "%d", sqlcode); if (stringParam1) str_sprintf(&errorBuf[strlen(errorBuf)], ", %s", stringParam1); if (intParam1 != ComDiags_UnInitialized_Int) str_sprintf(&errorBuf[strlen(errorBuf)], ", %d", intParam1); char * outBuf = new(getHeap()) char[errorBufLen+400]; getStatusString(task, "Error", NULL, outBuf, NULL, NULL, errorBuf); NADELETEBASIC(errorBuf, getHeap()); if ((moveErrorRow) && (moveRowToUpQueue(outBuf, 0, &rc))) { NADELETEBASIC(outBuf, getHeap()); return 1; } NADELETEBASIC(outBuf, getHeap()); } // close cursor, etc. Ignore errors. cliInterface()->fetchRowsEpilogue(""); if (continueOnError) { pqStep_ = ALL_DONE_; rc = WORK_RESCHEDULE_AND_RETURN; return 1; } else { pqStep_ = PROLOGUE_; return -1; } } break; case ALL_DONE_: { pqStep_ = PROLOGUE_; if (warning) *warning = warning_; return 0; } break; } } }
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 }