blob: 1c7fec2d269fd0bf0e511bc80570a9158fcdc74c [file] [log] [blame]
/* -*-C++-*-
// @@@ 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 @@@
*****************************************************************************
*
* File: Cli.C
* Description: CLI procedures body.
*
* Created: 7/10/95
* Language: C++
*
*
*
*
*****************************************************************************
*/
#include "Platform.h"
#include "ComCextdecs.h"
#include "cli_stdh.h"
#include "exp_stdh.h"
#include "ex_transaction.h"
#include "exp_expr.h"
#include "exp_clause_derived.h"
#include "exp_function.h"
#include "ExpLOB.h"
#include "ExpLOBinterface.h"
#include "sql_id.h"
#include "ExStats.h"
#include "ComTdb.h"
#include "ComTdbSplitTop.h"
#include "ex_root.h"
#include "ex_exe_stmt_globals.h"
#include "ex_frag_rt.h"
#include "NLSConversion.h"
#include "ExExeUtil.h"
#include <stdarg.h>
#include "NAString.h"
#include "Cli.h"
#include "ComRtUtils.h"
#include "ComSqlId.h"
#include "ComRegAPI.h"
#include "ExExplain.h"
#include "ExplainTuple.h"
#include "CmpMessage.h"
#include "ExSqlComp.h"
#include "logmxevent.h"
#include <time.h>
#include "fs/feerrors.h"
#include "csconvert.h"
#include "ExRsInfo.h"
#include "seabed/ms.h"
#include "dtm/tm.h"
#include "CmpContext.h"
#include "LmLangManager.h"
#include "LmLangManagerC.h"
#include "LmLangManagerJava.h"
#include "LmRoutine.h"
#include "CmpDDLCatErrorCodes.h"
#include "ExpLOBaccess.h"
#define DISPLAY_DONE_WARNING 1032
extern Lng32 getTotalTcbSpace(char * tdb, char * otherInfo,
char * parentMemory);
StrTarget::StrTarget() :
heap_(NULL),
str_(NULL),
externalCharset_(CharInfo::UnknownCharSet),
internalCharset_(CharInfo::UnknownCharSet),
cnvExternalCharset_(cnv_UnknownCharSet),
cnvInternalCharset_(cnv_UnknownCharSet)
{}
StrTarget::StrTarget(Descriptor *desc, Lng32 entry) :
heap_(NULL),
str_(NULL),
externalCharset_(CharInfo::UnknownCharSet),
internalCharset_(CharInfo::UnknownCharSet),
cnvExternalCharset_(cnv_UnknownCharSet),
cnvInternalCharset_(cnv_UnknownCharSet)
{
init(desc, entry);
}
void StrTarget::init(Descriptor *desc, Lng32 entry)
{
Lng32 sourceLen, sourceType, externalCharset, internalCharset;
CollHeap *heap = desc->getContext()->exCollHeap();
ComDiagsArea *diagsArea = desc->getContext()->getDiagsArea();
char * source = desc->getVarData(entry);
desc->getDescItem(entry, SQLDESC_TYPE_FS, &sourceType, 0, 0, 0, 0);
desc->getDescItem(entry, SQLDESC_OCTET_LENGTH, &sourceLen, 0, 0, 0, 0);
desc->getDescItem(1, SQLDESC_CHAR_SET, &externalCharset, 0, 0, 0, 0);
// If ISO_MAPPING is equal to the charset in the descriptor,
// then process as usual. Otherwise, convert
// the string from the input charset to ISO_MAPPING (on NSK platform)
// -- On SeaQuest platform, always convert to UTF8 (or keep as is if
// already in UTF8 or UCS2/UTF16).
if (externalCharset == CharInfo::UCS2)
internalCharset = CharInfo::UCS2;
else
internalCharset = CharInfo::UTF8;
init(source,
sourceLen,
sourceType,
externalCharset,
internalCharset,
heap,
diagsArea);
}
void StrTarget::init(char *source,
Lng32 sourceLen,
Lng32 sourceType,
Lng32 externalCharset,
Lng32 internalCharset,
CollHeap *heap,
ComDiagsArea *&diagsArea)
{
externalCharset_ = externalCharset;
internalCharset_ = internalCharset;
heap_ = heap;
cnvExternalCharset_ = convertCharsetEnum(externalCharset_);
cnvInternalCharset_ = convertCharsetEnum(internalCharset_);
if (sourceType < REC_MIN_CHARACTER || sourceType > REC_MAX_CHARACTER)
return;
// How many bytes will we need after conversion?
// Add one char length for the NULL terminator
Int32 intStrLen = CharInfo::getMaxConvertedLenInBytes(
(CharInfo::CharSet)externalCharset_,
sourceLen,
(CharInfo::CharSet)internalCharset_) +
CharInfo::minBytesPerChar(
(CharInfo::CharSet)internalCharset_);
str_ = (char *)heap_->allocateMemory(intStrLen);
short retCode = convDoIt( source,
sourceLen,
(short) sourceType,
0,
externalCharset_,
str_,
intStrLen,
CharInfo::getFSTypeANSIChar((CharInfo::CharSet) internalCharset_),
0,
internalCharset_,
NULL,
0,
heap_,
&diagsArea);
if (retCode != ex_expr::EXPR_OK)
{
heap_->deallocateMemory(str_);
str_ = NULL;
}
}
static inline NABoolean isERROR(Lng32 retcode)
{
return (retcode < 0);
}
static inline NABoolean isWARNING(Lng32 retcode)
{
// 100 is EOF, not WARNING
return ((retcode > 0) && (retcode != SQL_EOF));
}
static inline NABoolean isSUCCESS(Lng32 retcode)
{
return (retcode == 0);
}
static inline NABoolean isEOF(Lng32 retcode)
{
return (retcode == 100);
}
static Lng32 SQLCLI_ReturnCode(ContextCli * context,
Lng32 retcode)
{
return (context != NULL && isERROR(retcode) ?
context->diags().mainSQLCODE() :
retcode);
}
// Move this method to Statement class. TBD.
static Lng32 SQLCLI_Prepare_Setup_Pre(
ContextCli &currContext,
Statement * stmt,
ULng32 flags
)
{
Int64 compStartTime = NA_JulianTimestamp();
StmtStats * stmtStats = stmt->getStmtStats();
if (stmtStats != NULL)
{
if (stmtStats->getMasterStats() != NULL)
{
stmtStats->getMasterStats()->setElapsedStartTime(compStartTime);
stmtStats->getMasterStats()->setCompStartTime(compStartTime);
if (flags & PREPARE_STANDALONE_QUERY) // standalone query
stmtStats->getMasterStats()->setIsPrepAndExec(TRUE);
else
{
stmtStats->getMasterStats()->setIsPrepAndExec(FALSE);
stmtStats->getMasterStats()->setIsPrepare(TRUE);
}
}
}
return 0;
}
static Lng32 SQLCLI_Prepare_Setup_Post(
ContextCli &currContext,
Statement * stmt,
ULng32 flags
)
{
StmtStats * stmtStats = stmt->getStmtStats();
Int64 compEndTime = stmt->getCompileEndTime();
ExMasterStats *masterStats;
ex_root_tdb *rootTdb = NULL;
if (stmtStats != NULL)
{
if ((masterStats = stmtStats->getMasterStats()) != NULL)
{
masterStats->setCompEndTime(compEndTime);
rootTdb = (stmt ? stmt->getRootTdb() : NULL);
if (rootTdb)
stmtStats->getMasterStats()->setInvalidationKeys(
currContext.getCliGlobals(), rootTdb->getSikInfo(),
rootTdb->getNumObjectUIDs(), rootTdb->getObjectUIDs());
if (rootTdb != NULL && rootTdb->getCollectStatsType() != ComTdb::NO_STATS)
{
masterStats->setCollectStatsType(rootTdb->getCollectStatsType());
if (rootTdb->getQueryCostInfo())
masterStats->queryCostInfo() =
*(rootTdb->getQueryCostInfo());
if (rootTdb->getCompilerStatsInfo())
masterStats->compilerStatsInfo() =
*(rootTdb->getCompilerStatsInfo());
if (rootTdb->qCacheInfoIsClass() &&
rootTdb->qcInfo())
{
masterStats->setCompilerCacheHit
(rootTdb->qcInfo()->cacheWasHit());
}
masterStats->setQueryType((Int16)rootTdb->getQueryType(),
rootTdb->getSubqueryType());
masterStats->exePriority() = (short)
currContext.getCliGlobals()->myPriority();
if (currContext.getSessionDefaults()->getEspPriority() > 0)
masterStats->espPriority() = (short)
currContext.getSessionDefaults()->getEspPriority();
else if (currContext.
getSessionDefaults()->getEspPriorityDelta() != 0)
masterStats->espPriority() = (short)
(stmtStats->getMasterStats()->exePriority() +
currContext.getSessionDefaults()->getEspPriorityDelta());
else
masterStats->espPriority() =
masterStats->exePriority();
if (currContext.getSessionDefaults()->getMxcmpPriority() > 0)
masterStats->cmpPriority() = (short)
currContext.getSessionDefaults()->getMxcmpPriority();
else if (currContext.
getSessionDefaults()->getMxcmpPriorityDelta() != 0)
masterStats->cmpPriority() = (short)
(masterStats->exePriority() +
currContext.getSessionDefaults()->getMxcmpPriorityDelta());
else
masterStats->cmpPriority() =
masterStats->exePriority();
masterStats->fixupPriority() = (short)
currContext.getSessionDefaults()->getEspFixupPriorityDelta();
// detect if this query is sequential at top. If
// the root doesn't have an ESP exchange as its child,
// then it is sequential at top. A FirstN operator could
// also be between root and ESP exchange, that is
// not considered sequential.
UInt32 numOfRootEsps = 0;
const ComTdb * st = NULL;
if (((rootTdb->getChild(0)->getNodeType() == ComTdb::ex_FIRST_N) &&
((st=rootTdb->getChild(0)->getChild(0))->getNodeType() == ComTdb::ex_SPLIT_TOP) &&
(rootTdb->getChild(0)->getChild(0)->getChild(0)->getNodeType() == ComTdb::ex_SEND_TOP)) ||
(((st=rootTdb->getChild(0))->getNodeType() == ComTdb::ex_SPLIT_TOP) &&
(rootTdb->getChild(0)->getChild(0)->getNodeType() == ComTdb::ex_SEND_TOP)))
{
numOfRootEsps = ((ComTdbSplitTop*)st)->getBottomNumParts();
}
masterStats->numOfRootEsps() = numOfRootEsps;
if (rootTdb->transactionReqd())
masterStats->setXnReqd(TRUE);
masterStats->setElapsedEndTime(compEndTime);
ExStatisticsArea * newStats = new (currContext.exHeap())
ExStatisticsArea(currContext.exHeap(), 0,
rootTdb->getCollectStatsType(),
rootTdb->getCollectStatsType());
newStats->setStatsEnabled(TRUE);
ExMasterStats * ems = new(currContext.exHeap())
ExMasterStats(currContext.exHeap());
ems->copyContents(masterStats);
ems->setCollectStatsType(rootTdb->getCollectStatsType());
newStats->setMasterStats(ems);
currContext.setStatsArea(newStats, TRUE, FALSE);
}
else
{
masterStats->setCollectStatsType(ComTdb::NO_STATS);
if (rootTdb != NULL)
{
if (rootTdb->getCompilerStatsInfo())
masterStats->compilerStatsInfo() =
*(rootTdb->getCompilerStatsInfo());
masterStats->setQueryType((Int16)rootTdb->getQueryType(),
rootTdb->getSubqueryType());
}
}
}
}
return 0;
}
//
// A helper function to check whether SQL access is currently allowed.
// The UDR server is the only SQL application that disables SQL access
// from time to time. This is done in order to enforce a policy where
// a UDR registered with the NO SQL attribute is not allowed to access
// SQL/MX.
//
static Lng32 CheckNOSQLAccessMode(CliGlobals &cliGlobals)
{
// rare error condition
if (!cliGlobals.sqlAccessAllowed())
{
cliGlobals.setUdrAccessModeViolation(TRUE);
ContextCli *context = cliGlobals.currContext();
if (context)
{
ComDiagsArea &diags = context->diags();
diags << DgSqlCode(- CLI_NO_SQL_ACCESS_MODE_VIOLATION);
}
return - CLI_NO_SQL_ACCESS_MODE_VIOLATION;
}
return SUCCESS;
}
static Lng32 CliPrologue(CliGlobals * cliGlobals,
const SQLMODULE_ID * module)
{
Lng32 retcode;
ContextCli * context = cliGlobals->currContext();
ComDiagsArea & diags = context->diags();
// If this is not a recursive CLI call, inherit the current
// process transid into this context. (We don't want to
// inherit the current process transid if this is a recursive
// CLI call. A recursive CLI call should always be done in
// the transid of its calling context, and the process transid
// might be different. This can happen, for example, if we are
// in a recursive CLI call underneath FILE_COMPLETE_.)
Lng32 numOfCliCalls = context->getNumOfCliCalls();
if ((numOfCliCalls == 1) ||
((numOfCliCalls == 2) && (cliGlobals->isESPProcess())))
{
ExTransaction *exTransaction = context->getTransaction();
if (exTransaction != NULL)
{
retcode = exTransaction->inheritTransaction();
if (isERROR(retcode))
{
diags << DgSqlCode(- CLI_BEGIN_TRANSACTION_ERROR);
return ERROR;
}
}
}
if ((context->getVersionOfCompiler() != COM_VERS_COMPILER_VERSION) && (numOfCliCalls >1 ))
{
short index = 0;
cliGlobals->setSavedVersionOfCompiler(context->getVersionOfCompiler());
context->setOrStartCompiler(COM_VERS_COMPILER_VERSION,NULL, index);
}
// Initialize session defaults.
// if session defaults have not been read from the default table,
// read them now.
if (context->getSessionDefaults() == NULL)
{
retcode = context->initializeSessionDefaults();
if (isERROR(retcode))
return SQLCLI_ReturnCode(cliGlobals->currContext(),retcode);
}
return SUCCESS;
}
static Lng32 CliEpilogue(CliGlobals * cliGlobals,
SQLSTMT_ID * currentSqlStmt,
Lng32 inRetcode = 0)
{
ContextCli * context = cliGlobals->currContext();
// Validate the current process transid only if this is not
// a recursive CLI call. (It is legitimate, for example,
// for the process to not have a transid, or to have a
// different transid than the current context, if we are
// in a recursive CLI call inside FILE_COMPLETE_.)
Lng32 numOfCliCalls = context->getNumOfCliCalls();
if (numOfCliCalls == 1)
{
short retcode = context->getTransaction()->validateTransaction();
if (isERROR(retcode))
{
ComDiagsArea & diags = context->diags();
return diags.mainSQLCODE();
}
}
#if 0
if ((cliGlobals->getSavedVersionOfCompiler() != context->getVersionOfCompiler()) && (numOfCliCalls > 1 ))
{
short index;
cliGlobals->setSavedVersionOfCompiler(context->getVersionOfCompiler());
context->setOrStartCompiler(cliGlobals->getSavedVersionOfCompiler(),NULL, index);
}
#endif
if (inRetcode == SQL_EOF)
return SQL_EOF;
if (isERROR(inRetcode))
{
// if priority of master was changed for execution,
// switch it back to its original priority.
// Do this only for root cli level.
if ((numOfCliCalls == 1) &&
(cliGlobals->priorityChanged()))
{
ComRtSetProcessPriority(cliGlobals->myPriority(), FALSE);
cliGlobals->setPriorityChanged(FALSE);
}
return SQLCLI_ReturnCode(cliGlobals->currContext(),inRetcode);
}
// if there's stuff in diags, it's a warning, and we need to
// pass the warning code out
if (context->diags().getNumber())
return context->diags().mainSQLCODE();
return SQLCLI_ReturnCode(context,inRetcode);
}
// Set the pointers for the host variable and its indicator host variable in
// pairs. Note, we are setting only the addresses for the host variables in
// the first row of the Rowset. The other are implicitely set by the binding
// style.
Lng32 local_SetDescPointers(/*IN*/ Descriptor * desc,
/*IN*/ Lng32 starting_entry,
/*IN*/ Lng32 num_ptr_pairs,
/*IN*/ va_list * ap,
/*IN*/ SQLCLI_PTR_PAIRS ptr_pairs[])
{
ContextCli *context = desc->getContext();
if ((!desc) ||
(num_ptr_pairs < 0) ||
(starting_entry <= 0) ||
((num_ptr_pairs + starting_entry - 1) > desc->getUsedEntryCount()))
{
ComDiagsArea & diags = context->diags();
diags << DgSqlCode(-CLI_INTERNAL_ERROR);
return SQLCLI_ReturnCode(context, -CLI_INTERNAL_ERROR);
}
for (Lng32 entry=starting_entry, i = 0; entry < starting_entry+num_ptr_pairs;
entry++, i++)
{
// need to re-order this to avoid possible problems with not setting
// the data area (i.e. VAR_PTR) last.
char * vp, * ip;
if (*ap) {
vp = va_arg(*ap, char *);
ip = va_arg(*ap, char *);
}
else {
vp = (char *)ptr_pairs[i].var_ptr;
ip = ptr_pairs[i].ind_ptr == (void *)-1 ? 0 : (char *)ptr_pairs[i].ind_ptr;
}
if(ip && (context->boundsCheckMemory(ip, desc->getIndLength(entry))) ||
(context->boundsCheckMemory(vp, desc->getVarDataLength(entry))))
return SQLCLI_ReturnCode(context,-CLI_USER_MEMORY_IN_EXECUTOR_SEGMENT);
desc->setDescItem(entry, SQLDESC_IND_PTR, (Long)ip, 0);
desc->setDescItem(entry, SQLDESC_VAR_PTR, (Long)vp, 0);
}
return SUCCESS;
}
// Some CLI calls deal with numeric host variables without there being
// an input/output expression. So far, the CLI assumed those variables
// to be "long" C variables. The methods here are a slight improvement
// but no perfect solution. They handle a few more cases.
// Retrieve information about the pointers and lengths of a numeric host var
// for the first row of the RowSet. To get the addresses for other row sets,
// the member function, getDescPointers should be used.
static Lng32 getNumericHostVarInfo(Descriptor *desc,
Lng32 desc_entry,
// output parameters
void *&hv_ptr,
Lng32 &hv_length,
Lng32 &hv_type,
void *&ind_ptr,
Lng32 &ind_length,
Lng32 &ind_type)
{
Lng32 retcode = desc->getDescItem(desc_entry,
SQLDESC_VAR_PTR,
(Lng32*) &hv_ptr,
NULL, 0, NULL, 0);
if (retcode != 0)
return SQLCLI_ReturnCode(desc->getContext(),retcode);
retcode = desc->getDescItem(desc_entry,
SQLDESC_LENGTH,
(Lng32*) &hv_length,
NULL, 0, NULL, 0);
if (retcode != 0)
return SQLCLI_ReturnCode(desc->getContext(),retcode);
retcode = desc->getDescItem(desc_entry,
SQLDESC_TYPE_FS,
(Lng32*) &hv_type,
NULL, 0, NULL, 0);
if (retcode != 0)
return SQLCLI_ReturnCode(desc->getContext(),retcode);
retcode = desc->getDescItem(desc_entry,
SQLDESC_IND_PTR,
(Lng32*) &ind_ptr,
NULL, 0, NULL, 0);
if (retcode != 0)
return SQLCLI_ReturnCode(desc->getContext(),retcode);
// the host variable must have a scale of 0
Lng32 hv_scale;
retcode = desc->getDescItem(desc_entry,
SQLDESC_SCALE,
(Lng32*) &hv_scale,
NULL, 0, NULL, 0);
if (retcode != 0)
return SQLCLI_ReturnCode(desc->getContext(),retcode);
// $$$$ Enable this after scale got initialized
// if (hv_scale != 0)
// return -1;
if (ind_ptr)
{
retcode = desc->getDescItem(desc_entry,
SQLDESC_IND_TYPE,
(Lng32*) &ind_type,
NULL, 0, NULL, 0);
if (retcode != 0)
return SQLCLI_ReturnCode(desc->getContext(),retcode);
switch (ind_type)
{
case REC_BIN16_SIGNED:
case REC_BIN16_UNSIGNED:
ind_length = 2;
break;
case REC_BIN32_SIGNED:
case REC_BIN32_UNSIGNED:
ind_length = 4;
break;
case REC_BIN64_SIGNED:
case REC_BIN64_UNSIGNED:
ind_length = 8;
break;
default:
retcode = -1;
}
}
return SQLCLI_ReturnCode(desc->getContext(),retcode);
/* RS -- to be tested,debugged and re-enabled
long retcode;
short nullable;
retcode = desc->getDescItemMainVarInfo(desc_entry,
nullable,
hv_type,
hv_length,
(void *)&hv_ptr,
ind_type,
ind_length,
(void *)&ind_ptr);
return SQLCLI_ReturnCode(desc->getContext(),retcode);
*/
}
static Lng32 InputValueFromNumericHostvar(Descriptor *desc,
Lng32 desc_entry,
Lng32 &value)
{
void *hvPtr;
Lng32 hvLength;
Lng32 hvType;
void *indPtr;
Lng32 indLength;
Lng32 indType;
ex_expr::exp_return_type expRetcode;
CollHeap * heap;
ComDiagsArea * diagsArea;
heap = desc->getContext()->exCollHeap();
diagsArea = desc->getContext()->getDiagsArea();
Lng32 retcode = getNumericHostVarInfo(desc,
desc_entry,
hvPtr,
hvLength,
hvType,
indPtr,
indLength,
indType);
if (retcode)
return SQLCLI_ReturnCode(desc->getContext(),retcode);
expRetcode = convDoIt((char *) hvPtr,
hvLength,
(short) hvType,
0,
0,
(char *) &value,
(Lng32) sizeof(value),
REC_BIN32_SIGNED,
0,
0,
NULL,
0,
heap,
&diagsArea);
if (expRetcode != ex_expr::EXPR_OK)
return ERROR;
if (indPtr)
{
// values coming in should not be NULL, just make
// sure nobody passes in a NULL
Lng32 userIndicatorVal;
expRetcode = convDoIt((char *) indPtr,
indLength,
(short) indType,
0,
0,
(char *) &userIndicatorVal,
(Lng32) sizeof(userIndicatorVal),
REC_BIN32_SIGNED,
0,
0,
NULL,
0,
heap,
&diagsArea);
if (expRetcode != ex_expr::EXPR_OK)
return ERROR;
if (userIndicatorVal)
return ERROR; // user specified NULL or junk
}
return (SUCCESS);
}
static Lng32 OutputValueIntoNumericHostvar(Descriptor *desc,
Lng32 desc_entry,
Lng32 value)
{
void *hvPtr;
Lng32 hvLength;
Lng32 hvType;
void *indPtr;
Lng32 indLength;
Lng32 indType;
ex_expr::exp_return_type expRetcode;
CollHeap * heap;
ComDiagsArea * diagsArea;
ContextCli * context;
context = desc->getContext();
heap = context->exCollHeap();
diagsArea = context->getDiagsArea();
Lng32 retcode = getNumericHostVarInfo(desc,
desc_entry,
hvPtr,
hvLength,
hvType,
indPtr,
indLength,
indType);
if (retcode)
return ERROR;
if (hvType >= REC_MIN_NUMERIC && hvType <= REC_MAX_NUMERIC)
{
expRetcode = convDoIt((char *) &value,
(Lng32) sizeof(value),
REC_BIN32_SIGNED,
0,
0,
(char *) hvPtr,
hvLength,
(short) hvType,
0,
0,
NULL,
0,
heap,
&diagsArea);
if (expRetcode != ex_expr::EXPR_OK)
return ERROR;
}
else
{
ComDiagsArea & diags = context->diags();
diags << DgSqlCode(-3164);
return ERROR;
}
if (indPtr)
{
// move a zero into the indicator host variable
Lng32 nonNull = 0;
expRetcode = convDoIt((char *) &nonNull,
(Lng32) sizeof(nonNull),
REC_BIN32_SIGNED,
0,
0,
(char *) indPtr,
indLength,
(short) indType,
0,
0,
NULL,
0,
heap,
&diagsArea);
if (expRetcode != ex_expr::EXPR_OK)
return ERROR;
}
return SUCCESS;
}
Lng32 SQLCLI_GetDiskMaxSize (
/*IN*/ CliGlobals *cliGlobals,
/*IN*/ char *volname,
/*OUT*/ Int64 *totalCapacity,
/*OUT*/ Int64 *totalFreespace)
{
Lng32 retcode = 0;
// create initial context, if first call, don't add module because
// that would cause infinite recursion
retcode = CliPrologue(cliGlobals,NULL);
if (isERROR(retcode))
return retcode;
ContextCli & currContext = *(cliGlobals->currContext());
ComDiagsArea & diags = currContext.diags();
return retcode;
}
Lng32 SQLCLI_GetListOfDisks (
/*IN*/ CliGlobals *cliGlobals,
/*IN/OUT*/ char *diskBuf,
/* OUT */ Int32 *numTSEs,
/*OUT */Int32 *maxTSELength,
/*IN/OUT */ Int32* diskBufLen
)
{
Lng32 retcode = 0;
Int32 numPrimaries = 0;
MS_Mon_Process_Info_Type *tseInfo = NULL;
// create initial context, if first call, don't add module because
// that would cause infinite recursion
retcode = CliPrologue(cliGlobals,NULL);
if (isERROR(retcode))
return retcode;
ContextCli & currContext = *(cliGlobals->currContext());
ComDiagsArea & diags = currContext.diags();
NAHeap *heap = cliGlobals->currContext()->exHeap();
*maxTSELength = MS_MON_MAX_PROCESS_NAME;
retcode = msg_mon_get_process_info_type(MS_ProcessType_TSE,
numTSEs,
0,
NULL);
if (retcode)
{
diags << DgSqlCode(-EXE_ERROR_FROM_FS2)
<< DgNskCode(retcode)
<< DgString0("msg_mon_get_process_info_type");
retcode = -EXE_ERROR_FROM_FS2;
}
tseInfo = new (heap) MS_Mon_Process_Info_Type[*numTSEs];
retcode = msg_mon_get_process_info_type(MS_ProcessType_TSE,
numTSEs,
*numTSEs,
tseInfo);
if (retcode)
{
diags << DgSqlCode(-EXE_ERROR_FROM_FS2)
<< DgNskCode(retcode)
<< DgString0("msg_mon_get_process_info_type");
retcode = -EXE_ERROR_FROM_FS2;
}
if ( *diskBufLen < *numTSEs*MS_MON_MAX_PROCESS_NAME)
{
diags << DgSqlCode(-CLI_BUFFER_TOO_SMALL);
retcode = -CLI_BUFFER_TOO_SMALL;
*diskBufLen = (*numTSEs * MS_MON_MAX_PROCESS_NAME)+MS_MON_MAX_PROCESS_NAME;
}
else
{
// Fill in the TSE disk name information in the output param.
str_pad(diskBuf ,*numTSEs*MS_MON_MAX_PROCESS_NAME, ' ');
for (short j=0,i =0; i < *numTSEs; i++)
{
if (!tseInfo[i].backup)
{
str_cpy((char *)&diskBuf[j], tseInfo[i].process_name,MS_MON_MAX_PROCESS_NAME,'\0');
numPrimaries++;
j += MS_MON_MAX_PROCESS_NAME;
}
}
*numTSEs = numPrimaries;
}
if (isERROR(retcode))
return SQLCLI_ReturnCode(&currContext,retcode);
return retcode;
}
Lng32 SQLCLI_AllocDesc(/*IN*/ CliGlobals * cliGlobals,
/*INOUT*/ SQLDESC_ID * desc_id,
/*IN OPTIONAL*/ SQLDESC_ID * input_descriptor)
{
Lng32 retcode;
// create initial context, if first call, and add module, if any.
retcode = CliPrologue(cliGlobals,desc_id->module);
if (isERROR(retcode))
return retcode;
ContextCli & currContext = *(cliGlobals->currContext());
ComDiagsArea & diags = currContext.diags();
Lng32 maxEntries = 0L;
if (input_descriptor)
{
Descriptor * input_desc = currContext.getDescriptor(input_descriptor);
/* descriptor must exist */
if (!input_desc)
{
diags << DgSqlCode(-CLI_DESC_NOT_EXISTS);
return SQLCLI_ReturnCode(&currContext,-CLI_DESC_NOT_EXISTS);
}
retcode = InputValueFromNumericHostvar(input_desc,
1,
maxEntries);
if (isERROR(retcode))
return SQLCLI_ReturnCode(&currContext,retcode);
}
else
{
// no input descriptor was passed in. Allocate the
// max entries allowed.
maxEntries = 500;
}
if (maxEntries < 1)
{
diags << DgSqlCode(- CLI_DATA_OUTOFRANGE)
<< DgInt0(maxEntries);
return SQLCLI_ReturnCode(&currContext,-CLI_DATA_OUTOFRANGE);
}
/* allocate a new descriptor in the current context. */
/* return the descriptor handle in desc_id, if name mode */
/* is "desc_handle" */
retcode = currContext.allocateDesc(desc_id, maxEntries);
if (isERROR(retcode))
return SQLCLI_ReturnCode(&currContext,retcode);
return CliEpilogue(cliGlobals, NULL);
}
#define MULTIPLE_CURSORS_PER_STATEMENT 1
#define KLUGE_CURSOR 1
#if defined(MULTIPLE_CURSORS_PER_STATEMENT) && defined(KLUGE_CURSOR)
#include "ComQueue.h"
#endif
Lng32 SQLCLI_AllocStmt(/*IN*/ CliGlobals * cliGlobals,
/*INOUT*/ SQLSTMT_ID * statement_id,
/*IN OPTIONAL*/ SQLSTMT_ID * cloned_statement)
{
Lng32 retcode;
// create initial context, if first call, and add module, if any.
retcode = CliPrologue(cliGlobals,statement_id->module);
if (isERROR(retcode))
return retcode;
ContextCli & currContext = *(cliGlobals->currContext());
ComDiagsArea & diags = currContext.diags();
if (!cloned_statement)
{
/* allocate a new statement entry in the current context. */
/* return the statement handle in statement_id, if name mode */
/* is "stmt_handle" */
retcode = currContext.allocateStmt(statement_id, Statement::DYNAMIC_STMT);
if (isERROR(retcode))
return SQLCLI_ReturnCode(&currContext,retcode);
}
else
{
if (
// cloned statement must be a statement, not a cursor
// so it's an error if it's not stmt_name or stmt_handle...
((cloned_statement->name_mode != stmt_name ) &&
(cloned_statement->name_mode != stmt_handle) &&
(cloned_statement->name_mode != stmt_via_desc) ) ||
// new statement, must be a cursor or a stmt handle
(statement_id->name_mode == stmt_name) ||
(statement_id->name_mode == stmt_via_desc))
{
diags << DgSqlCode(-CLI_INTERNAL_ERROR);
return SQLCLI_ReturnCode(cliGlobals->currContext(),
-CLI_INTERNAL_ERROR);
}
#if defined(MULTIPLE_CURSORS_PER_STATEMENT)
retcode = currContext.allocateStmt(statement_id,
Statement::DYNAMIC_STMT,
cloned_statement);
#else
// kluge!!! this avoids the problem that we don't know how to
// allocate cursors which are separate from statements
// For beta, the limitation is 1 cursor per statement
SQLDESC_ID desc;
desc.module = statement_id->module;
desc.identifier = statement_id->identifier;
desc.name_mode = desc_name;
retcode = SQLCLI_SetCursorName(cliGlobals, cloned_statement, &desc);
#endif
if (isERROR(retcode))
return SQLCLI_ReturnCode(cliGlobals->currContext(),retcode);
}
return CliEpilogue(cliGlobals, NULL);
}
Lng32 SQLCLI_AllocStmtForRS(/*IN*/ CliGlobals *cliGlobals,
/*IN*/ SQLSTMT_ID *callStmtId,
/*IN*/ Lng32 resultSetIndex,
/*INOUT*/ SQLSTMT_ID *resultSetStmtId)
{
Lng32 retcode;
// create initial context, if first call, and add module, if any.
retcode = CliPrologue(cliGlobals, callStmtId->module);
if (isERROR(retcode))
return retcode;
ContextCli & currContext = *(cliGlobals->currContext());
ComDiagsArea & diags = currContext.diags();
// The CALL statement must exist
Statement *callStmt = currContext.getStatement(callStmtId);
if (!callStmt)
{
diags << DgSqlCode(-CLI_STMT_NOT_EXISTS);
return SQLCLI_ReturnCode(&currContext, -CLI_STMT_NOT_EXISTS);
}
// The parent statement must be a CALL. This can be determine
// from the root TDB's query type
NABoolean parentIsCall = FALSE;
ex_root_tdb *parentRoot = callStmt->getRootTdb();
if (parentRoot)
{
Lng32 queryType = parentRoot->getQueryType();
if (queryType == SQL_CALL_NO_RESULT_SETS ||
queryType == SQL_CALL_WITH_RESULT_SETS)
parentIsCall = TRUE;
}
if (!parentIsCall)
{
diags << DgSqlCode(-EXE_UDR_RS_ALLOC_STMT_NOT_CALL);
return SQLCLI_ReturnCode(&currContext, -EXE_UDR_RS_ALLOC_STMT_NOT_CALL);
}
// The RS index must not be out of range
Lng32 maxRS = 0;
if (parentRoot)
maxRS = parentRoot->getMaxResultSets();
if (resultSetIndex < 1 || resultSetIndex > maxRS)
{
diags << DgSqlCode(-EXE_UDR_RS_ALLOC_INVALID_INDEX)
<< DgInt0(resultSetIndex)
<< DgInt1(maxRS);
return SQLCLI_ReturnCode(&currContext, -EXE_UDR_RS_ALLOC_INVALID_INDEX);
}
// A result set must not already exist at the specified position
ExRsInfo *rsInfo = callStmt->getResultSetInfo();
if (rsInfo && rsInfo->statementExists(resultSetIndex))
{
diags << DgSqlCode(-EXE_UDR_RS_ALLOC_ALREADY_EXISTS)
<< DgInt0(resultSetIndex)
<< DgInt1(resultSetIndex);
return SQLCLI_ReturnCode(&currContext, -EXE_UDR_RS_ALLOC_ALREADY_EXISTS);
}
// The RS statement must not exist
Statement *rs = currContext.getStatement(resultSetStmtId);
if (rs)
{
diags << DgSqlCode(-CLI_DUPLICATE_STMT);
return SQLCLI_ReturnCode(&currContext, -CLI_DUPLICATE_STMT);
}
// Create the new statement
retcode = SQLCLI_AllocStmt(cliGlobals, resultSetStmtId, NULL);
if (isERROR(retcode))
return SQLCLI_ReturnCode(&currContext, retcode);
// Locate the new statement
rs = currContext.getStatement(resultSetStmtId);
if (!rs)
{
diags << DgSqlCode(-CLI_STMT_NOT_EXISTS);
return SQLCLI_ReturnCode(&currContext, -CLI_STMT_NOT_EXISTS);
}
// Bind the new statement to its parent CALL statement
rsInfo = callStmt->getOrCreateResultSetInfo();
rsInfo->setNumEntries(maxRS);
rsInfo->bind(resultSetIndex, rs);
rs->setParentCall(callStmt);
return CliEpilogue(cliGlobals, resultSetStmtId);
} // SQLCLI_AllocStmtForRS
Lng32 SQLCLI_AssocFileNumber(/*IN*/ CliGlobals * cliGlobals,
/*IN*/ SQLSTMT_ID * statement_id,
/*IN*/ short file_num)
{
return 0;
}
Lng32 SQLCLI_BreakEnabled(/*IN*/ CliGlobals * cliGlobals,
/*IN*/ UInt32 enabled )
{
if (!cliGlobals)
{
return -CLI_NO_CURRENT_CONTEXT;
}
cliGlobals->setBreakEnabled (enabled);
return 0;
}
Lng32 SQLCLI_SPBreakRecvd(/*IN*/ CliGlobals * cliGlobals,
/*OUT*/ UInt32 *breakRecvd)
{
if (!cliGlobals)
{
return -CLI_NO_CURRENT_CONTEXT;
}
*breakRecvd = cliGlobals->SPBreakReceived();
cliGlobals->setSPBreakReceived(FALSE);
return 0;
}
Lng32 SQLCLI_CreateContext(/*IN*/ CliGlobals * cliGlobals,
/*OUT*/ SQLCTX_HANDLE *contextHandle,
/*IN*/ char * sqlAuthId,
/*IN*/ Lng32 mustBeZero /* for future use */)
{
Lng32 retcode;
ContextCli & currContext = *(cliGlobals->currContext());
ComDiagsArea & diags = currContext.diags();
if (mustBeZero != 0)
{
//
// We constrain "for future use" parameters so that only a
// particular value (in this case 0) is accepted. Without this
// restriction things might break should we suddenly give the
// parameters some semantics.
//
diags << DgSqlCode(-CLI_RESERVED_ARGUMENT)
<< DgString0("2")
<< DgString1("SQL_EXEC_CreateContext")
<< DgString2("0");
return SQLCLI_ReturnCode(&currContext, -CLI_RESERVED_ARGUMENT);
}
ContextCli * newContext = NULL;
retcode = cliGlobals->createContext(newContext);
if (! newContext)
{
diags << DgSqlCode(-CLI_INTERNAL_ERROR);
return SQLCLI_ReturnCode(&currContext,-CLI_INTERNAL_ERROR);
}
if (contextHandle)
*contextHandle = newContext->getContextHandle();
return SUCCESS;
}
Lng32 SQLCLI_CurrentContext(/*IN*/ CliGlobals * cliGlobals,
/*OUT*/ SQLCTX_HANDLE *contextHandle)
{
if (!cliGlobals) {
return -CLI_NO_CURRENT_CONTEXT;
}
ContextCli *currentContext = cliGlobals->currContext();
if (contextHandle)
*contextHandle = currentContext->getContextHandle();
return SUCCESS;
}
Lng32 SQLCLI_DeleteContext(/*IN*/ CliGlobals * cliGlobals,
/*IN*/ SQLCTX_HANDLE context_handle)
{
if (!cliGlobals) {
return -CLI_NO_CURRENT_CONTEXT;
}
return SQLCLI_DropContext(cliGlobals, context_handle);
}
Lng32 SQLCLI_DropModule(/*IN*/ CliGlobals * cliGlobals,
/*IN*/ const SQLMODULE_ID * module_id)
{
return SUCCESS;
}
Lng32 SQLCLI_ResetContext(/*IN*/ CliGlobals * cliGlobals,
/*IN*/ SQLCTX_HANDLE context_handle,
/*IN*/ void *contextMsg)
{
Lng32 retcode;
ContextCli *context = cliGlobals->getContext(context_handle);
ContextCli *defaultContext = cliGlobals->getDefaultContext();
ComDiagsArea &diags = defaultContext->diags();
if (context == NULL)
{
diags << DgSqlCode(-CLI_CONTEXT_NOT_FOUND);
return SQLCLI_ReturnCode(defaultContext, -CLI_CONTEXT_NOT_FOUND);
}
CLISemaphore *tmpSemaphore = context->getSemaphore();
tmpSemaphore->get();
try
{
retcode = cliGlobals->resetContext(context, contextMsg);
}
catch (...)
{
retcode = -CLI_INTERNAL_ERROR;
tmpSemaphore->release();
}
tmpSemaphore->release();
return SQLCLI_ReturnCode(context, retcode);
}
Lng32 SQLCLI_GetUdrErrorFlags_Internal(/*IN*/ CliGlobals * cliGlobals,
/*OUT*/ Lng32 * udrErrorFlags){
if (!cliGlobals) {
return -CLI_NO_CURRENT_CONTEXT;
}
if (!cliGlobals->getUdrErrorChecksEnabled())
{
return -CLI_NOT_CHECK_VIOLATION;
}
NABoolean sqlViolation = FALSE;
NABoolean xactViolation = FALSE;
NABoolean xactWasAborted = FALSE;
cliGlobals->getUdrErrorFlags(sqlViolation, xactViolation, xactWasAborted);
*udrErrorFlags = 0;
if (sqlViolation) {
*udrErrorFlags |= SQLUDR_SQL_VIOL;
}
if (xactViolation) {
*udrErrorFlags |= SQLUDR_XACT_VIOL;
}
if (xactWasAborted) {
*udrErrorFlags |= SQLUDR_XACT_ABORT;
}
return SUCCESS;
}
Lng32 SQLCLI_SetUdrAttributes_Internal(/*IN*/ CliGlobals * cliGlobals,
/*IN*/ Lng32 sqlAccessMode,
/*IN*/ Lng32 mustBeZero /* for future use */){
if (!cliGlobals) {
return -CLI_NO_CURRENT_CONTEXT;
}
if (mustBeZero != 0)
{
//
// We constrain "for future use" parameters so that only a
// particular value (in this case 0) is accepted. Without this
// restriction things might break should we suddenly give the
// parameters some semantics.
//
ContextCli & currContext = *(cliGlobals->currContext());
ComDiagsArea & diags = currContext.diags();
diags << DgSqlCode(-CLI_RESERVED_ARGUMENT)
<< DgString0("2")
<< DgString1("SQL_EXEC_SetUdrAttributes_Internal")
<< DgString2("0");
return SQLCLI_ReturnCode(&currContext, -CLI_RESERVED_ARGUMENT);
}
cliGlobals->setUdrErrorChecksEnabled(TRUE);
cliGlobals->setUdrSQLAccessMode((enum ComRoutineSQLAccess)sqlAccessMode);
return SUCCESS;
}
Lng32 SQLCLI_ResetUdrErrorFlags_Internal(/*IN*/ CliGlobals * cliGlobals){
if (!cliGlobals) {
return -CLI_NO_CURRENT_CONTEXT;
}
cliGlobals->clearUdrErrorFlags();
return SUCCESS;
}
// A CLI wrapper around a ContextCli method to dynamically set JVM
// startup options in the UDR server
Lng32 SQLCLI_SetUdrRuntimeOptions_Internal(/*IN*/ CliGlobals *cliGlobals,
/*IN*/ const char *options,
/*IN*/ ULng32 optionsLen,
/*IN*/ const char *delimiters,
/*IN*/ ULng32 delimsLen)
{
if (!cliGlobals)
{
return -CLI_NO_CURRENT_CONTEXT;
}
ContextCli &currContext = *(cliGlobals->currContext());
Lng32 retcode = currContext.setUdrRuntimeOptions(options, optionsLen,
delimiters, delimsLen);
return SQLCLI_ReturnCode(&currContext, retcode);
}
Lng32 SQLCLI_DeallocDesc(/*IN*/ CliGlobals * cliGlobals,
/*IN*/ SQLDESC_ID * desc_id)
{
Lng32 retcode;
if (!cliGlobals)
{
return -CLI_NO_CURRENT_CONTEXT;
}
ContextCli & currContext = *(cliGlobals->currContext());
ComDiagsArea & diags = currContext.diags();
retcode = currContext.deallocDesc(desc_id, FALSE);
return SQLCLI_ReturnCode(&currContext,retcode);
}
Lng32 SQLCLI_DeallocStmt(/*IN*/ CliGlobals * cliGlobals,
/*IN*/ SQLSTMT_ID * statement_id)
{
Lng32 retcode;
if (!cliGlobals)
{
return (-CLI_NO_CURRENT_CONTEXT);
}
retcode = CheckNOSQLAccessMode(*cliGlobals);
if (isERROR(retcode))
{
return retcode;
}
retcode = CliPrologue(cliGlobals,NULL);
if (isERROR(retcode))
return retcode;
ContextCli & currContext = *(cliGlobals->currContext());
ComDiagsArea & diags = currContext.diags();
retcode = currContext.deallocStmt(statement_id, FALSE);
return SQLCLI_ReturnCode(&currContext,retcode);
}
Lng32 SQLCLI_DefineDesc(/*IN*/ CliGlobals * cliGlobals,
/*IN*/ SQLSTMT_ID * statement_id,
/* (SQLWHAT_DESC) *IN*/ Lng32 what_descriptor,
/*IN*/ SQLDESC_ID * desc_id)
{
Lng32 retcode;
// create initial context, if first call, and add module, if any.
retcode = CliPrologue(cliGlobals,statement_id->module);
if (isERROR(retcode))
return retcode;
ContextCli & currContext = *(cliGlobals->currContext());
ComDiagsArea & diags = currContext.diags();
Statement * stmt = currContext.getStatement(statement_id);
/* stmt must exist */
if (!stmt)
{
diags << DgSqlCode(-CLI_STMT_NOT_EXISTS);
return SQLCLI_ReturnCode(&currContext,-CLI_STMT_NOT_EXISTS);
}
Descriptor * desc = currContext.getDescriptor(desc_id);
/* descriptor must exist */
if (!desc)
{
diags << DgSqlCode(-CLI_DESC_NOT_EXISTS);
return SQLCLI_ReturnCode(&currContext,-CLI_DESC_NOT_EXISTS);
}
stmt->addDefaultDesc(desc, what_descriptor);
return SUCCESS;
}
Lng32 SQLCLI_DescribeStmt(/*IN*/ CliGlobals * cliGlobals,
/*IN*/ SQLSTMT_ID * statement_id,
/*IN OPTIONAL*/ SQLDESC_ID * input_descriptor,
/*IN OPTIONAL*/ SQLDESC_ID * output_descriptor)
{
if (!cliGlobals)
{
return -CLI_NO_CURRENT_CONTEXT;
}
Lng32 retcode;
ContextCli & currContext = *(cliGlobals->currContext());
ComDiagsArea & diags = currContext.diags();
/* describe the statement */
Statement * stmt = currContext.getStatement(statement_id);
/* stmt must exist */
if (!stmt)
{
diags << DgSqlCode(-CLI_STMT_NOT_EXISTS);
return SQLCLI_ReturnCode(&currContext,-CLI_STMT_NOT_EXISTS);
}
/* stmt should be a dynamic statement and must not be in INITIAL state */
/* if it is in INITIAL state then the statement did not get prepared. */
/* If it is in PREPARE state, then it is a nowaited prepare which is
still being prepared. */
if ((stmt->getState() == Statement::INITIAL_) ||
(stmt->getState() == Statement::PREPARE_))
{
// One special case for CALL statements. A stored procedure result
// set proxy statement can be described without first being
// prepared by the CLI caller. The prepare gets done internally
// inside Statement::describe(). So for this case we do not want
// to return here with an error just because the statement is not
// yet prepared.
NABoolean reportAnError = TRUE;
if (stmt->getState() == Statement::INITIAL_ && stmt->getParentCall())
reportAnError = FALSE;
if (reportAnError)
{
diags << DgSqlCode(-CLI_STMT_NOT_PREPARED);
return SQLCLI_ReturnCode(&currContext,-CLI_STMT_NOT_PREPARED);
}
}
if (input_descriptor)
{
Descriptor * input_desc = currContext.getDescriptor(input_descriptor);
if (!input_desc)
{
diags << DgSqlCode(-CLI_DESC_NOT_EXISTS);
return SQLCLI_ReturnCode(&currContext,-CLI_DESC_NOT_EXISTS);
}
retcode = stmt->describe(input_desc,
SQLWHAT_INPUT_DESC,
diags);
if (isERROR(retcode))
return SQLCLI_ReturnCode(&currContext,retcode);
}
if (output_descriptor)
{
Descriptor * output_desc = currContext.getDescriptor(output_descriptor);
if (!output_desc)
{
diags << DgSqlCode(-CLI_DESC_NOT_EXISTS);
return SQLCLI_ReturnCode(&currContext,-CLI_DESC_NOT_EXISTS);
}
retcode = stmt->describe(output_desc,
SQLWHAT_OUTPUT_DESC,
diags);
if (isERROR(retcode))
return SQLCLI_ReturnCode(&currContext,retcode);
}
return CliEpilogue(cliGlobals, statement_id);
}
Lng32 SQLCLI_DisassocFileNumber(/*IN*/ CliGlobals * cliGlobals,
/*IN*/ SQLSTMT_ID * statement_id)
{
return 0;
}
Lng32 SQLCLI_DropContext(/*IN*/ CliGlobals * cliGlobals,
/*IN*/ SQLCTX_HANDLE context_handle )
{
ContextCli *defaultContext = cliGlobals->getDefaultContext();
ComDiagsArea & diags = defaultContext->diags();
ContextCli * droppedContext = cliGlobals->getContext(context_handle,
TRUE);
if (context_handle == cliGlobals->getDefaultContext()->getContextHandle())
{
diags << DgSqlCode(-CLI_DEFAULT_CONTEXT_NOT_ALLOWED);
return SQLCLI_ReturnCode(defaultContext,-CLI_DEFAULT_CONTEXT_NOT_ALLOWED);
}
if (droppedContext == NULL)
{
diags << DgSqlCode(-CLI_CONTEXT_NOT_FOUND);
return SQLCLI_ReturnCode(defaultContext,-CLI_CONTEXT_NOT_FOUND);
}
Lng32 retcode;
try
{
retcode = cliGlobals->dropContext(droppedContext);
if (retcode == -1)
{
// $$$ probably should be a different error message
diags << DgSqlCode(-CLI_NO_CURRENT_CONTEXT);
}
}
catch (...)
{
return -CLI_INTERNAL_ERROR;
}
return SQLCLI_ReturnCode(defaultContext,retcode);
}
Lng32 SQLCLI_SetRowsetDescPointers(CliGlobals * cliGlobals,
SQLDESC_ID * desc_id,
Lng32 rowset_size,
Lng32 *rowset_status_ptr,
Lng32 starting_entry,
Lng32 num_quadruple_fields,
va_list ap,
SQLCLI_QUAD_FIELDS quad_fields[])
{
if (!desc_id)
{
return -CLI_INTERNAL_ERROR;
}
ContextCli & currContext = *(cliGlobals->currContext());
ComDiagsArea & diags = currContext.diags();
Descriptor * desc = currContext.getDescriptor(desc_id);
/* descriptor must exist */
if (!desc)
{
diags << DgSqlCode(-CLI_DESC_NOT_EXISTS);
return SQLCLI_ReturnCode(&currContext,-CLI_DESC_NOT_EXISTS);
}
desc->setDescItem(0, SQLDESC_ROWSET_SIZE, rowset_size, 0);
desc->setDescItem(0, SQLDESC_ROWSET_STATUS_PTR, (Long)rowset_status_ptr, 0);
if (num_quadruple_fields > 0)
{
for (Lng32 entry=starting_entry, i = 0;
entry < starting_entry+num_quadruple_fields;
entry++, i++)
{
if (desc->getUsedEntryCount() < entry) {
diags << DgSqlCode(-CLI_INVALID_DESC_ENTRY);
return SQLCLI_ReturnCode(&currContext,-CLI_INVALID_DESC_ENTRY);
}
// need to re-order this to avoid possible problems with not setting
// the data area (i.e. VAR_PTR) last.
char * var_layout, * var_ptr, * ind_layout, * ind_ptr;
if (ap) {
var_layout = va_arg(ap, char *);
var_ptr = va_arg(ap, char *);
ind_layout = va_arg(ap, char *);
ind_ptr = va_arg(ap, char *);
}
else {
var_layout = (char *)((long)quad_fields[i].var_layout);
var_ptr = (char *)quad_fields[i].var_ptr;
ind_layout = (char *)((long)quad_fields[i].ind_layout);
ind_ptr = quad_fields[i].ind_ptr == (void *)-1 ? 0 : (char *)quad_fields[i].ind_ptr;
}
// setDescItems requires setting the rowset size and layout size items
// before setting the pointers. Do not change the following order.
desc->setDescItem(entry, SQLDESC_ROWSET_VAR_LAYOUT_SIZE,
(Long)var_layout, 0);
desc->setDescItem(entry, SQLDESC_ROWSET_IND_LAYOUT_SIZE,
(Long)ind_layout, 0);
desc->setDescItem(entry, SQLDESC_IND_PTR,
(Long)ind_ptr, 0);
desc->setDescItem(entry, SQLDESC_VAR_PTR,
(Long)var_ptr, 0);
}
va_end(ap);
}
return SUCCESS;
}
Lng32 SQLCLI_GetRowsetNumprocessed(CliGlobals * cliGlobals,
SQLDESC_ID * desc_id,
Lng32 &rowset_nprocessed)
{
Lng32 retcode = SUCCESS;
// create initial context, if first call, and add module, if any.
retcode = CliPrologue(cliGlobals,desc_id->module);
if (isERROR(retcode))
return retcode;
ContextCli & currContext = *(cliGlobals->currContext());
ComDiagsArea & diags = currContext.diags();
Descriptor * desc = currContext.getDescriptor(desc_id);
/* descriptor must exist */
if (!desc)
{
diags << DgSqlCode(-CLI_DESC_NOT_EXISTS);
return SQLCLI_ReturnCode(&currContext,-CLI_DESC_NOT_EXISTS);
}
retcode = desc->getDescItem(1,
SQLDESC_ROWSET_NUM_PROCESSED,
(Lng32*) &rowset_nprocessed,
NULL, 0, NULL, 0);
retcode = CliEpilogue(cliGlobals, NULL);
return SQLCLI_ReturnCode(&currContext,retcode);
}
static NABoolean SQLCLI_GetRetryInfo(CliGlobals * cliGlobals,
Lng32 retcode,
AQRStatementInfo * aqrSI,
short afterPrepare,
short afterExec,
short afterFetch,
short afterCEFC,
Lng32 &retries,
Lng32 &delay,
Lng32 &type,
Lng32 &numCQDs,
char* &cqdStr,
Lng32 &cmpInfo,
ComCondition* &cc)
{
retries = -1;
delay = -1;
type = -1;
cmpInfo = 0;
cc = NULL;
Lng32 intAQR;
ContextCli * context = cliGlobals->currContext();
AQRInfo * aqr = context->aqrInfo();
NABoolean doAqr = FALSE; // auto query retry
if ((aqr) &&
(aqrSI) &&
(aqrSI->getRetryStatementId()) &&
(aqrSI->getRetrySqlSource()) &&
(isERROR(retcode)) &&
(retcode != -EXE_CANCELED) &&
(context->diags().getNumber(DgSqlCode::ERROR_) > 0) &&
(context->getNumOfCliCalls() == 1))
{
type = AQRInfo::RETRY_NONE;
for (Int32 i = 1;
((NOT doAqr) &&
(i <= context->diags().getNumber(DgSqlCode::ERROR_)));
i++)
{
ComCondition * lcc = context->diags().getErrorEntry(i);
aqr->getAQREntry(lcc->getSQLCODE(), lcc->getNskCode(),
retries, delay, type,
numCQDs, cqdStr, cmpInfo, intAQR);
if ((type >= AQRInfo::RETRY_MIN_VALID_TYPE) &&
(type <= AQRInfo::RETRY_MAX_VALID_TYPE))
{
cc = lcc;
doAqr = TRUE;
} // if
} // for
if ((type != AQRInfo::RETRY_NONE) &&
((afterFetch) && (NOT aqrSI->retryFirstFetch())) &&
!(afterExec && aqrSI->retryAfterExec())
)
doAqr = FALSE;
} // if
return doAqr;
}
static Lng32 SQLCLI_RetryDeallocStmt(
/*IN*/ CliGlobals * cliGlobals,
AQRStatementInfo * aqrSI)
{
Lng32 retcode = 0;
ContextCli * currContext = cliGlobals->currContext();
ComDiagsArea & diags = currContext->diags();
diags.clear();
SQLDESC_ID * temp_input_desc_id = NULL;
SQLDESC_ID * temp_output_desc_id = NULL;
if (! aqrSI->getRetryInputDesc())
{
SQLMODULE_ID * module = new(currContext->exHeap()) SQLMODULE_ID;
init_SQLMODULE_ID(module);
temp_input_desc_id = new(currContext->exHeap()) SQLDESC_ID;
init_SQLDESC_ID(temp_input_desc_id, SQLCLI_CURRENT_VERSION, desc_handle, module);
retcode = SQLCLI_AllocDescInt(cliGlobals, temp_input_desc_id, 1);
if (isERROR(retcode))
return retcode;
}
if (! aqrSI->getRetryOutputDesc())
{
SQLMODULE_ID * module = new(currContext->exHeap()) SQLMODULE_ID;
init_SQLMODULE_ID(module);
temp_output_desc_id = new(currContext->exHeap()) SQLDESC_ID;
init_SQLDESC_ID(temp_output_desc_id, SQLCLI_CURRENT_VERSION, desc_handle, module);
retcode = SQLCLI_AllocDescInt(cliGlobals, temp_output_desc_id, 1);
if (isERROR(retcode))
return retcode;
}
retcode = SQLCLI_DescribeStmt(cliGlobals,
aqrSI->getRetryStatementId(),
temp_input_desc_id,
temp_output_desc_id);
if (isERROR(retcode) && (retcode != -CLI_STMT_NOT_PREPARED))
return retcode;
if (retcode == -CLI_STMT_NOT_PREPARED)
diags.clear();
aqrSI->setRetryTempInputDesc(temp_input_desc_id);
aqrSI->setRetryTempOutputDesc(temp_output_desc_id);
retcode = SQLCLI_DeallocStmt(cliGlobals,
aqrSI->getRetryStatementId());
if (isERROR(retcode))
return retcode;
return retcode;
}
// If a query was explicitly prepared and it gets a timestamp mismatch
// or a lost open error during its fixup or execute phase, then AQR
// is not done. This is needed to handle the case where the table shape
// or structure got changed by a ddl operation after the stmt was
// explicitly prepared. And that ddl operation caused the ts mismatch.
// Since this was an explicitly prepared stmt, it cannot be automatically
// re-described during the execute phase. Executing a statement that was
// internally prepared during AQR but not re-described can cause
// inconsistency between the structures/data that is returned or input
// and the structure that the caller had set up to handle during
// describe input/output phase of the initial prepare.
// Users need to explicitly reprepare this statement.
// Add an error indicating this condition and return the original
// error back to user.
static Lng32 SQLCLI_RetryValidateDescs
(/*IN*/ CliGlobals * cliGlobals,
/*IN*/ SQLSTMT_ID * statement_id,
/*IN OPTIONAL*/ SQLDESC_ID * curr_input_desc_id,
/*IN OPTIONAL*/ SQLDESC_ID * curr_output_desc_id)
{
Lng32 retcode = 0;
ContextCli & currContext = *(cliGlobals->currContext());
ComDiagsArea & diags = currContext.diags();
Statement * stmt = currContext.getStatement(statement_id);
if ((stmt == NULL) || (stmt->isStandaloneQ()))
return retcode;
SQLMODULE_ID module;
init_SQLMODULE_ID(&module);
SQLDESC_ID new_input_desc_id;
SQLDESC_ID new_output_desc_id;
init_SQLDESC_ID(&new_input_desc_id, SQLCLI_CURRENT_VERSION, desc_handle, &module);
init_SQLDESC_ID(&new_output_desc_id, SQLCLI_CURRENT_VERSION, desc_handle, &module);
retcode = SQLCLI_AllocDescInt(cliGlobals, &new_input_desc_id, 1);
if (isERROR(retcode))
return retcode;
retcode = SQLCLI_AllocDescInt(cliGlobals, &new_output_desc_id, 1);
if (isERROR(retcode))
return retcode;
Descriptor * currInputDesc = currContext.getDescriptor(curr_input_desc_id);
if (!currInputDesc)
{
diags << DgSqlCode(-CLI_DESC_NOT_EXISTS);
return -CLI_DESC_NOT_EXISTS;
}
Descriptor * currOutputDesc = currContext.getDescriptor(curr_output_desc_id);
if (!currOutputDesc)
{
diags << DgSqlCode(-CLI_DESC_NOT_EXISTS);
return -CLI_DESC_NOT_EXISTS;
}
Descriptor * newInputDesc = currContext.getDescriptor(&new_input_desc_id);
if (!newInputDesc)
{
diags << DgSqlCode(-CLI_DESC_NOT_EXISTS);
return -CLI_DESC_NOT_EXISTS;
}
Descriptor * newOutputDesc = currContext.getDescriptor(&new_output_desc_id);
if (!newOutputDesc)
{
diags << DgSqlCode(-CLI_DESC_NOT_EXISTS);
return -CLI_DESC_NOT_EXISTS;
}
// Before describing , save the flags from the old descriptors that the user
// may have set using a setDescItem call
newOutputDesc->setDescFlags( currOutputDesc->getDescFlags());
newInputDesc->setDescFlags(currInputDesc->getDescFlags());
retcode = SQLCLI_DescribeStmt(cliGlobals,
statement_id,
&new_input_desc_id,
&new_output_desc_id);
if (isERROR(retcode))
return retcode;
newInputDesc = currContext.getDescriptor(&new_input_desc_id);
if (!newInputDesc)
{
diags << DgSqlCode(-CLI_DESC_NOT_EXISTS);
return -CLI_DESC_NOT_EXISTS;
}
newOutputDesc = currContext.getDescriptor(&new_output_desc_id);
if (!newOutputDesc)
{
diags << DgSqlCode(-CLI_DESC_NOT_EXISTS);
return -CLI_DESC_NOT_EXISTS;
}
if (NOT (*currInputDesc == *newInputDesc))
{
retcode = -EXE_USER_PREPARE_NEEDED;
goto retError;
}
if (NOT (*currOutputDesc == *newOutputDesc))
{
retcode = -EXE_USER_PREPARE_NEEDED;
goto retError;
}
return retcode;
retError:
diags << DgSqlCode(retcode);
if (stmt)
stmt->setAqrReprepareNeeded(TRUE);
return retcode;
}
static Lng32 SQLCLI_RetryQuery(
/*IN*/ CliGlobals * cliGlobals,
AQRStatementInfo * aqrSI,
ULng32 flags,
short afterPrepare, short afterExec, short afterFetch, short afterCEFC,
StmtStats *savedStmtStats)
{
Lng32 retcode = 0;
ContextCli * currContext = cliGlobals->currContext();
ComDiagsArea & diags = currContext->diags();
SQL_QUERY_COST_INFO queryCostInfo;
SQL_QUERY_COMPILER_STATS_INFO queryCompStatsInfo;
// allocate a new statement which will be used for the retry
retcode = SQLCLI_AllocStmt(cliGlobals,
aqrSI->getRetryStatementId(), NULL);
// Copy the saved off statement attributes into the newly created stmt
Statement *newStmt = currContext->getStatement(aqrSI->getRetryStatementId());
if (newStmt)
{
aqrSI->copyAttributesToStmt(newStmt);
}
if (isERROR(retcode))
{
if (savedStmtStats)
savedStmtStats->setAqrInProgress(FALSE);
return retcode;
}
// In case of fsth path CLI calls, we need to clear out the statement handle // that may point to a StatementInfo() struct that no longer is valid.
if (aqrSI->getRetryStatementId()->name_mode == stmt_name)
aqrSI->getRetryStatementId()->handle = NULL;
// pass in the original query id when retrying this query.
char * uniqueQueryId = aqrSI->getAQRStatementAttributes()->uniqueStmtId_;
Lng32 uniqueQueryIdLen = aqrSI->getAQRStatementAttributes()->uniqueStmtIdLen_;
// prepare the statement that has been already allocated earlier
retcode = SQLCLI_Prepare2(cliGlobals,
aqrSI->getRetryStatementId(),
aqrSI->getRetrySqlSource(),
NULL, 0, NULL,
&queryCostInfo,
&queryCompStatsInfo,
uniqueQueryId,
&uniqueQueryIdLen,
flags
);
if (isERROR(retcode)) {
if (savedStmtStats)
savedStmtStats->setAqrInProgress(FALSE);
return retcode;
}
if (afterPrepare) {
if (savedStmtStats)
savedStmtStats->setAqrInProgress(FALSE);
return 0;
}
// before executing this statement,
// validate that the new prepare's input/output descriptors are the same
// as the original input/output descriptors.
retcode = SQLCLI_RetryValidateDescs
(cliGlobals,
aqrSI->getRetryStatementId(),
(aqrSI->getRetryInputDesc() ? aqrSI->getRetryInputDesc() :
aqrSI->getRetryTempInputDesc()),
(aqrSI->getRetryOutputDesc() ? aqrSI->getRetryOutputDesc() :
aqrSI->getRetryTempOutputDesc()));
if (isERROR(retcode))
return retcode;
va_list ap ;
memset(&ap, 0, sizeof(ap)); // 64-bit project
SQLCLI_PTR_PAIRS ptr_pairs[1];
if (afterCEFC)
{
// MXCS may pass a nam_mode of stmt_handle for this particular call.
// So handle tht case also. Reset the statement handle to be NULL.
// The StmtInfo() class
// would need to be reinitialized with this newly created statement
if (aqrSI->getRetryStatementId()->name_mode != desc_handle)
aqrSI->getRetryStatementId()->handle = NULL;
retcode =
SQLCLI_ClearExecFetchClose(cliGlobals,
aqrSI->getRetryStatementId(),
aqrSI->getRetryInputDesc(),
aqrSI->getRetryOutputDesc(),
0,
0,
0,
ap,
0,
0);
if (isERROR(retcode))
return retcode;
}
else
{
retcode = SQLCLI_Exec(cliGlobals,
aqrSI->getRetryStatementId(),
aqrSI->getRetryInputDesc(),
0, ap, ptr_pairs);
if (isERROR(retcode))
return retcode;
if (afterExec && !afterFetch)
return 0;
retcode = SQLCLI_Fetch(cliGlobals,
aqrSI->getRetryStatementId(),
aqrSI->getRetryOutputDesc(),
0, ap, ptr_pairs);
if (isERROR(retcode))
return retcode;
}
// If this is a retry of an ExecFetch ,also close the statement because
// SQCLI_ExecFetch also internally closes the statement. So we have to do
// the same when going through AQR
if (afterExec && afterFetch)
{
retcode = SQLCLI_CloseStmt(cliGlobals,aqrSI->getRetryStatementId());
if (isERROR(retcode))
return retcode;
}
return retcode;
}
// When previous attempt of a failed NO ROLLBACK did change
// the target table in ways that it could not undo, then
// do not allow retry, except in case of non-ACID DELETE which
// is configured to continue using AQR.
bool preventAqrWnr(ContextCli *currContext,
Statement *stmt, bool &addWarning8737)
{
bool preventAqr = true;
addWarning8737 = false;
// Get statistics from RMS shared segment via ssmp
// to guard against scenarios like 2034, where the stats
// would not flow back to the master due to broken data
// channels.
const ExStatisticsArea *constStatsArea = NULL;
Lng32 cliRc = SQL_EXEC_GetStatisticsArea_Internal(SQLCLI_STATS_REQ_QID,
stmt->getUniqueStmtId(),
stmt->getUniqueStmtIdLen(),
-1, SQLCLI_SAME_STATS,
constStatsArea);
ExStatisticsArea * statsArea = (ExStatisticsArea *) constStatsArea;
bool targetIsChanged = false;
if ((cliRc < 0) || (NULL == statsArea))
targetIsChanged = true; // Cannot ascertain, so assume worst
else if ((NULL == statsArea->getMasterStats()) ||
(statsArea->getMasterStats()->getStatsErrorCode() != 0))
targetIsChanged = true; // partial success, e.g., node down.
else
{
if (statsArea->anyHaveSentMsgIUD())
targetIsChanged = true;
}
if (stmt->getGlobals() &&
stmt->getGlobals()->getAqrWnrInsertCleanedup())
targetIsChanged = false;
if (targetIsChanged)
{
// for deletes, if AQR_WNR_DELETE_NO_ROWCOUNT, we may
// retry even if target has changed.
ex_root_tdb *rootTdb = stmt->getRootTdb();
if (((rootTdb->getQueryType() ==
ComTdbRoot::SQL_DELETE_UNIQUE) ||
(rootTdb->getQueryType() ==
ComTdbRoot::SQL_DELETE_NON_UNIQUE)) &&
rootTdb->aqrWnrDeleteContinue())
{
preventAqr = false;
addWarning8737 = true;
}
}
else
preventAqr = false;
return preventAqr;
}
Lng32 SQLCLI_ProcessRetryQuery(
/*IN*/ CliGlobals * cliGlobals,
SQLSTMT_ID * statement_id,
Lng32 sqlcode,
short afterPrepare, short afterExec, short afterFetch,
short afterCEFC)
{
Lng32 retcode = sqlcode;
if (NOT isERROR(retcode))
return retcode;
ContextCli * currContext = cliGlobals->currContext();
ComDiagsArea & diags = currContext->diags();
AQRInfo * aqr = currContext->aqrInfo();
ExTransaction * exTransaction = currContext->getTransaction();
bool addWarning8737 = false;
bool checkAqrWnr = false;
Statement * stmt = currContext->getStatement(statement_id);
if ((stmt == NULL) ||
(stmt->getStatementType() == Statement::STATIC_STMT) ||
(stmt->getStmtId() == NULL) ||
(stmt->getSrcStrSize() <= 0))
return retcode;
ex_root_tdb * rootTdb = stmt->getRootTdb();
if (rootTdb)
{
// Of course, there are many other checks to see if AQR can be
// attempted. This next check considers the SQLCODE and attributes
// of the statement which were set by the code generator.
if (NOT stmt->getRootTdb()->aqrEnabledForSqlcode(sqlcode))
return retcode;
// WITH NO ROLLBACK that has sent msgs to IUD cannot be
// retried
if (!rootTdb->isPacked() &&
(rootTdb->getTransMode()->anyNoRollback() ||
(exTransaction &&
exTransaction->getTransMode()->anyNoRollback())))
{
checkAqrWnr = true;
if (preventAqrWnr(currContext, stmt, addWarning8737))
return retcode;
}
if ((rootTdb->updDelInsertQuery()) ||
(rootTdb->ddlQuery()))
{
if (rootTdb->transactionReqd() &&
(NOT exTransaction->xnInProgress()))
{
if (exTransaction->autoCommit())
{
if ((aqr->abortedTransWasImplicit() == FALSE) &&
(diags.getNumber(DgSqlCode::ERROR_) > 0) &&
diags.containsError(-CLI_VALIDATE_TRANSACTION_ERROR))
return retcode;
// if aqr was enabled but cant be done at runtime, return.
if (aqr->noAQR())
return retcode;
}
else
{
// Part of the fix for 10-100604-0887. See statement.cpp
// for the other part and for more commentary.
return retcode;
}
}
}
// if this is a udr/call statement and not a standalone statement, return an error
//The caller will need to reprepare the query so we have an updated tdb to execute.
// If it's a standalone statement, the statement will get reprepared and executed.
if ((rootTdb->getUdrCount() > 0) && !stmt->isStandaloneQ())
{
return retcode;
}
}
AQRStatementInfo * aqrSI = NULL;
char * stmtId = NULL;
char * id = NULL;
char * charset = NULL;
SQLSTMT_ID sql_stmt;
SQLDESC_ID sql_src;
SQLMODULE_ID sql_module;
if (stmt)
{
aqrSI =
new(currContext->exHeap()) AQRStatementInfo(currContext->exHeap());
id = new(currContext->exHeap()) char[stmt->getStmtId()->identifier_len + 1];
str_cpy_all(id, stmt->getStmtId()->identifier, stmt->getStmtId()->identifier_len);
id[stmt->getStmtId()->identifier_len] = 0;
init_SQLMODULE_ID(&sql_module);
init_SQLSTMT_ID(&sql_stmt, SQLCLI_CURRENT_VERSION,
(SQLOBJ_ID_NAME_MODE)stmt->getStmtId()->name_mode,
&sql_module,
id, stmt->getStmtId()->handle, stmt->getStmtId()->charset,stmt->getStmtId()->identifier_len);
aqrSI->setRetryStatementId(&sql_stmt);
charset = NULL;
charset = new(currContext->exHeap()) char[strlen(SQLCHARSETSTRING_UTF8)+1];
strcpy(charset, SQLCHARSETSTRING_UTF8);
init_SQLDESC_ID(&sql_src, SQLCLI_CURRENT_VERSION, string_data,
NULL, NULL, 0, charset);
sql_src.identifier_len = stmt->getSrcStrSize();
sql_src.identifier =
new(currContext->exHeap()) char[sql_src.identifier_len + 2];
stmt->copyOutSourceStr((char*)sql_src.identifier, sql_src.identifier_len);
//Int32 isoMapping = SQLCHARSETCODE_ISO_MAPPING; //;
//if (isoMapping != 0)
//retcode = SQL_EXEC_SetDescItem(&sql_src, 1, SQLDESC_CHAR_SET,
// isoMapping,0);
aqrSI->setRetrySqlSource(&sql_src);
aqrSI->setRetryInputDesc(stmt->aqrStmtInfo()->getRetryInputDesc());
aqrSI->setRetryOutputDesc(stmt->aqrStmtInfo()->getRetryOutputDesc());
aqrSI->setRetryPrepareFlags(stmt->aqrStmtInfo()->getRetryPrepareFlags());
aqrSI->setRetryFirstFetch(stmt->aqrStmtInfo()->retryFirstFetch());
aqrSI->setRetryAfterExec(stmt->aqrStmtInfo()->retryAfterExec());
// Save of any statement attributes or other info from the old
// statement object into the AQR statement attribute struct
if(stmt)
{
aqrSI->saveAttributesFromStmt(stmt);
}
aqrSI->saveStatementHandle(stmt->getStmtId());
aqr->setAqrStmtInfo(aqrSI);
}
else
return retcode;
NABoolean done = FALSE;
Lng32 numRetries = 0;
Lng32 retries = 0;
Lng32 delay = 0;
Lng32 type = 0;
Lng32 numCQDs = 0;
char * cqdStr = NULL;
Lng32 cmpInfo = 0;
ComCondition * cc = NULL;
ComCondition * errCond = NULL;
Lng32 aqrDelay = 0;
Lng32 aqrCmpInfo = 0;
while (NOT done)
{
if (NOT SQLCLI_GetRetryInfo(
cliGlobals, retcode, aqrSI,
afterPrepare, afterExec, afterFetch, afterCEFC,
retries, delay, type,
numCQDs, cqdStr,
cmpInfo,
cc))
done = TRUE;
else
{
// need to check again if aqr is enabled on root because
// the previous retry may have disabled AQR
stmt = currContext->getStatement(statement_id);
if (stmt && stmt->getRootTdb())
{
if (NOT stmt->getRootTdb()->aqrEnabledForSqlcode(sqlcode))
done = TRUE;
else if (checkAqrWnr &&
preventAqrWnr(currContext, stmt, addWarning8737))
done = TRUE;
}
if (!done)
{
if (numRetries == 0)
{
// first retry.
// Save the error condition which caused this retry.
if (cc)
{
errCond = ComCondition::allocate(currContext->exHeap());
*errCond = *cc;
}
// set cqds before reprepare
if (numCQDs > 0)
{
// set the desired cqds before recompiling the query.
retcode = aqr->setCQDs(numCQDs, cqdStr, currContext);
if (retcode < 0)
{
return retcode;
}
}
if (cmpInfo == 1)
{
// send relevant information to compiler through a
// control session statement.
retcode =
aqr->setCompilerInfo(stmt->getUniqueStmtId(),
errCond,
currContext);
if (retcode < 0)
{
return retcode;
}
}
aqrDelay = delay;
aqrCmpInfo = cmpInfo;
}
if (numRetries < retries)
{
if (type == AQRInfo::RETRY_WITH_ESP_CLEANUP)
aqr->setEspCleanup(TRUE);
// Before deallocating the statement, set an indication in the
// master stats for this query id to indicate that AQR is being
// done
// Get the statement again in case if was reallocated in the
// previous loop.
stmt = currContext->getStatement(statement_id);
if(stmt && stmt->getStmtStats())
{
stmt->getStmtStats()->setAqrInProgress(TRUE);
ExMasterStats *ms = (stmt->getStmtStats())->getMasterStats();
if (ms)
{
ms->setAqrLastErrorCode(sqlcode);
ms->setNumAqrRetries(numRetries+1);
ms->setAqrDelayBeforeRetry(delay);
}
}
if (afterPrepare && ((type == AQRInfo::RETRY_MXCMP_KILL)))
{
// Kill the current mxcmp. A new one will get started
// when the query is prepared
ExeCliInterface *cliInterface = new (currContext->exHeap())
ExeCliInterface(currContext->exHeap(),
SQLCHARSETCODE_UTF8,
currContext,
NULL);
ComDiagsArea *tmpDiagsArea = &diags;
retcode = cliInterface->
executeImmediate( (char *) "SELECT TESTEXIT;",
NULL, NULL, TRUE, NULL, 0, &tmpDiagsArea);
//ignore errors from this call.
}
else
// only kill mxcmp if the retry error happened suring a prepare
// otherwise return it to the user.
if (!afterPrepare && ((type == AQRInfo::RETRY_MXCMP_KILL)))
{
if (stmt->getStmtStats())
stmt->getStmtStats()->setAqrInProgress(FALSE);
return retcode;
}
// deallocate the statement before the delay.
StmtStats *saveStmtStat = NULL;
if (stmt)
saveStmtStat = stmt->getStmtStats();
// if the original statement_id had its 'handle' field pointed to
// StatementInfo struct to do stmt lookup optimization(see method
// SQLCLI_PerformTasks for details), reset that field.
// The original statement now deallocated and
// any reference to it(StatementInfo struct points to it) is invalid.
if ( ((statement_id->name_mode != desc_handle) && (afterCEFC))
||(statement_id->name_mode == stmt_name))
statement_id->handle = NULL;
retcode =
SQLCLI_RetryDeallocStmt(cliGlobals, aqrSI);
if (isERROR(retcode))
{
if (saveStmtStat)
{
saveStmtStat->setAqrInProgress(FALSE);
ExMasterStats *ms = saveStmtStat->getMasterStats();
if (ms)
{
ms->setAqrLastErrorCode(0);
ms->setNumAqrRetries(0);
ms->setAqrDelayBeforeRetry(0);
}
}
}
// delay for the specified 'delay'
if (NOT isERROR(retcode) && (delay >= 0))
{
Sleep(delay * 1000);
}
numRetries++;
if (NOT isERROR(retcode))
{
ULng32 flags = aqrSI->getRetryPrepareFlags();
flags |= PREPARE_AUTO_QUERY_RETRY;
if (type == AQRInfo::RETRY_WITH_DECACHE)
flags |= PREPARE_WITH_DECACHE;
// log an ems event, unless disabled or if regressions
// are running.
char *sqlmxRegr = NULL;
sqlmxRegr = getenv("SQLMX_REGRESS");
if ((currContext->getSessionDefaults()->getAqrEmsEvent()) &&
(sqlmxRegr == NULL))
{
Lng32 sqlcode = 0;
Lng32 nskcode = 0;
char * stringParam1 = NULL;
Lng32 intParam1 = ComDiags_UnInitialized_Int;
char emsText[300];
if (errCond)
{
sqlcode = errCond->getSQLCODE();
nskcode = errCond->getNskCode();
if (errCond->getOptionalStringCharSet(0) == CharInfo::ISO88591)
stringParam1 = (char*)errCond->getOptionalString(0);
intParam1 = errCond->getOptionalInteger(0);
str_sprintf(emsText, "AutoQueryRetry will be attempted for Sqlcode=%d, Nskcode=%d, StringParam=%s, IntParam=%d",
sqlcode, nskcode,
(stringParam1 ? stringParam1 : "NULL"),
(intParam1 != ComDiags_UnInitialized_Int
? intParam1 : 0));
}
else
{
str_sprintf(emsText, "AutoQueryRetry will be attempted");
}
SQLMXLoggingArea::logExecRtInfo(NULL, 0, emsText, 0);
}
retcode =
SQLCLI_RetryQuery(
cliGlobals, aqrSI, flags,
afterPrepare, afterExec, afterFetch, afterCEFC, saveStmtStat);
}
if (type == AQRInfo::RETRY_WITH_ESP_CLEANUP)
aqr->setEspCleanup(FALSE);
}
else
{
done = TRUE;
}
}
}
}
if (numRetries > 0)
{
if (numCQDs > 0)
{
// reset the desired cqds after recompiling the query.
Lng32 rc = aqr->resetCQDs(numCQDs, cqdStr, currContext);
if (rc < 0)
return rc;
}
if (aqrCmpInfo == 1)
{
// reset the control session stmt.
Lng32 rc = aqr->resetCompilerInfo(stmt->getUniqueStmtId(),
errCond,
currContext);
if (rc < 0)
return rc;
}
// if recomp warnings are to be returned, then add a warning.
// Also return the error which was previously returned to the caller
// causing the retry.
if (currContext->getSessionDefaults()->aqrWarnings() != 0)
{
NABoolean add100 = FALSE;
if ((NOT isERROR(retcode)) &&
(diags.getNumber(DgSqlCode::ERROR_) == 0) &&
(diags.mainSQLCODE() == SQL_EOF))
{
diags.removeFinalCondition100();
add100 = TRUE;
}
diags << DgSqlCode(EXE_RECOMPILE_AUTO_QUERY_RETRY) // a warning only
<< DgInt0(numRetries)
<< DgInt1(aqrDelay)
<< DgString0("")
<< (errCond
? DgString1("See next entry for the error that caused this retry.")
: DgString1(""));
if (errCond)
{
ComCondition * newCC = diags.makeNewCondition();
*newCC = *errCond;
if (isERROR(newCC->getSQLCODE()))
newCC->setSQLCODE(- newCC->getSQLCODE());
diags.acceptNewCondition();
}
if (NOT isERROR(retcode) && addWarning8737)
diags << DgSqlCode(CLI_INVALID_ROWS_AFFECTED);
if (add100)
{
retcode = diags.mainSQLCODE();
diags << DgSqlCode(SQL_EOF);
}
if (isSUCCESS(retcode))
retcode = EXE_RECOMPILE_AUTO_QUERY_RETRY;
else if (isEOF(retcode))
{
//if (aqrSI->getRetryOutputDesc() == NULL)
//retcode = EXE_RECOMPILE_AUTO_QUERY_RETRY;
}
}
}
if ((isERROR(retcode)) &&
(numRetries > 0))
{
// close this stmt. Ignore errors, the stmt may already be closed.
// Rewind diags area to get rid of any errors from SQLCLI_CloseStmt.
Lng32 oldDiagsAreaMark = diags.mark();
Lng32 rc = SQLCLI_CloseStmt(cliGlobals, aqrSI->getRetryStatementId());
diags.rewind(oldDiagsAreaMark, TRUE);
}
// Retry done. Clear up any retry related information
// before returning.
if (charset)
currContext->exHeap()->deallocateMemory((void *)charset);
if (sql_src.identifier)
currContext->exHeap()->deallocateMemory((void *)sql_src.identifier);
if (stmtId)
NADELETEBASIC(stmtId, currContext->exHeap());
if (id)
NADELETEBASIC(id, currContext->exHeap());
Statement *newStmt = currContext->getStatement(aqrSI->getRetryStatementId());
StmtStats *stmtStats = (newStmt ? newStmt->getStmtStats() : NULL);
if (stmtStats)
stmtStats->setAqrInProgress(FALSE);
aqr->clearRetryInfo();
if (aqrSI)
{
if (aqrSI->getRetryTempInputDesc())
{
SQLCLI_DeallocDesc(cliGlobals, aqrSI->getRetryTempInputDesc());
NADELETEBASIC(aqrSI->getRetryTempInputDesc()->module, currContext->exHeap());
NADELETEBASIC(aqrSI->getRetryTempInputDesc(), currContext->exHeap());
aqrSI->setRetryTempInputDesc(NULL);
}
if (aqrSI->getRetryTempOutputDesc())
{
SQLCLI_DeallocDesc(cliGlobals, aqrSI->getRetryTempOutputDesc());
NADELETEBASIC(aqrSI->getRetryTempOutputDesc()->module, currContext->exHeap());
NADELETEBASIC(aqrSI->getRetryTempOutputDesc(), currContext->exHeap());
aqrSI->setRetryTempOutputDesc(NULL);
}
//aqrSI->clearRetryInfo();
NADELETE(aqrSI, AQRStatementInfo, currContext->exHeap());
aqrSI=NULL;
}
if (errCond)
errCond->deAllocate();
return retcode;
}
////////////////////////////////////////////////////////////////////////
// This method is called by various Exec, Fetch and Close methods.
// It performs the tasks (see enum CliTasks) that are asked for.
//
////////////////////////////////////////////////////////////////////////
Lng32 SQLCLI_PerformTasks(
/*IN*/ CliGlobals * cliGlobals,
/*IN*/ ULng32 tasks,
/*IN*/ SQLSTMT_ID * statement_id,
/*IN OPTIONAL*/ SQLDESC_ID * input_descriptor,
/*IN OPTIONAL*/ SQLDESC_ID * output_descriptor,
/*IN*/ Lng32 num_input_ptr_pairs,
/*IN*/ Lng32 num_output_ptr_pairs,
/*IN*/ va_list ap,
/*IN*/ SQLCLI_PTR_PAIRS input_ptr_pairs[],
/*IN*/ SQLCLI_PTR_PAIRS output_ptr_pairs[])
{
Lng32 retcode = SUCCESS;
if (!statement_id)
return -CLI_STMT_NOT_EXISTS;
ContextCli & currContext = *(cliGlobals->currContext());
ComDiagsArea & diags = currContext.diags();
StatementInfo * stmtInfo = NULL;
StmtStats *stmtStats = NULL;
if ((tasks & CLI_PT_OPT_STMT_INFO) &&
(statement_id->name_mode != desc_handle))
{
stmtInfo = (StatementInfo *)(statement_id->handle);
if (stmtInfo == NULL)
{
// when do we deallocate this heap? Or do we?
CollHeap * heap = cliGlobals->currContext()->exCollHeap();
stmtInfo = new(heap) StatementInfo();
statement_id->handle = stmtInfo;
}
}
// create initial context, if first call, and add module, if any.
if (tasks & CLI_PT_PROLOGUE)
{
retcode = CliPrologue(cliGlobals,
((stmtInfo && stmtInfo->moduleAdded()) ?
NULL : statement_id->module));
if (isERROR(retcode))
return retcode;
if (stmtInfo)
stmtInfo->setModuleAdded(TRUE);
}
else
{
// module must have been added
if ((statement_id->module) &&
(statement_id->module->module_name) &&
(!currContext.moduleAdded(statement_id->module)))
{
diags << DgSqlCode(-CLI_MODULE_NOT_ADDED);
return SQLCLI_ReturnCode(&currContext,
-CLI_MODULE_NOT_ADDED);
}
}
if (tasks & CLI_PT_CLEAR_DIAGS)
{
// Don't clear diags if this is a recursive call. Otherwise,
// warning conditions that have acumulated will be lost.
if (currContext.getNumOfCliCalls() == 1)
diags.clear();
}
Int64 startTime = NA_JulianTimestamp();
/* stmt must exist */
Statement * stmt = NULL;
if ((stmtInfo) && (stmtInfo->statement()))
stmt = stmtInfo->statement();
else
{
stmt = currContext.getStatement(statement_id);
if (!stmt)
{
diags << DgSqlCode(-CLI_STMT_NOT_EXISTS);
return SQLCLI_ReturnCode(&currContext,-CLI_STMT_NOT_EXISTS);
}
if (stmtInfo)
{
stmtInfo->statement() = stmt;
stmt->setStmtInfo(stmtInfo);
if (tasks & CLI_PT_CLEAREXECFETCHCLOSE)
stmt->setOltOpt(TRUE);
}
}
stmt->getGlobals()->setNoNewRequest(FALSE);
Descriptor * input_desc = NULL;
Descriptor * output_desc = NULL;
va_list cpy;
if (num_input_ptr_pairs || num_output_ptr_pairs)
va_copy(cpy, ap);
if (tasks & CLI_PT_GET_INPUT_DESC)
{
NABoolean setPtrs = FALSE;
if ((stmtInfo) && (stmtInfo->inputDesc()))
{
input_desc = stmtInfo->inputDesc();
setPtrs = TRUE;
// If this call is made from multiple callers and the stack address
// of input pointers are not the same, then this optimization
// incorrectly uses the previously set pointers.
// It needs to be enhanced so it either validates that the stack
// is the same as the previous call or that the pointers are
// not stack addresses.
// Removing this optimization for now.
setPtrs = TRUE;
}
else
{
if (!input_descriptor)
input_desc = stmt->getDefaultDesc(SQLWHAT_INPUT_DESC);
else
input_desc = currContext.getDescriptor(input_descriptor);
if (stmtInfo)
stmtInfo->inputDesc() = input_desc;
setPtrs = TRUE;
}
if ((setPtrs) && (num_input_ptr_pairs > 0))
{
/* descriptor must exist */
if (!input_desc)
{
diags << DgSqlCode(-CLI_DESC_NOT_EXISTS);
return SQLCLI_ReturnCode(&currContext,-CLI_DESC_NOT_EXISTS);
}
retcode = local_SetDescPointers(input_desc, 1,
num_input_ptr_pairs, &cpy, input_ptr_pairs);
if (isERROR(retcode))
return SQLCLI_ReturnCode(&currContext,retcode);
}
}
if (tasks & CLI_PT_GET_OUTPUT_DESC)
{
NABoolean setPtrs = FALSE;
if ((stmtInfo) && (stmtInfo->outputDesc()))
{
output_desc = stmtInfo->outputDesc();
setPtrs = TRUE;
// If this call is made from multiple callers and the stack address
// of output pointers are not the same, then this optimization
// incorrectly uses the previously set pointers.
// It needs to be enhanced so it either validates that the stack
// is the same as the previous call or that the pointers are
// not stack addresses.
// Removing this optimization for now.
setPtrs = TRUE;
}
else
{
if (!output_descriptor)
output_desc = stmt->getDefaultDesc(SQLWHAT_OUTPUT_DESC);
else
output_desc = currContext.getDescriptor(output_descriptor);
if (stmtInfo)
stmtInfo->outputDesc() = output_desc;
setPtrs = TRUE;
}
if ((setPtrs) && (num_output_ptr_pairs > 0))
{
// if we do have something to set... the output descriptor
// had better be available by the time we call local_SetDescPointers
//
if (!output_desc)
{
diags << DgSqlCode(-CLI_DESC_NOT_EXISTS);
return SQLCLI_ReturnCode(&currContext,-CLI_DESC_NOT_EXISTS);
}
retcode = local_SetDescPointers(output_desc, 1,
num_output_ptr_pairs, &cpy, output_ptr_pairs);
if (isERROR(retcode))
return SQLCLI_ReturnCode(&currContext,retcode);
}
}
va_end(ap);
stmtStats = stmt->getStmtStats();
// Execute the statement.
if (tasks & CLI_PT_EXEC)
{
if (tasks & CLI_PT_SET_AQR_INFO)
{
if (stmt->aqrStmtInfo())
{
stmt->aqrStmtInfo()->setRetryInputDesc(input_descriptor);
}
}
// if priority of master was changed for execution and didn't get
// changed back to its original priority at the end of that stmt,
// switch it back to its original priority now.
// Do this only for root cli level.
if ((currContext.getNumOfCliCalls() == 1) &&
(cliGlobals->priorityChanged()))
{
ComRtSetProcessPriority(cliGlobals->myPriority(), FALSE);
cliGlobals->setPriorityChanged(FALSE);
}
Lng32 retcode;
retcode = CheckNOSQLAccessMode(*cliGlobals);
if(isERROR(retcode)){
return retcode;
}
if ((stmt->getRootTdb()) &&
(((ComTdb*)stmt->getRootTdb())->getCollectStats()))
{
stmt->getGlobals()->setStatsEnabled(TRUE);
#ifdef _DEBUG
if (getenv("DISABLE_STATS"))
stmt->getGlobals()->setStatsEnabled(FALSE);
#endif
}
if (!stmt->noWaitOpPending())
stmt->getGlobals()->clearCancelState();
// if OLT optimization is being done, call our special
// execute method(doOltExecute).
// Only done for embedded, waited requests...these requests
// have their version set to VERSION_1.
NABoolean doNormalExecute = FALSE;
NABoolean reExecute = FALSE;
if ( stmtInfo && stmt->oltOpt() &&
( statement_id->version == SQLCLI_STATEMENT_VERSION_1 ||
( statement_id->version == SQLCLI_STATEMENT_VERSION_2
)
)
)
{
retcode = stmt->doOltExecute(cliGlobals, input_desc,output_desc, diags,
doNormalExecute, reExecute);
// redrive this query using normal execution, if doNormalExecute
// is TRUE. This could happen for certain cases, like timestamp
// mismatch or blown away opens. These cases are not handled
// by fastpath OLT execution.
if (NOT doNormalExecute)
{
if (stmt->getState() != Statement::CLOSE_)
stmt->close(diags);
return CliEpilogue(cliGlobals,statement_id,retcode);
}
}
if (input_desc)
{
if (stmt->computeInputDescBulkMoveInfo())
{
input_desc->reComputeBulkMoveInfo();
stmt->setComputeInputDescBulkMoveInfo(FALSE);
}
else if (NOT input_desc->bulkMoveDisabled())
{
if (input_desc->bulkMoveStmt() != stmt)
input_desc->reComputeBulkMoveInfo();
}
}
Statement::ExecState execute_state =Statement::INITIAL_STATE_;
if (reExecute)
execute_state = Statement::RE_EXECUTE_;
retcode = stmt->execute(cliGlobals, input_desc,diags,
execute_state );
if (isERROR(retcode))
{
if (stmt->aqrStmtInfo())
stmt->aqrStmtInfo()->setRetryAfterExec(TRUE);
// If statement is in a closeable state, then
// close on error but return the retcode from execute.
if (
(tasks & CLI_PT_CLOSE_ON_ERROR) &&
(stmt->getState() == Statement::OPEN_ ||
stmt->getState() == Statement::FETCH_ ||
stmt->getState() == Statement::EOF_ ||
stmt->getState() == Statement::RELEASE_TRANS_ ||
stmt->getState() == Statement::PREPARE_)
)
stmt->close(diags);
return CliEpilogue(cliGlobals,statement_id,retcode);
}
// if bulk move was done, remember the statement it was done for.
if ((input_desc) && (NOT input_desc->bulkMoveDisabled()))
{
//if (getenv("BULKMOVEWARN"))
// diags << DgSqlCode(EXE_ERROR_NOT_IN_USE_8350);
input_desc->bulkMoveStmt() = stmt;
}
}
// do a fetch to retrieve one row or EOD.
if (tasks & CLI_PT_FETCH)
{
if (tasks & CLI_PT_SET_AQR_INFO)
{
if (stmt->aqrStmtInfo())
{
stmt->aqrStmtInfo()->setRetryOutputDesc(output_descriptor);
}
}
// In case of multiple cursors fetching into the same descriptor,
// the bulkMove flag in the descriptor applies to the statement/cursor
// it was computed for. Validate that the current statement is the
// one bulk move was done for. If not, reset bulk move flag so
// bulk move compatibility checks could be done again in
// outputValues.
// disable rowwise rowset fetch for ExeUtil operator.
// This is done so status messages could be returned to caller as
// soon as they are sent up by executor. With RWRS, returned msgs
// will be blocked until the output rowset is filled up.
if (output_desc)
{
if (stmt->computeOutputDescBulkMoveInfo())
{
output_desc->reComputeBulkMoveInfo();
stmt->setComputeOutputDescBulkMoveInfo(FALSE);
if ((currContext.getSessionDefaults()->getCliBulkMove() == FALSE) ||
((stmt->getRootTdb()) &&
(stmt->getRootTdb()->getQueryType() == ComTdbRoot::SQL_EXE_UTIL) &&
(NOT stmt->getRootTdb()->exeUtilRwrs())))
{
output_desc->setBulkMoveDisabled(TRUE);
output_desc->setRowwiseRowsetDisabled(TRUE);
}
}
else if (NOT output_desc->bulkMoveDisabled())
{
if ((currContext.getSessionDefaults()->getCliBulkMove() == FALSE) ||
((stmt->getRootTdb()) &&
(stmt->getRootTdb()->getQueryType() == ComTdbRoot::SQL_EXE_UTIL) &&
(NOT stmt->getRootTdb()->exeUtilRwrs())))
{
output_desc->setBulkMoveDisabled(TRUE);
output_desc->setRowwiseRowsetDisabled(TRUE);
}
else if (output_desc->bulkMoveStmt() != stmt)
{
output_desc->reComputeBulkMoveInfo();
output_desc->bulkMoveStmt() = stmt;
}
}
}
// if this statement is already in FETCH_ state
if ((stmt->getState() == Statement::INITIAL_) ||
(stmt->getState() == Statement::OPEN_))
{
if (stmt->aqrStmtInfo())
stmt->aqrStmtInfo()->setRetryFirstFetch(TRUE);
}
else
if (stmt->aqrStmtInfo())
stmt->aqrStmtInfo()->setRetryFirstFetch(FALSE);
retcode = stmt->fetch(cliGlobals, output_desc, diags, TRUE);
if (isERROR(retcode))
{
return CliEpilogue(cliGlobals,statement_id,retcode);
}
else if (retcode == WARNING)
{
Lng32 mainSQLcode = diags.mainSQLCODE();
}
// 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()) &&
(retcode == SUCCESS))
{
// BertBert VV
if (stmt->isEmbeddedUpdateOrDelete() || stmt->isStreamScan())
{
// For streams and destructive selects, we don't want the above behavior,
// 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.
retcode = stmt->fetch(cliGlobals, 0 /*no output desc*/,diags, TRUE);
if (retcode == SUCCESS)
{
diags << DgSqlCode(-CLI_SELECT_INTO_ERROR);
stmt->close(diags);
return CliEpilogue(cliGlobals,statement_id,-CLI_SELECT_INTO_ERROR);
}
if (retcode == SQL_EOF)
{
// remove warning 100 from diags.
diags.removeFinalCondition100();
retcode = SUCCESS;
}
}
}
if ((output_desc == NULL) && (retcode == SQL_EOF))
{
// remove warning 100 from diags.
diags.removeFinalCondition100();
retcode = SUCCESS;
}
}
// Close the statement.
if (tasks & CLI_PT_CLOSE)
{
Lng32 tretcode = stmt->close(diags);
if (isERROR(tretcode))
{
return CliEpilogue(cliGlobals,statement_id,tretcode);
}
// if priority of master was changed for execution,
// switch it back to its original priority.
// Do this only for root cli level.
if ((currContext.getNumOfCliCalls() == 1) &&
(cliGlobals->priorityChanged()))
{
ComRtSetProcessPriority(cliGlobals->myPriority(), FALSE);
cliGlobals->setPriorityChanged(FALSE);
}
}
if (tasks & CLI_PT_SPECIAL_END_PROCESS)
{
if (stmt->handleUpdDelCurrentOf(diags) == SQL_EOF)
retcode = SQL_EOF;
}
if (tasks & CLI_PT_EPILOGUE)
return CliEpilogue(cliGlobals,statement_id,retcode);
else
return SQLCLI_ReturnCode(&currContext,retcode);
}
Lng32 SQLCLI_CloseStmt(/*IN*/ CliGlobals * cliGlobals,
/*IN*/ SQLSTMT_ID * statement_id)
{
ULng32 tasks = CLI_PT_PROLOGUE | CLI_PT_CLOSE | CLI_PT_EPILOGUE |
// stmt lookup opt also done for version_2 queries
// with stmt_name name mode. Currently only jdbc
// could make use of this optimization.
(((statement_id->version == SQLCLI_STATEMENT_VERSION_2) &&
(statement_id->name_mode == stmt_name))
? CLI_PT_OPT_STMT_INFO : 0);
return SQLCLI_PerformTasks(cliGlobals, tasks, statement_id,
NULL, NULL, 0, 0, NULL, 0, 0);
}
Lng32 SQLCLI_Exec(/*IN*/ CliGlobals * cliGlobals,
/*IN*/ SQLSTMT_ID * statement_id,
/*IN OPTIONAL*/ SQLDESC_ID * input_descriptor,
/*IN*/ Lng32 num_ptr_pairs,
/*IN*/ va_list ap,
/*IN*/ SQLCLI_PTR_PAIRS ptr_pairs[])
{
ULng32 tasks = CLI_PT_PROLOGUE | CLI_PT_GET_INPUT_DESC |
CLI_PT_EXEC | CLI_PT_SET_AQR_INFO | CLI_PT_EPILOGUE |
// stmt lookup opt also done for version_2 queries
// with stmt_name name mode. Currently only jdbc
// could make use of this optimization.
(((statement_id->version == SQLCLI_STATEMENT_VERSION_2) &&
(statement_id->name_mode == stmt_name))
? CLI_PT_OPT_STMT_INFO : 0);
return SQLCLI_PerformTasks(cliGlobals, tasks, statement_id,
input_descriptor, NULL,
num_ptr_pairs, 0, ap, ptr_pairs, 0);
}
Lng32 SQLCLI_ExecClose(/*IN*/ CliGlobals * cliGlobals,
/*IN*/ SQLSTMT_ID * statement_id,
/*IN OPTIONAL*/ SQLDESC_ID * input_descriptor,
/*IN*/ Lng32 num_ptr_pairs,
/*IN*/ va_list ap,
/*IN*/ SQLCLI_PTR_PAIRS ptr_pairs[])
{
ULng32 tasks = CLI_PT_PROLOGUE | CLI_PT_GET_INPUT_DESC |
CLI_PT_EXEC | CLI_PT_CLOSE_ON_ERROR |
CLI_PT_EPILOGUE
;
return SQLCLI_PerformTasks(cliGlobals, tasks, statement_id,
input_descriptor, NULL,
num_ptr_pairs, 0, ap, ptr_pairs, 0);
}
/////////////////////////////////////////////////////////////////
// if sql_source->name_mode is string_data, then
// sql_source->identifier points to the sql_source string and
// identifier_len is the length of that string.
/////////////////////////////////////////////////////////////////
Lng32 SQLCLI_ExecDirect(/*IN*/ CliGlobals * cliGlobals,
/*IN*/ SQLSTMT_ID * statement_id,
/*IN*/ SQLDESC_ID * sql_source,
/*IN OPTIONAL*/ SQLDESC_ID * input_descriptor,
/*IN*/ Lng32 num_ptr_pairs,
/*IN*/ va_list ap,
/*IN*/ SQLCLI_PTR_PAIRS ptr_pairs[])
{
Lng32 retcode;
// create initial context, if first call, and add module, if any.
retcode = CliPrologue(cliGlobals,statement_id->module);
if (isERROR(retcode))
return retcode;
ContextCli & currContext = *(cliGlobals->currContext());
ComDiagsArea & diags = currContext.diags();
/* prepare the statement */
Statement * stmt = currContext.getStatement(statement_id);
/* stmt must exist */
if (!stmt)
{
diags << DgSqlCode(-CLI_STMT_NOT_EXISTS);
return SQLCLI_ReturnCode(&currContext,-CLI_STMT_NOT_EXISTS);
}
stmt->getGlobals()->clearCancelState();
StrTarget strTarget;
retcode = stmt->initStrTarget(sql_source, currContext, diags, strTarget);
if (isERROR(retcode))
return SQLCLI_ReturnCode(&currContext,retcode);
// CLI callers are not allowed to request PREPARE or EXEC DIRECT
// operations on stored procedure result sets.
if (stmt->getParentCall())
{
diags << DgSqlCode(-EXE_UDR_RS_PREPARE_NOT_ALLOWED);
return SQLCLI_ReturnCode(&currContext, -EXE_UDR_RS_PREPARE_NOT_ALLOWED);
}
// For ExecDirect, MXOSRVR calls SQL_EXEC_SetStmtAttr(NULL) to set the unique id
// before calling SQL_EXEC_EXECDirect. So, we need to use them
if (stmt->getUniqueStmtId() == NULL)
stmt->setUniqueStmtId(NULL);
// Set the StmtStats in the shared segment
stmt->setStmtStats(FALSE);
SQLCLI_Prepare_Setup_Pre(currContext, stmt, 1);
UInt32 flags;
SessionDefaults *sd = currContext.getSessionDefaults();
if (sd != NULL && sd->getCallEmbeddedArkcmp())
flags = PREPARE_USE_EMBEDDED_ARKCMP;
else
flags = 0;
retcode =
stmt->prepare(strTarget.getStr(), diags, NULL, 0L,
strTarget.getIntCharSet(), TRUE, flags);
SQLCLI_Prepare_Setup_Post(currContext, stmt, 1);
if (isERROR(retcode))
return SQLCLI_ReturnCode(&currContext,retcode);
stmt->issuePlanVersioningWarnings (diags);
ULng32 tasks = CLI_PT_GET_INPUT_DESC | CLI_PT_EXEC | CLI_PT_FETCH |
CLI_PT_CLOSE |CLI_PT_SPECIAL_END_PROCESS | CLI_PT_EPILOGUE;
return SQLCLI_PerformTasks(cliGlobals, tasks, statement_id,
input_descriptor, NULL,
num_ptr_pairs, 0, ap, ptr_pairs, 0);
}
/////////////////////////////////////////////////////////////////
// if sql_source->name_mode is string_data, then
// sql_source->identifier points to the sql_source string and
// identifier_len is the length of that string.
/////////////////////////////////////////////////////////////////
Lng32 SQLCLI_ExecDirect2(/*IN*/ CliGlobals * cliGlobals,
/*IN*/ SQLSTMT_ID * statement_id,
/*IN*/ SQLDESC_ID * sql_source,
/*IN*/ Int32 prepFlags,
/*IN OPTIONAL*/ SQLDESC_ID * input_descriptor,
/*IN*/ Lng32 num_ptr_pairs,
/*IN*/ va_list ap,
/*IN*/ SQLCLI_PTR_PAIRS ptr_pairs[]
)
{
Lng32 retcode;
// create initial context, if first call, and add module, if any.
retcode = CliPrologue(cliGlobals,statement_id->module);
if (isERROR(retcode))
return retcode;
ContextCli & currContext = *(cliGlobals->currContext());
ComDiagsArea & diags = currContext.diags();
/* prepare the statement */
Statement * stmt = currContext.getStatement(statement_id);
/* stmt must exist */
if (!stmt)
{
diags << DgSqlCode(-CLI_STMT_NOT_EXISTS);
return SQLCLI_ReturnCode(&currContext,-CLI_STMT_NOT_EXISTS);
}
stmt->getGlobals()->clearCancelState();
StrTarget strTarget;
retcode = stmt->initStrTarget(sql_source, currContext, diags, strTarget);
if (isERROR(retcode))
return SQLCLI_ReturnCode(&currContext,retcode);
// CLI callers are not allowed to request PREPARE or EXEC DIRECT
// operations on stored procedure result sets.
if (stmt->getParentCall())
{
diags << DgSqlCode(-EXE_UDR_RS_PREPARE_NOT_ALLOWED);
return SQLCLI_ReturnCode(&currContext, -EXE_UDR_RS_PREPARE_NOT_ALLOWED);
}
// For ExecDirect, MXOSRVR calls SQL_EXEC_SetStmtAttr(NULL) to set the unique id
// before calling SQL_EXEC_EXECDirect. So, we need to use them
if (stmt->getUniqueStmtId() == NULL)
stmt->setUniqueStmtId(NULL);
// Set the StmtStats in the shared segment
stmt->setStmtStats(FALSE);
SQLCLI_Prepare_Setup_Pre(currContext, stmt, 1);
UInt32 tmpFlags;
SessionDefaults *sd = currContext.getSessionDefaults();
if (sd != NULL && sd->getCallEmbeddedArkcmp())
tmpFlags = prepFlags | PREPARE_USE_EMBEDDED_ARKCMP;
else
tmpFlags = prepFlags;
if (sql_source)
retcode =
stmt->prepare(strTarget.getStr(), diags, NULL, 0L,
strTarget.getIntCharSet(),TRUE,tmpFlags);
SQLCLI_Prepare_Setup_Post(currContext, stmt, 1);
if (isERROR(retcode))
return SQLCLI_ReturnCode(&currContext,retcode);
stmt->issuePlanVersioningWarnings (diags);
ULng32 tasks = CLI_PT_GET_INPUT_DESC | CLI_PT_EXEC | CLI_PT_FETCH |
CLI_PT_CLOSE |CLI_PT_SPECIAL_END_PROCESS | CLI_PT_EPILOGUE;
return SQLCLI_PerformTasks(cliGlobals, tasks, statement_id,
input_descriptor, NULL,
num_ptr_pairs, 0, ap, ptr_pairs, 0);
}
Lng32 SQLCLI_ExecDirectDealloc( /*IN*/ CliGlobals * cliGlobals,
/*IN*/ SQLSTMT_ID * statement_id,
/*IN*/ SQLDESC_ID * sql_source,
/*IN OPTIONAL*/ SQLDESC_ID * input_descriptor,
/*IN*/ Lng32 num_ptr_pairs,
/*IN*/ va_list ap,
/*IN*/ SQLCLI_PTR_PAIRS ptr_pairs[])
{
Lng32 retCode1 = SQLCLI_ExecDirect(cliGlobals,
statement_id,
sql_source,
input_descriptor,
num_ptr_pairs,
ap,
ptr_pairs);
Lng32 retCode2 = SQLCLI_DeallocStmt(cliGlobals, statement_id);
if (isERROR(retCode1))
return(retCode1);
if (isERROR(retCode2))
return(retCode2);
if (isWARNING(retCode1) || isEOF(retCode1))
return(retCode1);
return retCode2;
}
Lng32 SQLCLI_ClearExecFetchClose(/*IN*/ CliGlobals * cliGlobals,
/*IN*/ SQLSTMT_ID * statement_id,
/*IN OPTIONAL*/ SQLDESC_ID * input_descriptor,
/*IN OPTIONAL*/ SQLDESC_ID * output_descriptor,
/*IN*/ Lng32 num_input_ptr_pairs,
/*IN*/ Lng32 num_output_ptr_pairs,
/*IN*/ Lng32 num_total_ptr_pairs,
/*IN*/ va_list ap,
/*IN*/ SQLCLI_PTR_PAIRS input_ptr_pairs[],
/*IN*/ SQLCLI_PTR_PAIRS output_ptr_pairs[])
{
ULng32 tasks = CLI_PT_PROLOGUE | CLI_PT_CLEAR_DIAGS |
CLI_PT_GET_INPUT_DESC | CLI_PT_GET_OUTPUT_DESC |
CLI_PT_EXEC | CLI_PT_FETCH | CLI_PT_CLOSE |
CLI_PT_SET_AQR_INFO |
CLI_PT_SPECIAL_END_PROCESS | CLI_PT_EPILOGUE |
CLI_PT_CLEAREXECFETCHCLOSE |
((statement_id->name_mode == stmt_name)
? CLI_PT_OPT_STMT_INFO : 0);
return SQLCLI_PerformTasks(cliGlobals, tasks, statement_id, input_descriptor,
output_descriptor, num_input_ptr_pairs,
num_output_ptr_pairs, ap, input_ptr_pairs, output_ptr_pairs);
}
Lng32 SQLCLI_ExecFetch( /*IN*/ CliGlobals * cliGlobals,
/*IN*/ SQLSTMT_ID * statement_id,
/*IN OPTIONAL*/ SQLDESC_ID * input_descriptor,
/*IN*/ Lng32 num_ptr_pairs,
/*IN*/ va_list ap,
/*IN*/ SQLCLI_PTR_PAIRS ptr_pairs[])
{
ULng32 tasks = CLI_PT_PROLOGUE | CLI_PT_GET_INPUT_DESC |
CLI_PT_SET_AQR_INFO |
CLI_PT_EXEC | CLI_PT_FETCH | CLI_PT_CLOSE |
CLI_PT_SPECIAL_END_PROCESS | CLI_PT_EPILOGUE |
// stmt lookup opt also done for version_2 queries
// with stmt_name name mode. Currently only jdbc
// could make use of this optimization.
(((statement_id->version == SQLCLI_STATEMENT_VERSION_2) &&
(statement_id->name_mode == stmt_name))
? CLI_PT_OPT_STMT_INFO : 0);
return SQLCLI_PerformTasks(cliGlobals, tasks, statement_id,
input_descriptor, NULL, num_ptr_pairs, 0, ap, ptr_pairs, 0);
}
Lng32 SQLCLI_Fetch(/*IN*/ CliGlobals * cliGlobals,
/*IN*/ SQLSTMT_ID * statement_id,
/*IN OPTIONAL*/ SQLDESC_ID * output_descriptor,
/*IN*/ Lng32 num_ptr_pairs,
/*IN*/ va_list ap,
/*IN*/ SQLCLI_PTR_PAIRS ptr_pairs[])
{
ULng32 tasks = CLI_PT_PROLOGUE | CLI_PT_GET_OUTPUT_DESC |
CLI_PT_FETCH | CLI_PT_SET_AQR_INFO | CLI_PT_EPILOGUE |
// stmt lookup opt also done for version_2 queries
// with stmt_name name mode. Currently only jdbc
// could make use of this optimization.
(((statement_id->version == SQLCLI_STATEMENT_VERSION_2) &&
(statement_id->name_mode == stmt_name))
? CLI_PT_OPT_STMT_INFO : 0);
return SQLCLI_PerformTasks(cliGlobals, tasks, statement_id, NULL,
output_descriptor, 0,
num_ptr_pairs, ap, 0, ptr_pairs);
}
Lng32 SQLCLI_FetchClose(/*IN*/ CliGlobals * cliGlobals,
/*IN*/ SQLSTMT_ID * statement_id,
/*IN OPTIONAL*/ SQLDESC_ID * output_descriptor,
/*IN*/ Lng32 num_ptr_pairs,
/*IN*/ va_list ap,
/*IN*/ SQLCLI_PTR_PAIRS ptr_pairs[])
{
ULng32 tasks = CLI_PT_GET_OUTPUT_DESC | CLI_PT_FETCH |
CLI_PT_CLOSE | CLI_PT_EPILOGUE;
return SQLCLI_PerformTasks(cliGlobals, tasks, statement_id, NULL,
output_descriptor,
0, num_ptr_pairs, ap, 0, ptr_pairs);
}
Lng32 SQLCLI_FetchMultiple(/*IN*/ CliGlobals * cliGlobals,
/*IN*/ SQLSTMT_ID * statement_id,
/*IN OPTIONAL*/ SQLDESC_ID * output_descriptor,
/*IN*/ Lng32 rowset_size,
/*IN*/ Lng32 * rowset_status_ptr,
/*OUT*/ Lng32 * rowset_nfetched,
/*IN*/ Lng32 num_quadruple_fields,
/*IN*/ va_list ap,
/*IN*/ SQLCLI_QUAD_FIELDS quad_fields[])
{
if (!cliGlobals)
return -CLI_NO_CURRENT_CONTEXT;
Lng32 retcode = SQLCLI_SetRowsetDescPointers(cliGlobals,
output_descriptor, rowset_size,
rowset_status_ptr, 1,
num_quadruple_fields,
ap,
quad_fields);
if (isERROR(retcode))
return SQLCLI_ReturnCode(cliGlobals->currContext(),retcode);
retcode = SQLCLI_Fetch(cliGlobals, statement_id, output_descriptor, 0, 0, 0);
if (isERROR(retcode))
return SQLCLI_ReturnCode(cliGlobals->currContext(),retcode);
Lng32 tempRowsetNfetched;
retcode = SQLCLI_GetRowsetNumprocessed(cliGlobals, output_descriptor,
tempRowsetNfetched);
*rowset_nfetched = tempRowsetNfetched;
return retcode;
}
/////////////////////////////////////////////////////////////////////
Lng32 SQLCLI_Cancel(/*IN*/ CliGlobals * cliGlobals,
/*IN OPTIONAL*/ SQLSTMT_ID * statement_id)
{
if (!cliGlobals)
return -CLI_NO_CURRENT_CONTEXT;
ContextCli &currContext = *(cliGlobals->currContext());
ComDiagsArea & diags = currContext.diags();
// Enter a critical section for this async cancel request.
///////////////////////////////////////////////////////////
currContext.semaphoreLock();
HashQueue stmtList(TRUE, *(currContext.getStatementList()) );
// Copy to make getStatement thread-safe.
Statement *stmt;
Lng32 retcode;
Lng32 error;
if (statement_id)
{
stmt = currContext.getStatement(statement_id, &stmtList);
if (!stmt)
{
currContext.semaphoreRelease();
return -CLI_STMT_NOT_EXISTS;
}
retcode = stmt->cancel();
}
else
{ // Cancel all statements on the ContextCli::statementList_.
retcode = 0;
error = -CLI_CANCEL_REJECTED;
NABoolean anyOne = FALSE;
stmtList.position();
while (stmt = (Statement *)(stmtList.getNext()))
{ // Report the least serious error.
// One success -> success.
// Otherwise -> -CLI_CANCEL_REJECTED.
retcode = stmt->cancel();
if (!retcode)
{
anyOne = TRUE;
continue;
}
}
if (anyOne)
retcode = 0;
if (retcode)
retcode = error;
}
currContext.semaphoreRelease();
///////////////////////////////////////////////////////////
// Exit the critical section.
return retcode;
}
Lng32 SQLCLI_GetDescEntryCount(/*IN*/ CliGlobals * cliGlobals,
/*IN*/ SQLDESC_ID * desc_id,
/*IN*/ SQLDESC_ID * output_descriptor)
{
if (!cliGlobals)
{
return -CLI_NO_CURRENT_CONTEXT;
}
if (!desc_id || !output_descriptor)
{
return -CLI_INTERNAL_ERROR;
}
ContextCli & currContext = *(cliGlobals->currContext());
ComDiagsArea & diags = currContext.diags();
Descriptor * desc = currContext.getDescriptor(desc_id);
/* descriptor must exist */
if (!desc)
{
diags << DgSqlCode(-CLI_DESC_NOT_EXISTS);
return SQLCLI_ReturnCode(&currContext,-CLI_DESC_NOT_EXISTS);
}
Descriptor * output_desc = currContext.getDescriptor(output_descriptor);
/* descriptor must exist */
if (!output_desc)
{
diags << DgSqlCode(-CLI_DESC_NOT_EXISTS);
return SQLCLI_ReturnCode(&currContext,-CLI_DESC_NOT_EXISTS);
}
Lng32 retcode = OutputValueIntoNumericHostvar(
output_desc,
1,
desc->getUsedEntryCount());
if (isERROR(retcode))
return SQLCLI_ReturnCode(&currContext,retcode);
return SUCCESS;
}
Lng32 SQLCLI_GetDescItems(/*IN*/ CliGlobals * cliGlobals,
/*IN*/ SQLDESC_ID * desc_id,
/*IN*/ SQLDESC_ITEM desc_items[],
/*IN*/ SQLDESC_ID * value_num_descriptor,
/*IN*/ SQLDESC_ID * output_descriptor)
{
#if 0
// sanity check
if (!desc_id || !value_num_descriptor || !output_descriptor)
return -CLI_INTERNAL_ERROR;
#endif
Lng32 retcode;
CollHeap * heap;
ComDiagsArea * diagsArea;
heap = cliGlobals->currContext()->exCollHeap();
diagsArea = cliGlobals->currContext()->getDiagsArea();
// create initial context, if first call, and add module, if any.
retcode = CliPrologue(cliGlobals,desc_id->module);
if (isERROR(retcode))
return -CLI_INTERNAL_ERROR;
ContextCli & currContext = *(cliGlobals->currContext());
ComDiagsArea & diags = currContext.diags();
Descriptor * desc = currContext.getDescriptor(desc_id);
/* descriptor must exist */
if (!desc)
{
diags << DgSqlCode(-CLI_DESC_NOT_EXISTS);
return SQLCLI_ReturnCode(&currContext,-CLI_DESC_NOT_EXISTS);
}
Descriptor * value_num_desc = currContext.getDescriptor(value_num_descriptor);
/* descriptor must exist */
if (!value_num_desc)
{
diags << DgSqlCode(-CLI_DESC_NOT_EXISTS);
return SQLCLI_ReturnCode(&currContext,-CLI_DESC_NOT_EXISTS);
}
Descriptor *output_desc = currContext.getDescriptor(output_descriptor);
/* descriptor must exist */
if (!output_desc)
{
diags << DgSqlCode(-CLI_DESC_NOT_EXISTS);
return SQLCLI_ReturnCode(&currContext,-CLI_DESC_NOT_EXISTS);
}
Lng32 outputUsedEntryCount = output_desc->getUsedEntryCount();
for (Lng32 i = 0; i < outputUsedEntryCount; i++) {
//
// Get the entry number of the descriptor entry whose item is to be
// retrieved.
//
Lng32 entry;
retcode = InputValueFromNumericHostvar(
value_num_desc,
desc_items[i].value_num_desc_entry,
entry);
if (isERROR(retcode))
return SQLCLI_ReturnCode(&currContext,retcode);
// check that the item entry is < the max num of occurrences specified
// when the SQL descriptor area was allocated (must also be > 0)
if ( (entry < 1) || (entry > desc->getUsedEntryCount()) )
{
diags << DgSqlCode(-CLI_ITEM_NUM_OUT_OF_RANGE)
<< DgInt0(desc->getMaxEntryCount());
return SQLCLI_ReturnCode(&currContext,-CLI_ITEM_NUM_OUT_OF_RANGE);
}
Lng32 targetType, targetLen, targetPrecision, targetScale;
Lng32 sourceLen, sourcePrecision, sourceScale;
short sourceType;
char *source;
Lng32 temp;
Long tempPtr;
//set source, source type, source length, source precision
//and source scale according to the desciptor item being choosen.
//get the value of the source into temp if the data type is long
//else get the address of descItem for char data types by calling
//Descriptor::getDescItemPtr()
switch (desc_items[i].item_id)
{
case SQLDESC_TYPE:
case SQLDESC_DATETIME_CODE:
case SQLDESC_TYPE_FS:
case SQLDESC_LENGTH:
case SQLDESC_OCTET_LENGTH:
case SQLDESC_PRECISION:
case SQLDESC_SCALE:
case SQLDESC_INT_LEAD_PREC:
case SQLDESC_NULLABLE:
// charset and coll_seq are stored as long.
case SQLDESC_CHAR_SET:
case SQLDESC_COLLATION:
case SQLDESC_UNNAMED:
case SQLDESC_IND_TYPE:
case SQLDESC_IND_LENGTH:
// case SQLDESC_VAR_PTR:
//case SQLDESC_IND_PTR:
case SQLDESC_RET_LEN :
case SQLDESC_RET_OCTET_LEN :
case SQLDESC_IND_DATA:
case SQLDESC_ROWSET_VAR_LAYOUT_SIZE:
case SQLDESC_ROWSET_IND_LAYOUT_SIZE:
case SQLDESC_ROWSET_SIZE:
//case SQLDESC_ROWSET_STATUS_PTR:
case SQLDESC_ROWSET_NUM_PROCESSED:
case SQLDESC_ROWSET_HANDLE:
case SQLDESC_PARAMETER_MODE:
case SQLDESC_ORDINAL_POSITION:
case SQLDESC_PARAMETER_INDEX:
case SQLDESC_DATA_OFFSET:
case SQLDESC_NULL_IND_OFFSET:
case SQLDESC_ALIGNED_LENGTH:
{
retcode = desc->getDescItem(entry,
desc_items[i].item_id,
&temp,
NULL, 0, NULL, 0);
if (retcode != 0)
return SQLCLI_ReturnCode(&currContext,retcode);
source = (char *) &temp;
sourceLen = sizeof(Lng32);
sourceType = REC_BIN32_SIGNED;
sourcePrecision = 0;
sourceScale = 0;
}
break;
case SQLDESC_VAR_PTR:
case SQLDESC_IND_PTR:
case SQLDESC_ROWSET_STATUS_PTR:
case SQLDESC_ROWWISE_ROWSET_PTR:
{
retcode = desc->getDescItem(entry,
desc_items[i].item_id,
&tempPtr,
NULL, 0, NULL, 0);
if (retcode != 0)
return SQLCLI_ReturnCode(&currContext,retcode);
source = (char *) &tempPtr;
sourceLen = sizeof(Long);
sourceType = REC_BIN64_SIGNED;
sourcePrecision = 0;
sourceScale = 0;
}
break;
case SQLDESC_VAR_DATA:
case SQLDESC_CHAR_SET_NAM:
case SQLDESC_NAME:
case SQLDESC_HEADING:
case SQLDESC_TABLE_NAME:
case SQLDESC_SCHEMA_NAME:
case SQLDESC_CATALOG_NAME:
// R2
// SQLDESC_CHAR_SET_NAM, SQLDESC_CHAR_SET_CAT,
// SQLDESC_CHAR_SET_SCH, SQLDESC_COLL_NAM,
// SQLDESC_COLL_CAT and SQLDESC_COLL_SCH are exposed as
// character strings.
case SQLDESC_CHAR_SET_CAT:
case SQLDESC_CHAR_SET_SCH:
case SQLDESC_COLL_NAM:
case SQLDESC_COLL_CAT:
case SQLDESC_COLL_SCH:
{
retcode = desc->getDescItemPtr(entry,
desc_items[i].item_id,
&source,
&sourceLen);
if (retcode != 0)
return SQLCLI_ReturnCode(&currContext,retcode);
if (desc_items[i].item_id != SQLDESC_VAR_DATA)
{
sourceType = REC_BYTE_F_ASCII;
sourcePrecision = 0;
sourceScale = 0;
}
else
{
Lng32 sType;
desc->getDescItem(entry,
SQLDESC_TYPE_FS,
&sType,
NULL, 0, NULL, 0);
sourceType = (short)sType;
if ((sourceType >= REC_MIN_INTERVAL) &&
(sourceType <= REC_MAX_INTERVAL)) {
desc->getDescItem(entry, SQLDESC_INT_LEAD_PREC,
&sourcePrecision, 0, 0, 0, 0);
desc->getDescItem(entry, SQLDESC_PRECISION,
&sourceScale, 0, 0, 0, 0);
}
else if (sourceType == REC_DATETIME) {
desc->getDescItem(entry, SQLDESC_DATETIME_CODE,
&sourcePrecision, 0, 0, 0, 0);
desc->getDescItem(entry, SQLDESC_PRECISION,
&sourceScale, 0, 0, 0, 0);
}
else {
desc->getDescItem(entry, SQLDESC_PRECISION,
&sourcePrecision, 0, 0, 0, 0);
desc->getDescItem(entry, SQLDESC_SCALE,
&sourceScale, 0, 0, 0, 0);
};
}
}
break;
default:
diags << DgSqlCode(-CLI_INVALID_DESC_INFO_REQUEST);
return SQLCLI_ReturnCode(&currContext,-CLI_INVALID_DESC_INFO_REQUEST);
break;
}
//
// Get the address of the target where the item's value is to be stored.
//
char * pTarget = 0;
output_desc->getDescItem(i+1,
SQLDESC_VAR_PTR,
(Lng32*) &pTarget, // $$$$ hjz: don't assume this is not null hostvar
NULL, 0, NULL, 0);
if (!pTarget)
return -CLI_INTERNAL_ERROR;
output_desc->getDescItem(i+1,
SQLDESC_TYPE_FS,
&targetType,
NULL, 0, NULL, 0);
output_desc->getDescItem(i+1,
SQLDESC_OCTET_LENGTH,
&targetLen,
NULL, 0, NULL, 0);
if ((targetType >= REC_MIN_INTERVAL) &&
(targetType <= REC_MAX_INTERVAL))
{
output_desc->getDescItem(i+1, SQLDESC_INT_LEAD_PREC,
&targetPrecision, 0, 0, 0, 0);
output_desc->getDescItem(i+1, SQLDESC_PRECISION,
&targetScale, 0, 0, 0, 0);
}
else if (targetType == REC_DATETIME)
{
output_desc->getDescItem(i+1, SQLDESC_DATETIME_CODE,
&targetPrecision, 0, 0, 0, 0);
output_desc->getDescItem(i+1, SQLDESC_PRECISION,
&targetScale, 0, 0, 0, 0);
}
else
{
output_desc->getDescItem(i+1, SQLDESC_PRECISION,
&targetPrecision, 0, 0, 0, 0);
output_desc->getDescItem(i+1, SQLDESC_SCALE,
&targetScale, 0, 0, 0, 0);
};
char * targetVCLen = NULL;
short targetVCLenSize = 0;
if (DFS2REC::isSQLVarChar(targetType)) {
targetVCLen = pTarget;
targetVCLenSize = SQL_VARCHAR_HDR_SIZE; // user host vars have VCLen 2
pTarget = &pTarget[targetVCLenSize];
}
else
targetVCLenSize = 0;
// Check for ansi compatibility of source and target types
if (NOT (InputOutputExpr::areCompatible(sourceType,(short)targetType)))
{
diags << DgSqlCode(-EXE_CONVERT_NOT_SUPPORTED);
return SQLCLI_ReturnCode(&currContext,-EXE_CONVERT_NOT_SUPPORTED);
}
// CharSet Phase I work.
// To check the LHS and RHS character sets for the assignment
// If the character set for the host var is UCS2,
// then any conversion is legitimate;
// If the character set for the host var is not UCS2,
// then the charsets must be the same.
//
// The check is performed for VARIABLE_DATA and VARIABLE_POINTER.
if ( DFS2REC::isAnyCharacter(sourceType) &&
DFS2REC::isAnyCharacter(targetType) )
{
Lng32 csSource, csTarget;
retcode = output_desc->getDescItem(i+1,
SQLDESC_CHAR_SET,
&csTarget,
NULL, 0, NULL, 0);
if (retcode != 0)
return SQLCLI_ReturnCode(&currContext,retcode);
if ( (desc_items[i].item_id == SQLDESC_VAR_DATA ||
desc_items[i].item_id == SQLDESC_VAR_PTR) )
{
retcode = desc->getDescItem(entry,
SQLDESC_CHAR_SET,
&csSource,
NULL, 0, NULL, 0);
if (retcode != 0)
return SQLCLI_ReturnCode(&currContext,retcode);
if ( NOT CharInfo::isAssignmentCompatible((CharInfo::CharSet)csTarget, (CharInfo::CharSet)csSource) ) {
// Error 8896: The character set $0~string0 of a host variable does not match $1~string1 of the corresponding descriptor item (entry $2~Int0).
diags << DgSqlCode(-CLI_CHARSET_MISMATCH)
<< DgString0(CharInfo::getCharSetName((CharInfo::CharSet)csTarget))
<< DgString1(CharInfo::getCharSetName((CharInfo::CharSet)csSource))
<< DgInt0(entry);
return SQLCLI_ReturnCode(&currContext,-CLI_CHARSET_MISMATCH);
}
}
}
if (source)
{
// if the target is REC_DECIMAL_LS and the source is NOT
// REC_DECIMAL_LSE, convert the source to REC_DECIMAL_LSE first.
char * intermediate = NULL;
if ((targetType == REC_DECIMAL_LS) &&
(sourceType != REC_DECIMAL_LSE)) {
intermediate = new (heap) char[targetLen-1];
if (convDoIt(source,
sourceLen,
(short) sourceType,
sourcePrecision,
sourceScale,
intermediate,
targetLen-1,
REC_DECIMAL_LSE,
targetPrecision,
targetScale,
targetVCLen,
targetVCLenSize,
heap,
&diagsArea) != ex_expr::EXPR_OK) {
NADELETEBASIC(intermediate, heap);
retcode = ERROR;
}
if (isERROR(retcode))
return SQLCLI_ReturnCode(&currContext,retcode);
source = intermediate;
sourceLen = targetLen-1;
sourceType = REC_DECIMAL_LSE;
}
if ( (sourceType == REC_NCHAR_F_UNICODE ||
sourceType == REC_NCHAR_V_UNICODE )
)
{
// Charset can be retrieved as a long INTERNALLY
// using programatic interface by calling getDescItem(),
// and can only be retrieved as a character string EXTERNALLY
// using "get descriptor" syntax.
Lng32 char_set;
output_desc->getDescItem(
entry, SQLDESC_CHAR_SET, &char_set,
NULL, 0, NULL, 0);
if ( char_set == CharInfo::SJIS )
{
switch ( targetType ) {
case REC_BYTE_F_ASCII:
targetType = REC_MBYTE_F_SJIS;
break;
case REC_BYTE_V_ANSI:
case REC_BYTE_V_ASCII_LONG:
case REC_BYTE_V_ASCII:
targetType = REC_MBYTE_V_SJIS;
break;
default:
break;
}
}
}
//get the size of memory to be bounds checked
Int32 memorySize = targetLen;
//if varchar, add header size
if (DFS2REC::isAnyVarChar(targetType)) {
if (DFS2REC::isSQLVarChar(targetType))
memorySize += SQL_VARCHAR_HDR_SIZE; // count prefix
else if (targetType == REC_BYTE_V_ANSI_DOUBLE)
memorySize += SQL_DBCHAR_SIZE; // double-byte nul terminator
else
memorySize += 1; // single-byte nul terminator
}
if ((desc_items[i].item_id == SQLDESC_VAR_DATA) &&
((sourceType == REC_DATETIME) ||
((sourceType >= REC_MIN_INTERVAL) &&
(sourceType <= REC_MAX_INTERVAL))) &&
(sourceType == targetType))
{
// this is a datetime or interval conversion. The fetched VAR_DATA
// value was saved as an ascii string.
sourceType = REC_BYTE_F_ASCII;
sourceScale = 0;
sourcePrecision = 0;
targetType = REC_BYTE_F_ASCII;
targetScale = 0;
targetPrecision = 0;
}
//bounds check memory
if (currContext.boundsCheckMemory(pTarget,memorySize))
return SQLCLI_ReturnCode(&currContext,
-CLI_USER_MEMORY_IN_EXECUTOR_SEGMENT);
retcode = convDoIt(source,
sourceLen,
(short) sourceType,
sourcePrecision,
sourceScale,
pTarget,
targetLen,
(short)targetType,
targetPrecision,
targetScale,
targetVCLen,
targetVCLenSize,
heap,
&diagsArea);
if (retcode != ex_expr::EXPR_OK)
retcode = ERROR;
if (retcode == ex_expr::EXPR_OK &&
targetType >= REC_MIN_NUMERIC &&
targetType <= REC_MAX_NUMERIC &&
::scaleDoIt(pTarget,
targetLen,
targetType,
sourceScale,
targetScale,
sourceType,
heap) != ex_expr::EXPR_OK) {
retcode = ERROR;
}
NADELETEBASIC(intermediate, heap);
if (isERROR(retcode))
return SQLCLI_ReturnCode(&currContext,retcode);
}
}
return SUCCESS;
}
Lng32 SQLCLI_GetDescItems2(/*IN*/ CliGlobals * cliGlobals,
/*IN*/ SQLDESC_ID * desc_id,
/*IN*/ Lng32 no_of_desc_items,
/*IN*/ SQLDESC_ITEM desc_items[])
{
Lng32 retcode;
// create initial context, if first call, and add module, if any.
retcode = CliPrologue(cliGlobals,desc_id->module);
if (isERROR(retcode))
return retcode;
ContextCli & currContext = *(cliGlobals->currContext());
ComDiagsArea & diags = currContext.diags();
Descriptor * desc = currContext.getDescriptor(desc_id);
/* descriptor must exist */
if (!desc)
{
diags << DgSqlCode(-CLI_DESC_NOT_EXISTS);
return SQLCLI_ReturnCode(&currContext,-CLI_DESC_NOT_EXISTS);
}
for (Lng32 i = 0; i < no_of_desc_items; i++)
{
//
// Get the entry number of the descriptor entry whose item is to be
// retrieved.
//
Lng32 entry = desc_items[i].entry;
// check that the item entry is < the max num of occurrences specified
// when the SQL descriptor area was allocated (must also be > 0)
if ( (entry < 1) || (entry > desc->getUsedEntryCount()) )
{
diags << DgSqlCode(-CLI_ITEM_NUM_OUT_OF_RANGE)
<< DgInt0(desc->getMaxEntryCount());
return SQLCLI_ReturnCode(&currContext,-CLI_ITEM_NUM_OUT_OF_RANGE);
}
Lng32 sourceLen = 0;
char *source = NULL;
Lng32 tmp32BitVal;
switch (desc_items[i].item_id)
{
case SQLDESC_TYPE:
case SQLDESC_DATETIME_CODE:
case SQLDESC_TYPE_FS:
case SQLDESC_LENGTH:
case SQLDESC_OCTET_LENGTH:
case SQLDESC_PRECISION:
case SQLDESC_SCALE:
case SQLDESC_INT_LEAD_PREC:
case SQLDESC_NULLABLE:
case SQLDESC_CHAR_SET:
case SQLDESC_UNNAMED:
case SQLDESC_IND_TYPE:
case SQLDESC_IND_LENGTH:
//case SQLDESC_VAR_PTR:
//case SQLDESC_IND_PTR:
case SQLDESC_RET_LEN :
case SQLDESC_RET_OCTET_LEN :
case SQLDESC_IND_DATA:
case SQLDESC_ROWSET_VAR_LAYOUT_SIZE:
case SQLDESC_ROWSET_IND_LAYOUT_SIZE:
case SQLDESC_ROWSET_SIZE:
//case SQLDESC_ROWSET_STATUS_PTR:
case SQLDESC_ROWSET_NUM_PROCESSED:
case SQLDESC_ROWSET_HANDLE:
case SQLDESC_PARAMETER_MODE:
case SQLDESC_ORDINAL_POSITION:
case SQLDESC_PARAMETER_INDEX:
case SQLDESC_VC_IND_LENGTH:
{
retcode = desc->getDescItem(entry,
desc_items[i].item_id,
&tmp32BitVal,
NULL, 0, NULL, 0);
if (retcode != 0)
return SQLCLI_ReturnCode(&currContext,retcode);
else
desc_items[i].num_val_or_len = tmp32BitVal;
}
break;
case SQLDESC_VAR_PTR:
case SQLDESC_IND_PTR:
case SQLDESC_ROWSET_STATUS_PTR:
case SQLDESC_ROWWISE_ROWSET_PTR:
{
retcode = desc->getDescItem(entry,
desc_items[i].item_id,
&desc_items[i].num_val_or_len,
NULL, 0, NULL, 0);
if (retcode != 0)
return SQLCLI_ReturnCode(&currContext,retcode);
}
break;
case SQLDESC_VAR_DATA:
case SQLDESC_NAME:
case SQLDESC_HEADING:
case SQLDESC_TABLE_NAME:
case SQLDESC_SCHEMA_NAME:
case SQLDESC_CATALOG_NAME:
case SQLDESC_CHAR_SET_CAT:
case SQLDESC_CHAR_SET_SCH:
case SQLDESC_CHAR_SET_NAM:
case SQLDESC_COLL_CAT:
case SQLDESC_COLL_SCH:
case SQLDESC_COLL_NAM:
case SQLDESC_TEXT_FORMAT:
{
retcode = desc->getDescItemPtr(entry,
desc_items[i].item_id,
&source,
&sourceLen);
if (retcode != 0)
return SQLCLI_ReturnCode(&currContext,retcode);
if ((sourceLen > desc_items[i].num_val_or_len) ||
((sourceLen > 0) && (desc_items[i].string_val == NULL)))
{
diags << DgSqlCode(-EXE_STRING_OVERFLOW);
return SQLCLI_ReturnCode(&currContext,-EXE_STRING_OVERFLOW);
}
if (sourceLen > 0)
{
str_cpy_all(desc_items[i].string_val, source, sourceLen);
}
desc_items[i].num_val_or_len = sourceLen;
}
break;
default:
{
diags << DgSqlCode(-CLI_INTERNAL_ERROR);
return SQLCLI_ReturnCode(&currContext,-CLI_INTERNAL_ERROR);
}
break;
} // switch
} // for
return SUCCESS;
}
Lng32 SQLCLI_ClearDiagnostics(/*IN*/ CliGlobals * cliGlobals,
/*IN OPTIONAL*/SQLSTMT_ID * statement_id)
{
// create initial context, if first call, and add module, if any.
Lng32 retcode;
if ( statement_id == NULL )
retcode = CliPrologue(cliGlobals,0);
else
retcode = CliPrologue(cliGlobals,statement_id->module);
if (isERROR(retcode))
return retcode;
cliGlobals->currContext()->diags().clear();
return SUCCESS;
}
static Lng32 getStmtInfo(
/*IN*/ CliGlobals * cliGlobals,
/*IN*/ ComDiagsArea & diags,
/*IN*/ Statement * stmt,
/*IN* (SQLDIAG_STMT_INFO_ITEM_ID) */ Lng32 what_to_get,
/*OUT OPTIONAL*/ void * numeric_value,
/*OUT OPTIONAL*/ char * string_value,
/*IN OPTIONAL*/ Lng32 max_string_len,
/*OUT OPTIONAL*/ Lng32 * len_of_item)
{
switch (what_to_get)
{
case SQLDIAG_NUMBER:
*(Lng32*)numeric_value = diags.getNumber(); // actually returns long
break;
case SQLDIAG_MORE:
{
if (string_value && max_string_len > 0)
{
*string_value = diags.areMore() ? 'Y' : 'N' ;
if (len_of_item)
*len_of_item = 1;
}
}
break;
// A ComDiagsArea doesn't, itself, currently know the
// difference between a command and dynamic sql function.
case SQLDIAG_COMMAND_FUNC:
case SQLDIAG_DYNAMIC_FUNC:
*(Int32 *)numeric_value = diags.getFunction(); // returns FunctionEnum type
break;
case SQLDIAG_ROW_COUNT:
{
Int64 rowCount;
if (stmt)
rowCount = stmt->getRowsAffected(); // returns Int64
else
rowCount = diags.getRowCount(); // returns ComDiagBigInt
if ( rowCount > LONG_MAX)
return EXE_NUMERIC_OVERFLOW;
*(Int64*)numeric_value = rowCount;
break;
}
case SQLDIAG_ROWSET_ROW_COUNT:
{
if (!(diags.hasValidRowsetRowCountArray()))
return -EXE_ROWSET_ROW_COUNT_ARRAY_NOT_AVAILABLE;
if (max_string_len < diags.numEntriesInRowsetRowCountArray())
return -EXE_ROWSET_ROW_COUNT_ARRAY_WRONG_SIZE;
Int64 rowCount;
for(Lng32 i=0;i<diags.numEntriesInRowsetRowCountArray();i++)
{
rowCount = diags.getValueFromRowsetRowCountArray(i);
assert ( rowCount != -1 ); // accessing a row count array element that was never set.
if ( rowCount > INT_MAX)
return EXE_NUMERIC_OVERFLOW;
((Lng32 *)numeric_value)[i] = (Lng32) rowCount;
}
if (len_of_item)
*len_of_item = diags.numEntriesInRowsetRowCountArray();
}
break;
case SQLDIAG_AVERAGE_STREAM_WAIT:
*(ComDiagBigInt *)numeric_value = diags.getAvgStreamWaitTime();// returns ComDiagBigInt
break;
// The SQL/MP extension statement info items that are supported.
case SQLDIAG_COST:
{
double temp_double = diags.getCost();
if(((double) INT_MAX) <= temp_double)
{
*(Lng32 *)numeric_value = INT_MAX;
}
else
{
*(Lng32 *)numeric_value = (Lng32) temp_double;
};
}
break;
// The SQL/MP extension statement info items aren't currently unsupported.
// (but should be supported soon! ;-)
case SQLDIAG_FIRST_FSCODE:
case SQLDIAG_LAST_FSCODE:
case SQLDIAG_LAST_SYSKEY:
*(Lng32 *)numeric_value = 0;
break;
default:
return -CLI_INTERNAL_ERROR;
break;
}
return SUCCESS;
}
Lng32 SQLCLI_GetDiagnosticsStmtInfo(/*IN*/ CliGlobals * cliGlobals,
/*IN*/ Lng32 * stmt_info_items,
/*IN*/ SQLDESC_ID * output_descriptor)
{
// test to see if our inputs are even valid
if (!stmt_info_items)
{
return -CLI_INTERNAL_ERROR;
}
if (!output_descriptor)
{
return -CLI_DESC_NOT_EXISTS;
}
// go ahead...
// create initial context, if first call, and add module, if any.
Lng32 retcode = CliPrologue(cliGlobals,output_descriptor->module);
if (isERROR(retcode))
return retcode;
ContextCli & currContext = *(cliGlobals->currContext());
ComDiagsArea & diags = currContext.diags();
Descriptor * output_desc = currContext.getDescriptor(output_descriptor);
if (!output_desc)
{
return -CLI_DESC_NOT_EXISTS;
}
Lng32 outputUsedEntryCount = output_desc->getUsedEntryCount();
for (Lng32 i = 0; i < outputUsedEntryCount; i++)
{
if ((stmt_info_items[i] == SQLDIAG_ROW_COUNT) ||
(stmt_info_items[i] == SQLDIAG_NUMBER) ||
(stmt_info_items[i] == SQLDIAG_ROWSET_ROW_COUNT))
{
char * target;
Lng32 targetLen;
Lng32 targetType;
Lng32 targetPrecision;
Lng32 targetScale;
Lng32 targetRowsetSize = 1; // initialized to 1 for ROW_COUNT and NUMBER
Lng32 targetRowsetVarLayoutSize;
retcode = output_desc->getDescItem(i+1,
SQLDESC_VAR_PTR,
(Lng32*) &target,
NULL, 0, NULL, 0);
if (isERROR(retcode))
break;
retcode = output_desc->getDescItem(i+1,
SQLDESC_TYPE_FS,
&targetType,
NULL, 0, NULL, 0);
if (isERROR(retcode))
break;
retcode = output_desc->getDescItem(i+1,
SQLDESC_LENGTH,
&targetLen,
NULL, 0, NULL, 0);
if (isERROR(retcode))
break;
retcode = output_desc->getDescItem(i+1,
SQLDESC_PRECISION,
&targetPrecision,
NULL, 0, NULL, 0);
if (isERROR(retcode))
break;
retcode = output_desc->getDescItem(i+1,
SQLDESC_SCALE,
&targetScale,
NULL, 0, NULL, 0);
if (isERROR(retcode))
break;
if ((targetType >= REC_MIN_CHARACTER ) &&
(targetType <= REC_MAX_CHARACTER))
{
Lng32 temp_char_set;
output_desc->getDescItem(i+1, SQLDESC_CHAR_SET,
&temp_char_set, 0, 0, 0, 0);
if ( CharInfo::is_NCHAR_MP((CharInfo::CharSet)temp_char_set))
{
retcode = -EXE_CONVERT_NOT_SUPPORTED;
break;
}
}
Int64 value;
if (stmt_info_items[i] == SQLDIAG_ROW_COUNT)
value = diags.getRowCount();
else if (stmt_info_items[i] == SQLDIAG_NUMBER)
{
Lng32 number;
retcode =
getStmtInfo(cliGlobals, diags, NULL, stmt_info_items[i],
&number, NULL, 0, NULL);
if (isERROR(retcode))
break;
value = number;
}
else // SQLDIAG_ROWSET_ROW_COUNT
{
// retrieve user provided rowset size into targetRowsetSize
retcode = output_desc->getDescItem(0,
SQLDESC_ROWSET_SIZE,
&targetRowsetSize,
NULL, 0, NULL, 0);
if (isERROR(retcode))
break;
retcode = output_desc->getDescItem(i+1,
SQLDESC_ROWSET_VAR_LAYOUT_SIZE,
&targetRowsetVarLayoutSize,
NULL, 0, NULL, 0);
if (isERROR(retcode))
break;
if (!(diags.hasValidRowsetRowCountArray())){
retcode = -EXE_ROWSET_ROW_COUNT_ARRAY_NOT_AVAILABLE;
break;
}
if (targetRowsetSize < diags.numEntriesInRowsetRowCountArray()) {
retcode = -EXE_ROWSET_ROW_COUNT_ARRAY_WRONG_SIZE;
break;
}
else {
// reset targetRowsetSize to length of run-time rowset size
// i.e. the number of entries in rowCountArray, if this is smaller
// than user provided value.
targetRowsetSize = diags.numEntriesInRowsetRowCountArray();
}
}
CollHeap * heap = output_desc->getContext()->exCollHeap();
ComDiagsArea * diagsArea = output_desc->getContext()->getDiagsArea();
Lng32 oldDiagsAreaMark = diagsArea->mark();
Lng32 oldLastError = diagsArea->getNumber(DgSqlCode::ERROR_);
// we will go through this loop only once for NUMBER and ROW_COUNT
for (Lng32 j = 0; j < targetRowsetSize; j++) {
if (stmt_info_items[i] == SQLDIAG_ROWSET_ROW_COUNT) {
value = diags.getValueFromRowsetRowCountArray(j);
// increment target to point to the next element in the output rowset
if (j > 0)
target += targetRowsetVarLayoutSize;
}
ex_expr::exp_return_type convDoItRetcode =
convDoIt((char *) &value,
SQL_LARGE_SIZE,
(short) REC_BIN64_SIGNED,
0, // sourcePrecision
0, // sourceScale
target,
targetLen,
(short) targetType,
targetPrecision,
targetScale,
NULL, // varCharLen
0, // varCharLenSize,
heap,
&diagsArea
);
if (convDoItRetcode != ex_expr::EXPR_OK)
retcode = diagsArea->getErrorEntry(oldLastError+1)->getSQLCODE();
diagsArea->rewind(oldDiagsAreaMark, TRUE);
if (isERROR(retcode))
break;
}
if (isERROR(retcode))
break;
}
else if (stmt_info_items[i] == SQLDIAG_MORE){ // only string member in stmt info
char * more_entry = 0;
Lng32 targetLen;
retcode = output_desc->getDescItem(i+1,
SQLDESC_VAR_PTR,
(Lng32*) &more_entry,
NULL, 0, NULL, 0);
if (isERROR(retcode))
break;
retcode = output_desc->getDescItem(i+1,
SQLDESC_LENGTH,
&targetLen,
NULL, 0, NULL, 0);
if (isERROR(retcode))
break;
retcode =
getStmtInfo(cliGlobals, diags, NULL, stmt_info_items[i],
NULL, more_entry, targetLen, NULL);
if (isERROR(retcode))
break;
}
else
{
//
// Get the entry number of the descriptor entry whose item is to be set.
//
Lng32 * entry = 0;
// guess we need to get the datatype of the descriptor item
// and then decide what kind of variable to use...
// Right now, we assume that it is 'long' numeric type.
retcode = output_desc->getDescItem(i+1,
SQLDESC_VAR_PTR,
(Lng32*) &entry,
NULL, 0, NULL, 0);
if (isERROR(retcode))
break;
retcode =
getStmtInfo(cliGlobals, diags, NULL, stmt_info_items[i],
entry, NULL, 0, NULL);
if (isERROR(retcode))
break;
}
}
if (isERROR(retcode))
return retcode;
else
return SUCCESS;
}
Lng32 SQLCLI_GetDiagnosticsStmtInfo2(
/*IN*/ CliGlobals * cliGlobals,
/*IN OPTIONAL*/ SQLSTMT_ID * statement_id,
/*IN* (SQLDIAG_STMT_INFO_ITEM_ID) */ Lng32 what_to_get,
/*OUT OPTIONAL*/ void * numeric_value,
/*OUT OPTIONAL*/ char * string_value,
/*IN OPTIONAL*/ Lng32 max_string_len,
/*OUT OPTIONAL*/ Lng32 * len_of_item)
{
// go ahead...
// create initial context, if first call, and add module, if any.
Lng32 retcode = CliPrologue(cliGlobals,
statement_id ? statement_id->module : NULL);
if (isERROR(retcode))
return retcode;
ContextCli & currContext = *(cliGlobals->currContext());
ComDiagsArea & diags = currContext.diags();
Statement * stmt = NULL;
if (statement_id)
{
stmt = currContext.getStatement(statement_id);
// stmt must exist.
// Only rowsAffected supported for now, if statement_id is passed in.
if ((!stmt) ||
((what_to_get != SQLDIAG_NUMBER) && (what_to_get != SQLDIAG_ROW_COUNT)))
{
return -CLI_STMT_NOT_EXISTS;
}
}
retcode =
getStmtInfo(cliGlobals, diags, stmt, what_to_get,
numeric_value, string_value, max_string_len, len_of_item);
return SQLCLI_ReturnCode(&currContext, retcode);
}
static void copyResultString(char * dest, const char * src, Lng32 destLen,
Lng32 * copyLen = NULL)
{
if (!dest)
return;
if (copyLen)
*copyLen = 0;
if (src)
{
Lng32 len = MINOF(str_len(src)+1, destLen);
str_cpy_all(dest, src, len);
if (copyLen)
*copyLen = len;
}
else
*dest = '\0';
}
Lng32 SQLCLI_GetDiagnosticsCondInfo(/*IN*/ CliGlobals * cliGlobals,
/*IN*/ SQLDIAG_COND_INFO_ITEM * cond_info_items,
/*IN*/ SQLDESC_ID * cond_num_descriptor,
/*IN*/ SQLDESC_ID * output_descriptor,
/*OUT*/ IpcMessageBufferPtr message_buffer_ptr,
/*IN*/ IpcMessageObjSize message_obj_size,
/*OUT*/ IpcMessageObjSize * message_obj_size_needed,
/*OUT*/ IpcMessageObjType * message_obj_type,
/*OUT*/ IpcMessageObjVersion * message_obj_version,
/*IN*/ Lng32 condition_item_count,
/*OUT*/ Lng32 * condition_item_count_needed,
/*OUT*/ DiagsConditionItem * condition_item_array,
/*OUT*/ SQLMXLoggingArea::ExperienceLevel * emsEventEL)
{
Lng32 i;
// test to see if our inputs are even valid
if (!cond_info_items)
{
return -CLI_INTERNAL_ERROR;
}
if (!cond_num_descriptor || !output_descriptor)
{
return -CLI_DESC_NOT_EXISTS;
}
// go ahead...
// create initial context, if first call, and add module, if any.
Lng32 retcode = CliPrologue(cliGlobals,output_descriptor->module);
if (isERROR(retcode))
return retcode;
ContextCli & currContext = *(cliGlobals->currContext());
ComDiagsArea & diags = currContext.diags();
// *emsEventEL is assigned the system experience level value
// passed to the cli through the plan
if (emsEventEL != NULL)
*emsEventEL = cliGlobals->getEMSEventExperienceLevel();
#ifdef BOUNDS_CHECK_IN_CLI
#endif
if (currContext.boundsCheckMemory(message_buffer_ptr, message_obj_size) ||
currContext.boundsCheckMemory(message_obj_size_needed, sizeof(IpcMessageObjSize)) ||
currContext.boundsCheckMemory(message_obj_type, sizeof(IpcMessageObjType)) ||
currContext.boundsCheckMemory(message_obj_version, sizeof(IpcMessageObjVersion)) ||
currContext.boundsCheckMemory(condition_item_array, condition_item_count * sizeof(DiagsConditionItem)) ||
currContext.boundsCheckMemory(condition_item_count_needed, sizeof(Lng32)))
return SQLCLI_ReturnCode(&currContext,
-CLI_USER_MEMORY_IN_EXECUTOR_SEGMENT);
Descriptor * condnum_desc = currContext.getDescriptor(cond_num_descriptor);
if (!condnum_desc)
{
return -CLI_DESC_NOT_EXISTS;
}
Descriptor * output_desc = currContext.getDescriptor(output_descriptor);
if (!output_desc)
{
return -CLI_DESC_NOT_EXISTS;
}
Lng32 outputUsedEntryCount = output_desc->getUsedEntryCount();
// the condition number is contained in a single descriptor entry
if (condnum_desc->getUsedEntryCount() < 1)
{
return -CLI_INTERNAL_ERROR;
}
*message_obj_size_needed = diags.packedLength();
*condition_item_count_needed = 0;
for (i = 0; i < outputUsedEntryCount; i++) {
switch (cond_info_items[i].item_id) {
case SQLDIAG_RET_SQLSTATE: /* (string ) returned SQLSTATE */
case SQLDIAG_CLASS_ORIG: /* (string ) class origin, e.g. ISO 9075 */
case SQLDIAG_SUBCLASS_ORIG: /* (string ) subclass origin, e.g. ISO 9075 */
case SQLDIAG_MSG_TEXT: /* (string ) message text */
case SQLDIAG_MSG_LEN: /* (numeric) message length in characters */
case SQLDIAG_MSG_OCTET_LEN: /* (numeric) message length in bytes */
*condition_item_count_needed += 1;
}
if (cond_info_items[i].cond_number_desc_entry < 1
|| (condnum_desc->getUsedEntryCount() > 1
&& cond_info_items[i].cond_number_desc_entry > condnum_desc->getUsedEntryCount()))
return -CLI_INTERNAL_ERROR;
}
if (*condition_item_count_needed > 0
&& (condition_item_count < *condition_item_count_needed
|| message_obj_size < *message_obj_size_needed))
return 0; // Caller has to call again with larger array or buffer
if (*condition_item_count_needed > 0) {
*condition_item_count_needed = 0;
if (diags.getNumber(DgSqlCode::ERROR_) > SHRT_MAX)
return -CLI_INTERNAL_ERROR;
*message_obj_size_needed = diags.packObjIntoMessage(message_buffer_ptr);
*message_obj_type = diags.getType();
*message_obj_version = diags.getVersion();
}
CharInfo::CharSet messageCharSet = CharInfo::UnknownCharSet;
Int32 msgOctLenInd = -1;
for (i = 0; i < outputUsedEntryCount; i++) {
//
// Get the entry number of the descriptor entry whose item is to be set.
//
Lng32 *entry = 0;
retcode = output_desc->getDescItem(i+1,
SQLDESC_VAR_PTR,
(Lng32 *)&entry, // $$$$ hjz: don't assume this is a long hostvar
NULL, 0, NULL, 0);
if (isERROR(retcode))
return SQLCLI_ReturnCode(&currContext,retcode);
if (!entry)
return -CLI_INTERNAL_ERROR;
Lng32 theLength = 0L;
retcode = output_desc->getDescItem(i+1,
SQLDESC_LENGTH,
&theLength,
NULL, 0, NULL, 0);
if (isERROR(retcode))
return SQLCLI_ReturnCode(&currContext,retcode);
Lng32 userIndex = 0L;
retcode = InputValueFromNumericHostvar(
condnum_desc,
condnum_desc->getUsedEntryCount() > 1 ?
cond_info_items[i].cond_number_desc_entry :
1, // use 1 for compatibility (used to be this way)
userIndex);
if (isERROR(retcode))
return SQLCLI_ReturnCode(&currContext,retcode);
if (userIndex < 1 || userIndex > diags.getNumber())
{
return -CLI_ITEM_NUM_OUT_OF_RANGE; //index out of range
}
ComCondition & condition = diags[userIndex];
switch (cond_info_items[i].item_id) {
case SQLDIAG_SQLCODE: /* (numeric) the SQLCODE */
retcode = OutputValueIntoNumericHostvar(
output_desc,
i+1,
condition.getSQLCODE());
break;
case SQLDIAG_COND_NUMBER: /* (numeric) condition number */
retcode = OutputValueIntoNumericHostvar(
output_desc,
i+1,
condition.getConditionNumber());
break;
case SQLDIAG_NSK_CODE: /* (numeric) NSK/FS/DP2 FE error number */
retcode = OutputValueIntoNumericHostvar(
output_desc,
i+1,
condition.getNskCode());
break;
case SQLDIAG_MSG_TEXT: /* (string ) message text */
condition.incrEMSEventVisits();
case SQLDIAG_CLASS_ORIG: /* (string ) class origin, e.g. ISO 9075 */
case SQLDIAG_SUBCLASS_ORIG: /* (string ) subclass origin, e.g. ISO 9075 */
case SQLDIAG_MSG_LEN: /* (numeric) message length in characters */
case SQLDIAG_MSG_OCTET_LEN: /* (numeric) message length in bytes */
// UR2: should get the charset specified in the output_desc to
// condition_item_array so that the right charset can be used to
// translate the MSG_TEXT and length.
condition_item_array[*condition_item_count_needed].item_id = cond_info_items[i].item_id;
condition_item_array[*condition_item_count_needed].var_ptr = (char *)entry;
condition_item_array[(*condition_item_count_needed)].length = theLength;
condition_item_array[(*condition_item_count_needed)].output_entry = i;
condition_item_array[(*condition_item_count_needed)].condition_index = userIndex;
// The charset for the hostvar that the error message is assigned to
// has to be retrived. Use the internal fast SQLDESC_CHAR_SET version.
if (cond_info_items[i].item_id == SQLDIAG_MSG_TEXT) {
Lng32 charset;
retcode = output_desc->getDescItem(i+1,
SQLDESC_CHAR_SET,
&charset,
NULL, 0, NULL, 0);
if (retcode != 0)
return SQLCLI_ReturnCode(&currContext,retcode);
if (charset == (Lng32)CharInfo::ISO88591) // do not know where to set this field
charset = CharInfo::UTF8; // so set it here for now.
messageCharSet = (CharInfo::CharSet)charset;
// Only ISO88591 and UCS2 can be used to retrieve the diagnostic msg.
if ( CharInfo::isMsgCharSetSupported(messageCharSet) ) {
condition_item_array[(*condition_item_count_needed)].charset = messageCharSet;
} else {
return SQLCLI_ReturnCode(&currContext,-CLI_MSG_CHAR_SET_NOT_SUPPORTED);
}
} else if (cond_info_items[i].item_id == SQLDIAG_MSG_OCTET_LEN) {
// remember the index for SQLDIAG_MSG_OCTET_LEN into
// the condition_item_array.
msgOctLenInd = *condition_item_count_needed;
}
++(*condition_item_count_needed);
break;
case SQLDIAG_RET_SQLSTATE: /* (string ) returned SQLSTATE */
if(condition.getCustomSQLState() == NULL) {
condition_item_array[*condition_item_count_needed].item_id = cond_info_items[i].item_id;
condition_item_array[*condition_item_count_needed].var_ptr = (char *)entry;
condition_item_array[(*condition_item_count_needed)].length = theLength;
condition_item_array[(*condition_item_count_needed)].output_entry = i;
condition_item_array[(*condition_item_count_needed)++].condition_index = userIndex;
}
else {
copyResultString((char *)entry, condition.getCustomSQLState(), theLength);
}
break;
case SQLDIAG_SERVER_NAME: /* (string ) SQL server name */
copyResultString((char *)entry, condition.getServerName(), theLength);
break;
case SQLDIAG_CONNECT_NAME: /* (string ) connection name */
copyResultString((char *)entry, condition.getConnectionName(), theLength);
break;
case SQLDIAG_CONSTR_CAT: /* (string ) constraint catalog name */
copyResultString((char *)entry, condition.getConstraintCatalog(), theLength);
break;
case SQLDIAG_CONSTR_SCHEMA: /* (string ) constraint schema name */
copyResultString((char *)entry, condition.getConstraintSchema(), theLength);
break;
case SQLDIAG_CONSTR_NAME: /* (string ) constraint name */
copyResultString((char *)entry, condition.getConstraintName(), theLength);
break;
case SQLDIAG_TRIGGER_CAT: /* (string ) trigger catalog name */
copyResultString((char *)entry, condition.getTriggerCatalog(), theLength);
break;
case SQLDIAG_TRIGGER_SCHEMA: /* (string ) trigger schema name */
copyResultString((char *)entry, condition.getTriggerSchema(), theLength);
break;
case SQLDIAG_TRIGGER_NAME: /* (string ) trigger name */
copyResultString((char *)entry, condition.getTriggerName(), theLength);
break;
case SQLDIAG_CATALOG_NAME: /* (string ) catalog name */
copyResultString((char *)entry, condition.getCatalogName(), theLength);
break;
case SQLDIAG_SCHEMA_NAME: /* (string ) schema name */
copyResultString((char *)entry, condition.getSchemaName(), theLength);
break;
case SQLDIAG_TABLE_NAME: /* (string ) table name */
copyResultString((char *)entry, condition.getTableName(), theLength);
break;
case SQLDIAG_COLUMN_NAME: /* (string ) column name */
copyResultString((char *)entry, condition.getColumnName(), theLength);
break;
// CursorName is not implemented (co-opted for SqlID)
case SQLDIAG_CURSOR_NAME: /* (string ) cursor name */
copyResultString((char *)entry, "", theLength);
break;
/* ODBC -- not implemented currently */
case SQLDIAG_COLUMN_NUMBER: /* (numeric) column number */
case SQLDIAG_NATIVE: /* (numeric) native error code */
break;
case SQLDIAG_ROW_NUMBER: /* (numeric) row number of input rowset that caused the error */
retcode = OutputValueIntoNumericHostvar(
output_desc,
i+1,
condition.getRowNumber());
break;
/* SQL/MP -- not implemented yet (except for SQLCODE) */
case SQLDIAG_SOURCE_FILE: /* (string ) source file name */
case SQLDIAG_LINE_NUMBER: /* (numeric) source code line number */
case SQLDIAG_SUBSYSTEM_ID: /* (string ) component that issued error */
break;
default:
// do nothing -- no way to report error, so, okay.
break;
}
}
// SQLDIAG_MSG_OCT_LEN depends on the message char set.
// remember the message character set for the entry into
// the condition item array for SQLDIAG_MSG_OCT_LEN.
if (msgOctLenInd != -1) {
condition_item_array[msgOctLenInd].charset = messageCharSet;
}
return retcode;
}
Lng32 SQLCLI_GetPackedDiagnostics(
/*IN*/ CliGlobals * cliGlobals,
/*OUT*/ IpcMessageBufferPtr message_buffer_ptr,
/*IN*/ IpcMessageObjSize message_obj_size,
/*OUT*/ IpcMessageObjSize * message_obj_size_needed,
/*OUT*/ IpcMessageObjType * message_obj_type,
/*OUT*/ IpcMessageObjVersion * message_obj_version)
{
// create initial context, if first call, and add module, if any.
Lng32 retcode = CliPrologue(cliGlobals, NULL);
if (isERROR(retcode))
return retcode;
ContextCli & currContext = *(cliGlobals->currContext());
ComDiagsArea & diags = currContext.diags();
*message_obj_size_needed = diags.packedLength();
if (message_obj_size < *message_obj_size_needed)
return 0; // Caller has to call again with larger array or buffer
*message_obj_size_needed = diags.packObjIntoMessage(message_buffer_ptr);
*message_obj_type = diags.getType();
*message_obj_version = diags.getVersion();
return retcode;
}
Lng32 GetDiagnosticsCondInfoSwitchStatement(
/*IN*/ CliGlobals * cliGlobals,
/*IN* (SQLDIAG_COND_INFO_ITEM_ID) */ Lng32 what_to_get,
/*IN*/ Lng32 conditionNum,
/*OUT OPTIONAL*/ Lng32 * numeric_value,
/*OUT OPTIONAL*/ char * string_value,
/*IN OPTIONAL */ Lng32 max_string_len,
/*OUT OPTIONAL*/ Lng32 * len_of_item)
{
ContextCli & currContext = *(cliGlobals->currContext());
ComDiagsArea & diags = currContext.diags();
ComCondition & condition = diags[conditionNum];
// LPWSTR p = NULL;
switch (what_to_get)
{
case SQLDIAG_SQLCODE: /* (numeric) the SQLCODE */
*numeric_value = condition.getSQLCODE();
break;
case SQLDIAG_COND_NUMBER: /* (numeric) condition number */
*numeric_value = condition.getConditionNumber();
break;
case SQLDIAG_NSK_CODE: /* (numeric) NSK/FS/DP2 FE error number */
*numeric_value = condition.getNskCode();
break;
case SQLDIAG_SERVER_NAME: /* (string ) SQL server name */
copyResultString(string_value, condition.getServerName(),
max_string_len, len_of_item);
break;
case SQLDIAG_CONNECT_NAME: /* (string ) connection name */
copyResultString(string_value, condition.getConnectionName(),
max_string_len, len_of_item);
break;
case SQLDIAG_CONSTR_CAT: /* (string ) constraint catalog name */
copyResultString(string_value, condition.getConstraintCatalog(),
max_string_len, len_of_item);
break;
case SQLDIAG_CONSTR_SCHEMA: /* (string ) constraint schema name */
copyResultString(string_value, condition.getConstraintSchema(),
max_string_len, len_of_item);
break;
case SQLDIAG_CONSTR_NAME: /* (string ) constraint name */
copyResultString(string_value, condition.getConstraintName(),
max_string_len, len_of_item);
break;
case SQLDIAG_TRIGGER_CAT: /* (string ) trigger catalog name */
copyResultString(string_value, condition.getTriggerCatalog(),
max_string_len, len_of_item);
break;
case SQLDIAG_TRIGGER_SCHEMA: /* (string ) trigger schema name */
copyResultString(string_value, condition.getTriggerSchema(),
max_string_len, len_of_item);
break;
case SQLDIAG_TRIGGER_NAME: /* (string ) trigger name */
copyResultString(string_value, condition.getTriggerName(),
max_string_len, len_of_item);
break;
case SQLDIAG_CATALOG_NAME: /* (string ) catalog name */
copyResultString(string_value, condition.getCatalogName(),
max_string_len, len_of_item);
break;
case SQLDIAG_SCHEMA_NAME: /* (string ) schema name */
copyResultString(string_value, condition.getSchemaName(),
max_string_len, len_of_item);
break;
case SQLDIAG_TABLE_NAME: /* (string ) table name */
copyResultString(string_value, condition.getTableName(),
max_string_len, len_of_item);
break;
case SQLDIAG_COLUMN_NAME: /* (string ) column name */
copyResultString(string_value, condition.getColumnName(),
max_string_len, len_of_item);
break;
// CursorName is not implemented (co-opted for SqlID)
case SQLDIAG_CURSOR_NAME: /* (string ) cursor name */
copyResultString(string_value, "",
max_string_len, len_of_item);
break;
case SQLDIAG_CLASS_ORIG: /* (string ) class origin, e.g. ISO 9075 */
case SQLDIAG_SUBCLASS_ORIG: /* (string ) subclass origin, e.g. ISO 9075*/
case SQLDIAG_RET_SQLSTATE: /* (string ) returned SQLSTATE */
case SQLDIAG_MSG_TEXT: /* (string ) message text */
case SQLDIAG_MSG_LEN: /* (numeric) message length in characters */
case SQLDIAG_MSG_OCTET_LEN: /* (numeric) message length in bytes */
{
// for these cases, call GetDiagnosticsCondInfo().
// TBD.
}
break;
/* ODBC -- not implemented currently */
case SQLDIAG_COLUMN_NUMBER: /* (numeric) column number */
case SQLDIAG_NATIVE: /* (numeric) native error code */
break ;
case SQLDIAG_ROW_NUMBER: /* (numeric) row number of input rowset that caused the error */
*numeric_value = condition.getRowNumber() ;
break;
/* SQL/MP -- not implemented yet (except for SQLCODE) */
case SQLDIAG_SOURCE_FILE: /* (string ) source file name */
case SQLDIAG_LINE_NUMBER: /* (numeric) source code line number */
case SQLDIAG_SUBSYSTEM_ID: /* (string ) component that issued error */
break;
default:
// do nothing -- no way to report error, so, okay.
break;
}
return 0;
}
Lng32 SQLCLI_GetDiagnosticsCondInfo2(
/*IN*/ CliGlobals * cliGlobals,
/*IN* (SQLDIAG_COND_INFO_ITEM_ID) */ Lng32 what_to_get,
/*IN*/ Lng32 conditionNum,
/*OUT OPTIONAL*/ Lng32 * numeric_value,
/*OUT OPTIONAL*/ char * string_value,
/*IN OPTIONAL */ Lng32 max_string_len,
/*OUT OPTIONAL*/ Lng32 * len_of_item)
{
// go ahead...
// create initial context, if first call, and add module, if any.
Lng32 retcode = CliPrologue(cliGlobals,NULL);
if (isERROR(retcode))
return retcode;
retcode = GetDiagnosticsCondInfoSwitchStatement(
cliGlobals,
what_to_get,
conditionNum,
numeric_value,
string_value,
max_string_len,
len_of_item);
return retcode;
}
Lng32 SQLCLI_GetDiagnosticsCondInfo3 (
/*IN*/ CliGlobals * cliGlobals,
/*IN*/ Lng32 no_of_condition_items,
/*IN*/ SQLDIAG_COND_INFO_ITEM_VALUE
diag_cond_info_item_values[],
/*OUT*/ IpcMessageObjSize * message_obj_size_needed)
{
Lng32 retcode;
SQLDIAG_COND_INFO_ITEM_VALUE diagItemValues;
Lng32 max_string_len;
Lng32 what_to_get;
NABoolean executePartiallyInNonPriv = FALSE;
// go ahead...
// create initial context, if first call, and add module, if any.
retcode = CliPrologue(cliGlobals,NULL);
if (isERROR(retcode))
return retcode;
ContextCli & currContext = *(cliGlobals->currContext());
ComDiagsArea & diags = currContext.diags();
for(Int32 i=0; i<no_of_condition_items; i++)
{
diagItemValues = diag_cond_info_item_values[i];
if (diagItemValues.string_val)
max_string_len = *(diagItemValues.num_val_or_len);
else
max_string_len = 0;
what_to_get = diagItemValues.item_id_and_cond_number.item_id;
ComCondition & condition = diags[diagItemValues.item_id_and_cond_number.cond_number_desc_entry];
switch (what_to_get) {
case SQLDIAG_MSG_TEXT: /* (string ) message text */
condition.incrEMSEventVisits();
case SQLDIAG_RET_SQLSTATE: /* (string ) returned SQLSTATE */
case SQLDIAG_CLASS_ORIG: /* (string ) class origin, e.g. ISO 9075 */
case SQLDIAG_SUBCLASS_ORIG: /* (string ) subclass origin, e.g. ISO 9075 */
case SQLDIAG_MSG_LEN: /* (numeric) message length in characters */
case SQLDIAG_MSG_OCTET_LEN: /* (numeric) message length in bytes */
executePartiallyInNonPriv = TRUE;
}
retcode = GetDiagnosticsCondInfoSwitchStatement(cliGlobals,
what_to_get,
diagItemValues.item_id_and_cond_number.cond_number_desc_entry,
diagItemValues.num_val_or_len,
diagItemValues.string_val,
max_string_len,
diagItemValues.num_val_or_len) ;
if (retcode < 0)
return retcode;
}
*message_obj_size_needed = executePartiallyInNonPriv ? diags.packedLength() : 0;
return retcode;
}
Lng32 SQLCLI_GetDiagnosticsArea(/*IN*/ CliGlobals * cliGlobals,
/*OUT*/ IpcMessageBufferPtr message_buffer_ptr,
/*IN*/ IpcMessageObjSize message_obj_size,
/*OUT*/ IpcMessageObjType * message_obj_type,
/*OUT*/ IpcMessageObjVersion * message_obj_version)
{
// go ahead...
// create initial context, if first call, and add module, if any.
Lng32 retcode = CliPrologue(cliGlobals,NULL);
if (isERROR(retcode))
return retcode;
ContextCli & currContext = *(cliGlobals->currContext());
ComDiagsArea & diags = currContext.diags();
Lng32 oldDiagsAreaMark = diags.mark();
if (currContext.boundsCheckMemory(message_buffer_ptr, message_obj_size) ||
currContext.boundsCheckMemory(message_obj_type, sizeof(IpcMessageObjType)) ||
currContext.boundsCheckMemory(message_obj_version, sizeof(IpcMessageObjVersion)))
{
diags.rewind(oldDiagsAreaMark, TRUE);
return -CLI_USER_MEMORY_IN_EXECUTOR_SEGMENT;
}
if (diags.getNumber(DgSqlCode::ERROR_) > SHRT_MAX)
return -CLI_INTERNAL_ERROR;
if (diags.packedLength() > message_obj_size)
return -CLI_INTERNAL_ERROR;
// It is the caller's responsibility to pass in buffer of appropriate size.
// This method assumes that the buffer is large enough to hold the diagsArea,
// if not CLI_INTERNAL_ERROR is returned.
diags.packObjIntoMessage(message_buffer_ptr);
*message_obj_type = diags.getType();
*message_obj_version = diags.getVersion();
return 0;
}
Lng32 SQLCLI_GetSQLCODE(/*IN*/ CliGlobals * cliGlobals,
/*OUT*/ Lng32 *SQLCODE)
{
if (!cliGlobals)
return -CLI_NO_CURRENT_CONTEXT;
*SQLCODE = cliGlobals->currContext()->diags().mainSQLCODE();
return SUCCESS; // this call always succeeds, no need to check errors!
}
Lng32 SQLCLI_GetMainSQLSTATE(/*IN*/ CliGlobals * cliGlobals,
/*IN*/ SQLSTMT_ID * statement_id,
/*IN*/ Lng32 sqlcode,
/*OUT*/ char * sqlstate /* assumed to be char[6] */)
{
return -1;
}
/////////////////////////////////////////////////////////////////
// if sql_source->name_mode is string_data, then
// sql_source->identifier points to the sql_source string and
// identifier_len is the length of that string.
/////////////////////////////////////////////////////////////////
Lng32 SQLCLI_Prepare(/*IN*/ CliGlobals * cliGlobals,
/*IN*/ SQLSTMT_ID * statement_id,
/*IN*/ SQLDESC_ID * sql_source)
{
Lng32 retcode;
// create initial context, if first call, and add module, if any.
retcode = CliPrologue(cliGlobals,statement_id->module);
if (isERROR(retcode))
return retcode;
ContextCli & currContext = *(cliGlobals->currContext());
ComDiagsArea & diags = currContext.diags();
/* prepare the statement */
Statement * stmt = currContext.getStatement(statement_id);
/* stmt must exist */
if (!stmt)
{
diags << DgSqlCode(-CLI_STMT_NOT_EXISTS);
return SQLCLI_ReturnCode(&currContext,-CLI_STMT_NOT_EXISTS);
}
StrTarget strTarget;
retcode = stmt->initStrTarget(sql_source, currContext, diags, strTarget);
if (isERROR(retcode))
return SQLCLI_ReturnCode(&currContext,retcode);
// CLI callers do not prepare stored procedure result set
// statements. The prepare is done internally on-demand when the
// statement is described or executed.
if (stmt->getParentCall())
{
diags << DgSqlCode(-EXE_UDR_RS_PREPARE_NOT_ALLOWED);
return SQLCLI_ReturnCode(&currContext, -EXE_UDR_RS_PREPARE_NOT_ALLOWED);
}
// Set the uniqueStmtId in Statement
stmt->setUniqueStmtId(NULL);
// Set the StmtStats in the shared segment
stmt->setStmtStats(FALSE);
SQLCLI_Prepare_Setup_Pre(currContext, stmt, 0);
UInt32 flags;
SessionDefaults *sd = currContext.getSessionDefaults();
if (sd != NULL && sd->getCallEmbeddedArkcmp())
flags = PREPARE_USE_EMBEDDED_ARKCMP;
else
flags = 0;
retcode =
stmt->prepare(strTarget.getStr(), diags, NULL, 0L, strTarget.getIntCharSet(), TRUE, flags);
SQLCLI_Prepare_Setup_Post(currContext, stmt, 1);
if (isERROR(retcode))
return SQLCLI_ReturnCode(&currContext,retcode);
stmt->issuePlanVersioningWarnings (diags);
return CliEpilogue(cliGlobals,statement_id);
}
Lng32 SQLCLI_Prepare2(/*IN*/ CliGlobals * cliGlobals,
/*IN*/ SQLSTMT_ID * statement_id,
/*IN*/ SQLDESC_ID * sql_source,
/*INOUT*/ char * gencode_ptr,
/*IN*/ Lng32 gencode_len,
/*INOUT*/ Lng32 * ret_gencode_len,
/*INOUT*/ SQL_QUERY_COST_INFO *query_cost_info,
/*INOUT*/ SQL_QUERY_COMPILER_STATS_INFO *query_comp_stats_info,
/*INOUT*/ char * uniqueStmtId,
/*INOUT*/ Lng32 * uniqueStmtIdLen,
/*IN*/ ULng32 flags)
{
Lng32 retcode = 0;
// create initial context, if first call, and add module, if any.
retcode = CliPrologue(cliGlobals,statement_id->module);
if (isERROR(retcode))
{
return retcode;
}
ContextCli & currContext = *(cliGlobals->currContext());
ComDiagsArea & diags = currContext.diags();
AQRInfo * aqr = currContext.aqrInfo();
/* prepare the statement */
Statement * stmt = currContext.getStatement(statement_id);
/* stmt must exist */
if (!stmt)
{
diags << DgSqlCode(-CLI_STMT_NOT_EXISTS);
return SQLCLI_ReturnCode(&currContext,-CLI_STMT_NOT_EXISTS);
}
NABoolean retrieveGenCode = FALSE;
NABoolean reTry = ((flags & PREPARE_AUTO_QUERY_RETRY) != 0);
UInt32 tmpFlags;
SessionDefaults *sd = currContext.getSessionDefaults();
if (sd != NULL && sd->getCallEmbeddedArkcmp())
tmpFlags = flags | PREPARE_USE_EMBEDDED_ARKCMP;
else
tmpFlags = flags;
if (sql_source)
{
StrTarget strTarget;
retcode = stmt->initStrTarget(sql_source, currContext, diags, strTarget);
if (isERROR(retcode))
{
return SQLCLI_ReturnCode(&currContext,retcode);
}
NABoolean standaloneQ = tmpFlags & PREPARE_STANDALONE_QUERY;
if (reTry)
{
if ((uniqueStmtId == NULL) ||
(uniqueStmtIdLen == NULL) ||
(*uniqueStmtIdLen <= 0))
{
// Error
diags << DgSqlCode(-CLI_STMT_NOT_EXISTS);
return SQLCLI_ReturnCode(&currContext,-CLI_STMT_NOT_EXISTS);
}
stmt->setUniqueStmtId(uniqueStmtId);
}
// if uniqueStmt id buffer passed in contains a valid query id,
// use that as the query id and it should be same as the one
// that already exists
else if ((uniqueStmtId) &&
(uniqueStmtIdLen) &&
(*uniqueStmtIdLen >= (Lng32)strlen(COM_SESSION_ID_PREFIX)) &&
(str_cmp(uniqueStmtId, COM_SESSION_ID_PREFIX, strlen(COM_SESSION_ID_PREFIX)) == 0))
{
if (stmt->getUniqueStmtId() == NULL ||
(*uniqueStmtIdLen) != stmt->getUniqueStmtIdLen() ||
str_cmp(stmt->getUniqueStmtId(), uniqueStmtId, stmt->getUniqueStmtIdLen()) != 0)
{
diags << DgSqlCode(- CLI_QID_NOT_MATCHING);
return SQLCLI_ReturnCode(&currContext,-CLI_QID_NOT_MATCHING);
}
}
else
// generate a new query id.
stmt->setUniqueStmtId(NULL);
// Set the StmtStats in the shared segment
stmt->setStmtStats(reTry);
SQLCLI_Prepare_Setup_Pre(currContext, stmt, tmpFlags);
if (! reTry)
{
// new prepare. Clear any previously set retry condition.
aqr->clearRetryInfo();
stmt->aqrStmtInfo()->clearRetryInfo();
stmt->aqrStmtInfo()->setRetryPrepareFlags(tmpFlags);
}
if (ret_gencode_len == NULL)
{
// assign passed in source str and gen code to 'this'
retcode =
stmt->prepare(strTarget.getStr(), diags,
gencode_ptr, gencode_len,
strTarget.getIntCharSet(),
TRUE /* unpack tdbs */,
tmpFlags);
retrieveGenCode = FALSE;
}
else
{
// prepare this statement.
retcode =
stmt->prepare(strTarget.getStr(), diags,
NULL, 0L,
strTarget.getIntCharSet(),
FALSE, /* do not unpack tdbs */
tmpFlags);
retrieveGenCode = TRUE;
}
}
else
retrieveGenCode = TRUE;
if (uniqueStmtId)
{
if ((uniqueStmtIdLen) &&
(*uniqueStmtIdLen >= stmt->getUniqueStmtIdLen()))
{
str_cpy_all(uniqueStmtId, stmt->getUniqueStmtId(),
stmt->getUniqueStmtIdLen());
*uniqueStmtIdLen = stmt->getUniqueStmtIdLen();
}
}
if (isERROR(retcode))
{
return SQLCLI_ReturnCode(&currContext,retcode);
}
if (query_cost_info)
{
query_cost_info->cpuTime = 0;
query_cost_info->ioTime = 0;
query_cost_info->msgTime = 0;
query_cost_info->idleTime = 0;
query_cost_info->totalTime = 0;
query_cost_info->cardinality = 0;
query_cost_info->estimatedTotalMem = 0;
query_cost_info->resourceUsage = 0;
query_cost_info->maxCpuUsage = 0;
if (stmt->getRootTdb())
{
if (stmt->getRootTdb()->getQueryCostInfo())
{
stmt->getRootTdb()->getQueryCostInfo()->translateToExternalFormat(query_cost_info);
}
else
query_cost_info->totalTime = stmt->getRootTdb()->getCost();
}
}
if (query_comp_stats_info)
{
if (stmt->getRootTdb())
{
CompilerStatsInfo *cmpStatsInfo =
stmt->getRootTdb()->getCompilerStatsInfo();
if (cmpStatsInfo)
{
short xnNeeded = (stmt->transactionReqd() ? 1 : 0);
cmpStatsInfo->translateToExternalFormat(query_comp_stats_info,xnNeeded);
}
// CompilationStatsData.
CompilationStatsData *cmpData =
stmt->getRootTdb()->getCompilationStatsData();
SQL_COMPILATION_STATS_DATA *query_cmp_data =
&query_comp_stats_info->compilationStats;
if( cmpData )
{
StmtStats *stmtStats = stmt->getStmtStats();
ExMasterStats *masterStats;
Int64 cmpStartTime = -1;
Int64 cmpEndTime = NA_JulianTimestamp();
if (stmtStats != NULL && (masterStats = stmtStats->getMasterStats()) != NULL)
cmpStartTime = masterStats->getCompStartTime();
cmpData->translateToExternalFormat(query_cmp_data,
cmpStartTime, cmpEndTime);
stmt->setCompileEndTime(cmpEndTime);
}
}
}
// A cursor on an embedded INSERT is not supported.
if (stmt->getRootTdb() && stmt->getRootTdb()->isEmbeddedInsert())
{
if (statement_id->identifier &&
strstr ((char *) statement_id->identifier,"SQLCI_PREPSTMT_FOR_CURSOR_") != NULL)
{
diags << DgSqlCode(-3409);
return SQLCLI_ReturnCode(&currContext,-3409);
}
}
if (retrieveGenCode)
{
if (ret_gencode_len)
*ret_gencode_len = stmt->getRootTdbSize();
if ((gencode_ptr == NULL) ||
(gencode_len < stmt->getRootTdbSize()))
{
diags << DgSqlCode(-CLI_GENCODE_BUFFER_TOO_SMALL);
return SQLCLI_ReturnCode(&currContext,-CLI_GENCODE_BUFFER_TOO_SMALL);
}
memcpy(gencode_ptr, stmt->getRootTdb(), stmt->getRootTdbSize());
Lng32 unpackRetcode = stmt->unpackAndInit(diags, -1);
if (isERROR(unpackRetcode) && !isERROR(retcode))
retcode = unpackRetcode;
// root tdb is not unpacked in some cases.
// See Statement::unpackAndInit for details.
// For those cases, do not do stats post prepare setup as that will
// try to access fields in root tdb.
if (NOT stmt->getRootTdb()->isFromShowplan())
SQLCLI_Prepare_Setup_Post(currContext, stmt, tmpFlags);
}
else
SQLCLI_Prepare_Setup_Post(currContext, stmt, tmpFlags);
if (cliGlobals->currContext()->diags().getNumber())
{
return cliGlobals->currContext()->diags().mainSQLCODE();
}
else
{
return retcode;
}
}
Lng32 SQLCLI_GetExplainData(
/*IN*/ CliGlobals * cliGlobals,
/*IN*/ SQLSTMT_ID * statement_id,
/*INOUT*/ char * explain_ptr,
/*IN*/ Int32 explain_buf_len,
/*INOUT*/ Int32 * ret_explain_len)
{
Lng32 retcode = 0;
// create initial context, if first call, and add module, if any.
retcode = CliPrologue(cliGlobals,statement_id->module);
if (isERROR(retcode))
{
return retcode;
}
ContextCli & currContext = *(cliGlobals->currContext());
ComDiagsArea & diags = currContext.diags();
/* get the statement from context */
Statement * stmt = currContext.getStatement(statement_id);
/* stmt must exist */
if ((!stmt) || (!stmt->getRootTdb()) || (! ret_explain_len))
{
diags << DgSqlCode(-CLI_STMT_NOT_EXISTS);
return SQLCLI_ReturnCode(&currContext,-CLI_STMT_NOT_EXISTS);
}
retcode = ExExplainTcb::getExplainData(stmt->getRootTdb(),
explain_ptr, explain_buf_len, ret_explain_len,
&diags, currContext.exCollHeap());
if (diags.getNumber())
{
return diags.mainSQLCODE();
}
else if (retcode < 0)
{
diags << DgSqlCode(retcode);
return retcode;
}
return retcode;
}
Lng32 SQLCLI_StoreExplainData(
/*IN*/ CliGlobals * cliGlobals,
/*IN*/ Int64 * exec_start_utc_ts,
/*IN*/ char * query_id,
/*INOUT*/ char * explain_ptr,
/*IN*/ Int32 explain_buf_len)
{
Lng32 retcode = 0;
// create initial context, if first call, and add module, if any.
retcode = CliPrologue(cliGlobals, NULL);
if (isERROR(retcode))
{
return retcode;
}
ContextCli & currContext = *(cliGlobals->currContext());
ComDiagsArea & diags = currContext.diags();
if ((! explain_ptr) || (explain_buf_len <= 0))
{
diags << DgSqlCode(-CLI_GENCODE_BUFFER_TOO_SMALL);
return SQLCLI_ReturnCode(&currContext,-CLI_GENCODE_BUFFER_TOO_SMALL);
}
retcode =
ExExplainTcb::storeExplainInRepos(cliGlobals, exec_start_utc_ts,
query_id, strlen(query_id), explain_ptr, explain_buf_len);
if (retcode < 0)
{
if (diags.getNumber())
{
return diags.mainSQLCODE();
}
else
{
diags << DgSqlCode(retcode);
}
return retcode;
}
return retcode;
}
Lng32 SQLCLI_ResDescName(/*IN*/ CliGlobals * cliGlobals,
/*INOUT*/ SQLDESC_ID * descriptor_id,
/*IN OPTIONAL*/ SQLSTMT_ID * from_statement,
/* (SQLWHAT_DESC) *IN OPTIONAL*/ Lng32 what_desc)
{
Lng32 retcode;
// create initial context, if first call, and add module, if any.
retcode = CliPrologue(cliGlobals,descriptor_id->module);
if (isERROR(retcode))
return retcode;
ContextCli & currContext = *(cliGlobals->currContext());
ComDiagsArea & diags = currContext.diags();
Descriptor * desc = 0;
if (from_statement)
{
Statement * stmt = currContext.getStatement(from_statement);
/* stmt must exist */
if (!stmt)
{
diags << DgSqlCode(-CLI_STMT_NOT_EXISTS);
return SQLCLI_ReturnCode(&currContext,-CLI_STMT_NOT_EXISTS);
}
desc = stmt->getDefaultDesc(what_desc);
}
else
{
desc = currContext.getDescriptor(descriptor_id);
}
/* desc must exist */
if (!desc)
{
diags << DgSqlCode(-CLI_DESC_NOT_EXISTS);
return SQLCLI_ReturnCode(&currContext,-CLI_DESC_NOT_EXISTS);
}
if (descriptor_id->name_mode == desc_handle)
{
descriptor_id->handle = desc->getDescHandle();
}
else if (descriptor_id->name_mode == desc_name)
{
if ((! descriptor_id->identifier) ||
(! desc->getDescName()) ||
(! desc->getDescName()->identifier))
{
diags << DgSqlCode(-CLI_INVALID_DESC_INFO_REQUEST);
return SQLCLI_ReturnCode(&currContext,
-CLI_INVALID_DESC_INFO_REQUEST);
}
// On input, descriptor_id->identifier_len contains the max length of
// the buffer where identifier name will be copied.
// On output, it contains the actual length of the identifier copied.
// Returned identifier is NOT null terminated as this method could
// be called from both C and Cobol.
Int32 lenToCopy =
MINOF(descriptor_id->identifier_len,
desc->getDescName()->identifier_len);
str_cpy_all((char*)descriptor_id->identifier, desc->getDescName()->identifier,
lenToCopy);
descriptor_id->identifier_len = lenToCopy;
}
return SUCCESS;
}
Lng32 SQLCLI_ResStmtName(/*IN*/ CliGlobals * cliGlobals,
/*INOUT*/ SQLSTMT_ID * statement_id)
{
Lng32 retcode;
// create initial context, if first call, and add module, if any.
retcode = CliPrologue(cliGlobals,statement_id->module);
if (isERROR(retcode))
return retcode;
ContextCli & currContext = *(cliGlobals->currContext());
ComDiagsArea & diags = currContext.diags();
/* get the statement */
Statement * stmt = currContext.getStatement(statement_id);
/* stmt must exist */
if (!stmt)
{
diags << DgSqlCode(-CLI_STMT_NOT_EXISTS);
return SQLCLI_ReturnCode(&currContext,-CLI_STMT_NOT_EXISTS);
}
statement_id->name_mode = stmt_handle;
statement_id->handle = stmt->getStmtHandle();
return SUCCESS;
}
// statement_id must point to an existing statement
// The Descriptor Id cursor_name must be of name_mode
// cursor_name or cursor_via_desc **exception ODBC/JDBC
Lng32 SQLCLI_SetCursorName(/*IN*/ CliGlobals * cliGlobals,
/*IN*/ SQLSTMT_ID * statement_id,
/*IN*/ SQLSTMT_ID * cursor_id)// must of name_mode cursor_name or cursor_via_desc **exception ODBC/JDBC
{
Lng32 retcode;
SQLDESC_ID *curs_id;
NAHeap &heap = *(cliGlobals->currContext()->exHeap());
// create initial context, if first call, and add module, if any.
retcode = CliPrologue(cliGlobals,statement_id->module);
if (isERROR(retcode))
return retcode;
ContextCli & currContext = *(cliGlobals->currContext());
ComDiagsArea & diags = currContext.diags();
Statement * stmt = currContext.getStatement(statement_id);
/* stmt must exist */
if (!stmt)
{
diags << DgSqlCode(-CLI_STMT_NOT_EXISTS);
return SQLCLI_ReturnCode(&currContext,-CLI_STMT_NOT_EXISTS);
}
else if (!stmt->allocated())
{
diags << DgSqlCode(-CLI_NOT_DYNAMIC_STMT)
<< DgString0("set cursor name for");
return SQLCLI_ReturnCode(&currContext,-CLI_NOT_DYNAMIC_STMT);
}
// For the sake of ODBC/JDBC, we will leave this check in here
// since they do not pass a STMT_ID for cursor_name but a DESC_ID
// with name mode desc_handle
if (cursor_id->name_mode == desc_handle)
{
Descriptor * desc = currContext.getDescriptor(cursor_id);
/* descriptor must exist */
if (!desc)
{
diags << DgSqlCode(-CLI_DESC_NOT_EXISTS);
return SQLCLI_ReturnCode(&currContext,-CLI_DESC_NOT_EXISTS);
}
stmt->setCursorName(desc->getVarData(1));
return SUCCESS;
}
switch(cursor_id->name_mode)
{
case cursor_name:
// Simply set the cursor name as it is passed. Do not parse it
// Assumption is that the caller is passing it in valid ansi format
stmt->setCursorName(cursor_id->identifier);
break;
case curs_via_desc:
// This is the extended dynamic case. In this case the CLI will
// convert/check the input to valid ansi format
curs_id = Descriptor::GetNameViaDesc((SQLDESC_ID *)cursor_id,&currContext,heap);
if (curs_id)
stmt->setCursorName(curs_id->identifier);
break;
default:
diags << DgSqlCode(-CLI_INVALID_ATTR_VALUE);
return SQLCLI_ReturnCode(&currContext,-CLI_INVALID_ATTR_VALUE);
break;
}
return SUCCESS;
}
Lng32 SQLCLI_SetStmtAttr( /*IN*/ CliGlobals *cliGlobals,
/*IN*/ SQLSTMT_ID *statement_id,
/*IN SQLATTR_TYPE */ Lng32 attrName,
/*IN OPTIONAL*/ Lng32 numeric_value,
/*IN OPTIONAL*/ char * string_value)
{
Lng32 retcode = SUCCESS;
// create initial context, if first call, and add module, if any.
retcode = CliPrologue(cliGlobals,statement_id->module);
if (isERROR(retcode))
return retcode;
ContextCli & currContext = *(cliGlobals->currContext());
ComDiagsArea & diags = currContext.diags();
Statement * stmt = currContext.getStatement(statement_id);
/* stmt must exist */
if (!stmt)
{
diags << DgSqlCode(-CLI_STMT_NOT_EXISTS);
return SQLCLI_ReturnCode(&currContext,-CLI_STMT_NOT_EXISTS);
}
if (attrName == SQL_ATTR_CURSOR_HOLDABLE)
{
switch (numeric_value)
{
case SQL_NONHOLDABLE:
retcode = stmt->setHoldable(diags, FALSE);
break;
case SQL_HOLDABLE:
retcode = stmt->setHoldable(diags, TRUE);
break;
default:
diags << DgSqlCode(-CLI_INVALID_ATTR_VALUE);
return SQLCLI_ReturnCode(&currContext,-CLI_INVALID_ATTR_VALUE);
}
}
else if (attrName == SQL_ATTR_INPUT_ARRAY_MAXSIZE)
{
retcode = stmt->setInputArrayMaxsize(diags, numeric_value);
}
else if (attrName == SQL_ATTR_ROWSET_ATOMICITY)
{
switch (numeric_value)
{
case SQL_NOT_SPECIFIED:
retcode = stmt->setRowsetAtomicity(diags, Statement::UNSPECIFIED_);
break;
case SQL_ATOMIC:
retcode = stmt->setRowsetAtomicity(diags, Statement::ATOMIC_);
break;
case SQL_NOT_ATOMIC:
retcode = stmt->setRowsetAtomicity(diags, Statement::NOT_ATOMIC_);
break;
default:
diags << DgSqlCode(-CLI_INVALID_ATTR_VALUE);
return SQLCLI_ReturnCode(&currContext,-CLI_INVALID_ATTR_VALUE);
}
// If stmt is in INITIAL state then the statement did not get prepared.
// Or if it is in PREPARE state, then it is a nowaited prepare which is
// still being prepared.
if ((stmt->getState() != Statement::INITIAL_) &&
(stmt->getState() != Statement::PREPARE_))
{
diags << DgSqlCode(CLI_STMT_NEEDS_PREPARE);
return SQLCLI_ReturnCode(&currContext,CLI_STMT_NEEDS_PREPARE);
}
}
else if (attrName == SQL_ATTR_NOT_ATOMIC_FAILURE_LIMIT)
{
if ((numeric_value >= 30)||
(numeric_value == ComCondition::NO_LIMIT_ON_ERROR_CONDITIONS)) {
retcode = stmt->setNotAtomicFailureLimit(diags, numeric_value);
}
else {
diags << DgSqlCode(-CLI_INVALID_ATTR_VALUE);
return SQLCLI_ReturnCode(&currContext,-CLI_INVALID_ATTR_VALUE);
}
}
else if (attrName == SQL_ATTR_UNIQUE_STMT_ID)
{
stmt->setUniqueStmtId(string_value);
}
else if (attrName == SQL_ATTR_COPY_STMT_ID_TO_DIAGS)
{
diags.setAllSqlID(stmt->getUniqueStmtId());
}
else if (attrName == SQL_ATTR_PARENT_QID)
{
retcode = stmt->setParentQid(string_value);
if (retcode != 0)
{
diags << DgSqlCode(retcode);
}
}
else {
diags << DgSqlCode(-CLI_INVALID_ATTR_NAME);
return SQLCLI_ReturnCode(&currContext,-CLI_INVALID_ATTR_NAME);
}
if (retcode)
return diags.mainSQLCODE();
return retcode;
}
Lng32 SQLCLI_GetSessionAttr( /*IN*/ CliGlobals *cliGlobals,
/*IN SESSIONATTR_TYPE */ Lng32 attrName,
/*OUT OPTIONAL*/ Lng32 * numeric_value,
/*OUT OPTIONAL*/ char * string_value,
/*IN OPTIONAL*/ Lng32 max_string_len,
/*OUT OPTIONAL*/ Lng32 * len_of_item)
{
Lng32 retcode = SUCCESS;
// create initial context, if first call, and add module, if any.
retcode = CliPrologue(cliGlobals, NULL);
if (isERROR(retcode))
return retcode;
ContextCli & currContext = *(cliGlobals->currContext());
ComDiagsArea & diags = currContext.diags();
NABoolean bufferNullOrTooSmall = FALSE;
switch (attrName)
{
case SESSION_ATTR_ID:
{
const char *sessionID = currContext.getSessionId();
Int32 bytesNeeded = (sessionID ? strlen(sessionID) + 1 : 0);
if (sessionID && string_value && max_string_len >= bytesNeeded)
strcpy(string_value, sessionID);
else
bufferNullOrTooSmall = TRUE;
if (len_of_item)
*len_of_item = bytesNeeded;
}
break;
case SESSION_PARENT_QID:
{
SessionDefaults *sd = currContext.getSessionDefaults();
const char *queryID = (sd ? sd->getParentQid() : NULL);
Int32 bytesNeeded = (queryID ? strlen(queryID) + 1 : 0);
if (queryID && string_value && max_string_len >= bytesNeeded)
strcpy(string_value, queryID);
else
bufferNullOrTooSmall = TRUE;
if (len_of_item)
*len_of_item = bytesNeeded;
if (bufferNullOrTooSmall)
{
// Prior to Seaquest we were returning CLI_BUFFER_TOO_SMALL
// (which is specific to query IDs) when the query ID target
// buffer is null or too small. We will continue to return
// that code in case any CLI callers expect it. For other
// attributes we return a more general error saying the
// "session attribute" is null or too small.
diags << DgSqlCode(-CLI_BUFFER_TOO_SMALL);
return SQLCLI_ReturnCode(&currContext,-CLI_BUFFER_TOO_SMALL);
}
}
break;
case SESSION_DATABASE_USER_NAME:
{
const char *authID = currContext.getDatabaseUserName();
Int32 bytesNeeded = (authID ? strlen(authID) + 1 : 0);
if (authID && string_value && max_string_len >= bytesNeeded)
strcpy(string_value, authID);
else
bufferNullOrTooSmall = TRUE;
if (len_of_item)
*len_of_item = bytesNeeded;
}
break;
case SESSION_DATABASE_USER_ID:
{
Int32 *userID = currContext.getDatabaseUserID();
ex_assert(userID, "Context user ID should never be NULL");
if (numeric_value)
*numeric_value = *userID;
else
bufferNullOrTooSmall = TRUE;
}
break;
case SESSION_SESSION_USER_ID:
{
Int32 *sessionUserID = currContext.getSessionUserID();
ex_assert(sessionUserID, "Context session user ID should never be NULL");
if (numeric_value)
*numeric_value = *sessionUserID;
else
bufferNullOrTooSmall = TRUE;
}
break;
case SESSION_EXTERNAL_USER_NAME:
{
const char *externalUsername = currContext.getExternalUserName();
Int32 bytesNeeded = (externalUsername ? strlen(externalUsername) + 1 : 0);
if (externalUsername && string_value && max_string_len >= bytesNeeded)
strcpy(string_value, externalUsername);
else
bufferNullOrTooSmall = TRUE;
if (len_of_item)
*len_of_item = bytesNeeded;
}
break;
default:
{
diags << DgSqlCode(-CLI_INVALID_ATTR_NAME);
return SQLCLI_ReturnCode(&currContext,-CLI_INVALID_ATTR_NAME);
}
break;
} // switch (attrName)
if (bufferNullOrTooSmall)
{
diags << DgSqlCode(-CLI_SESSION_ATTR_BUFFER_TOO_SMALL);
return SQLCLI_ReturnCode(&currContext,
-CLI_SESSION_ATTR_BUFFER_TOO_SMALL);
}
return SUCCESS;
}
Lng32 SQLCLI_GetAuthID(
CliGlobals * cliGlobals,
const char * authName,
Lng32 & authID)
{
Lng32 retcode = 0;
// create initial context, if first call, and add module, if any.
retcode = CliPrologue(cliGlobals, NULL);
if (isERROR(retcode))
return retcode;
ContextCli &currContext = *(cliGlobals->currContext());
ComDiagsArea &diags = currContext.diags();
retcode = currContext.getAuthIDFromName(authName,authID);
return CliEpilogue(cliGlobals, NULL, retcode);
}
Lng32 SQLCLI_GetAuthName (
/*IN*/ CliGlobals *cliGlobals,
/*IN*/ Lng32 auth_id,
/*OUT*/ char *string_value,
/*IN*/ Lng32 max_string_len,
/*OUT */ Lng32 &len_of_item)
{
Lng32 retcode = 0;
// create initial context, if first call, and add module, if any.
retcode = CliPrologue(cliGlobals, NULL);
if (isERROR(retcode))
return retcode;
ContextCli &currContext = *(cliGlobals->currContext());
ComDiagsArea &diags = currContext.diags();
retcode = currContext.getAuthNameFromID(auth_id,
string_value,
max_string_len,
len_of_item);
return CliEpilogue(cliGlobals, NULL, retcode);
}
Lng32 SQLCLI_GetDatabaseUserName (
/*IN*/ CliGlobals *cliGlobals,
/*IN*/ Lng32 user_id,
/*OUT*/ char *string_value,
/*IN*/ Lng32 max_string_len,
/*OUT OPTIONAL*/ Lng32 *len_of_item)
{
Lng32 retcode = 0;
// create initial context, if first call, and add module, if any.
retcode = CliPrologue(cliGlobals, NULL);
if (isERROR(retcode))
return retcode;
ContextCli &currContext = *(cliGlobals->currContext());
ComDiagsArea &diags = currContext.diags();
retcode = currContext.getAuthNameFromID(user_id,
string_value,
max_string_len,
*len_of_item);
return CliEpilogue(cliGlobals, NULL, retcode);
}
Lng32 SQLCLI_GetDatabaseUserID (
/*IN*/ CliGlobals *cliGlobals,
/*IN*/ char *string_value,
/*OUT*/ Lng32 *numeric_value)
{
Lng32 retcode = 0;
// create initial context, if first call, and add module, if any.
retcode = CliPrologue(cliGlobals, NULL);
if (isERROR(retcode))
return retcode;
ContextCli &currContext = *(cliGlobals->currContext());
ComDiagsArea &diags = currContext.diags();
retcode = currContext.getAuthIDFromName(string_value,
*numeric_value);
return CliEpilogue(cliGlobals, NULL, retcode);
}
Int32 SQLCLI_GetAuthState (
/*IN*/ CliGlobals *cliGlobals,
/*OUT*/ bool &authenticationEnabled,
/*OUT*/ bool &authorizationEnabled,
/*OUT*/ bool &authorizationReady,
/*OUT*/ bool &auditingEnabled)
{
Int32 retcode = 0;
// create initial context, if first call, and add module, if any.
retcode = CliPrologue(cliGlobals, NULL);
if (isERROR(retcode))
return retcode;
ContextCli &currContext = *(cliGlobals->currContext());
ComDiagsArea &diags = currContext.diags();
currContext.getAuthState(authenticationEnabled,
authorizationEnabled,
authorizationReady,
auditingEnabled);
return CliEpilogue(cliGlobals, NULL, retcode);
}
Lng32 SQLCLI_GetRoleList(
CliGlobals * cliGlobals,
Int32 &numEntries,
Int32 *& roleIDs,
Int32 *& granteeIDs)
{
Lng32 retcode = 0;
// create initial context, if first call, and add module, if any.
retcode = CliPrologue(cliGlobals, NULL);
if (isERROR(retcode))
return retcode;
ContextCli &currContext = *(cliGlobals->currContext());
ComDiagsArea &diags = currContext.diags();
retcode = currContext.getRoleList(numEntries,roleIDs,granteeIDs);
return CliEpilogue(cliGlobals, NULL, retcode);
}
Lng32 SQLCLI_ResetRoleList(
CliGlobals * cliGlobals)
{
Lng32 retcode = 0;
// create initial context, if first call, and add module, if any.
retcode = CliPrologue(cliGlobals, NULL);
if (isERROR(retcode))
return retcode;
ContextCli &currContext = *(cliGlobals->currContext());
ComDiagsArea &diags = currContext.diags();
retcode = currContext.resetRoleList();
return CliEpilogue(cliGlobals, NULL, retcode);
}
Lng32 SQLCLI_SetSessionAttr(/*IN*/ CliGlobals *cliGlobals,
/*IN SESSIONATTR_TYPE*/ Lng32 attrName,
/*IN OPTIONAL*/ Lng32 numeric_value,
/*IN OPTIONAL*/ char *string_value)
{
Lng32 retcode = SUCCESS;
// create initial context, if first call, and add module, if any.
retcode = CliPrologue(cliGlobals, NULL);
if (isERROR(retcode))
return retcode;
ContextCli &currContext = *(cliGlobals->currContext());
ComDiagsArea &diags = currContext.diags();
switch (attrName)
{
case SESSION_DATABASE_USER_ID:
{
retcode = currContext.setDatabaseUserByID(numeric_value);
}
break;
case SESSION_DATABASE_USER_NAME:
{
retcode = currContext.setDatabaseUserByName(string_value);
}
break;
case SESSION_DATABASE_USER:
{
// The call to setDatabaseUser set values in the Context
// it does not return any errors
currContext.setDatabaseUser(numeric_value, string_value);
}
break;
case SESSION_PARENT_QID:
{
SessionDefaults *sd = currContext.getSessionDefaults();
if (sd && string_value)
sd->setParentQid(string_value, strlen(string_value));
}
break;
default:
{
// Other attributes can be supported in time
diags << DgSqlCode(-CLI_INVALID_ATTR_NAME);
return SQLCLI_ReturnCode(&currContext,-CLI_INVALID_ATTR_NAME);
}
break;
}
return CliEpilogue(cliGlobals, NULL);
}
Lng32 SQLCLI_GetUniqueQueryIdAttrs( /*IN*/ CliGlobals *cliGlobals,
/*IN*/ char * queryId,
/*IN*/ Lng32 queryIdLen,
/*IN*/ Lng32 no_of_attrs,
/*INOUT*/ UNIQUEQUERYID_ATTR queryid_attrs[])
{
Lng32 retcode = SUCCESS;
// create initial context, if first call, and add module, if any.
retcode = CliPrologue(cliGlobals, NULL);
if (isERROR(retcode))
return retcode;
ContextCli & currContext = *(cliGlobals->currContext());
ComDiagsArea & diags = currContext.diags();
/* stmt must exist */
if (!queryId)
{
diags << DgSqlCode(-CLI_STMT_NOT_EXISTS);
return SQLCLI_ReturnCode(&currContext,-CLI_STMT_NOT_EXISTS);
}
for (Int32 i = 0; i < no_of_attrs && !retcode; i++)
{
Int64 temp_nvol = (Int64)queryid_attrs[i].num_val_or_len;
retcode = ComSqlId::getSqlQueryIdAttr(queryid_attrs[i].attr_type,
queryId, queryIdLen,
temp_nvol,
queryid_attrs[i].string_val);
queryid_attrs[i].num_val_or_len = temp_nvol;
}
return retcode;
}
// A helper function to copy one statement attribute into the target
// buffer
Lng32 CopyOneStmtAttr (/*IN*/ Statement &stmt,
/*IN*/ ContextCli &context,
/*OUT*/ ComDiagsArea &diags,
/*IN*/ Lng32 attrName,
/*IN*/ Lng32 index,
/*OUT*/ Lng32 *numeric_value,
/*OUT*/ char *string_value,
/*IN*/ Lng32 max_string_len,
/*OUT*/ Lng32 *len_of_item )
{
Lng32 retcode = SUCCESS;
if (attrName == SQL_ATTR_CURSOR_HOLDABLE)
{
if (stmt.isAnsiHoldable() || stmt.isPubsubHoldable())
{
*numeric_value = SQL_HOLDABLE;
}
else
{
*numeric_value = SQL_NONHOLDABLE;
}
}
else if (attrName == SQL_ATTR_INPUT_ARRAY_MAXSIZE)
{
*numeric_value = (Lng32) stmt.getInputArrayMaxsize() ;
}
else if (attrName == SQL_ATTR_QUERY_TYPE)
{
if (!stmt.getRootTdb())
{
//for display query e.g. display select ...
//just return SUCCESS to suppress error message
if(stmt.isDISPLAY())
{
return SQLCLI_ReturnCode(&context, DISPLAY_DONE_WARNING);
}
else
{
diags << DgSqlCode(-CLI_STMT_NOT_EXISTS);
return SQLCLI_ReturnCode(&context, -CLI_STMT_NOT_EXISTS);
}
}
*numeric_value = stmt.getRootTdb()->getQueryType();
}
else if (attrName == SQL_ATTR_SUBQUERY_TYPE)
{
if (!stmt.getRootTdb())
{
//for display query e.g. display select ...
//just return SUCCESS to suppress error message
if(stmt.isDISPLAY())
{
return SQLCLI_ReturnCode(&context, DISPLAY_DONE_WARNING);
}
else
{
diags << DgSqlCode(-CLI_STMT_NOT_EXISTS);
return SQLCLI_ReturnCode(&context, -CLI_STMT_NOT_EXISTS);
}
}
*numeric_value = stmt.getRootTdb()->getSubqueryType();
}
else if (attrName == SQL_ATTR_MAX_RESULT_SETS)
{
if (!stmt.getRootTdb())
{
diags << DgSqlCode(-CLI_STMT_NOT_EXISTS);
return SQLCLI_ReturnCode(&context, -CLI_STMT_NOT_EXISTS);
}
*numeric_value = stmt.getRootTdb()->getMaxResultSets();
}
else if (attrName == SQL_ATTR_XN_NEEDED)
{
*numeric_value =
(stmt.getRootTdb()->transactionReqd() ? 1 : 0);
}
else if (attrName == SQL_ATTR_UNIQUE_STMT_ID)
{
Lng32 actual_len = stmt.getUniqueStmtIdLen();
if (len_of_item)
*len_of_item = actual_len;
if (stmt.getUniqueStmtId())
{
if ((max_string_len) && (actual_len > max_string_len))
{
diags << DgSqlCode(-CLI_BUFFER_TOO_SMALL);
return SQLCLI_ReturnCode(&context,-CLI_BUFFER_TOO_SMALL);
}
strncpy(string_value, stmt.getUniqueStmtId(),
stmt.getUniqueStmtIdLen());
}
}
else if (attrName == SQL_ATTR_RS_PROXY_SYNTAX)
{
if (!stmt.getRootTdb())
{
diags << DgSqlCode(-CLI_STMT_NOT_EXISTS);
return SQLCLI_ReturnCode(&context, -CLI_STMT_NOT_EXISTS);
}
stmt.getRSProxySyntax(string_value, max_string_len, len_of_item);
if (!string_value || (len_of_item && (max_string_len < *len_of_item)))
{
diags << DgSqlCode(-CLI_RS_PROXY_BUFFER_SMALL_OR_NULL);
return SQLCLI_ReturnCode(&context,
-CLI_RS_PROXY_BUFFER_SMALL_OR_NULL);
}
}
else if (attrName == SQL_ATTR_CONSUMER_QUERY_TEXT)
{
Lng32 actual_len = stmt.getConsumerQueryLen(index - 1);
if (len_of_item)
*len_of_item = actual_len;
if (actual_len > 0)
{
if (actual_len > max_string_len)
{
diags << DgSqlCode(-CLI_CONSUMER_QUERY_BUF_TOO_SMALL)
<< DgInt0(index);
return SQLCLI_ReturnCode(&context,-CLI_CONSUMER_QUERY_BUF_TOO_SMALL);
}
stmt.getConsumerQuery(index - 1,
string_value, max_string_len);
}
}
else if (attrName == SQL_ATTR_CONSUMER_CPU)
{
*numeric_value = stmt.getConsumerCpu(index - 1);
}
else if (attrName == SQL_ATTR_PARENT_QID)
{
Lng32 actual_len;
const char *parentQid = stmt.getParentQid();
if (parentQid)
actual_len = str_len(parentQid);
else
actual_len = 0;
if (len_of_item)
*len_of_item = actual_len;
if (parentQid)
{
if ((max_string_len) && (actual_len > max_string_len))
{
diags << DgSqlCode(-CLI_BUFFER_TOO_SMALL);
return SQLCLI_ReturnCode(&context,-CLI_BUFFER_TOO_SMALL);
}
strncpy(string_value, parentQid, actual_len);
}
}
else if (attrName == SQL_ATTR_CURSOR_UPDATABLE)
{
if (stmt.getRootTdb())
{
*numeric_value = stmt.getRootTdb()->getCursorType();
}
else
{
diags << DgSqlCode(-CLI_STMT_NOT_EXISTS);
return SQLCLI_ReturnCode(&context, -CLI_STMT_NOT_EXISTS);
}
}
else
{
diags << DgSqlCode(-CLI_INVALID_ATTR_NAME);
return SQLCLI_ReturnCode(&context,-CLI_INVALID_ATTR_NAME);
}
return retcode;
}
Lng32 SQLCLI_GetStmtAttr( /*IN*/ CliGlobals *cliGlobals,
/*IN*/ SQLSTMT_ID *statement_id,
/*IN SQLATTR_TYPE */ Lng32 attrName,
/*OUT OPTIONAL*/ Lng32 * numeric_value,
/*OUT OPTIONAL*/ char * string_value,
/*IN OPTIONAL*/ Lng32 max_string_len,
/*OUT OPTIONAL*/ Lng32 * len_of_item)
{
Lng32 retcode = SUCCESS;
// create initial context, if first call, and add module, if any.
retcode = CliPrologue(cliGlobals,statement_id->module);
if (isERROR(retcode))
return retcode;
ContextCli & currContext = *(cliGlobals->currContext());
ComDiagsArea & diags = currContext.diags();
Statement * stmt = currContext.getStatement(statement_id);
/* stmt must exist */
if (!stmt)
{
diags << DgSqlCode(-CLI_STMT_NOT_EXISTS);
return SQLCLI_ReturnCode(&currContext,-CLI_STMT_NOT_EXISTS);
}
retcode = CopyOneStmtAttr(*stmt, currContext, diags,
attrName, 0, numeric_value, string_value,
max_string_len, len_of_item);
return retcode;
}
Lng32 SQLCLI_GetStmtAttrs( /*IN*/ CliGlobals *cliGlobals,
/*IN*/ SQLSTMT_ID *statement_id,
/*IN*/ Lng32 number_of_attrs,
/*INOUT*/ SQLSTMT_ATTR attrs[],
/*OUT OPTIONAL*/ Lng32 * num_returned)
{
Lng32 retcode = SUCCESS;
*num_returned = 0;
// create initial context, if first call, and add module, if any.
retcode = CliPrologue(cliGlobals,statement_id->module);
if (isERROR(retcode))
return retcode;
ContextCli & currContext = *(cliGlobals->currContext());
ComDiagsArea & diags = currContext.diags();
Statement * stmt = currContext.getStatement(statement_id);
/* stmt must exist */
if (!stmt)
{
diags << DgSqlCode(-CLI_STMT_NOT_EXISTS);
return SQLCLI_ReturnCode(&currContext,-CLI_STMT_NOT_EXISTS);
}
for (Int32 i = 0; i < number_of_attrs && retcode >= 0; i++)
{
const SQLSTMT_ATTR &attr = attrs[i];
retcode = CopyOneStmtAttr(*stmt, currContext, diags,
attr.attr_type, attr.index, attr.numeric_value,
attr.string_value, attr.max_string_len,
attr.len_of_item);
if (retcode >= 0)
(*num_returned)++;
}
return retcode;
}
Lng32 SQLCLI_SetDescEntryCount(/*IN*/ CliGlobals * cliGlobals,
/*IN*/ SQLDESC_ID * desc_id,
/*IN*/ SQLDESC_ID * input_descriptor)
{
Lng32 retcode;
if (!desc_id)
return -CLI_INTERNAL_ERROR;
// create initial context, if first call, and add module, if any.
retcode = CliPrologue(cliGlobals,desc_id->module);
if (isERROR(retcode))
return retcode;
ContextCli & currContext = *(cliGlobals->currContext());
ComDiagsArea & diags = currContext.diags();
Descriptor * desc = currContext.getDescriptor(desc_id);
/* descriptor must exist */
if (!desc)
{
diags << DgSqlCode(-CLI_DESC_NOT_EXISTS);
return SQLCLI_ReturnCode(&currContext,-CLI_DESC_NOT_EXISTS);
}
Descriptor * input_desc = currContext.getDescriptor(input_descriptor);
/* descriptor must exist */
if (!input_desc)
{
diags << DgSqlCode(-CLI_DESC_NOT_EXISTS);
return SQLCLI_ReturnCode(&currContext,-CLI_DESC_NOT_EXISTS);
}
// JORGE: Why are we doing it this way. It may be better if we call
// getUsedEntryCount() on the input descriptor. ??
Lng32 num_entries = 0L;
retcode = InputValueFromNumericHostvar(
input_desc,
1,
num_entries);
if (isERROR(retcode))
return SQLCLI_ReturnCode(&currContext,retcode);
desc->setUsedEntryCount(num_entries);
//Now allocate the space for num_entries worth of descriptors.
desc->addEntry(num_entries);
return SUCCESS;
}
Lng32 SQLCLI_SetDescItems(/*IN*/ CliGlobals * cliGlobals,
/*IN*/ SQLDESC_ID * desc_id,
/*IN*/ SQLDESC_ITEM desc_items[],
/*IN*/ SQLDESC_ID * value_num_descriptor,
/*IN*/ SQLDESC_ID * input_descriptor)
{
Lng32 retcode;
Lng32 first_set = SQLDESC_ITEM_ORDER_COUNT, desc_item_entry[SQLDESC_ITEM_ORDER_COUNT];
const Lng32 not_set = -1;
// create initial context, if first call, and add module, if any.
retcode = CliPrologue(cliGlobals,desc_id->module);
if (isERROR(retcode))
return retcode;
ContextCli & currContext = *(cliGlobals->currContext());
ComDiagsArea & diags = currContext.diags();
Descriptor * desc = currContext.getDescriptor(desc_id);
/* descriptor must exist */
if (!desc)
{
diags << DgSqlCode(-CLI_DESC_NOT_EXISTS);
return SQLCLI_ReturnCode(&currContext,-CLI_DESC_NOT_EXISTS);
}
Descriptor * value_num_desc = currContext.getDescriptor(value_num_descriptor);
/* descriptor must exist */
if (!value_num_desc)
{
diags << DgSqlCode(-CLI_DESC_NOT_EXISTS);
return SQLCLI_ReturnCode(&currContext,-CLI_DESC_NOT_EXISTS);
}
Descriptor * input_desc = currContext.getDescriptor(input_descriptor);
/* descriptor must exist */
if (!input_desc)
{
diags << DgSqlCode(-CLI_DESC_NOT_EXISTS);
return SQLCLI_ReturnCode(&currContext,-CLI_DESC_NOT_EXISTS);
}
Lng32 inputUsedEntryCount = input_desc->getUsedEntryCount();
Lng32 i = 0;
for (; i < SQLDESC_ITEM_ORDER_COUNT; i ++)
desc_item_entry[i] = not_set;
for (i = 0; i < inputUsedEntryCount; i++)
if (desc_items[i].item_id <= SQLDESC_ITEM_MAX &&
SQLDESC_ITEM_ORDER[desc_items[i].item_id-1] >= 0 &&
desc_item_entry[SQLDESC_ITEM_ORDER[desc_items[i].item_id-1]] == not_set) {
desc_item_entry[SQLDESC_ITEM_ORDER[desc_items[i].item_id-1]] = i;
if (SQLDESC_ITEM_ORDER[desc_items[i].item_id-1] < first_set)
first_set = SQLDESC_ITEM_ORDER[desc_items[i].item_id-1];
}
else {
diags << DgSqlCode(-CLI_INVALID_DESC_ENTRY);
return diags.mainSQLCODE();
}
for (Lng32 j = first_set, count = 0; count < inputUsedEntryCount; j++) {
if (desc_item_entry[j] != not_set) {
count += 1;
i = desc_item_entry[j];
//
// Get the entry number of the descriptor entry whose item is to be set.
//
Lng32 entry = 0L;
retcode = InputValueFromNumericHostvar(
value_num_desc,
desc_items[i].value_num_desc_entry,
entry);
if (isERROR(retcode))
return SQLCLI_ReturnCode(&currContext,retcode);
if (entry > desc->getMaxEntryCount())
{
diags << DgSqlCode(-CLI_INVALID_DESC_ENTRY);
return diags.mainSQLCODE();
}
if (entry > desc->getUsedEntryCount()) {
retcode = desc->addEntry(entry);
if (isERROR(retcode))
{
diags << DgSqlCode(-CLI_INTERNAL_ERROR);
return SQLCLI_ReturnCode(&currContext,-CLI_INTERNAL_ERROR);
}
}
//
// Get the address of the source where the item's value is stored.
//
char *var_ptr = 0;
retcode = input_desc->getDescItem(i+1,
SQLDESC_VAR_PTR,
(Lng32 *)&var_ptr,
NULL, 0, NULL, 0);
if (isERROR(retcode))
return SQLCLI_ReturnCode(&currContext,retcode);
if (!var_ptr)
return -CLI_INTERNAL_ERROR;
// if item to be set is vardata, get input data length.
// This is needed so that we can make a copy of input data.
// Do the same for any attribute that need copying of data,
// like SQLDESC_NAME, etc.
Lng32 numericInput;
numericInput = *(Lng32*)var_ptr;
if ((desc_items[i].item_id == SQLDESC_VAR_DATA) ||
(desc_items[i].item_id == SQLDESC_NAME) ||
(desc_items[i].item_id == SQLDESC_HEADING))
{
Lng32 length;
retcode =
input_desc->getDescItem(i+1, SQLDESC_LENGTH, &length, 0, 0, 0, 0);
if (isERROR(retcode))
return SQLCLI_ReturnCode(&currContext,retcode);
numericInput = length;
}
//get size of memory to be bounds checked
Int32 memorySize = input_desc->getVarDataLength(i+1);
//if setting indicator variable get length of indicator variable
if((desc_items[i].item_id == SQLDESC_IND_PTR)||
(desc_items[i].item_id == SQLDESC_IND_DATA)){
//since indicator, get length of indicator
memorySize = input_desc->getIndLength(i+1);
}
if(currContext.boundsCheckMemory((void*)var_ptr,memorySize))
return SQLCLI_ReturnCode(&currContext,
-CLI_USER_MEMORY_IN_EXECUTOR_SEGMENT);
//
// Set the item in the descriptor.
//
retcode = desc->setDescItem(entry,
desc_items[i].item_id,
numericInput,
var_ptr, input_desc, i);
if (isERROR(retcode))
return SQLCLI_ReturnCode(&currContext,retcode);
}
}
return SUCCESS;
}
Lng32 SQLCLI_SetDescItems2(/*IN*/ CliGlobals * cliGlobals,
/*IN*/ SQLDESC_ID * desc_id,
/*IN*/ Lng32 no_of_desc_items,
/*IN*/ SQLDESC_ITEM desc_items[])
{
Lng32 retcode;
// create initial context, if first call, and add module, if any.
retcode = CliPrologue(cliGlobals,desc_id->module);
if (isERROR(retcode))
return retcode;
ContextCli & currContext = *(cliGlobals->currContext());
ComDiagsArea & diags = currContext.diags();
Descriptor * desc = currContext.getDescriptor(desc_id);
/* descriptor must exist */
if (!desc)
{
diags << DgSqlCode(-CLI_DESC_NOT_EXISTS);
return SQLCLI_ReturnCode(&currContext,-CLI_DESC_NOT_EXISTS);
}
for (Lng32 i = 0; i < no_of_desc_items; i++)
{
//
// Get the entry number of the descriptor entry whose item is to be
// set.
//
Lng32 entry = desc_items[i].entry;
if (entry > desc->getUsedEntryCount())
{
retcode = desc->addEntry(entry);
if (isERROR(retcode))
{
diags << DgSqlCode(-CLI_INTERNAL_ERROR);
return SQLCLI_ReturnCode(&currContext,-CLI_INTERNAL_ERROR);
}
}
// if item to be set is vardata, get input data length.
// This is needed so that we can make a copy of input data.
// Do the same for any attribute that need copying of data,
// like SQLDESC_NAME, etc.
if ((desc_items[i].item_id == SQLDESC_VAR_DATA) ||
(desc_items[i].item_id == SQLDESC_CHAR_SET_NAM) ||
(desc_items[i].item_id == SQLDESC_NAME) ||
(desc_items[i].item_id == SQLDESC_HEADING))
{
if (currContext.boundsCheckMemory((void*)desc_items[i].string_val,
desc_items[i].num_val_or_len))
return SQLCLI_ReturnCode(&currContext,
-CLI_USER_MEMORY_IN_EXECUTOR_SEGMENT);
}
//
// Set the item in the descriptor.
//
retcode = desc->setDescItem(desc_items[i].entry,
desc_items[i].item_id,
desc_items[i].num_val_or_len,
desc_items[i].string_val);
if (isERROR(retcode))
return SQLCLI_ReturnCode(&currContext,retcode);
}
return SUCCESS;
}
Lng32 SQLCLI_SetDescPointers(/*IN*/ CliGlobals * cliGlobals,
/*IN*/ SQLDESC_ID * desc_id,
/*IN*/ Lng32 starting_entry,
/*IN*/ Lng32 num_ptr_pairs,
/*IN*/ va_list ap,
/*IN*/ SQLCLI_PTR_PAIRS ptr_pairs[])
{
Lng32 retcode = SUCCESS;
// create initial context, if first call, and add module, if any.
retcode = CliPrologue(cliGlobals,desc_id->module);
if (isERROR(retcode))
return retcode;
ContextCli & currContext = *(cliGlobals->currContext());
ComDiagsArea & diags = currContext.diags();
Descriptor * desc = currContext.getDescriptor(desc_id);
/* descriptor must exist */
if (!desc)
{
diags << DgSqlCode(-CLI_DESC_NOT_EXISTS);
return SQLCLI_ReturnCode(&currContext,-CLI_DESC_NOT_EXISTS);
}
va_list cpy;
va_copy(cpy, ap);
va_end(ap);
retcode = local_SetDescPointers(desc, starting_entry, num_ptr_pairs, &cpy, ptr_pairs);
va_end(ap);
return SQLCLI_ReturnCode(&currContext,retcode);
}
Lng32 SQLCLI_SwitchContext(
/*IN*/ CliGlobals * cliGlobals,
/*IN*/ SQLCTX_HANDLE context_handle,
/*OUT OPTIONAL*/ SQLCTX_HANDLE * prev_context_handle,
/*IN */ bool allowSwitchBackToDefault )
{
Lng32 retcode = SUCCESS;
ContextCli & currContext = *(cliGlobals->currContext());
ComDiagsArea & diags = currContext.diags();
if (!allowSwitchBackToDefault && (context_handle == cliGlobals->getDefaultContext()->getContextHandle()))
{
diags << DgSqlCode(-CLI_DEFAULT_CONTEXT_NOT_ALLOWED);
return SQLCLI_ReturnCode(&currContext,-CLI_DEFAULT_CONTEXT_NOT_ALLOWED);
}
// find the new context
ContextCli * newContext = cliGlobals->getContext(context_handle);
if (! newContext)
{
diags << DgSqlCode(-CLI_CONTEXT_NOT_FOUND);
return SQLCLI_ReturnCode(&currContext,-CLI_CONTEXT_NOT_FOUND);
}
try
{
if (prev_context_handle)
*prev_context_handle = currContext.getContextHandle();
// The CLI sometimes starts transactions during recursive CLI
// calls (e.g. metadata lookup or resource fork reads during
// fixup). Such transactions should have been committed before
// the top-level CLI call returned. Make sure this is true
// before allowing a switch context; if it is not true, data
// integrity could be compromised if another context inherits
// such a transaction.
ExTransaction * exTransaction = currContext.getTransaction();
if (exTransaction != NULL && exTransaction->exeStartedXnDuringRecursiveCLICall())
{
// abort the transaction so this problem doesn't persist
exTransaction->rollbackStatement();
// report the error
diags << DgSqlCode(-CLI_INTERR_ON_CONTEXT_SWITCH);
return SQLCLI_ReturnCode(&currContext,-CLI_INTERR_ON_CONTEXT_SWITCH);
}
// Recursive calls to the CLI assume that the context is not
// changed. Therefore, prevent attempts within the CLI to
// switch contexts.
if (currContext.getNumOfCliCalls() > 1)
{
// Just raise a vanilla internal error; this should never
// happen.
//diags << DgSqlCode(-CLI_INTERNAL_ERROR);
//tmpSemaphore->release();
//return SQLCLI_ReturnCode(&currContext,-CLI_INTERNAL_ERROR);
}
// Do not call CliPrologue which will switch transaction.
// Wait till next CLI call to do the switching.
retcode = cliGlobals->switchContext(newContext);
if (retcode != 0)
{
diags << DgSqlCode(-20567)
<< DgInt0(retcode);
return SQLCLI_ReturnCode(&currContext,-20567);
}
}
catch (...)
{
return -CLI_INTERNAL_ERROR;
}
return retcode;
}
Lng32 SQLCLI_Xact(/*IN*/ CliGlobals * cliGlobals,
/* IN (SQLTRANS_COMMAND) */ Lng32 command,
/* OUT OPTIONAL */ SQLDESC_ID * transid_descriptor)
{
Lng32 retcode;
// create initial context, if first call, and add module, if any.
retcode = CliPrologue(cliGlobals,0);
if (isERROR(retcode))
return retcode;
ContextCli & currContext = *(cliGlobals->currContext());
ComDiagsArea & diags = currContext.diags();
switch (command)
{
case SQLTRANS_STATUS:
{
// returns ERROR, if no transaction has been started.
// Otherwise returns SUCCESS and (optionally) returns
// the transaction id.
if (! currContext.getTransaction()->xnInProgress())
{
// this is used internally for checking, diags area is not set
return (-CLI_TRANSACTION_NOT_STARTED);
}
}
break;
case SQLTRANS_QUIESCE:
{
if (currContext.getTransaction()->xnInProgress())
{
// go through each context that has matched transid, and
// release all transactional messages to ESPs,MXCMPs,MXUDR,and DP2.
ContextCli * cntxt;
cliGlobals->getContextList()->position();
while (cntxt = (ContextCli *)cliGlobals->getContextList()->getNext())
{
if ( cntxt->getTransaction()->xnInProgress() &&
(currContext.getTransaction()->getExeXnId() ==
cntxt->getTransaction()->getExeXnId()) )
cntxt->releaseAllTransactionalRequests();
}
}
}
break;
case SQLTRANS_ROLLBACK_IMPLICIT_XN:
{
if ((currContext.getTransaction()->xnInProgress()) &&
(currContext.getTransaction()->exeStartedXn()) &&
(currContext.getTransaction()->autoCommit()))
{
retcode = currContext.getTransaction()->rollbackTransactionWaited();
if (retcode)
{
diags.mergeAfter(*(currContext.getTransaction()->getDiagsArea()));
return -1;
}
}
}
break;
case SQLTRANS_COMMIT:
{
if ((currContext.getTransaction()->xnInProgress()) &&
(currContext.getTransaction()->exeStartedXn()))
{
retcode = currContext.getTransaction()->commitTransaction();
if (retcode)
{
diags.mergeAfter(*(currContext.getTransaction()->getDiagsArea()));
return -1;
}
}
}
break;
case SQLTRANS_ROLLBACK:
{
if ((currContext.getTransaction()->xnInProgress()) &&
(currContext.getTransaction()->exeStartedXn()))
{
retcode= currContext.getTransaction()->rollbackTransaction();
if (retcode)
{
diags.mergeAfter(*(currContext.getTransaction()->getDiagsArea()));
return -1;
}
}
}
break;
case SQLTRANS_BEGIN:
{
if (! (currContext.getTransaction()->xnInProgress()))
{
retcode = currContext.getTransaction()->beginTransaction();
if (retcode)
{
diags.mergeAfter(*(currContext.getTransaction()->getDiagsArea()));
return -1;
}
}
}
break;
case SQLTRANS_INHERIT:
{
currContext.getTransaction()->resetXnState();
currContext.getTransaction()->inheritTransaction();
}
break;
case SQLTRANS_SUSPEND:
{
currContext.getTransaction()->suspendTransaction();
}
break;
case SQLTRANS_RESUME:
{
currContext.getTransaction()->resumeTransaction();
}
break;
default:
diags << DgSqlCode(-CLI_INVALID_SQLTRANS_COMMAND);
return SQLCLI_ReturnCode(&currContext,diags.mainSQLCODE());
} // switch command
// return transid, if transid_descriptor is provided.
if (transid_descriptor)
{
Descriptor * transid_desc =
currContext.getDescriptor(transid_descriptor);
// descriptor must exist
if (!transid_desc)
{
diags << DgSqlCode(-CLI_DESC_NOT_EXISTS);
return SQLCLI_ReturnCode(&currContext,-CLI_DESC_NOT_EXISTS);
}
// return the transaction identifier in the
// descriptor provided. Note that for commit/rollback
// requests, this will return a -1 in the transid desc.
Int64 * pTransid = 0;
retcode = transid_desc->getDescItem(1,
SQLDESC_VAR_PTR,
(Lng32*) &pTransid,
NULL, 0, NULL, 0);
if (isERROR(retcode))
return SQLCLI_ReturnCode(&currContext,retcode);
if (!pTransid)
return -CLI_INTERNAL_ERROR;
if (currContext.boundsCheckMemory(pTransid, sizeof(Int64)))
{
return SQLCLI_ReturnCode(&currContext,
-CLI_USER_MEMORY_IN_EXECUTOR_SEGMENT);
}
else
{
*pTransid = currContext.getTransaction()->getExeXnId();
}
}
return SUCCESS;
}
#pragma page "SQLCLI_SetAuthID"
// *****************************************************************************
// * *
// * Function: SQLCLI_SetAuthID *
// * *
// * Sets user authentication values in CLI context. *
// * *
// *****************************************************************************
// * *
// * Parameters: *
// * *
// * <cliGlobals> CliGlobals * In *
// * is a pointer to CLI globals. *
// * *
// * <externalUsername> const char * In *
// * is the external username of the user that was authenticated. *
// * *
// * <databaseUsername> const char * In *
// * is the database username of the user that was authenticated. *
// * *
// * <authToken> const char * In *
// * is the token generated for this user session. *
// * *
// * <authTokenLen> Int32 In *
// * is the length of the token in bytes. *
// * *
// * <effectiveUserID> Int32 In *
// * is the user ID to use in authorization decisions. *
// * *
// * <sessionUserID> Int32 In *
// * is the user ID to record for accountability. *
// * *
// *****************************************************************************
Lng32 SQLCLI_SetAuthID(
CliGlobals * cliGlobals,
const char * externalUsername,
const char * databaseUsername,
const char * authToken,
Int32 authTokenLen,
Int32 effectiveUserID,
Int32 sessionUserID)
{
// create initial context, if first call, and add module, if any.
Lng32 retcode = CliPrologue(cliGlobals,0);
if (isERROR(retcode))
return retcode;
ContextCli & currContext = *(cliGlobals->currContext());
ComDiagsArea & diags = currContext.diags();
//ACH can this be removed? Seems to be an artifact of NSK priv boundary check
if (currContext.boundsCheckMemory((void *)externalUsername,str_len(externalUsername)))
return SQLCLI_ReturnCode(&currContext,
-CLI_USER_MEMORY_IN_EXECUTOR_SEGMENT);
// This method is a no-op on platforms other than Linux. Only on
// Linux do we need to update the ContextCli instance.
retcode = currContext.setAuthID(externalUsername,
databaseUsername,
authToken,
authTokenLen,
effectiveUserID,
sessionUserID);
return SQLCLI_ReturnCode(&currContext,retcode);
}
//************************** End of SQLCLI_SetAuthID ***************************
/* temporary functions -- for use by sqlcat simulator only */
Lng32 SQLCLI_AllocDescInt(/*IN*/ CliGlobals * cliGlobals,
/*INOUT*/ SQLDESC_ID * desc_id,
/*IN*/ Lng32 max_entries)
{
Lng32 retcode;
// create initial context, if first call, and add module, if any.
retcode = CliPrologue(cliGlobals,desc_id->module);
if (isERROR(retcode))
return retcode;
ContextCli & currContext = *(cliGlobals->currContext());
ComDiagsArea & diags = currContext.diags();
if (max_entries < 0)
{
diags << DgSqlCode(-CLI_DATA_OUTOFRANGE) << DgInt0(max_entries);
return diags.mainSQLCODE();
}
/* allocate a new descriptor in the current context. */
/* return the descriptor handle in desc_id, if name mode */
/* is "desc_handle" */
retcode = currContext.allocateDesc(desc_id, max_entries);
return SQLCLI_ReturnCode(&currContext,retcode);
}
Lng32 SQLCLI_GetDescEntryCountInt(/*IN*/ CliGlobals * cliGlobals,
/*IN*/ SQLDESC_ID * desc_id,
/*OUT*/ Lng32 * num_entries)
{
if (!cliGlobals || !num_entries)
{
return (-CLI_NO_CURRENT_CONTEXT);
}
ContextCli & currContext = *(cliGlobals->currContext());
ComDiagsArea & diags = currContext.diags();
Descriptor * desc = currContext.getDescriptor(desc_id);
/* descriptor must exist */
if (!desc)
{
diags << DgSqlCode(-CLI_DESC_NOT_EXISTS);
return SQLCLI_ReturnCode(&currContext,-CLI_DESC_NOT_EXISTS);
}
if (currContext.boundsCheckMemory(num_entries,sizeof(num_entries)))
return SQLCLI_ReturnCode(&currContext,
-CLI_USER_MEMORY_IN_EXECUTOR_SEGMENT);
*num_entries = desc->getUsedEntryCount();
return SUCCESS;
}
Lng32 SQLCLI_GetDescItem(/*IN*/ CliGlobals * cliGlobals,
/*IN*/ SQLDESC_ID * desc_id,
/*IN*/ Lng32 entry,
/* (SQLDESC_ITEM_ID) *IN*/ Lng32 what_to_get,
/*OUT OPTIONAL*/ void * numeric_value,
/*OUT OPTIONAL*/ char * string_value,
/*IN OPTIONAL*/ Lng32 max_string_len,
/*OUT OPTIONAL*/ Lng32 * len_of_item,
/*IN OPTIONAL*/ Lng32 start_from_offset)
{
Lng32 retcode;
// create initial context, if first call, and add module, if any.
retcode = CliPrologue(cliGlobals,desc_id->module);
if (isERROR(retcode))
return retcode;
ContextCli & currContext = *(cliGlobals->currContext());
ComDiagsArea & diags = currContext.diags();
Descriptor * desc = currContext.getDescriptor(desc_id);
/* descriptor must exist */
if (!desc)
{
diags << DgSqlCode(-CLI_DESC_NOT_EXISTS);
return SQLCLI_ReturnCode(&currContext,-CLI_DESC_NOT_EXISTS);
}
if(numeric_value){
if(currContext.boundsCheckMemory((void*)numeric_value,4))
return SQLCLI_ReturnCode(&currContext,
-CLI_USER_MEMORY_IN_EXECUTOR_SEGMENT);
}
if(string_value){
if(currContext.boundsCheckMemory((void*)string_value,max_string_len))
return SQLCLI_ReturnCode(&currContext,
-CLI_USER_MEMORY_IN_EXECUTOR_SEGMENT);
}
retcode = desc->getDescItem(entry, what_to_get,
numeric_value, string_value,
max_string_len, len_of_item,
start_from_offset);
return SQLCLI_ReturnCode(&currContext,retcode);
}
Lng32 SQLCLI_SetDescEntryCountInt(/*IN*/ CliGlobals * cliGlobals,
/*IN*/ SQLDESC_ID * desc_id,
/*IN*/ Lng32 num_entries)
{
Lng32 retcode;
// create initial context, if first call, and add module, if any.
retcode = CliPrologue(cliGlobals,desc_id->module);
if (isERROR(retcode))
return retcode;
ContextCli & currContext = *(cliGlobals->currContext());
ComDiagsArea & diags = currContext.diags();
Descriptor * desc = currContext.getDescriptor(desc_id);
/* descriptor must exist */
if (!desc)
{
diags << DgSqlCode(-CLI_DESC_NOT_EXISTS);
return SQLCLI_ReturnCode(&currContext,-CLI_DESC_NOT_EXISTS);
}
desc->setUsedEntryCount(num_entries);
return SUCCESS;
}
Lng32 SQLCLI_SetDescItem(
/*IN*/ CliGlobals * cliGlobals,
/*IN*/ SQLDESC_ID * desc_id,
/*IN*/ Lng32 entry,
/* (SQLDESC_ITEM_ID) *IN*/ Lng32 what_to_set,
/*IN OPTIONAL*/ Long numeric_value,
/*IN OPTIONAL*/ char * string_value)
{
Lng32 retcode;
// create initial context, if first call, and add module, if any.
retcode = CliPrologue(cliGlobals,desc_id->module);
if (isERROR(retcode))
return retcode;
ContextCli & currContext = *(cliGlobals->currContext());
ComDiagsArea & diags = currContext.diags();
Descriptor * desc = currContext.getDescriptor(desc_id);
/* descriptor must exist */
if (!desc)
{
diags << DgSqlCode(-CLI_DESC_NOT_EXISTS);
return SQLCLI_ReturnCode(&currContext,-CLI_DESC_NOT_EXISTS);
}
if (entry > desc->getMaxEntryCount())
{
diags << DgSqlCode(-CLI_INVALID_DESC_ENTRY);
return diags.mainSQLCODE();
}
if (entry > desc->getUsedEntryCount())
{
retcode = desc->addEntry(entry);
if (isERROR(retcode))
{
diags << DgSqlCode(-CLI_INTERNAL_ERROR);
return SQLCLI_ReturnCode(&currContext,-CLI_INTERNAL_ERROR);
}
}
Lng32 length = 0;
if(what_to_set==SQLDESC_VAR_PTR){
length=desc->getVarDataLength(entry);
if(currContext.boundsCheckMemory((void*)numeric_value,length))
return SQLCLI_ReturnCode(&currContext,
-CLI_USER_MEMORY_IN_EXECUTOR_SEGMENT);
}
if(what_to_set==SQLDESC_IND_PTR){
length=desc->getIndLength(entry);
if(currContext.boundsCheckMemory((void*)numeric_value,length))
return SQLCLI_ReturnCode(&currContext,
-CLI_USER_MEMORY_IN_EXECUTOR_SEGMENT);
}
if(string_value){
//get length from varchar
length = desc->getVarDataLength(entry);
if(currContext.boundsCheckMemory(string_value,length))
return SQLCLI_ReturnCode(&currContext,
-CLI_USER_MEMORY_IN_EXECUTOR_SEGMENT);
}
retcode = desc->setDescItem(entry, what_to_set, numeric_value, string_value);
if (isERROR(retcode))
return SQLCLI_ReturnCode(&currContext, retcode);
return SUCCESS;
}
// -----------------------------------------------------------------------
// NOTE: this procedure will go away, please use GetDiagnosticsStmtInfo()
// instead!!!
// -----------------------------------------------------------------------
Lng32 SQLCLI_GetRowsAffected(/*IN*/ CliGlobals * cliGlobals,
/*IN*/ SQLSTMT_ID * statement_id,
Int64 & rowsAffected)
{
if (!cliGlobals)
return -CLI_NO_CURRENT_CONTEXT;
ContextCli & currContext = *(cliGlobals->currContext());
ComDiagsArea & diags = currContext.diags();
Statement * stmt = currContext.getStatement(statement_id);
if (!stmt)
{
diags << DgSqlCode(-CLI_STMT_NOT_EXISTS);
return SQLCLI_ReturnCode(&currContext,-CLI_STMT_NOT_EXISTS);
}
if(currContext.boundsCheckMemory(&rowsAffected,sizeof(rowsAffected)))
return SQLCLI_ReturnCode(&currContext,
-CLI_USER_MEMORY_IN_EXECUTOR_SEGMENT);
rowsAffected = stmt->getRowsAffected();
return SUCCESS;
}
Lng32 SQLCLI_MergeDiagnostics(/*IN*/ CliGlobals * cliGlobals,
/*INOUT*/ ComDiagsArea & newDiags)
{
if (&newDiags == NULL)
return ERROR;
if (!cliGlobals)
return -CLI_NO_CURRENT_CONTEXT;
ContextCli & currContext = *(cliGlobals->currContext());
ComDiagsArea & diags = currContext.diags();
newDiags.mergeAfter(cliGlobals->currContext()->diags());
return SUCCESS;
}
// For internal use only -- do not document!
static Lng32 GetStatement_Internal(/*IN*/ CliGlobals * cliGlobals,
/*INOUT*/ Statement ** statement_ptr,
/*IN*/ SQLSTMT_ID * statement_id)
{
Lng32 retcode;
Long stmtHandle = (Long)statement_id->handle;
NABoolean getnext = ((((statement_id->name_mode != stmt_handle) &&
((stmtHandle & 0x0001) != 0)))
? TRUE : FALSE);
NABoolean position = (((stmtHandle & 0x0002) != 0) ? TRUE : FALSE);
NABoolean advance = (((stmtHandle & 0x0004) != 0) ? TRUE : FALSE);
ContextCli & currContext = *(cliGlobals->currContext());
ComDiagsArea & diags = currContext.diags();
if (statement_id->name_mode != stmt_handle)
{
NABoolean sequentialAdd =
(((stmtHandle & 0x0008) != 0) ? TRUE : FALSE);
currContext.getStatementList()->setSequentialAdd(sequentialAdd);
}
Statement * stmt = NULL;
if (getnext)
stmt = currContext.getNextStatement(statement_id, position, advance);
else
stmt = currContext.getStatement(statement_id);
/* stmt must exist */
if (!stmt)
{
return SQL_EOF;
}
*statement_ptr = stmt;
return SUCCESS;
}
//Function to get the length of the desc_items array
//returns the length if no error occurs, if error_occurred
//is 1 on return then return value indicates error
Lng32 GetDescItemsEntryCount(
/*IN*/ CliGlobals * cliGlobals,
/*IN*/ SQLDESC_ID * desc_id,
/*IN*/ SQLDESC_ITEM desc_items[],
/*IN*/ SQLDESC_ID * value_num_descriptor,
/*IN*/ SQLDESC_ID * descriptor,
/*Out*/Int32 & error_occurred)
{
error_occurred = 0;
#if 0
// sanity check
if (!desc_id || !value_num_descriptor || !output_descriptor){
error_occurred = 1;
return -CLI_INTERNAL_ERROR;
}
#endif
Lng32 retcode;
// create initial context, if first call, and add module, if any.
retcode = CliPrologue(cliGlobals,desc_id->module);
if (isERROR(retcode)){
error_occurred = 1;
return -CLI_INTERNAL_ERROR;
}
ContextCli & currContext = *(cliGlobals->currContext());
ComDiagsArea & diags = currContext.diags();
Descriptor *desc = currContext.getDescriptor(descriptor);
/* descriptor must exist */
if (!desc)
{
error_occurred = 1;
diags << DgSqlCode(-CLI_DESC_NOT_EXISTS);
return SQLCLI_ReturnCode(&currContext,-CLI_DESC_NOT_EXISTS);
}
Lng32 UsedEntryCount = desc->getUsedEntryCount();
return UsedEntryCount;
}
// For internal use only -- do not document!
Lng32 SQLCLI_GetRootTdb_Internal(/*IN*/ CliGlobals * cliGlobals,
/*INOUT*/ char * roottdb_ptr,
/*IN*/ Int32 roottdb_len,
/*INOUT*/ char * srcstr_ptr,
/*IN*/ Int32 srcstr_len,
/*IN*/ SQLSTMT_ID * statement_id)
{
Lng32 retcode;
Statement *statement;
retcode = GetStatement_Internal(cliGlobals,
&statement, statement_id);
if (retcode)
return retcode;
if (!statement) // statement must exists
return -1;
ex_root_tdb *exRootTdb = statement->getRootTdb();
Lng32 rootTdbSize = statement->getRootTdbSize();
ex_assert(rootTdbSize <= roottdb_len, "Insufficient space for root TDB");
memcpy(roottdb_ptr, exRootTdb, rootTdbSize);
if (srcstr_ptr)
{
char *srcStr = statement->getSrcStr();
Lng32 srcStrSize = statement->getSrcStrSize();
ex_assert(srcStrSize <= srcstr_len, "Insufficient space for source");
memcpy(srcstr_ptr, srcStr, srcStrSize);
}
return retcode;
}
// For internal use only -- do not document!
Lng32 SQLCLI_GetRootTdbSize_Internal(/*IN*/ CliGlobals * cliGlobals,
/*INOUT*/ Lng32* roottdb_size,
/*INOUT*/ Lng32* srcstr_size,
/*IN*/ SQLSTMT_ID * statement_id)
{
Lng32 retcode;
Statement *statement;
retcode = GetStatement_Internal(cliGlobals,
&statement, statement_id);
if (retcode)
return retcode;
if (!statement) // statement must exists
return -1;
*roottdb_size = statement->getRootTdbSize();
*srcstr_size = statement->getSrcStrSize();
return retcode;
}
// For internal use only -- do not document!
Lng32 SQLCLI_GetCollectStatsType_Internal(/*IN*/ CliGlobals * cliGlobals,
/*OUT*/ ULng32 * collectStatsType,
/*IN*/ SQLSTMT_ID * statement_id)
{
Lng32 retcode = 0;
Statement *statement;
ContextCli & currContext = *(cliGlobals->currContext());
ComDiagsArea & diags = currContext.diags();
if (statement_id)
{
statement = currContext.getStatement(statement_id);
if ((!statement) || (!statement->getRootTdb()))
*collectStatsType = (ULng32)ComTdb::NO_STATS;
else
*collectStatsType =
(ULng32)((ComTdb*)statement->getRootTdb())->getCollectStatsType();
}
else
{
if (currContext.getStats())
*collectStatsType = (ULng32)currContext.getStats()->getCollectStatsType();
else
*collectStatsType = (ULng32)ComTdb::NO_STATS;
}
return retcode;
}
// For internal use only -- do not document!
Lng32 SQLCLI_GetTotalTcbSpace(/*IN*/ CliGlobals * cliGlobals,
/*IN*/ char * tdb,
/*IN*/ char * otherInfo)
{
Lng32 retcode;
ContextCli & currContext = *(cliGlobals->currContext());
ComDiagsArea & diags = currContext.diags();
retcode = getTotalTcbSpace(tdb, otherInfo,
(char*)cliGlobals->getExecutorMemory());
return retcode;
}
Lng32 SQLCLI_SetParserFlagsForExSqlComp_Internal(
/*IN*/ CliGlobals * cliGlobals,
/*IN*/ULng32 flagbits)
{
if (cliGlobals->currContext())
cliGlobals->currContext()->setSqlParserFlags(flagbits);
return 0;
}
Lng32 SQLCLI_ResetParserFlagsForExSqlComp_Internal(
/*IN*/ CliGlobals * cliGlobals,
/*IN*/ULng32 flagbits)
{
if (cliGlobals->currContext())
cliGlobals->currContext()->resetSqlParserFlags(flagbits);
return 0;
}
Lng32 SQLCLI_AssignParserFlagsForExSqlComp_Internal(
/*IN*/ CliGlobals * cliGlobals,
/*IN*/ULng32 flagbits)
{
if (cliGlobals->currContext())
cliGlobals->currContext()->assignSqlParserFlags(flagbits);
return 0;
}
Lng32 SQLCLI_GetParserFlagsForExSqlComp_Internal(
/*IN*/ CliGlobals * cliGlobals,
/*IN*/ULng32 &flagbits)
{
flagbits = 0;
if (cliGlobals->currContext())
flagbits = cliGlobals->currContext()->getSqlParserFlags();
return 0;
}
Lng32 SQLCLI_OutputValueIntoNumericHostvar(
/*IN*/ CliGlobals * cliGlobals,
/*IN*/ SQLDESC_ID * output_descriptor,
/*IN*/ Lng32 desc_entry,
/*IN*/ Lng32 value)
{
// go ahead...
// create initial context, if first call, and add module, if any.
Lng32 retcode = CliPrologue(cliGlobals,output_descriptor->module);
if (isERROR(retcode))
return retcode;
ContextCli & currContext = *(cliGlobals->currContext());
ComDiagsArea & diags = currContext.diags();
Descriptor * output_desc = currContext.getDescriptor(output_descriptor);
if (!output_desc)
{
return -CLI_DESC_NOT_EXISTS;
}
retcode = OutputValueIntoNumericHostvar(output_desc, desc_entry, value);
return retcode;
}
Lng32 SQLCLI_SetEnviron_Internal(/*IN*/ CliGlobals * cliGlobals,
char ** envvars, Lng32 propagate)
{
Lng32 retcode = 0;
ContextCli & currContext = *(cliGlobals->currContext());
ComDiagsArea & diags = currContext.diags();
retcode = cliGlobals->setEnvVars(envvars);
if (retcode)
return SQLCLI_ReturnCode(&currContext,retcode);
return 0;
}
Lng32 SQLCLI_SetErrorCodeInRTS(
CliGlobals *cliGlobals,
SQLSTMT_ID * statement_id,
Lng32 sqlErrorCode)
{
Lng32 retcode = 0;
// create initial context, if first call, and add module, if any.
retcode = CliPrologue(cliGlobals,statement_id->module);
if (isERROR(retcode))
return retcode;
ContextCli & currContext = *(cliGlobals->currContext());
ComDiagsArea & diags = currContext.diags();
/* prepare the statement */
Statement * stmt = currContext.getStatement(statement_id);
/* stmt must exist */
if (stmt)
{
StmtStats *stmtStats = stmt->getStmtStats();
if (stmtStats != NULL && stmtStats->getMasterStats() != NULL)
{
if (diags.mainSQLCODE() < 0)
{
Int64 exeEndTime = NA_JulianTimestamp();
stmtStats->getMasterStats()->setExeEndTime(exeEndTime);
stmtStats->getMasterStats()->setElapsedEndTime(exeEndTime);
}
stmtStats->getMasterStats()->setSqlErrorCode(diags.mainSQLCODE() != 0 ?
diags.mainSQLCODE() : sqlErrorCode);
}
}
else
retcode = -CLI_STMT_NOT_EXISTS;
return retcode;
}
Lng32 SQLCLI_LocaleToUTF8 (
CliGlobals *cliGlobals,
Int32 conv_charset,
void * Input_Buffer_Addr,
Int32 Input_Buffer_Length,
void * Output_Buffer_Addr,
Int32 Output_Buffer_Length,
void ** First_Untranslated_Char_Addr,
Int32 *Output_Data_Length,
Int32 add_null_at_end_Flag,
Int32 *num_translated_char)
{
short error = 0;
ContextCli & currContext = *(cliGlobals->currContext());
char * &firstUntranslatedChar = (char * &)First_Untranslated_Char_Addr;
// Bounds check the input buffer
if (currContext.boundsCheckMemory((void *)Input_Buffer_Addr,
Input_Buffer_Length))
return FEBOUNDSERR;
// Bounds check the output buffer
if (currContext.boundsCheckMemory((void *)Output_Buffer_Addr,
Output_Buffer_Length))
return FEBOUNDSERR;
error = LocaleToUTF8( cnv_version1,
(char *)Input_Buffer_Addr,
Input_Buffer_Length,
(char *)Output_Buffer_Addr,
Output_Buffer_Length,
(cnv_charset)conv_charset,
firstUntranslatedChar,
(UInt32 *)Output_Data_Length,
add_null_at_end_Flag,
(UInt32 *)num_translated_char
);
return error;
}
Lng32 SQLCLI_LocaleToUTF16 (
CliGlobals *cliGlobals,
Int32 conv_charset,
void * Input_Buffer_Addr,
Int32 Input_Buffer_Length,
void * Output_Buffer_Addr,
Int32 Output_Buffer_Length,
void ** First_Untranslated_Char_Addr,
Int32 *Output_Data_Length,
Int32 conv_flags,
Int32 add_null_at_end_Flag,
Int32 *num_translated_char)
{
short error = 0;
ContextCli & currContext = *(cliGlobals->currContext());
char * &firstUntranslatedChar = (char * &)First_Untranslated_Char_Addr;
// Bounds check the input buffer
if (currContext.boundsCheckMemory((void *)Input_Buffer_Addr,
Input_Buffer_Length))
return FEBOUNDSERR;
// Bounds check the output buffer
if (currContext.boundsCheckMemory((void *)Output_Buffer_Addr,
Output_Buffer_Length))
return FEBOUNDSERR;
error = LocaleToUTF16(cnv_version1,
(char *)Input_Buffer_Addr,
Input_Buffer_Length,
(char *)Output_Buffer_Addr,
Output_Buffer_Length,
(cnv_charset)conv_charset,
firstUntranslatedChar,
(UInt32 *)Output_Data_Length,
conv_flags,
add_null_at_end_Flag,
(UInt32 *)num_translated_char
);
return error;
}
Lng32 SQLCLI_UTF8ToLocale(
CliGlobals *cliGlobals,
Int32 conv_charset,
void * Input_Buffer_Addr,
Int32 Input_Buffer_Length,
void * Output_Buffer_Addr,
Int32 Output_Buffer_Length,
void ** First_Untranslated_Char_Addr,
Int32 *Output_Data_Length,
Int32 add_null_at_end_Flag,
Int32 allow_invalids,
Int32 *num_translated_char,
void * substitution_char_addr)
{
short error = 0;
ContextCli & currContext = *(cliGlobals->currContext());
char * &firstUntranslatedChar = (char * &)First_Untranslated_Char_Addr;
const char *substitutionChar = (const char *)substitution_char_addr;
// Bounds check the input buffer
if (currContext.boundsCheckMemory((void *)Input_Buffer_Addr,
Input_Buffer_Length))
return FEBOUNDSERR;
// Bounds check the output buffer
if (currContext.boundsCheckMemory((void *)Output_Buffer_Addr,
Output_Buffer_Length))
return FEBOUNDSERR;
error = UTF8ToLocale ( cnv_version1,
(char *)Input_Buffer_Addr,
Input_Buffer_Length,
(char *)Output_Buffer_Addr,
Output_Buffer_Length,
(cnv_charset)conv_charset,
firstUntranslatedChar,
(UInt32 *)Output_Data_Length,
add_null_at_end_Flag,
allow_invalids,
(UInt32 *)num_translated_char,
substitutionChar
);
return error;
}
Lng32 SQLCLI_UTF16ToLocale (
CliGlobals *cliGlobals,
Int32 conv_charset,
void * Input_Buffer_Addr,
Int32 Input_Buffer_Length,
void * Output_Buffer_Addr,
Int32 Output_Buffer_Length,
void ** First_Untranslated_Char_Addr,
Int32 *Output_Data_Length,
Int32 conv_flags,
Int32 add_null_at_end_Flag,
Int32 allow_invalids,
Int32 *num_translated_char,
void * substitution_char_addr)
{
short error = 0;
ContextCli & currContext = *(cliGlobals->currContext());
char * &firstUntranslatedChar = (char * &)First_Untranslated_Char_Addr;
const char *substitutionChar = (const char *)substitution_char_addr;
// Bounds check the input buffer
if (currContext.boundsCheckMemory((void *)Input_Buffer_Addr,
Input_Buffer_Length))
return FEBOUNDSERR;
// Bounds check the output buffer
if (currContext.boundsCheckMemory((void *)Output_Buffer_Addr,
Output_Buffer_Length))
return FEBOUNDSERR;
error = UTF16ToLocale( cnv_version1,
(char *)Input_Buffer_Addr,
Input_Buffer_Length,
(char *)Output_Buffer_Addr,
Output_Buffer_Length,
(cnv_charset)conv_charset,
firstUntranslatedChar,
(UInt32 *)Output_Data_Length,
conv_flags,
add_null_at_end_Flag,
allow_invalids,
(UInt32 *)num_translated_char,
substitutionChar
);
return error;
}
Lng32 SQLCLI_SetSecInvalidKeys(CliGlobals *cliGlobals,
/* IN */ Int32 numSiKeys,
/* IN */ SQL_QIKEY siKeys[])
{
return cliGlobals->currContext()->setSecInvalidKeys(numSiKeys, siKeys);
}
Lng32 SQLCLI_GetSecInvalidKeys(CliGlobals *cliGlobals,
/* IN */ Int64 prevTimestamp,
/* IN/OUT */ SQL_QIKEY siKeys[],
/* IN */ Int32 maxNumSiKeys,
/* IN/OUT */ Int32 *returnedNumSiKeys,
/* IN/OUT */ Int64 *maxTimestamp)
{
Lng32 retcode = 0;
*returnedNumSiKeys = 0;
StatsGlobals *statsGlobals = cliGlobals->getStatsGlobals();
if (statsGlobals)
{
Int64 newestSik = statsGlobals->getNewestRevokeTimestamp();
Int64 newMaxTimestamp = NA_JulianTimestamp();
if (prevTimestamp < newestSik)
retcode = cliGlobals->getStatsGlobals()->getSecInvalidKeys(
cliGlobals,
prevTimestamp,
siKeys,
maxNumSiKeys,
returnedNumSiKeys);
if (retcode == 0)
*maxTimestamp = newMaxTimestamp;
}
else
{
// This could happens as the instance starts -- some compilers could
// call this CLI before the RMS shared segment is ready. It
// definitely happens when the init_sql createsysmdf step is
// executed, because at that time the compiler is compiling
// without having the instance up. This is too early for a
// revoke, so we handle the scenario by returning success, but
// leave the maxTimestamp to the same value as the prevTimestamp,
// so that the compiler will continue asking for SQL_QIKEYs each
// time it compiles a query, until the RMS shared segment is
// ready.
*maxTimestamp = prevTimestamp;
}
return retcode;
}
Lng32 SQLCLI_SetLobLock(CliGlobals *cliGlobals,
/* IN */ char *lobLockId
)
{
return cliGlobals->currContext()->setLobLock(lobLockId);
}
Lng32 SQLCLI_CheckLobLock(CliGlobals *cliGlobals,
/* IN */ char *lobLockId,
/*OUT */ NABoolean *found
)
{
Int32 retcode = 0;
retcode = cliGlobals->currContext()->checkLobLock(lobLockId, found);
return retcode;
}
Lng32 SQLCLI_GetStatistics2(CliGlobals *cliGlobals,
/* IN */ short statsReqType,
/* IN */ char *statsReqStr,
/* IN */ Lng32 statsReqStrLen,
/* IN */ short activeQueryNum,
/* IN */ short statsMergeType,
/* OUT */ short *statsCollectType,
/* IN/OUT */ SQLSTATS_DESC sqlstats_desc[],
/* IN */ Lng32 max_stats_desc,
/* OUT */ Lng32 *no_returned_stats_desc)
{
Lng32 retcode;
ContextCli *currContext = cliGlobals->currContext();
retcode = currContext->GetStatistics2(statsReqType,
statsReqStr,
statsReqStrLen,
activeQueryNum,
statsMergeType,
statsCollectType,
sqlstats_desc,
max_stats_desc,
no_returned_stats_desc);
return retcode;
}
Lng32 SQLCLI_GetStatisticsItems(CliGlobals *cliGlobals,
/* IN */ short statsReqType,
/* IN */ char *queryId,
/* IN */ Lng32 queryIdLen,
/* IN */ Lng32 no_of_stats_items,
/* IN/OUT */ SQLSTATS_ITEM sqlStats_items[])
{
Lng32 retcode;
ContextCli *currContext = cliGlobals->currContext();
ComDiagsArea & diags = currContext->diags();
ExStatisticsArea *mergedStats = currContext->getMergedStats();
ExMasterStats *masterStats;
if (mergedStats == NULL)
{
diags << DgSqlCode(-CLI_MERGED_STATS_NOT_AVAILABLE);
return SQLCLI_ReturnCode(currContext,-CLI_MERGED_STATS_NOT_AVAILABLE);
}
if (statsReqType == SQLCLI_STATS_REQ_QID)
{
masterStats = mergedStats->getMasterStats();
if (masterStats != NULL && queryId != NULL)
{
if (queryIdLen != masterStats->getQueryIdLen() ||
str_cmp(masterStats->getQueryId(), queryId, masterStats->getQueryIdLen()) != 0)
{
diags << DgSqlCode(-CLI_QID_NOT_MATCHING);
return SQLCLI_ReturnCode(currContext,-CLI_QID_NOT_MATCHING);
}
}
}
retcode = mergedStats->getStatsItems(no_of_stats_items, sqlStats_items);
return retcode;
}
Lng32 SQLCLI_RegisterQuery(CliGlobals *cliGlobals,
SQLQUERY_ID *queryId,
Lng32 fragId,
Lng32 tdbId,
Lng32 explainTdbId,
short collectStatsType,
Lng32 instNum,
Lng32 tdbType,
char *tdbName,
Lng32 tdbNameLen)
{
ContextCli *currContext = cliGlobals->currContext();
ComDiagsArea & diags = currContext->diags();
Lng32 retcode = SUCCESS;
StatsGlobals *statsGlobals = cliGlobals->getStatsGlobals();
if (statsGlobals == NULL)
return retcode;
int error;
error = statsGlobals->getStatsSemaphore(cliGlobals->getSemId(),
cliGlobals->myPin());
retcode = statsGlobals->registerQuery(diags, cliGlobals->myPin(), queryId,
fragId, tdbId, explainTdbId, collectStatsType, instNum,
(ComTdb::ex_node_type)tdbType,
tdbName, tdbNameLen);
statsGlobals->releaseStatsSemaphore(cliGlobals->getSemId(),
cliGlobals->myPin());
return retcode;
}
Lng32 SQLCLI_DeregisterQuery(CliGlobals *cliGlobals,
SQLQUERY_ID *queryId,
Lng32 fragId)
{
ContextCli *currContext = cliGlobals->currContext();
ComDiagsArea & diags = currContext->diags();
Lng32 retcode = SUCCESS;
StatsGlobals *statsGlobals = cliGlobals->getStatsGlobals();
if (statsGlobals == NULL)
return retcode;
int error;
error = statsGlobals->getStatsSemaphore(cliGlobals->getSemId(),
cliGlobals->myPin());
retcode = statsGlobals->deregisterQuery(diags, cliGlobals->myPin(), queryId,
fragId);
statsGlobals->releaseStatsSemaphore(cliGlobals->getSemId(),
cliGlobals->myPin());
return retcode;
}
// This method returns the pointer to the CLI ExStatistics area.
// The returned pointer is a read only pointer, its contents cannot be
// modified by the caller.
Lng32 SQLCLI_GetStatisticsArea_Internal
(
/* IN */ CliGlobals *cliGlobals,
/* IN */ short statsReqType,
/* IN */ char *statsReqStr,
/* IN */ Lng32 statsReqStrLen,
/* IN */ short activeQueryNum,
/* IN */ short statsMergeType,
/*INOUT*/ const ExStatisticsArea* &exStatsArea)
{
ContextCli *currContext = cliGlobals->currContext();
ComDiagsArea & diagsArea = currContext->diags();
Lng32 retcode = SUCCESS;
short retryAttempts = 0;
exStatsArea = currContext->getMergedStats
(statsReqType,
statsReqStr,
statsReqStrLen,
activeQueryNum,
statsMergeType,
retryAttempts);
if (exStatsArea == NULL)
{
if (diagsArea.getNumber(DgSqlCode::ERROR_) > 0)
return diagsArea.mainSQLCODE();
else if (statsReqType == SQLCLI_STATS_REQ_QID)
{
(diagsArea) << DgSqlCode(-EXE_RTS_QID_NOT_FOUND) << DgString0(statsReqStr);
return diagsArea.mainSQLCODE();
}
else
{
(diagsArea) << DgSqlCode(-CLI_MERGED_STATS_NOT_AVAILABLE);
return -CLI_MERGED_STATS_NOT_AVAILABLE;
}
}
else
{
currContext->setMergedStats((ExStatisticsArea *) exStatsArea);
// temporary assert to see if I can catch this statsArea in
// the shared segment.
long statsAddr = (long) exStatsArea;
if ((statsAddr > 0x10000000) && (statsAddr < 0x14000000))
ex_assert(0, "ExStatisticsArea in shared seg, need a sema4.");
}
return retcode;
}
Lng32 SQLCLI_GetChildQueryInfo(CliGlobals *cliGlobals,
SQLSTMT_ID * statement_id,
char * uniqueQueryId,
Lng32 uniqueQueryIdMaxLen,
Lng32 * uniqueQueryIdLen,
SQL_QUERY_COST_INFO *query_cost_info,
SQL_QUERY_COMPILER_STATS_INFO *comp_stats_info)
{
Lng32 retcode = 0;
ContextCli & currContext = *(cliGlobals->currContext());
ComDiagsArea & diags = currContext.diags();
/* prepare the statement */
Statement * stmt = currContext.getStatement(statement_id);
if (!stmt)
{
diags << DgSqlCode(-CLI_STMT_NOT_EXISTS);
return SQLCLI_ReturnCode(&currContext,-CLI_STMT_NOT_EXISTS);
}
retcode = stmt->getChildQueryInfo(diags, uniqueQueryId,
uniqueQueryIdMaxLen, uniqueQueryIdLen,
query_cost_info, comp_stats_info);
return retcode;
}
Lng32 SQLCLI_LOBcliInterface
(
/*IN*/ CliGlobals *cliGlobals,
/*IN*/ char * inLobHandle,
/*IN*/ Lng32 inLobHandleLen,
/*IN*/ char * blackBox,
/*INOUT*/ Int32 *blackBoxLen,
/*OUT*/ char * outLobHandle,
/*OUT*/ Lng32 * outLobHandleLen,
/*IN*/ LOBcliQueryType qType,
/*IN*/ LOBcliQueryPhase qPhase,
/*INOUT*/ Int64 * dataOffset, /* IN: for insert,
OUT: for select */
/*INOUT*/ Int64 * dataLen, /* length of data.
IN: for insert, out: for select */
/*INOUT*/ Int64 * inoutDescPartnKey, /* returned after insert and select
/*INOUT*/ Int64 * inoutDescSyskey, /* returned after insert and select
/*INOUT*/ void* *inCliInterface,
/*IN*/ Int64 xnId, /* xn id of the parent process, if non-zero */
/*IN*/ NABoolean lobTrace
)
{
ContextCli & currContext = *(cliGlobals->currContext());
ComDiagsArea & diags = currContext.diags();
ComDiagsArea * myDiags = NULL;
ExeCliInterface *cliInterface = NULL;
if (inCliInterface && (*inCliInterface))
{
cliInterface = (ExeCliInterface*)(*inCliInterface);
}
else
{
cliInterface = new (currContext.exHeap())
ExeCliInterface(currContext.exHeap(),
SQLCHARSETCODE_UTF8,
&currContext,
NULL);
}
Int16 flags = 0;
Lng32 lobType = 1;
Lng32 lobNum = 0;
Int64 uid = 0;
Int64 inDescSyskey, descPartnKey;
short schNameLen = 0;
char schName[512];
char logBuf[4096];
Int64 inputValues[5];
Lng32 inputValuesLen = 0;
Int64 rowsAffected = 0;
lobDebugInfo("In LobCliInterface",0,__LINE__,lobTrace);
if (inLobHandle)
{
ExpLOBoper::extractFromLOBhandle(&flags, &lobType, &lobNum, &uid,
&inDescSyskey, &descPartnKey,
&schNameLen, schName,
inLobHandle);
str_sprintf(logBuf,"Handle contents : flags %d, lobType %d, lobNum :%d, uid : %ld, descSyskey: %ld, descPartnKey : %ld, schNameLen:%d, schName %s", flags,lobType,lobNum,uid,inDescSyskey,descPartnKey,schNameLen,schName);
lobDebugInfo(logBuf,0,__LINE__,lobTrace);
}
char tgtLobNameBuf[100];
char * tgtLobName =
ExpLOBoper::ExpGetLOBname(uid, lobNum, tgtLobNameBuf, 100);
str_sprintf(logBuf,"lobName %s", tgtLobName);
lobDebugInfo(logBuf,0,__LINE__,lobTrace);
char lobDescHandleNameBuf[1024];
Lng32 lobDescHandleNameLen = 1024;
char * lobDescHandleName =
ExpLOBoper::ExpGetLOBDescHandleName(schNameLen, schName, uid, lobNum,
lobDescHandleNameBuf, lobDescHandleNameLen);
str_sprintf(logBuf,"lobDescHandleName %s", lobDescHandleName);
lobDebugInfo(logBuf,0,__LINE__,lobTrace);
char lobDescChunksNameBuf[1024];
Lng32 lobDescChunksNameLen = 1024;
char * lobDescChunksName =
ExpLOBoper::ExpGetLOBDescChunksName(schNameLen, schName, uid, lobNum,
lobDescChunksNameBuf, lobDescChunksNameLen);
str_sprintf(logBuf,"lobDescChunksName %s", lobDescChunksName);
lobDebugInfo(logBuf,0,__LINE__,lobTrace);
char * query = new(currContext.exHeap()) char[4096];
char stmtName[200];
if (outLobHandleLen)
*outLobHandleLen = 0;
if (blackBoxLen)
{
if ((qType == LOB_CLI_CREATE) ||
(qType == LOB_CLI_DROP) ||
(qType == LOB_CLI_INIT))
*blackBoxLen = 0;
else if ((qType == LOB_CLI_SELECT_UNIQUE) ||
(qType == LOB_CLI_SELECT_OPEN) ||
(qType == LOB_CLI_SELECT_FETCH) ||
(qType == LOB_CLI_SELECT_CLOSE))
*blackBoxLen = 0;
}
Lng32 cliRC = 0;
NABoolean xnAutoCommit = FALSE;
NABoolean xnJoined = FALSE;
Int64 transId;
cliRC = GETTRANSID((short *)&transId);
if ((xnId != 0) && // xnid passed in
(cliRC == 0)) // and global xn present
{
// inherit it
SQL_EXEC_Xact(SQLTRANS_INHERIT, NULL);
}
switch (qType)
{
case LOB_CLI_INIT:
{
strcpy(query, "set transaction autocommit on;");
cliRC = cliInterface->executeImmediate(query);
if (cliRC < 0)
goto error_return;
cliRC = 0;
}
break;
case LOB_CLI_CREATE:
{
// create lob descriptor handle table salted
str_sprintf(query, "create ghost table %s (descPartnKey largeint not null, numChunks int not null, lobLen largeint not null) salt using 8 partitions store by (descPartnKey, syskey) ",
lobDescHandleName);
lobDebugInfo(query,0,__LINE__,lobTrace);
currContext.setSqlParserFlags(0x1);
cliRC = cliInterface->executeImmediate(query);
currContext.resetSqlParserFlags(0x1);
if (cliRC < 0)
goto error_return;
// create lob descriptor chunks table salted
str_sprintf(query, "create ghost table %s (descPartnKey largeint not null, descSysKey largeint not null, chunkNum int not null, chunkLen largeint not null, dataOffset largeint, stringParam varchar(400), primary key(descPartnKey, descSysKey, chunkNum)) salt using 8 partitions",
lobDescChunksName);
lobDebugInfo(query,0,__LINE__,lobTrace);
// set parserflags to allow ghost table
currContext.setSqlParserFlags(0x1);
cliRC = cliInterface->executeImmediate(query);
currContext.resetSqlParserFlags(0x1);
if (cliRC < 0)
goto error_return;
cliRC = 0;
}
break;
case LOB_CLI_DROP:
{
str_sprintf(query, "drop ghost table %s",
lobDescHandleName);
lobDebugInfo(query,0,__LINE__,lobTrace);
// set parserflags to allow ghost table
currContext.setSqlParserFlags(0x1);
cliRC = cliInterface->executeImmediate(query);
currContext.resetSqlParserFlags(0x1);
if (cliRC < 0)
goto error_return;
str_sprintf(query, "drop ghost table %s",
lobDescChunksName);
lobDebugInfo(query,0,__LINE__,lobTrace);
// set parserflags to allow ghost table
currContext.setSqlParserFlags(0x1);
cliRC = cliInterface->executeImmediate(query);
currContext.resetSqlParserFlags(0x1);
if (cliRC < 0)
goto error_return;
cliRC = 0;
}
break;
case LOB_CLI_CLEANUP:
{
str_sprintf(query, "cleanup table %s",
lobDescHandleName);
lobDebugInfo(query,0,__LINE__,lobTrace);
// set parserflags to allow ghost table
currContext.setSqlParserFlags(0x1);
cliRC = cliInterface->executeImmediate(query);
currContext.resetSqlParserFlags(0x1);
if (cliRC < 0)
goto error_return;
str_sprintf(query, "cleanup table %s",
lobDescChunksName);
lobDebugInfo(query,0,__LINE__,lobTrace);
// set parserflags to allow ghost table
currContext.setSqlParserFlags(0x1);
cliRC = cliInterface->executeImmediate(query);
currContext.resetSqlParserFlags(0x1);
if (cliRC < 0)
goto error_return;
cliRC = 0;
}
break;
case LOB_CLI_INSERT:
{
// insert into lob descriptor handle table
str_sprintf(query, "select syskey from (insert into table(ghost table %s) values (%ld, 1, %ld)) x",
lobDescHandleName, descPartnKey, (dataLen ? *dataLen : 0));
lobDebugInfo(query,0,__LINE__,lobTrace);
// set parserflags to allow ghost table
currContext.setSqlParserFlags(0x1);
Int64 descSyskey = 0;
Lng32 len = 0;
cliRC = cliInterface->executeImmediate(query,
(char*)&descSyskey, &len, FALSE);
if (cliRC < 0)
goto error_return;
currContext.resetSqlParserFlags(0x1);
if (cliRC < 0)
goto error_return;
// insert into lob descriptor chunks table
if (blackBox && (blackBoxLen && (*blackBoxLen > 0)))
{
//blackBox points to external file name
str_sprintf(query, "insert into table(ghost table %s) values (%ld, %ld, 1, %ld, %ld, '%s')",
lobDescChunksName, descPartnKey, descSyskey,
(dataLen ? *dataLen : 0),
(dataOffset ? *dataOffset : 0),
blackBox);
lobDebugInfo(query,0,__LINE__,lobTrace);
}
else
{
str_sprintf(query, "insert into table(ghost table %s) values (%ld, %ld, 1, %ld, %ld, NULL)",
lobDescChunksName, descPartnKey, descSyskey,
(dataLen ? *dataLen : 0),
(dataOffset ? *dataOffset : 0));
lobDebugInfo(query,0,__LINE__,lobTrace);
}
// set parserflags to allow ghost table
currContext.setSqlParserFlags(0x1);
cliRC = cliInterface->executeImmediate(query);
currContext.resetSqlParserFlags(0x1);
if (cliRC < 0)
goto error_return;
if (inoutDescPartnKey)
*inoutDescPartnKey = descPartnKey;
if (inoutDescSyskey)
*inoutDescSyskey = descSyskey;
// update lob handle with the returned values
if (outLobHandle)
{
str_cpy_all(outLobHandle, inLobHandle, inLobHandleLen);
ExpLOBoper::updLOBhandle(descSyskey, 0, outLobHandle);
if (outLobHandleLen)
*outLobHandleLen = inLobHandleLen;
}
cliRC = 0;
}
break;
case LOB_CLI_INSERT_APPEND:
{
if (lobType == Lob_External_HDFS_File)
{
// Not allowed. For external Lobs there shoudl be only one
// chunk associated with the contents of the external file.
cliRC = -LOB_DESC_APPEND_ERROR;
goto error_return;
}
str_sprintf(query, "update table(ghost table %s) set numChunks = numChunks + 1, lobLen = lobLen + %ld where descPartnKey = %ld and syskey = %ld",
lobDescHandleName,
(dataLen ? *dataLen : 0),
descPartnKey, inDescSyskey);
lobDebugInfo(query,0,__LINE__,lobTrace);
// set parserflags to allow ghost table
currContext.setSqlParserFlags(0x1);
cliRC = cliInterface->executeImmediate(query);
currContext.resetSqlParserFlags(0x1);
if (cliRC < 0)
goto error_return;
str_sprintf(query, "select numChunks from table(ghost table %s) h where h.descPartnKey = %ld and h.syskey = %ld for read committed access",
lobDescHandleName,
descPartnKey, inDescSyskey);
// set parserflags to allow ghost table
currContext.setSqlParserFlags(0x1);
Lng32 numChunks = 0;
Lng32 len;
cliRC = cliInterface->executeImmediate(query, (char*)&numChunks, &len, FALSE);
currContext.resetSqlParserFlags(0x1);
if (cliRC < 0)
goto error_return;
// insert into lob descriptor chunks table
if (blackBox && (blackBoxLen && (*blackBoxLen > 0)))
{
str_sprintf(query, "insert into table(ghost table %s) values (%ld, %ld, %d, %ld, %ld, '%s')",
lobDescChunksName, descPartnKey, inDescSyskey,
numChunks, (dataLen ? *dataLen : 0),
(dataOffset ? *dataOffset : 0),
blackBox);
lobDebugInfo(query,0,__LINE__,lobTrace);
}
else
{
str_sprintf(query, "insert into table(ghost table %s) values (%ld, %ld, %d, %ld, %ld, NULL)",
lobDescChunksName, descPartnKey, inDescSyskey,
numChunks, (dataLen ? *dataLen : 0),
(dataOffset ? *dataOffset : 0)
);
lobDebugInfo(query,0,__LINE__,lobTrace);
}
// set parserflags to allow ghost table
currContext.setSqlParserFlags(0x1);
cliRC = cliInterface->executeImmediate(query);
currContext.resetSqlParserFlags(0x1);
if (cliRC < 0)
goto error_return;
if (inoutDescPartnKey)
*inoutDescPartnKey = descPartnKey;
if (inoutDescSyskey)
*inoutDescSyskey = inDescSyskey;
if(blackBoxLen)
*blackBoxLen = numChunks;
cliRC = 0;
// if (outDescSyskey)
// *outDescSyskey = inDescSyskey;
}
break;
case LOB_CLI_UPDATE_UNIQUE:
{
// update desc handle table
str_sprintf(query, "update table(ghost table %s) set numChunks = 1, lobLen = %ld where descPartnKey = %ld and syskey = %ld",
lobDescHandleName,
(dataLen ? *dataLen : 0),
descPartnKey, inDescSyskey);
lobDebugInfo(query,0,__LINE__,lobTrace);
// set parserflags to allow ghost table
currContext.setSqlParserFlags(0x1);
cliRC = cliInterface->executeImmediate(query);
currContext.resetSqlParserFlags(0x1);
if (cliRC < 0)
goto error_return;
// delete all chunks from lob descriptor chunks table
str_sprintf(query, "delete from table(ghost table %s) where descPartnKey = %ld and descSysKey = %ld",
lobDescChunksName, descPartnKey, inDescSyskey);
// set parserflags to allow ghost table
currContext.setSqlParserFlags(0x1);
cliRC = cliInterface->executeImmediate(query);
currContext.resetSqlParserFlags(0x1);
if (cliRC < 0)
goto error_return;
if ((lobType != Lob_External_HDFS_File) && blackBox)
{
//Error . Cannot update an LOB column that has a non-external LOB
// with an external LOB.
cliRC = -LOB_DESC_UPDATE_ERROR;
goto error_return;
}
// insert the new chunk into lob descriptor chunks table
if (blackBox && (blackBoxLen && (*blackBoxLen > 0)))
{
str_sprintf(query, "insert into table(ghost table %s) values (%ld, %ld, 1, %ld, %ld, '%s')",
lobDescChunksName, descPartnKey, inDescSyskey,
(dataLen ? *dataLen : 0),
(dataOffset ? *dataOffset : 0),
blackBox);
lobDebugInfo(query,0,__LINE__,lobTrace);
}
else
{
str_sprintf(query, "insert into table(ghost table %s) values (%ld, %ld, 1, %ld, %ld, NULL)",
lobDescChunksName, descPartnKey, inDescSyskey,
(dataLen ? *dataLen : 0),
(dataOffset ? *dataOffset : 0));
lobDebugInfo(query,0,__LINE__,lobTrace);
}
// set parserflags to allow ghost table
currContext.setSqlParserFlags(0x1);
cliRC = cliInterface->executeImmediate(query);
currContext.resetSqlParserFlags(0x1);
if (cliRC < 0)
goto error_return;
// update lob handle with the returned values
if (outLobHandle)
{
str_cpy_all(outLobHandle, inLobHandle, inLobHandleLen);
ExpLOBoper::updLOBhandle(inDescSyskey, 0, outLobHandle);
if (outLobHandleLen)
*outLobHandleLen = inLobHandleLen;
}
if (inoutDescPartnKey)
*inoutDescPartnKey = descPartnKey;
if (inoutDescSyskey)
*inoutDescSyskey = inDescSyskey;
cliRC = 0;
}
break;
case LOB_CLI_DELETE:
{
// delete from lob descriptor handle table
str_sprintf(query, "delete from table(ghost table %s) where descPartnKey = %ld and syskey = %ld",
lobDescHandleName, descPartnKey, inDescSyskey);
lobDebugInfo(query,0,__LINE__,lobTrace);
// set parserflags to allow ghost table
currContext.setSqlParserFlags(0x1);
cliRC = cliInterface->executeImmediate(query);
currContext.resetSqlParserFlags(0x1);
if (cliRC < 0)
goto error_return;
// delete from lob descriptor chunks table
str_sprintf(query, "delete from table(ghost table %s) where descPartnKey = %ld and descSysKey = %ld",
lobDescChunksName, descPartnKey, inDescSyskey);
lobDebugInfo(query,0,__LINE__,lobTrace);
// set parserflags to allow ghost table
currContext.setSqlParserFlags(0x1);
cliRC = cliInterface->executeImmediate(query);
currContext.resetSqlParserFlags(0x1);
if (cliRC < 0)
goto error_return;
}
break;
case LOB_CLI_SELECT_UNIQUE:
{
// check if there are multiple chunks.
Int32 numChunks = 0;
str_sprintf(query, "select numChunks from table(ghost table %s) where descPartnKey = %ld for read committed access",
lobDescHandleName,
descPartnKey);
lobDebugInfo(query,0,__LINE__,lobTrace);
// set parserflags to allow ghost table
currContext.setSqlParserFlags(0x1);
cliRC = cliInterface->fetchRowsPrologue(query);
currContext.resetSqlParserFlags(0x1);
if (cliRC < 0)
goto error_return;
cliRC = cliInterface->fetch();
if (cliRC < 0)
{
cliInterface->fetchRowsEpilogue(0);
goto error_return;
}
if (cliRC != 100)
{
char * ptr;
Lng32 len;
cliInterface->getPtrAndLen(1, ptr, len);
str_cpy_all((char*)&numChunks, ptr, len);
}
if (numChunks > 1)
{
//The master will redrive with a cursor read
*blackBoxLen = -1;
cliInterface->fetchRowsEpilogue(0);
goto error_return;
}
else if ((numChunks > 1 ) && (lobType == Lob_External_HDFS_File))
{
// Should not happen. For external Lobs there should be only one
// chunk associated with the contents of the external file.
cliRC = -LOB_DATA_READ_ERROR;
goto error_return;
}
else
{
cliRC = cliInterface->fetchRowsEpilogue(0);
if (cliRC < 0)
goto error_return;
}
// This lob has only one chunk. Read and return the single descriptor.
str_sprintf(query, "select c.chunkLen, c.dataOffset ,c.stringParam from table(ghost table %s) h, table(ghost table %s) c where h.descPartnKey = c.descPartnKey and h.syskey = c.descSyskey and h.descPartnKey = %ld and h.syskey = %ld and c.chunkNum = h.numChunks for read committed access",
lobDescHandleName, lobDescChunksName,
descPartnKey, inDescSyskey);
lobDebugInfo(query,0,__LINE__,lobTrace);
// set parserflags to allow ghost table
currContext.setSqlParserFlags(0x1);
cliRC = cliInterface->fetchRowsPrologue(query);
currContext.resetSqlParserFlags(0x1);
if (cliRC < 0)
goto error_return;
cliRC = cliInterface->fetch();
if (cliRC < 0)
{
cliInterface->fetchRowsEpilogue(0);
goto error_return;
}
if (cliRC != 100)
{
char * ptr;
Lng32 len;
cliInterface->getPtrAndLen(1, ptr, len);
if (dataLen)
str_cpy_all((char*)dataLen, ptr, len);
cliInterface->getPtrAndLen(2, ptr, len);
if (dataOffset)
str_cpy_all((char*)dataOffset, ptr, len);
cliInterface->getPtrAndLen(3, ptr, len);
if (blackBox)
{
str_cpy_all((char*)blackBox, ptr, len);
*blackBoxLen = len;
}
if (inoutDescPartnKey)
*inoutDescPartnKey = descPartnKey;
if (inoutDescSyskey)
*inoutDescSyskey = inDescSyskey;
}
else
{
if (cliRC == 100)
{
if (dataLen)
*dataLen = 0;
if (dataOffset)
*dataOffset = 0;
if (blackBoxLen)
*blackBoxLen = 0;
if (inoutDescPartnKey)
*inoutDescPartnKey = descPartnKey;
if (inoutDescSyskey)
*inoutDescSyskey = inDescSyskey;
}
}
Lng32 saveCliErr = cliRC;
cliRC = cliInterface->fetchRowsEpilogue(0);
if (cliRC < 0)
goto error_return;
cliRC = saveCliErr;
}
break;
case LOB_CLI_SELECT_CURSOR:
{
str_sprintf(query, "select dataOffset, chunkLen, stringParam from table(ghost table %s) where descPartnKey = %ld and descSyskey = %ld order by chunkNum for read committed access",
lobDescChunksName, descPartnKey, inDescSyskey);
lobDebugInfo(query,0,__LINE__,lobTrace);
// set parserflags to allow ghost table
currContext.setSqlParserFlags(0x1);
cliRC = cliInterface->fetchRowsPrologue(query);
currContext.resetSqlParserFlags(0x1);
if (cliRC < 0)
goto error_return;
if (inCliInterface)
*inCliInterface = cliInterface;
}
break;
case LOB_CLI_SELECT_FETCH:
{
cliRC = cliInterface->fetch();
if (cliRC < 0)
{
cliInterface->fetchRowsEpilogue(0);
if (inCliInterface)
*inCliInterface = NULL;
goto error_return;
}
if (cliRC != 100)
{
char * ptr;
Lng32 len;
cliInterface->getPtrAndLen(1, ptr, len);
if (dataOffset)
str_cpy_all((char*)dataOffset, ptr, len);
cliInterface->getPtrAndLen(2, ptr, len);
if (dataLen)
str_cpy_all((char*)dataLen, ptr, len);
cliInterface->getPtrAndLen(3, ptr, len);
if (blackBox)
{
str_cpy_all((char*)blackBox, ptr, len);
*blackBoxLen = len;
}
cliRC = 0;
}
else
{
cliRC = 100;
}
}
break;
case LOB_CLI_SELECT_CLOSE:
{
cliRC = cliInterface->fetchRowsEpilogue(0);
if (cliRC < 0)
{
if (inCliInterface)
*inCliInterface = NULL;
goto error_return;
}
cliRC = 100;
if (inCliInterface)
*inCliInterface = NULL;
}
break;
case LOB_CLI_PURGEDATA:
{
// delete data from the handle desc table
str_sprintf(query, "delete from table(ghost table %s)",
lobDescHandleName);
lobDebugInfo(query,0,__LINE__,lobTrace);
// set parserflags to allow ghost table
currContext.setSqlParserFlags(0x1);
cliRC = cliInterface->executeImmediate(query);
currContext.resetSqlParserFlags(0x1);
if (cliRC < 0)
goto error_return;
// delete data from the chunks desc table
str_sprintf(query, "delete from table(ghost table %s)",
lobDescChunksName);
lobDebugInfo(query,0,__LINE__,lobTrace);
// set parserflags to allow ghost table
currContext.setSqlParserFlags(0x1);
cliRC = cliInterface->executeImmediate(query);
currContext.resetSqlParserFlags(0x1);
if (cliRC < 0)
goto error_return;
}
break;
case LOB_CLI_SELECT_LOBLENGTH:
{
//aggregate on chunklen for this lob.
str_sprintf (query, "select sum(chunklen) from %s where descpartnkey = %ld and descsyskey = %ld ", lobDescChunksName, descPartnKey, inDescSyskey );
lobDebugInfo(query,0,__LINE__,lobTrace);
// set parserflags to allow ghost table
currContext.setSqlParserFlags(0x1);
Int64 outlen = 0;Lng32 len = 0;
cliRC = cliInterface->executeImmediate(query,(char *)dataLen, &len, FALSE);
currContext.resetSqlParserFlags(0x1);
if (inoutDescPartnKey)
*inoutDescPartnKey = descPartnKey;
if (inoutDescSyskey)
*inoutDescSyskey = inDescSyskey;
Lng32 saveCliErr = cliRC;
if (cliRC < 0)
{
cliInterface->retrieveSQLDiagnostics(myDiags);
goto error_return;
}
cliRC = saveCliErr;
}
break;
case LOB_CLI_SELECT_LOBOFFSET:
{
//Retrive offset of the first chunk
str_sprintf(query, "select c.dataOffset from table(ghost table %s) h, table(ghost table %s) c where h.descPartnKey = c.descPartnKey and h.syskey = c.descSyskey and h.descPartnKey = %ld and h.syskey = %ld and c.chunkNum = 1 for read committed access",
lobDescHandleName, lobDescChunksName,
descPartnKey, inDescSyskey);
lobDebugInfo(query,0,__LINE__,lobTrace);
// set parserflags to allow ghost table
currContext.setSqlParserFlags(0x1);
Lng32 len = 0;
cliRC = cliInterface->executeImmediate(query,(char *)dataOffset, &len, FALSE);
currContext.resetSqlParserFlags(0x1);
if (inoutDescPartnKey)
*inoutDescPartnKey = descPartnKey;
if (inoutDescSyskey)
*inoutDescSyskey = inDescSyskey;
Lng32 saveCliErr = cliRC;
if (cliRC < 0)
goto error_return;
cliRC = saveCliErr;
}
break;
} // switch
// normal return. Fall down to deallocate of structures.
error_return:
Lng32 tempCliRC = 0;
if (xnJoined)
{
tempCliRC = SUSPENDTRANSACTION((short *) &xnId);
if (tempCliRC)
cliRC = -EXE_BEGIN_TRANSACTION_ERROR;
}
if (xnAutoCommit)
{
strcpy(query, "set transaction autocommit off;");
tempCliRC = cliInterface->executeImmediate(query);
if (tempCliRC < 0)
cliRC = tempCliRC;
}
NADELETEBASIC(query, currContext.exHeap());
if (cliRC < 0)
{
if (myDiags == NULL)
myDiags = ComDiagsArea::allocate(currContext.exHeap());
cliInterface->retrieveSQLDiagnostics(myDiags);
diags.mergeAfter(*myDiags);
myDiags->decrRefCount();
}
if (NOT (inCliInterface && (*inCliInterface)))
{
delete cliInterface;
cliInterface = NULL;
}
if (cliRC < 0)
return cliRC;
else if (cliRC == 100)
return 100;
else
return 0;
}
/* The process for GC is as follows:
1. Check LOB descriptor chunks table (per column) for any holes in the LOB sections.
2. Create an in memory array that can be used to calculate new offsets.
3. Update the lob descriptor chunks table to reflect the new offsets
if any error, return an error and rollback the user transaction.
4. Compact the lob data file buy doing hte following :
a) Save a copy of the LOB data file.
b) Create a temp lob file to copy the sections contiguously from the lob data file to the temp file.
If any error return an error and rollback all updates to the lob descriptor chunks table.
c) Delete the lob data file.
d) Rename the tempfile to original lob data file name.
If any error, restore the lob data file from the saved backup in step (a)
e) Purge the saved backup.
*/
Lng32 SQLCLI_LOB_GC_Interface
(
/*IN*/ CliGlobals *cliGlobals,
/*IN*/ ExLobGlobals *lobGlobals, // can be passed or NULL
/*IN*/ char * handle,
/*IN*/ Lng32 handleLen,
/*IN*/ char* hdfsServer,
/*IN*/ Lng32 hdfsPort,
/*IN*/ char *lobLocation,
/*IN*/ Int64 lobMaxMemChunkLen, // if passed in as 0, will use default value of 1G for the in memory buffer to do compaction.
/*IN*/ NABoolean lobTrace
)
{
Lng32 cliRC = 0;
char logBuf[4096];
lobDebugInfo("In LOB_GC_Interface",0,__LINE__,lobTrace);
ContextCli & currContext = *(cliGlobals->currContext());
ComDiagsArea & diags = currContext.diags();
ComDiagsArea * myDiags = NULL;
ExeCliInterface *cliInterface = NULL;
cliInterface = new (currContext.exHeap())
ExeCliInterface(currContext.exHeap(),
SQLCHARSETCODE_UTF8,
&currContext,
NULL);
Int32 rc = 0;
Int16 flags = 0;
Lng32 lobType = 1;
Lng32 lobNum = 0;
Int64 uid = 0;
Int64 inDescSyskey, inDescPartnKey;
short schNameLen = 0;
char schName[512];
if (handle)
{
ExpLOBoper::extractFromLOBhandle(&flags, &lobType, &lobNum, &uid,
&inDescSyskey, &inDescPartnKey,
&schNameLen, schName,
handle);
}
str_sprintf(logBuf,"flags %d, lobType %d, lobNum :%d, uid : %ld, descSyskey: %ld, descPartnKey : %ld, schNameLen:%d, schName %s", flags,lobType,lobNum,uid,inDescSyskey,inDescPartnKey,schNameLen,schName);
lobDebugInfo(logBuf,0,__LINE__,lobTrace);
char tgtLobNameBuf[100];
char * tgtLobName =
ExpLOBoper::ExpGetLOBname(uid, lobNum, tgtLobNameBuf, 100);
str_sprintf(logBuf,"lobName %s", tgtLobName);
lobDebugInfo(logBuf,0,__LINE__,lobTrace);
char lobDescHandleNameBuf[1024];
Lng32 lobDescHandleNameLen = 1024;
char * lobDescHandleName =
ExpLOBoper::ExpGetLOBDescHandleName(schNameLen, schName, uid, lobNum,
lobDescHandleNameBuf, lobDescHandleNameLen);
str_sprintf(logBuf,"lobDescHandleName %s", lobDescHandleName);
lobDebugInfo(logBuf,0,__LINE__,lobTrace);
char lobDescChunksNameBuf[1024];
Lng32 lobDescChunksNameLen = 1024;
char * lobDescChunksName =
ExpLOBoper::ExpGetLOBDescChunksName(schNameLen, schName, uid, lobNum,
lobDescChunksNameBuf, lobDescChunksNameLen);
str_sprintf(logBuf,"lobDescChunksName %s", lobDescChunksName);
lobDebugInfo(logBuf,0,__LINE__,lobTrace);
char * query = new(currContext.exHeap()) char[4096];
//Find how many entries in the descchunks table to allocate
//in memory array.
str_sprintf(query, "select count(*) from table(ghost table %s) ",
lobDescChunksName);
lobDebugInfo(query,0,__LINE__,lobTrace);
// set parserflags to allow ghost table
currContext.setSqlParserFlags(0x1);
Int64 numEntries = 0;
Lng32 len;
cliRC = cliInterface->executeImmediate(query, (char*)&numEntries, &len, FALSE);
str_sprintf(logBuf,"Number of entries in descchunktable %s is %ld",lobDescChunksName, numEntries);
lobDebugInfo(logBuf,0,__LINE__,lobTrace);
currContext.resetSqlParserFlags(0x1);
if (cliRC < 0)
goto error_return;
{
//Allocate an inmemory array of numEntries.
ExLobInMemoryDescChunksEntry *dcInMemoryArray = new ExLobInMemoryDescChunksEntry[numEntries];
//Read the desc chunks table into memory
str_sprintf(query, "select dataOffset, descPartnKey,descSyskey,chunkLen,chunkNum from table(ghost table %s) order by dataOffset,chunkLen for read committed access",
lobDescChunksName);
lobDebugInfo(logBuf,0,__LINE__,lobTrace);
// set parserflags to allow ghost table
currContext.setSqlParserFlags(0x1);
cliRC = cliInterface->fetchRowsPrologue(query);
currContext.resetSqlParserFlags(0x1);
if (cliRC < 0)
goto error_return;
cliRC = cliInterface->fetch();
if (cliRC < 0)
{
cliInterface->fetchRowsEpilogue(0);
goto error_return;
}
short i = 0;
Int64 currentOffset = 0;
Int64 descPartnKey = 0;
Int64 descSyskey = 0;
Int64 chunkLen = 0;
Int64 chunkNum = 0;
while (cliRC != 100)
{
char * ptr;
Lng32 len;
cliInterface->getPtrAndLen(1, ptr, len);
str_cpy_all((char*)&currentOffset, ptr, len);
cliInterface->getPtrAndLen(2, ptr, len);
str_cpy_all((char*)&descPartnKey, ptr, len);
cliInterface->getPtrAndLen(3, ptr, len);
str_cpy_all((char*)&descSyskey, ptr, len);
cliInterface->getPtrAndLen(4, ptr, len);
str_cpy_all((char*)&chunkLen, ptr, len);
cliInterface->getPtrAndLen(5, ptr, len);
str_cpy_all((char*)&chunkNum, ptr, len);
dcInMemoryArray[i].setCurrentOffset(currentOffset);
dcInMemoryArray[i].setNewOffset(currentOffset);
dcInMemoryArray[i].setDescPartnKey(descPartnKey);
dcInMemoryArray[i].setSyskey(descSyskey);
dcInMemoryArray[i].setChunkLen(chunkLen);
dcInMemoryArray[i].setChunkNum(chunkNum);
str_sprintf(logBuf,"Fetched for entry i=%d; currentOffset:%ld, descPartnKey:%ld, sysKey:%ld, chunkLen:%ld,chunkNum %ld", i,currentOffset,descPartnKey,descSyskey,chunkLen,chunkNum);
lobDebugInfo(logBuf,0,__LINE__,lobTrace);
cliRC = cliInterface->fetch();
i++;
if (cliRC < 0)
{
cliInterface->fetchRowsEpilogue(0);
goto error_return;
}
}
cliRC = cliInterface->fetchRowsEpilogue(0);
if (cliRC < 0)
goto error_return;
// adjust in memory array to calculate holes and new offsets.
ExpLOBoper::calculateNewOffsets(dcInMemoryArray,numEntries);
lobDebugInfo("Calculated new offsets",0,__LINE__,lobTrace);
// Update the descChunks table with new offsets
//TBD start a separate transaction to manage this.
//For now use the transaction associated with the IUD operation
//that triggered this GC
i = 0;
while (i < numEntries)
{
if (dcInMemoryArray[i].getCurrentOffset() == dcInMemoryArray[i].getNewOffset())
i++;
else
{
str_sprintf(query, "update table(ghost table %s) set dataOffset=%ld, chunkLen = %ld where descPartnKey = %ld and descSysKey = %ld",
lobDescChunksName,
dcInMemoryArray[i].getNewOffset(),
dcInMemoryArray[i].getChunkLen(),
dcInMemoryArray[i].getDescPartnKey(),
dcInMemoryArray[i].getSyskey());
// set parserflags to allow ghost table
lobDebugInfo(query,0,__LINE__,lobTrace);
currContext.setSqlParserFlags(0x1);
cliRC = cliInterface->executeImmediate(query);
currContext.resetSqlParserFlags(0x1);
if (cliRC < 0)
{
//tbd Give warning and rollback just these updates and return with warning. For now return error and abort the iud operation itself since there is no support for nested transactions or SUSPEND and RESUME.
goto error_return;
}
i++;
}
}
// Compact into new temp file
rc = ExpLOBoper::compactLobDataFile(lobGlobals,dcInMemoryArray,numEntries,tgtLobName,lobMaxMemChunkLen, currContext.exHeap(), &currContext,hdfsServer, hdfsPort,lobLocation);
if (rc )
{
cliRC = 1; // Warning
ComDiagsArea * da = &diags;
lobDebugInfo("compactLobDataFile Failed",0,__LINE__,lobTrace);
ExRaiseSqlError(currContext.exHeap(), &da,
(ExeErrorCode)(8442), NULL, &cliRC ,
&rc, NULL, (char*)"Lob GC call",
getLobErrStr(rc), (char*)getSqlJniErrorStr());
// TBD When local transaction support is in
// rollback all the updates to the lob desc chunks file too.
// return with warning
// For now, return error for the IUD operation
// Restore original data file.
Int32 rc2=ExpLOBoper::restoreLobDataFile(lobGlobals,tgtLobName, currContext.exHeap(),&currContext,hdfsServer,hdfsPort,lobLocation);
if (rc2)
{
lobDebugInfo("restoreLobDataFile Failed",0,__LINE__,lobTrace);
}
// if error restoring, this lob could become corrupt.
goto error_return;
}
else
{
//TBD :commit all updates and remove the saved copy of datafile
ExpLOBoper::purgeBackupLobDataFile(lobGlobals, tgtLobName,currContext.exHeap(),&currContext,hdfsServer,hdfsPort,lobLocation);
lobDebugInfo("purgedLobDataFile ",0,__LINE__,lobTrace);
}
}
error_return:
Lng32 tempCliRC = 0;
NADELETEBASIC(query, currContext.exHeap());
if (cliRC < 0)
{
if (myDiags == NULL)
myDiags = ComDiagsArea::allocate(currContext.exHeap());
diags.mergeAfter(*myDiags);
myDiags->decrRefCount();
}
if (cliRC < 0)
return cliRC;
else if (cliRC == 100)
return 100;
else
return 0;
}
Lng32 SQLCLI_LOBddlInterface
(
/*IN*/ CliGlobals *cliGlobals,
/*IN*/ char * schName,
/*IN*/ Lng32 schNameLen,
/*IN*/ Int64 objectUID,
/*IN*/ Lng32 &numLOBs,
/*IN*/ LOBcliQueryType qType,
/*IN*/ short *lobNumList,
/*IN*/ short *lobTypList,
/*IN*/ char* *lobLocList,
/*IN*/ char* *lobColNameList,
/*IN*/ char *lobHdfsServer,
/*IN*/ Int32 hdfsPort,
/*IN*/ Int64 lobMaxSize,
/*IN*/ NABoolean lobTrace
)
{
Lng32 cliRC = 0;
ExLobGlobals *exLobGlob = NULL;
ContextCli & currContext = *(cliGlobals->currContext());
ComDiagsArea & diags = currContext.diags();
ComDiagsArea * myDiags = NULL;
NABoolean useLibHdfs = currContext.getSessionDefaults()->getUseLibHdfs();
char logBuf[4096];
lobDebugInfo("In LOBddlInterface",0,__LINE__,lobTrace);
ExeCliInterface *cliInterface = NULL;
cliInterface = new (currContext.exHeap())
ExeCliInterface(currContext.exHeap(),
SQLCHARSETCODE_UTF8,
&currContext,
NULL);
char lobMDNameBuf[1024];
Lng32 lobMDNameLen = 1024;
char * lobMDName =
ExpLOBoper::ExpGetLOBMDName(schNameLen, schName, objectUID,
lobMDNameBuf, lobMDNameLen);
str_sprintf(logBuf,"lobMDName %s", lobMDName);
lobDebugInfo(logBuf,0,__LINE__,lobTrace);
char * query = new(currContext.exHeap()) char[4096];
char *hdfsServer = new(currContext.exHeap()) char[256];
strcpy(hdfsServer,lobHdfsServer);
Int32 rc = 0;
switch (qType)
{
case LOB_CLI_CREATE:
case LOB_CLI_ALTER :
{
// create lob metadata table
str_sprintf(query, "create ghost table %s (lobnum smallint not null, storagetype smallint not null, location varchar(4096) not null, column_name varchar(256 bytes) character set utf8, primary key (lobnum)) ",lobMDName);
lobDebugInfo(query,0,__LINE__,lobTrace);
// set parserflags to allow ghost table
currContext.setSqlParserFlags(0x1);
cliRC = cliInterface->executeImmediate(query);
currContext.resetSqlParserFlags(0x1);
if (cliRC < 0)
{
ComDiagsArea *tempDiags = ComDiagsArea::allocate(currContext.exHeap());
cliInterface->retrieveSQLDiagnostics(tempDiags);
if (tempDiags->containsError(-CAT_TRAFODION_OBJECT_EXISTS))
{
if (qType ==LOB_CLI_ALTER)
{
//Clear the diags . This table already has a lob column
//So no need to create an MD table. Just continue
cliInterface->clearGlobalDiags();
tempDiags->decrRefCount();
}
}
else
goto error_return;
}
// populate the lob metadata table
for (Lng32 i = 0; i < numLOBs; i++)
{
str_sprintf(query, "insert into table (ghost table %s) values (%d, %d, '%s','%s')",
lobMDName,
lobNumList[i], lobTypList[i], lobLocList[i],lobColNameList[i]);
lobDebugInfo(query,0,__LINE__,lobTrace);
// set parserflags to allow ghost table
currContext.setSqlParserFlags(0x1);
cliRC = cliInterface->executeImmediate(query);
currContext.resetSqlParserFlags(0x1);
if (cliRC < 0)
goto error_return;
} // for
//Initialize LOB interface
exLobGlob = ExpLOBoper::initLOBglobal(currContext.exHeap(), &currContext, useLibHdfs);
if (exLobGlob == NULL)
{
cliRC = -1;
ComDiagsArea * da = &diags;
ExRaiseSqlError(currContext.exHeap(), &da,
(ExeErrorCode)(8442), NULL, &cliRC ,
&rc, NULL, (char*)"ExpLOBInterfaceCreate",
getLobErrStr(rc), (char*)getSqlJniErrorStr());
goto non_cli_error_return;
}
for (Lng32 i = 0; i < numLOBs; i++)
{
// create lob data tables
rc = ExpLOBoper::createLOB
(exLobGlob, &currContext,
lobLocList[i], hdfsPort,hdfsServer,
objectUID, lobNumList[i],lobMaxSize);
if (rc)
{
cliRC = -1;
ComDiagsArea * da = &diags;
ExRaiseSqlError(currContext.exHeap(), &da,
(ExeErrorCode)(8442), NULL, &cliRC ,
&rc, NULL, (char*)"ExpLOBInterfaceCreate",
getLobErrStr(rc), (char*)getSqlJniErrorStr());
goto non_cli_error_return;
}
// create LOB descriptor and LOB header tables
char lobHandle[LOB_HANDLE_LEN];
Lng32 handleLen = 0;
ExpLOBoper::genLOBhandle(objectUID,
lobNumList[i],
lobTypList[i],
0, 0, 0,
schNameLen,
schName,
handleLen,
lobHandle);
cliRC = SQL_EXEC_LOBcliInterface(lobHandle, handleLen,
NULL, 0,
NULL, NULL,
LOB_CLI_CREATE,
LOB_CLI_ExecImmed,
NULL,
NULL,
NULL,
NULL,
NULL,
0,lobTrace);
if (cliRC < 0)
goto error_return;
} // for
}
break;
case LOB_CLI_DROP:
{
str_sprintf(query, "drop ghost table %s",
lobMDName);
lobDebugInfo(query,0,__LINE__,lobTrace);
// set parserflags to allow ghost table
currContext.setSqlParserFlags(0x1);
cliRC = cliInterface->executeImmediate(query);
currContext.resetSqlParserFlags(0x1);
if (cliRC < 0)
goto error_return;
// drop descriptor table
for (Lng32 i = 0; i < numLOBs; i++)
{
// drop LOB descriptor and LOB header tables
char lobHandle[LOB_HANDLE_LEN];
Lng32 handleLen = 0;
ExpLOBoper::genLOBhandle(objectUID,
lobNumList[i],
lobTypList[i],
0, 0, 0,
schNameLen,
schName,
handleLen,
lobHandle);
cliRC = SQL_EXEC_LOBcliInterface(lobHandle, handleLen,
NULL, 0,
NULL, NULL,
LOB_CLI_DROP,
LOB_CLI_ExecImmed,
NULL,
NULL,
NULL,
NULL,
NULL,
0,lobTrace);
if (cliRC < 0)
goto error_return;
} // for
//If all the descriptor tables got dropped correctly, drop the hdfs
//lob data files. Note that if there is an error in the drop of the
//descriptor tables above , the transaction will restore each of the
//above tables .
//Initialize LOB interface
exLobGlob = ExpLOBoper::initLOBglobal(currContext.exHeap(), &currContext, useLibHdfs);
if (exLobGlob == NULL)
{
cliRC = -1;
ComDiagsArea * da = &diags;
ExRaiseSqlError(currContext.exHeap(), &da,
(ExeErrorCode)(8442), NULL, &cliRC ,
&rc, NULL, (char*)"ExpLOBInterfaceCreate",
getLobErrStr(rc), (char*)getSqlJniErrorStr());
goto non_cli_error_return;
}
for (Lng32 i = 0; i < numLOBs; i++)
{
rc = ExpLOBoper::dropLOB
(exLobGlob,&currContext,
lobLocList[i],hdfsPort,hdfsServer,
objectUID, lobNumList[i]);
// Ignore 'not found' error from hdfs file deletes until this is made transactional just like Hbase tables are.
if (rc && (rc != -LOB_DATA_FILE_DELETE_ERROR))
{
cliRC = -1;
ComDiagsArea * da = &diags;
ExRaiseSqlError(currContext.exHeap(), &da,
(ExeErrorCode)(8442), NULL, &cliRC ,
&rc, NULL, (char*)"ExpLOBInterfaceDrop ",
getLobErrStr(rc), (char*)getSqlJniErrorStr());
goto non_cli_error_return;
}
}//for
}
break;
case LOB_CLI_CLEANUP:
{
str_sprintf(query, "cleanup table %s", lobMDName);
lobDebugInfo(query,0,__LINE__,lobTrace);
// set parserflags to allow ghost table
currContext.setSqlParserFlags(0x1);
cliRC = cliInterface->executeImmediate(query);
currContext.resetSqlParserFlags(0x1);
if (cliRC < 0)
goto error_return;
//Initialize LOB interface
exLobGlob = ExpLOBoper::initLOBglobal(currContext.exHeap(), &currContext, useLibHdfs);
if (exLobGlob == NULL)
{
cliRC = -1;
ComDiagsArea * da = &diags;
ExRaiseSqlError(currContext.exHeap(), &da,
(ExeErrorCode)(8442), NULL, &cliRC ,
&rc, NULL, (char*)"ExpLOBInterfaceCreate",
getLobErrStr(rc), (char*)getSqlJniErrorStr());
goto non_cli_error_return;
}
// drop descriptor table
for (Lng32 i = 0; i < numLOBs; i++)
{
Lng32 rc = ExpLOBoper::dropLOB
(exLobGlob,&currContext,
lobLocList[i],hdfsPort, hdfsServer,
objectUID, lobNumList[i]);
if (rc && rc != -LOB_DATA_FILE_DELETE_ERROR)
{
cliRC = -1;
ComDiagsArea * da = &diags;
ExRaiseSqlError(currContext.exHeap(), &da,
(ExeErrorCode)(8442), NULL, &cliRC ,
&rc, NULL, (char*)"ExpLOBInterfaceDrop ",
getLobErrStr(rc), (char*)getSqlJniErrorStr());
goto non_cli_error_return;
}
// drop LOB descriptor and LOB header tables
char lobHandle[512];
Lng32 handleLen = 0;
ExpLOBoper::genLOBhandle(objectUID,
lobNumList[i],
lobTypList[i],
0, 0, 0,
schNameLen,
schName,
handleLen,
lobHandle);
cliRC = SQL_EXEC_LOBcliInterface(lobHandle, handleLen,
NULL, 0,
NULL, NULL,
LOB_CLI_CLEANUP,
LOB_CLI_ExecImmed,
NULL,
NULL,
NULL,
NULL,
NULL,
0,lobTrace);
if (cliRC < 0)
goto error_return;
} // for
}
break;
case LOB_CLI_SELECT_CURSOR:
case LOB_CLI_SELECT_UNIQUE:
{
if (qType == LOB_CLI_SELECT_CURSOR)
str_sprintf(query, "select lobnum, storagetype, location,column_name from table(ghost table %s) order by lobnum for read uncommitted access",
lobMDName);
else
str_sprintf(query, "select lobnum, storagetype, location ,column_name from table(ghost table %s) where lobnum = %d for read uncommitted access",
lobMDName, numLOBs);
lobDebugInfo(query,0,__LINE__,lobTrace);
// set parserflags to allow ghost table
currContext.setSqlParserFlags(0x1);
cliRC = cliInterface->fetchRowsPrologue(query);
currContext.resetSqlParserFlags(0x1);
if (cliRC < 0)
goto error_return;
cliRC = 0;
Lng32 j = 0;
numLOBs = 0;
while (cliRC != 100)
{
cliRC = cliInterface->fetch();
if (cliRC < 0)
{
cliInterface->fetchRowsEpilogue(0);
goto error_return;
}
if (cliRC != 100)
{
char * ptr;
Lng32 len;
short lobNum;
cliInterface->getPtrAndLen(1, ptr, len);
str_cpy_all((char*)&lobNum, ptr, len);
lobNumList[j] = lobNum;
short stType;
cliInterface->getPtrAndLen(2, ptr, len);
str_cpy_all((char*)&stType, ptr, len);
lobTypList[j] = stType;
cliInterface->getPtrAndLen(3, ptr, len);
str_cpy_and_null(lobLocList[j], ptr, len, '\0', ' ', TRUE);
cliInterface->getPtrAndLen(4, ptr, len);
str_cpy_and_null(lobColNameList[j], ptr, len, '\0', ' ', TRUE);
j++;
if ((qType == LOB_CLI_SELECT_UNIQUE) &&
(j > 1))
{
// error. Unique cannot return multiple rows.
cliRC = -8900;
cliInterface->fetchRowsEpilogue(0);
goto error_return;
}
}
else
{
Lng32 ccliRC = cliInterface->fetchRowsEpilogue(0);
if (ccliRC < 0)
{
cliRC = ccliRC;
goto error_return;
}
}
} // while
if (j > 0)
cliRC = 0;
else
cliRC = 100;
if (qType == LOB_CLI_SELECT_CURSOR)
numLOBs = j;
}
break;
} // switch
error_return:
if (cliRC < 0)
{
if (myDiags == NULL)
myDiags = ComDiagsArea::allocate(currContext.exHeap());
cliInterface->retrieveSQLDiagnostics(myDiags);
diags.mergeAfter(*myDiags);
myDiags->decrRefCount();
}
non_cli_error_return:
if (exLobGlob != NULL)
ExpLOBoper::deleteLOBglobal(exLobGlob, currContext.exHeap());
NADELETEBASIC(query, currContext.exHeap());
NADELETEBASIC(hdfsServer,currContext.exHeap());
delete cliInterface;
if (cliRC < 0)
return cliRC;
else if (cliRC == 100)
return 100;
else
return 0;
}
/*
Int32 SQLCLI_SWITCH_TO_COMPILER_TYPE(CliGlobals * cliGlobals,
Int32 compiler_class_type)
- switch to unused CmpContext instance with the same class type,
if compiler_class_type is 0, switch to any unused CmpContext,
if no desired CmpContext to switch to, create new one
- return value
0 success
-1 failed to create new CmpContext
-2 invalid compile_class_type
*/
Int32 SQLCLI_SWITCH_TO_COMPILER_TYPE (
/*IN*/ CliGlobals *cliGlobals,
/*IN*/ Int32 cmpClassType
)
{
ContextCli *currContext = GetCliGlobals()->currContext();
Int32 retCode = currContext->switchToCmpContext(cmpClassType);
if (retCode == 0)
return retCode; // success
ComDiagsArea &diagsArea = currContext->diags();
if (retCode == -1)
diagsArea << DgSqlCode(2032)
<< DgString0(CmpContextInfo::getCmpContextClassName(cmpClassType))
;
else
diagsArea << DgSqlCode(2032)
<< DgString0("(invalid type)"); // give warning
return retCode;
}
/*
Int32 SQLCLI_SWITCH_TO_COMPILER(CliGlobals * cliGlobals,
void * cmpCntxt)
- switch to given CmpContext instance
if the given instance is not known, add it to the CmpContext
list with class name "NONE" (default)
- return value
0 success
-1 given instance is null
1 given instance is in use but switched anyway
*/
Int32 SQLCLI_SWITCH_TO_COMPILER (
/*IN*/ CliGlobals *cliGlobals,
/*IN*/ void * cmpCntxt
)
{
ContextCli *currContext = cliGlobals->currContext();
Int32 retCode = currContext->switchToCmpContext(cmpCntxt);
if (retCode >= 0)
return retCode; // success
ComDiagsArea &diagsArea = currContext->diags();
diagsArea << DgSqlCode(2032)
<< DgString0("invalid compiler pointer"); // give warning
return retCode;
}
/*
Int32 SQLCLI_SWITCH_BACK_COMPILER(CliGlobals *cliGlobals)
- switch back to previous used CmpContext instance
- return value
0 success
-1 no previous CmpContext to switch back
*/
Int32 SQLCLI_SWITCH_BACK_COMPILER (
/*IN*/ CliGlobals *cliGlobals
)
{
ContextCli *currContext = cliGlobals->currContext();
return (currContext->switchBackCmpContext());
}
Lng32 SQLCLI_SEcliInterface
(
CliGlobals *cliGlobals,
SECliQueryType qType,
void* *inCliInterface,
const char * inStrParam1,
const char * inStrParam2,
Lng32 inIntParam1,
Lng32 inIntParam2,
char* *outStrParam1,
char* *outStrParam2,
Lng32 *outIntParam1
)
{
Lng32 rc = 0;
ContextCli & currContext = *(cliGlobals->currContext());
ComDiagsArea & diags = currContext.diags();
ExeCliInterface *cliInterface = NULL;
if (inCliInterface && (*inCliInterface))
{
cliInterface = (ExeCliInterface*)(*inCliInterface);
}
else
{
cliInterface = new (currContext.exHeap())
ExeCliInterface(currContext.exHeap(),
SQLCHARSETCODE_UTF8,
&currContext,
NULL);
cliInterface->setNotExeUtilInternalQuery(TRUE);
if (inCliInterface)
*inCliInterface = cliInterface;
}
switch (qType)
{
case SE_CLI_CREATE_CONTEXT:
{
rc = cliInterface->createContext((char*)inStrParam1);
}
break;
case SE_CLI_SWITCH_CONTEXT:
{
rc = cliInterface->switchContext((char*)inStrParam1);
}
break;
case SE_CLI_CURRENT_CONTEXT:
{
rc = cliInterface->currentContext((char*)inStrParam1);
}
break;
case SE_CLI_DROP_CONTEXT:
{
rc = cliInterface->deleteContext((char*)inStrParam1);
}
break;
case SE_CLI_CLEAR_DIAGS:
{
cliInterface->clearGlobalDiags();
rc = 0;
}
break;
case SE_CLI_EXEC_IMMED:
{
rc = cliInterface->executeImmediate((char*)inStrParam1);
}
break;
case SE_CLI_EXEC_IMMED_PREP:
{
rc = cliInterface->executeImmediatePrepare((char*)inStrParam1,
NULL, NULL, NULL, FALSE,
(char*)inStrParam2);
}
break;
case SE_CLI_EXEC_IMMED_CEFC:
{
rc = cliInterface->executeImmediateCEFC((char*)inStrParam1, NULL, 0,
(char*)inStrParam2, NULL);
}
break;
case SE_CLI_FETCH_ROWS_PROLOGUE:
{
rc = cliInterface->fetchRowsPrologue((char*)inStrParam1, FALSE, FALSE,
(char*)inStrParam2);
}
break;
case SE_CLI_EXEC:
{
rc = cliInterface->exec((char*)inStrParam1, inIntParam1);
}
break;
case SE_CLI_FETCH:
{
rc = cliInterface->fetch();
}
break;
case SE_CLI_CLOSE:
{
rc = cliInterface->close();
}
break;
case SE_CLI_CEFC:
{
rc = cliInterface->clearExecFetchClose((char*)inStrParam1, inIntParam1);
}
break;
case SE_CLI_BEGIN_XN:
{
rc = cliInterface->beginXn();
}
break;
case SE_CLI_COMMIT_XN:
{
rc = cliInterface->commitXn();
}
break;
case SE_CLI_ROLLBACK_XN:
{
rc = cliInterface->rollbackXn();
}
break;
case SE_CLI_STATUS_XN:
{
rc = cliInterface->statusXn();
}
break;
case SE_CLI_GET_DATA_OFFSETS:
{
rc = cliInterface->getDataOffsets( inIntParam1, inIntParam2,
(Lng32*)inStrParam1, (Lng32*)inStrParam2);
}
break;
case SE_CLI_GET_PTR_AND_LEN:
{
char * ptr = NULL;
Lng32 len = 0;
short * ind = NULL;
rc = cliInterface->getPtrAndLen(inIntParam1, ptr, len, &ind);
if (outStrParam1)
*outStrParam1 = ptr;
if (outStrParam2)
*outStrParam2 = (char*)ind;
if (outIntParam1)
*outIntParam1 = len;
}
break;
case SE_CLI_GET_IO_LEN:
{
if (inIntParam1 == 0)
{
*outIntParam1 = cliInterface->inputDatalen();
}
if (inIntParam1 == 1)
{
*outIntParam1 = cliInterface->outputDatalen();
}
rc = 0;
}
break;
case SE_CLI_GET_STMT_ATTR:
{
rc = cliInterface->getStmtAttr((char*)inStrParam1, (Lng32)inIntParam1,
(Lng32*)outIntParam1, *outStrParam1);
}
break;
case SE_CLI_DEALLOC:
{
rc = cliInterface->dealloc();
}
break;
case SE_CLI_TRAFQ_INSERT:
{
currContext.trafSElist()->insert(inStrParam1, inIntParam1, (void*)inStrParam2);
}
break;
case SE_CLI_TRAFQ_GET:
{
currContext.trafSElist()->position(inStrParam1, inIntParam1);
*outStrParam1 = (char*)currContext.trafSElist()->getNext();
}
break;
} // switch
return rc;
}
///////////////////////////////////////////////////////////////////////
// Current design to update sequence metadata:
//
// If there is no Xn running:
// A transaction is started, update is done within it, and then that Xn is committed.
// If there is a conflict during commit, then update is retried.
//
// If there is a user Xn running:
// Seq Gen table is not updated as part of user xn. It is run in non-transactional
// mode using hbase transactions.
// To avoid concurrent updates to seq gen table,
// Sequence gen table col upd_ts is updated with a generated unique value.
// Table is then updated with new nextValue and current value is retrieved.
// At the end, upd_ts value is retrieved and compared to the generated unique
// value. If they are different, update is retried.
//
// seq gen update is retried max 10 times.
// An error is returned if we dont get consistent result after that.
//
//
// Future design:
//
// When support for local transactions and repeatable reads are in,
// then the select...update will be done in one local transaction.
// That will guarantee that the select and update are done in the same transaction.
//
// If a transaction is already running when this update is to be done, then that Xn
// will be suspended and a new local transaction wil be started.
// This local Xn will be committed after update and the
// original transaction will be resumed(joined back).
//
////////////////////////////////////////////////////////////////////////////
#define SEQ_GEN_NUM_PREPS 4
#define SEQ_UPD_TS_QRY_IDX 0
#define SEQ_SEL_TS_QRY_IDX 1
#define SEQ_PROCESS_QRY_IDX 2
#define SEQ_CQD_IDX 3
static Lng32 SeqGenCliInterfacePrepQry(
const char * qryStr,
Lng32 qryIdx,
const char * qryName,
ExeCliInterface ** cliInterfaceArr,
SequenceGeneratorAttributes* sga,
ContextCli &currContext,
ComDiagsArea & diags,
NAHeap *exHeap)
{
Lng32 cliRC = 0;
char query[2000];
char stmtName[200];
Int64 rowsAffected = 0;
ComDiagsArea *myDiags = NULL;
ExeCliInterface * cliInterface = NULL;
ExeCliInterface * cqdCliInterface = NULL;
NABoolean doPrep = FALSE;
if (! cliInterfaceArr[qryIdx])
{
str_sprintf(query, qryStr,
TRAFODION_SYSCAT_LIT, SEABASE_MD_SCHEMA, SEABASE_SEQ_GEN,
sga->getSGObjectUID().get_value());
cliInterfaceArr[qryIdx] = new (currContext.exHeap())
ExeCliInterface(currContext.exHeap(),
SQLCHARSETCODE_UTF8,
&currContext,
NULL);
if (! cliInterfaceArr[SEQ_CQD_IDX])
cliInterfaceArr[SEQ_CQD_IDX] = new (currContext.exHeap())
ExeCliInterface(currContext.exHeap(),
SQLCHARSETCODE_UTF8,
&currContext,
NULL);
str_sprintf(stmtName, "%s_%ld", qryName, sga->getSGObjectUID().get_value());
doPrep = TRUE;
}
cliInterface = cliInterfaceArr[qryIdx];
cqdCliInterface = cliInterfaceArr[SEQ_CQD_IDX];
if (doPrep)
{
cliRC = cqdCliInterface->holdAndSetCQD("limit_max_numeric_precision", "ON");
if (cliRC < 0)
{
if (myDiags == NULL)
myDiags = ComDiagsArea::allocate(exHeap);
cqdCliInterface->retrieveSQLDiagnostics(myDiags);
diags.mergeAfter(*myDiags);
myDiags->decrRefCount();
return cliRC;
}
cliRC = cliInterface->executeImmediatePrepare(query,
NULL, 0,
&rowsAffected, FALSE,
stmtName);
if (cliRC < 0)
{
if (myDiags == NULL)
myDiags = ComDiagsArea::allocate(exHeap);
cliInterface->retrieveSQLDiagnostics(myDiags);
diags.mergeAfter(*myDiags);
myDiags->decrRefCount();
cqdCliInterface->restoreCQD("limit_max_numeric_precision");
return cliRC;
}
cqdCliInterface->restoreCQD("limit_max_numeric_precision");
}
return 0;
}
//static Int64 globalUID = 0;
static Lng32 SeqGenCliInterfaceUpdAndValidate(
ExeCliInterface ** cliInterfaceArr,
SequenceGeneratorAttributes* sga,
NABoolean recycleQry,
NABoolean startLocalXn,
ContextCli &currContext,
ComDiagsArea & diags,
NAHeap *exHeap,
Int64 &nextValue,
Int64 &endValue)
{
Lng32 cliRC;
Int64 outputValues[5];
Int64 inputValues[5];
Lng32 outputValuesLen = 0;
Lng32 inputValuesLen = 0;
Int64 rowsAffected = 0;
ExeCliInterface * cliInterface = NULL;
ComDiagsArea *myDiags = NULL;
char queryBuf[2000];
Int64 updUID = 0;
if (NOT startLocalXn)
{
if (! cliInterfaceArr[SEQ_UPD_TS_QRY_IDX])
{
cliRC = SeqGenCliInterfacePrepQry(
"update %s.\"%s\".%s set upd_ts = cast(? as largeint not null) where seq_uid = %ld",
SEQ_UPD_TS_QRY_IDX,
"SEQ_UPD_TS_QRY_IDX",
cliInterfaceArr, sga, currContext, diags, exHeap);
if (cliRC < 0)
return cliRC;
}
cliInterface = cliInterfaceArr[SEQ_UPD_TS_QRY_IDX];
// generated a unique id and update it. If this value changes later, then
// this operation will be retried.
ComUID comUID;
comUID.make_UID();
updUID = comUID.get_value();
inputValues[0] = updUID;
inputValuesLen = sizeof(updUID);
cliRC = cliInterface->clearExecFetchCloseOpt
((char*)inputValues, inputValuesLen, NULL, NULL, &rowsAffected);
if (cliRC < 0)
{
if (myDiags == NULL)
myDiags = ComDiagsArea::allocate(exHeap);
cliInterface->retrieveSQLDiagnostics(myDiags);
diags.mergeAfter(*myDiags);
myDiags->decrRefCount();
return cliRC;
}
// if not found, aqr
if (rowsAffected == 0)
{
ComDiagsArea * da = &diags;
ExRaiseSqlError(exHeap, &da, (ExeErrorCode)(1584));
return -1584;
}
}
if (! cliInterfaceArr[SEQ_PROCESS_QRY_IDX])
{
cliRC = SeqGenCliInterfacePrepQry(
"select case when cast(? as largeint not null) = 1 then t.startVal else t.nextValue end, t.redefTS from (update %s.\"%s\".%s set next_value = (case when cast(? as largeint not null) = 1 then start_value + cast(? as largeint not null) else (case when next_value + cast(? as largeint not null) > max_value then max_value+1 else next_value + cast(? as largeint not null) end) end), num_calls = num_calls + 1 where seq_uid = %ld return old.start_value, old.next_value, old.redef_ts) t(startVal, nextValue, redefTS);",
SEQ_PROCESS_QRY_IDX,
"SEQ_PROCESS_QRY_IDX",
cliInterfaceArr, sga, currContext, diags, exHeap);
if (cliRC < 0)
return cliRC;
}
cliInterface = cliInterfaceArr[SEQ_PROCESS_QRY_IDX];
// execute using optimized path
Int64 delta = sga->getSGIncrement() *
(sga->getSGCache() > 0 ? sga->getSGCache() : 1);
inputValues[0] = (recycleQry ? 1 : 0);
inputValues[1] = (recycleQry ? 1 : 0);
inputValues[2] = delta;
inputValues[3] = delta;
inputValues[4] = delta;
inputValuesLen = 5 * sizeof(Int64);
cliRC = cliInterface->clearExecFetchCloseOpt
((char*)inputValues, inputValuesLen, (char*)outputValues, &outputValuesLen,
&rowsAffected);
if (cliRC < 0)
{
if (myDiags == NULL)
myDiags = ComDiagsArea::allocate(exHeap);
cliInterface->retrieveSQLDiagnostics(myDiags);
diags.mergeAfter(*myDiags);
myDiags->decrRefCount();
if (diags.mainSQLCODE() == -EXE_NUMERIC_OVERFLOW)
{
cliRC = -EXE_SG_MAXVALUE_EXCEEDED;
}
return cliRC;
}
// must find this uid in seq generator. if not found, aqr.
if (rowsAffected == 0)
{
ComDiagsArea * da = &diags;
ExRaiseSqlError(exHeap, &da, (ExeErrorCode)(1584));
return -1584;
}
Int64 startValue = outputValues[0];
Int64 redefTS = outputValues[1];
// if timestamp mismatch, aqr
if (redefTS != sga->getSGRedefTime())
{
ComDiagsArea * da = &diags;
ExRaiseSqlError(exHeap, &da, (ExeErrorCode)(1584));
return -1584;
}
if (NOT startLocalXn)
{
// this query retrieves upd_ts after this seqgen has been updated.
// it is used to validate that it didn't get updated by someone else
// after my update.
if (! cliInterfaceArr[SEQ_SEL_TS_QRY_IDX])
{
cliRC = SeqGenCliInterfacePrepQry(
"select upd_ts from %s.\"%s\".%s where seq_uid = %ld",
SEQ_SEL_TS_QRY_IDX,
"SEQ_SEL_TS_QRY_IDX",
cliInterfaceArr, sga, currContext, diags, exHeap);
if (cliRC < 0)
return cliRC;
}
cliInterface = cliInterfaceArr[SEQ_SEL_TS_QRY_IDX];
cliRC = cliInterface->clearExecFetchCloseOpt
(NULL, 0, (char*)outputValues, &outputValuesLen, &rowsAffected);
if (cliRC < 0)
{
if (myDiags == NULL)
myDiags = ComDiagsArea::allocate(exHeap);
cliInterface->retrieveSQLDiagnostics(myDiags);
diags.mergeAfter(*myDiags);
myDiags->decrRefCount();
return cliRC;
}
// must find this uid in seq generator. if not found, is an error.
if (rowsAffected == 0)
{
ComDiagsArea * da = &diags;
ExRaiseSqlError(exHeap, &da, (ExeErrorCode)(1582));
return -1582;
}
// if update time different than my upd time, retry.
if (outputValues[0] != updUID)
{
return -2;
}
}
nextValue = startValue;
endValue = nextValue + sga->getSGIncrement() * (sga->getSGCache() - 1);
if (endValue > sga->getSGMaxValue())
endValue = sga->getSGMaxValue();
return 0;
}
static Lng32 SeqGenCliInterfaceUpdAndValidateMulti(
ExeCliInterface ** cliInterfaceArr,
SequenceGeneratorAttributes* sga,
NABoolean recycleQry,
ContextCli &currContext,
ComDiagsArea & diags,
NAHeap *exHeap,
Int64 &nextValue,
Int64 &endValue)
{
Lng32 cliRC = 0;
Lng32 retCliRC = 0;
ComDiagsArea *myDiags = NULL;
if (! cliInterfaceArr[SEQ_CQD_IDX])
cliInterfaceArr[SEQ_CQD_IDX] = new (currContext.exHeap())
ExeCliInterface(currContext.exHeap(),
SQLCHARSETCODE_UTF8,
&currContext,
NULL);
ExeCliInterface * cqdCliInterface = cliInterfaceArr[SEQ_CQD_IDX];
NABoolean startLocalXn = FALSE;
if (cqdCliInterface->statusXn())
{
// no xn in progress. Start one.
startLocalXn = TRUE;
}
else
{
// a transaction is already running. Do not run seq queries as part of
// that transaction.
cliRC = cqdCliInterface->holdAndSetCQD("traf_no_dtm_xn", "ON");
}
Lng32 numTries = 0, maxRetryNum = sga->getSGRetryNum();
NABoolean isOk = FALSE;
while ((NOT isOk) && (numTries < maxRetryNum))
{
if (startLocalXn)
{
// no xn in progress. Start one.
cliRC = cqdCliInterface->beginWork();
if (cliRC < 0)
{
if (myDiags == NULL)
myDiags = ComDiagsArea::allocate(exHeap);
cqdCliInterface->retrieveSQLDiagnostics(myDiags);
diags.mergeAfter(*myDiags);
myDiags->decrRefCount();
retCliRC = cliRC;
goto label_return;
}
}
cliRC = SeqGenCliInterfaceUpdAndValidate(
cliInterfaceArr,
sga,
recycleQry,
startLocalXn,
currContext,
diags,
exHeap,
nextValue,
endValue);
if (cliRC == 0)
{
if (startLocalXn)
{
// xn was started here, commit it.
// If an error happens during commit, retry.
cliRC = cqdCliInterface->commitWork();
if (cliRC < 0)
{
currContext.diags().clear();
cliRC = -2; // retry
}
}
}
else
{
if (startLocalXn)
{
if (cqdCliInterface->statusXn() == 0) // xn running
{
// error case. If xn was started here, abort it.
cqdCliInterface->rollbackWork();
}
}
}
if (cliRC == 0)
{
isOk = TRUE;
}
else if (cliRC != -2)
{
retCliRC = cliRC;
goto label_return;
}
numTries++;
Lng32 delayTime = 100 + numTries*25 + rand()%10;
if( delayTime < 1000) //MAX is 1 second
DELAY(delayTime);
else
DELAY( 900 + rand() % 100);
}
// could not update it after 10 tries. Return error.
if (NOT isOk)
{
ComDiagsArea * da = &diags;
ExRaiseSqlError(exHeap, &da, (ExeErrorCode)(1583));
retCliRC = -1583;
goto label_return;
}
label_return:
if (NOT startLocalXn)
cliRC = cqdCliInterface->restoreCQD("traf_no_dtm_xn");
return retCliRC;
}
Lng32 SQLCLI_SeqGenCliInterface
(
CliGlobals *cliGlobals,
void ** inCliInterfaceArr,
void * seqGenAttrs
)
{
Lng32 rc = 0;
Lng32 cliRC = 0;
ContextCli & currContext = *(cliGlobals->currContext());
ComDiagsArea & diags = currContext.diags();
ExeCliInterface ** cliInterfaceArr = NULL;
if (inCliInterfaceArr && (*inCliInterfaceArr))
{
cliInterfaceArr = (ExeCliInterface**)(*inCliInterfaceArr);
}
else
{
cliInterfaceArr = new(currContext.exHeap()) ExeCliInterface*[SEQ_GEN_NUM_PREPS];
for (Lng32 i = 0; i < SEQ_GEN_NUM_PREPS; i++)
{
cliInterfaceArr[i] = NULL;
}
if (inCliInterfaceArr)
*inCliInterfaceArr = cliInterfaceArr;
}
SequenceGeneratorAttributes* sga = (SequenceGeneratorAttributes*)seqGenAttrs;
Int64 nextValue = 0;
Int64 endValue = 0;
cliRC = SeqGenCliInterfaceUpdAndValidateMulti(
cliInterfaceArr,
sga,
FALSE,
currContext,
diags,
currContext.exHeap(),
nextValue,
endValue);
if (cliRC < 0) {
return cliRC;
}
if ((sga->getSGCycleOption()) &&
(nextValue > sga->getSGMaxValue()))
{
cliRC = SeqGenCliInterfaceUpdAndValidateMulti(
cliInterfaceArr,
sga,
TRUE,
currContext,
diags,
currContext.exHeap(),
nextValue,
endValue);
if (cliRC < 0) {
return cliRC;
}
}
sga->setSGNextValue(nextValue);
sga->setSGEndValue(endValue);
return 0;
}
Int32 SQLCLI_GetRoutine
(
/* IN */ CliGlobals *cliGlobals,
/* IN */ const char *serializedInvocationInfo,
/* IN */ Int32 invocationInfoLen,
/* IN */ const char *serializedPlanInfo,
/* IN */ Int32 planInfoLen,
/* IN */ Int32 language,
/* IN */ Int32 paramStyle,
/* IN */ const char *externalName,
/* IN */ const char *containerName,
/* IN */ const char *externalPath,
/* IN */ const char *librarySqlName,
/* OUT */ Int32 *handle
)
{
Lng32 cliRC = 0;
ContextCli & currContext = *(cliGlobals->currContext());
ComDiagsArea & diags = currContext.diags();
LmLanguageManager *lm = cliGlobals->getLanguageManager(
(ComRoutineLanguage) language);
LmRoutine *createdRoutine = NULL;
LmResult lmres = LM_ERR;
*handle = NullCliRoutineHandle;
if (lm)
lmres = lm->getObjRoutine(
serializedInvocationInfo,
invocationInfoLen,
serializedPlanInfo,
planInfoLen,
(ComRoutineLanguage) language,
(ComRoutineParamStyle) paramStyle,
externalName,
containerName,
externalPath,
librarySqlName,
&createdRoutine,
&diags);
if (lmres == LM_OK && createdRoutine != NULL)
{
// At the moment we don't set any callback pointers for getRow/emitRow,
// so the object we are getting can't be used to call the runtime interface,
// only compile-time calls will work.
// createdRoutine->setFunctionPtrs(TBD, TBD);
// assign a CLI handle to the routine and remember it in the context
*handle = (Int32) currContext.addTrustedRoutine(createdRoutine);
}
else
{
cliRC = diags.mainSQLCODE();
if (lmres == LM_OK &&
cliRC >= 0 &&
invocationInfoLen == 0)
// The DDL code calls getRoutine to validate the routine
// entry point. It does not specify an InvocationInfo and
// therefore no routine is created, due to insufficient
// info. Indicate this through this special warning code.
// Note: No diags area is set, since this is an expected
// code.
cliRC = LME_ROUTINE_VALIDATED;
else
ex_assert(cliRC < 0, "no diags from getObjRoutine");
}
return cliRC;
}
Int32 SQLCLI_InvokeRoutine
(
/* IN */ CliGlobals *cliGlobals,
/* IN */ Int32 handle,
/* IN */ Int32 phaseEnumAsInt,
/* IN */ const char *serializedInvocationInfo,
/* IN */ Int32 invocationInfoLen,
/* OUT */ Int32 *invocationInfoLenOut,
/* IN */ const char *serializedPlanInfo,
/* IN */ Int32 planInfoLen,
/* IN */ Int32 planNum,
/* OUT */ Int32 *planInfoLenOut,
/* IN */ char *inputRow,
/* IN */ Int32 inputRowLen,
/* OUT */ char *outputRow,
/* IN */ Int32 outputRowLen
)
{
Lng32 cliRC = 0;
ContextCli &currContext = *(cliGlobals->currContext());
ComDiagsArea &diags = currContext.diags();
LmResult res = LM_ERR;
LmRoutine *lmRoutine = cliGlobals->currContext()->findTrustedRoutine(handle);
if (lmRoutine)
res = lmRoutine->invokeRoutineMethod(
static_cast<tmudr::UDRInvocationInfo::CallPhase>(phaseEnumAsInt),
serializedInvocationInfo,
invocationInfoLen,
invocationInfoLenOut,
serializedPlanInfo,
planInfoLen,
planNum,
planInfoLenOut,
inputRow,
inputRowLen,
outputRow,
outputRowLen,
&diags);
if (res != LM_OK)
{
cliRC = diags.mainSQLCODE();
if (cliRC >= 0)
{
// make sure the diags area indicates an error
cliRC = -CLI_ROUTINE_INVOCATION_ERROR;
diags << DgSqlCode(cliRC);
}
}
return cliRC;
}
Int32 SQLCLI_GetRoutineInvocationInfo
(
/* IN */ CliGlobals *cliGlobals,
/* IN */ Int32 handle,
/* IN/OUT */ char *serializedInvocationInfo,
/* IN */ Int32 invocationInfoMaxLen,
/* OUT */ Int32 *invocationInfoLenOut,
/* IN/OUT */ char *serializedPlanInfo,
/* IN */ Int32 planInfoMaxLen,
/* IN */ Int32 planNum,
/* OUT */ Int32 *planInfoLenOut
)
{
Lng32 cliRC = 0;
ContextCli &currContext = *(cliGlobals->currContext());
ComDiagsArea &diags = currContext.diags();
LmResult res = LM_ERR;
LmRoutine *lmRoutine = cliGlobals->currContext()->findTrustedRoutine(handle);
if (lmRoutine)
res = lmRoutine->getRoutineInvocationInfo(
serializedInvocationInfo,
invocationInfoMaxLen,
invocationInfoLenOut,
serializedPlanInfo,
planInfoMaxLen,
planNum,
planInfoLenOut,
&diags);
if (res != LM_OK)
{
cliRC = diags.mainSQLCODE();
if (cliRC >= 0)
{
cliRC = -CLI_ROUTINE_INVOCATION_INFO_ERROR;
diags << DgSqlCode(cliRC);
}
}
return cliRC;
}
Int32 SQLCLI_PutRoutine
(
/* IN */ CliGlobals *cliGlobals,
/* IN */ Int32 handle
)
{
if (handle != NullCliRoutineHandle)
cliGlobals->currContext()->putTrustedRoutine(handle);
return 0;
}