blob: 8430d85fcea6bb820202b66b19e00deb91e123f4 [file] [log] [blame]
/**********************************************************************
// @@@ START COPYRIGHT @@@
//
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
//
// @@@ END COPYRIGHT @@@
**********************************************************************/
/* -*-C++-*-
*****************************************************************************
*
* File: NoWaitOp.cpp
* Description: Functions of NowaitOp class.
*
* Created: 3/26/2002
* Language: C++
*
*
*
*
*****************************************************************************
*/
#include "Platform.h"
#include "ComCextdecs.h"
#include "cextdecs/cextdecs.h"
#include <stdlib.h>
#include "cli_stdh.h"
#include "Ipc.h"
#include "ex_stdh.h"
#include "SQLCLI.h"
#include "NoWaitOp.h"
#include "Statement.h"
#include "Descriptor.h"
#include "ExStats.h"
#include "ex_exe_stmt_globals.h"
// Methods for class NoWaitOp
NoWaitOp::NoWaitOp(Statement * stmt,
Descriptor * inputDesc, Descriptor * outputDesc,
Lng32 tag, NoWaitOp::opType op, NABoolean initiated)
: stmt_(stmt), inputDesc_(inputDesc),
outputDesc_(outputDesc),tag_(tag),op_(op),
initiated_(initiated)
{
// lock Descriptors ($$$ what happens if already locked?)
if (inputDesc)
inputDesc->lockForNoWaitOp(); // $$$ ignores possible error return code
if (outputDesc)
outputDesc->lockForNoWaitOp(); // $$$ ignores possible error return code
}
NoWaitOp::~NoWaitOp(void)
{
// unlock Descriptors ($$$ what happens if already unlocked?)
if (inputDesc_)
inputDesc_->unlockForNoWaitOp(); // $$$ ignores possible error return code
if (outputDesc_)
outputDesc_->unlockForNoWaitOp(); // $$$ ignores possible error return code
}
RETCODE NoWaitOp::awaitIox(Lng32 * tag)
{
RETCODE rc = NOT_FINISHED; // assume not finished yet
RETCODE rc1;
// set current context to that of this Statement
// $$$ note that the diagsArea might be from a different context;
// I think this is OK, but it bears closer inspection.
// $$$ this code should be bracketed with a try-catch block to
// restore the original context in the event of an exception.
ContextCli * stmtContext = stmt_->getContext();
ComDiagsArea &diagsArea = stmtContext->diags();
CliGlobals * cliGlobals = stmtContext->getCliGlobals();
ContextCli * oldCurrentContext = cliGlobals->currContext();
cliGlobals->setCurrentContext(stmtContext);
jmp_buf jmpBuf, *oldJmpBufPtr;
oldJmpBufPtr = cliGlobals->getJmpBufPtr();
cliGlobals->setJmpBufPtr(&jmpBuf);
Lng32 jmpRetcode;
Int32 jmpRc = setjmp(jmpBuf);
if (jmpRc)
{
if (jmpRc == MEMALLOC_FAILURE)
jmpRetcode = -EXE_NO_MEM_TO_EXEC;
else
{
stmt_->resetNoWaitOpPending();
jmpRetcode = -CLI_INTERNAL_ERROR;
}
*tag = tag_;
diagsArea << DgSqlCode(jmpRetcode);
rc = ERROR;
}
else
{
Int64 startTime = NA_JulianTimestamp();
switch (op_)
{
case FETCH:
case FETCH_CLOSE:
{
// drive the fetch with a zero time limit (since we drive
// the IPC wait in this layer instead of in the Executor
// layer), but drive it only if there is dispatchable work
// to do
if (stmt_->mightHaveWorkToDo()) //Do this for fetch but not prepare
{
// redrive the fetch (FALSE indicates not a new fetch)
rc = stmt_->fetch(cliGlobals,outputDesc_,diagsArea,FALSE);
// $$$ for the moment, assume at most one no-wait op per
// Statement; can relax this later
if (rc != NOT_FINISHED)
{
stmt_->resetNoWaitOpPending();
*tag = tag_;
// Fixup the diags area and outputDesc.
// if bulk move was done, remember the statement it was done for.
if ((outputDesc_) && (NOT outputDesc_->bulkMoveDisabled()))
{
//if (getenv("BULKMOVEWARN"))
// diags << DgSqlCode(EXE_ERROR_NOT_IN_USE_8350);
outputDesc_->bulkMoveStmt() = stmt_;
}
// if select into query, then make sure that atmost one
// row is returned by executor. More than one would
// result in an error.
if ((stmt_->isSelectInto()) &&
(rc == SUCCESS))
{
// BertBert VV
if (stmt_->isEmbeddedUpdateOrDelete() || stmt_->isStreamScan())
{
// For streams and destructive selects, we don't want the
// abovebehavior,instead, we should just return the first row.
}
// BertBert ^^
else
{
// select into and a row was returned.
// See if we can get one more row.
// Do not send in an output desc. We want
// to return the first row to application.
// This is being consistent with SQL/MP behavior.
stmt_->resetNoWaitOpEnabled(); // waited mode
rc = stmt_->fetch(cliGlobals, 0 /*no output desc*/,
diagsArea, TRUE);
if (rc == SUCCESS)
{
diagsArea << DgSqlCode(-CLI_SELECT_INTO_ERROR);
if (op_ == FETCH)
stmt_->close(diagsArea);
rc = ERROR;
}
if (rc == SQL_EOF)
{
// remove warning 100 from diags.
diagsArea.removeFinalCondition100();
rc = SUCCESS;
}
}
}
if ((rc == SQL_EOF) && (outputDesc_ == NULL))
{
// remove warning 100 from diags.
diagsArea.removeFinalCondition100();
rc = SUCCESS;
}
} // end if rc != NOT_FINISHED
// update Measure elapsed time if Measure enabled.
if (stmt_->getRootTdb() &&
((ComTdb*)stmt_->getRootTdb())->getCollectStatsType() ==
ComTdb::MEASURE_STATS &&
stmt_->getGlobals()->getStatsArea() != NULL)
{
if (stmt_->getGlobals()->getStatsArea()->getStmtCntrs() != NULL)
{
stmt_->getGlobals()->getStatsArea()->getStmtCntrs()->
incElapseBusyTime(NA_JulianTimestamp() - startTime);
}
}
}
if (rc != NOT_FINISHED && op_ == FETCH_CLOSE)
{
rc1 = stmt_->close(diagsArea);
if (rc1 == ERROR)
rc = rc1;
}
if ((op_ == FETCH_CLOSE) &&
(rc != NOT_FINISHED) &&
(rc != ERROR) &&
(stmt_->noRowsAffected(diagsArea)))
{
rc =
((diagsArea.getNumber(DgSqlCode::WARNING_) > 0) ? SUCCESS : SQL_EOF);
// move EOF warning to diags area.
if (rc == SQL_EOF)
diagsArea << DgSqlCode(SQL_EOF);
}
break;
}
case PREPARE:
{
// drive the prepare with a zero time limit
ULng32 flags = PREPARE_NOT_A_NEW_OPERATION;
rc = stmt_->prepare(NULL,diagsArea,NULL,0,0,TRUE,flags);
// $$$ for the moment, assume at most one no-wait op per
// Statement; can relax this later
if (rc != NOT_FINISHED)
{
stmt_->issuePlanVersioningWarnings (diagsArea);
stmt_->resetNoWaitOpPending();
*tag = tag_;
}
break;
}
default:
{
// $$$ operation invalid or not supported yet
rc = ERROR;
diagsArea << DgSqlCode(-EXE_INTERNAL_ERROR);
break;
}
}
}
// restore original current context
cliGlobals->setCurrentContext(oldCurrentContext);
cliGlobals->setJmpBufPtr(oldJmpBufPtr);
return rc;
}