/////////////////////////////////////////////////////////////////////////// // This method is used to retrieve input rows from the input buffer // that is sent from Executor to Arkcmp. // // Returns the 'current' row and increments the internal rownum. // // Also returns control information associated with this input row. // Caller needs to pass this control info pointer to ExSPPutReplyRow // when the reply buffer (sent from Arkcmp to Executor) is being filled // in. All reply(output) rows that correspond to this input row have // the same control info. // // RETURNS: 0, if all is Ok. 1, if all rows have been returned. // -1, in case of error. //////////////////////////////////////////////////////////////////////////// SQLCLI_LIB_FUNC short ExSPGetInputRow(void * inputBuffer, // IN: input sql buffer void* &controlInfo, // OUT: control info char* &rowPtr, // OUT: pointer to the row ULng32 &rowLen)// OUT: length of returned row { SqlBuffer * ib = (SqlBuffer *)inputBuffer; if ( !ib ) return -1; tupp tp; ControlInfo * ci = NULL; up_state us; ComDiagsArea* diags; if (ib->moveOutSendOrReplyData(TRUE, // send (input) value &us, tp, &ci, &diags) == TRUE) return 1; // No more input rows. controlInfo = ci; rowPtr = tp.getDataPointer(); rowLen = tp.getAllocatedSize(); return 0; }
void backoutTupps(SqlBuffer &b, Lng32 numTuppsBefore) { while (b.getTotalTuppDescs() > numTuppsBefore) { b.remove_tuple_desc(); } }
///////////////////////////////////////////////////////////////// // Positions to the first row in input buffer. This proc MUST be // called before retrieving input rows from it. // RETURNS: 0, if all ok. -1, in case of an error. ///////////////////////////////////////////////////////////////// short ExSPPosition(void * inputBuffer) { SqlBuffer * ib = (SqlBuffer *)inputBuffer; if (ib == NULL) return -1; ib->position(); return 0; }
/////////////////////////////////////////////////////////////// // Prepares the input buffer so input rows could be retrieved // from it. Unpacks sql buffer which would convert offsets to // pointers. To be called after receiving the input buffer // from Executor and before retrieving rows from it. /////////////////////////////////////////////////////////////// short ExSPPrepareInputBuffer(void * inputBuffer) { SqlBuffer * ib = (SqlBuffer *)inputBuffer; if (ib == NULL) return -1; ib->driveUnpack(); return 0; }
///////////////////////////////////////////////////////////////// // Initializes the reply buffer. // Caller must allocate contiguous space of length replyBufLen // and then call this proc. // This proc MUST be called BEFORE moving any reply rows to it. // Once the reply buffer is sent from Arkcmp to Executor, it // must be re-initialized by calling this proc again. ///////////////////////////////////////////////////////////////// short ExSPInitReplyBuffer(void * replyBuffer, ULng32 replyBufLen) { SqlBuffer * rb = (SqlBuffer *)replyBuffer; if ((rb == NULL) || (replyBufLen == 0)) return -1; rb->driveInit(replyBufLen, FALSE, SqlBuffer::NORMAL_); return 0; }
/////////////////////////////////////////////////////////// // Prepares the reply buffer so it could be sent back // from Arkcmp to Executor. // Packs sql buffer which would convert pointers to // offsets. To be called before sending the reply buffer to // Executor. /////////////////////////////////////////////////////////// short ExSPPrepareReplyBuffer(void * replyBuffer) { SqlBuffer * rb = (SqlBuffer *)replyBuffer; if (rb == NULL) return -1; rb->drivePack(); // this reply buffer needs to be sent back to executor. // Mark it as being in use. rb->bufferInUse(); return 0; }
void UdrServerDataStream::actOnReceive(IpcConnection *conn) { const char *moduleName = "UdrServerDataStream::actOnReceive()"; IpcMessageObjType t; NABoolean somethingArrived = FALSE; // // A note about control flow in this method. It was originally // written under the assumption that only one message arrives at a // time. It would call getNextReceiveMsg() only once, then process // incoming objects, then return. It turns out this creates a memory // leak. Internally within the stream, the incoming message buffer // never moved from the "receive" list to the "in use" list and // never got cleaned up. Now this method calls getNextReceiveMsg() // until it returns FALSE. The result is that after the incoming // message has been processed, the next getNextReceiveMsg() call // will move the request buffer to the "in use" list where it later // gets cleaned up by a call to cleanupBuffers() or // releaseBuffers(). // while (getNextReceiveMsg(t)) { somethingArrived = TRUE; while (getNextObjType(t)) { switch (t) { case UDR_MSG_DATA_HEADER: { // Do nothing for now except extract the object from the stream UdrDataHeader *h = new (receiveMsgObj()) UdrDataHeader(this); } // case UDR_MSG_DATA_HEADER break; case UDR_MSG_CONTINUE_REQUEST: { // Extract the object from the stream and call SPInfo's work() UdrContinueMsg *m = new (receiveMsgObj()) UdrContinueMsg(this); if(spinfo_->getParamStyle() == COM_STYLE_TM) spinfo_->workTM(); else spinfo_->work(); } // case UDR_MSG_CONTINUE_REQUEST break; case UDR_MSG_DATA_REQUEST: { UdrDataBuffer *request = new (receiveMsgObj()) UdrDataBuffer(this); if (udrGlob_->verbose_ && udrGlob_->traceLevel_ >= TRACE_DETAILS && udrGlob_->showMain_) { ServerDebug( ""); ServerDebug("[UdrServ (%s)] Invoke Request has %ld tupps.", moduleName, request->getSqlBuffer()->getTotalTuppDescs()); ServerDebug("[UdrServ (%s)] Invoke Request SQL Buffer", moduleName); displaySqlBuffer(request->getSqlBuffer(), (Lng32) request->getSqlBufferLength()); } udrGlob_->numReqInvokeSP_++; // Let the SPInfo process the request spinfo_->setCurrentRequest(request); spinfo_->work(); } // case UDR_MSG_DATA_REQUEST break; case UDR_MSG_TMUDF_DATA_HEADER: { // Extract the object. UDR Handle and RS Handle are // interesting things in this message. UdrTmudfDataHeader *h = new (receiveMsgObj()) UdrTmudfDataHeader(this); UdrHandle udrHandle = h->getHandle(); NABoolean anyMore = getNextObjType(t); UDR_ASSERT(anyMore, "DATA_REQUEST must follow TMUDF DATA_HEADER"); UDR_ASSERT(t == UDR_MSG_DATA_REQUEST, "DATA_REQUEST must follow TMUDF DATA_HEADER"); UdrDataBuffer *request = new (receiveMsgObj()) UdrDataBuffer(this, FALSE); //Avoid unpack. // Let the SPInfo process the request spinfo_->setCurrentRequest(request); spinfo_->workTM(); } break; case UDR_MSG_RS_DATA_HEADER: { // Extract the object. UDR Handle and RS Handle are // interesting things in this message. UdrRSDataHeader *h = new (receiveMsgObj()) UdrRSDataHeader(this); UdrHandle udrHandle = h->getHandle(); RSHandle rsHandle = h->getRSHandle(); NABoolean anyMore = getNextObjType(t); UDR_ASSERT(anyMore, "DATA_REQUEST must follow RS_DATA_HEADER"); UDR_ASSERT(t == UDR_MSG_DATA_REQUEST, "DATA_REQUEST must follow RS_DATA_HEADER"); UdrDataBuffer *request = new (receiveMsgObj()) UdrDataBuffer(this); udrGlob_->numReqRSFetch_++; processAnRSFetchMessage(udrGlob_, *this, udrHandle, rsHandle, request); // We need the request buffer in a state where the stream // knows it can be freed. We call SqlBuffer::bufferFull() to // accomplish this even though the method name is a bit // misleading. SqlBuffer *sqlBuf = request->getSqlBuffer(); UDR_ASSERT(sqlBuf, "UDR request buffer is corrupt or contains no data"); sqlBuf->bufferFull(); } break; case UDR_MSG_RS_CONTINUE: { UdrRSContinueMsg *rsContinue = new (receiveMsgObj()) UdrRSContinueMsg(this); udrGlob_->numReqRSContinue_++; processAnRSContinueMessage(udrGlob_, *this, *rsContinue); } break; default: { UDR_ASSERT(FALSE, "Unknown message type arrived on UDR data stream"); } // default break; } // switch (t) } // while (getNextObjType(t)) } // while (getNextReceiveMsg(t)) // Make sure all reply buffers have been given to the connection. If // the only objects that arrived during this callback were continue // requests, then this action allows reply buffers associated with // those continue requests to propagate out of the stream and onto // the connection. // // If numOfInputBuffers() is > 0 then we do not need to do anything // at this point. This callback will be invoked again when the // incoming message is complete and ready to be processed. Lng32 numInputBuffers = numOfInputBuffers(); if (somethingArrived && numInputBuffers == 0 && spinfo_->getCurrentRequest() == NULL) { responseDone(); if (udrGlob_->verbose_ && udrGlob_->traceLevel_ >= TRACE_IPMS && udrGlob_->showMain_) { ServerDebug("[UdrServ (%s)] All messages marked as replied", moduleName); } // Cleanup any unpacked message buffers containing only objects // that are no longer in use, as determined by the virtual method // IpcMessageObj::msgObjIsFree() releaseBuffers(); // Do final garbage collection } } // UdrServerDataStream::actOnReceive()
///////////////////////////////////////////////////////////////// // Copies the row pointer by rowPtr for rowLen inside sqlBuffer. // The controlInfo must be the same pointer that was returned by // proc ExSPGetInputRow along with the input row that corresponds // to the reply rows. // If replyRow is NULL, that that indicates that all reply rows // for this input have been returned. A NULL replyRow MUST be // passed in to this proc to end the request. // // This proc returns a value of 1, if replyBuffer is full. // The reply row that was passed in in that call is NOT moved // in to the replyBuffer. Caller must call this proc again with // the replyRow. This applies to both non-null and null reply row. // // Returns 1, if buffer is full. 0, if row moved in. // -1, in case of error. // 2 in case of warning. ///////////////////////////////////////////////////////////////// SQLCLI_LIB_FUNC short ExSPPutReplyRow(void * replyBuffer, // IN: the reply buffer void * controlInfo, // IN: control info char * replyRow, // IN: pointer to reply row ULng32 rowLen, // IN: length of reply row ComDiagsArea* diagsDesc)// IN: pointer to diags { if ((replyBuffer == NULL) || (controlInfo == NULL)) return -1; SqlBuffer * rb = (SqlBuffer *)replyBuffer; ControlInfo * ci = (ControlInfo *)controlInfo; short rc = 0; up_state us; us.parentIndex = ci->getDownState().parentIndex; us.downIndex = 0; us.setMatchNo(0); if (replyRow == NULL) // indicate end of reply rows { if (diagsDesc != NULL) { if (diagsDesc->getNumber(DgSqlCode::ERROR_) > 0) us.status = ex_queue::Q_SQLERROR; else if (diagsDesc->getNumber(DgSqlCode::WARNING_) > 0) { us.status = ex_queue::Q_NO_DATA; rc = 2; } } else us.status = ex_queue::Q_NO_DATA; tupp_descriptor* dDesc = 0; if (rb->moveInSendOrReplyData(FALSE, // reply TRUE, // do move EOD indication FALSE, // don't move data. (void *)&us, sizeof(ControlInfo), 0, 0, 0, diagsDesc, &dDesc) == SqlBuffer::MOVE_SUCCESS) { if (diagsDesc) diagsDesc->packObjIntoMessage(dDesc->getTupleAddress()); } else { rc = 1; // buffer is full } } else { tupp_descriptor * tdesc = NULL; us.status = ex_queue::Q_OK_MMORE; if (rb->moveInSendOrReplyData(FALSE, // reply FALSE, // don't move control,if not needed. TRUE, // do move data. (void *)&us, sizeof(ControlInfo), 0, rowLen, &tdesc, 0, 0) == SqlBuffer::MOVE_SUCCESS) { #pragma nowarn(1506) // warning elimination str_cpy_all(tdesc->getTupleAddress(), replyRow, rowLen); #pragma warn(1506) // warning elimination } else { rc = 1;// buffer is full. } } return rc; }
NABoolean allocateReplyRow(UdrGlobals *UdrGlob, SqlBuffer &replyBuffer, // [IN] A reply buffer queue_index parentIndex, // [IN] Identifies the request queue entry Int32 replyRowLen, // [IN] Length of reply row char *&newReplyRow, // [OUT] The allocated reply row ControlInfo *&newControlInfo, // [OUT] The allocated ControlInfo entry ex_queue::up_status upStatus // [IN] Q_OK_MMORE, Q_NO_DATA, Q_SQLERROR ) { const char *moduleName = "allocateReplyRow"; doMessageBox(UdrGlob, TRACE_SHOW_DIALOGS, UdrGlob->showInvoke_, moduleName); NABoolean result = FALSE; SqlBufferBase::moveStatus status; up_state upState; upState.parentIndex = parentIndex; upState.downIndex = 0; upState.setMatchNo(0); upState.status = upStatus; tupp_descriptor *tdesc = NULL, **tuppDesc; ControlInfo **ctrlInfo; NABoolean moveCtrlInfo, moveDataInfo; switch (upStatus) { case ex_queue::Q_OK_MMORE : { ctrlInfo = &newControlInfo; moveCtrlInfo = TRUE; moveDataInfo = TRUE; tuppDesc = &tdesc; break; } case ex_queue::Q_SQLERROR : { ctrlInfo = &newControlInfo; moveCtrlInfo = TRUE; moveDataInfo = FALSE; tuppDesc = NULL; break; } case ex_queue::Q_NO_DATA : { ctrlInfo = NULL; moveCtrlInfo = TRUE; moveDataInfo = FALSE; tuppDesc = NULL; break; } default: { UDR_ASSERT(FALSE, "Unknown ex_queue::up_status value."); return FALSE; } } status = replyBuffer.moveInSendOrReplyData( FALSE, // [IN] sending? (vs. replying) moveCtrlInfo, // [IN] force move of ControlInfo? moveDataInfo, // [IN] move data? (void *) &upState, // [IN] queue state sizeof(ControlInfo), // [IN] length of ControlInfo ctrlInfo, // [OUT] new ControlInfo replyRowLen, // [IN] data row length tuppDesc, // [OUT] new data tupp_desc NULL, // [IN] diags area 0 // [OUT] new diags tupp_desc ); if (status == SqlBufferBase::MOVE_SUCCESS) { if (upStatus == ex_queue::Q_OK_MMORE) { newReplyRow = tdesc->getTupleAddress(); memset(newReplyRow, 0, replyRowLen); } result = TRUE; } else { result = FALSE; } return result; }