blob: 59280887b32cc57a69806341e6f2956b7a662449 [file] [log] [blame]
/**********************************************************************
// @@@ START COPYRIGHT @@@
//
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
//
// @@@ END COPYRIGHT @@@
**********************************************************************/
/* -*-C++-*-
*****************************************************************************
*
* File: ExExeUtilCli.cpp
* Description:
*
*
* Language: C++
*
*
*
*
*****************************************************************************
*/
//#include "ComCextdecs.h"
#include "cli_stdh.h"
#include "ex_stdh.h"
#include "sql_id.h"
#include "ComSqlId.h"
#include "ExExeUtilCli.h"
OutputInfo::OutputInfo(Lng32 numEntries)
: numEntries_(numEntries)
{
ex_assert( numEntries <= MAX_OUTPUT_ENTRIES, "try to fetch more than max columns allowed");
for (Int32 i = 0; i < numEntries_; i++)
{
data_[i] = NULL;
len_[i] = 0;
}
}
void OutputInfo::insert(Lng32 index, char * data)
{
data_[index] = data;
}
void OutputInfo::insert(Lng32 index, char * data, Lng32 len)
{
data_[index] = data;
len_[index] = len;
}
void OutputInfo::insert(Lng32 index, char * data, Lng32 len, Lng32 type, Lng32 *indOffset , Lng32 *varOffset )
{
data_[index] = data;
len_[index] = len;
type_[index] = type;
}
char * OutputInfo::get(Lng32 index)
{
if (index < numEntries_)
return data_[index];
else
return NULL;
}
short OutputInfo::get(Lng32 index, char* &data, Lng32 &len)
{
if (index < numEntries_)
{
data = data_[index];
len = len_[index];
return 0;
}
return -1;
}
short OutputInfo::get(Lng32 index, char* &data, Lng32 &len, Lng32 &type, Lng32 *indOffset , Lng32 *varOffset )
{
if (index < numEntries_)
{
data = data_[index];
len = len_[index];
type = type_[index];
return 0;
}
return -1;
}
void OutputInfo::dealloc(CollHeap * heap)
{
for (Int32 i = 0; i < numEntries_; i++)
{
if(data_[i] != NULL)
NADELETEBASIC(data_[i], heap);
}
}
/////////////////////////////////////////////////////////////////
// class ExeCliInterface
/////////////////////////////////////////////////////////////////
ExeCliInterface::ExeCliInterface(CollHeap * heap, Int32 isoMapping,
ContextCli * currContext,
const char *parentQid)
: heap_(heap),
module_(NULL),
stmt_(NULL),
sql_src_(NULL),
input_desc_(NULL),
output_desc_(NULL),
rs_input_maxsize_desc_(NULL),
outputBuf_(NULL),
inputBuf_(NULL),
currContext_(currContext),
moduleWithCK_(NULL),
stmtWithCK_(NULL),
sql_src_withCK_(NULL),
input_desc_withCK_(NULL),
output_desc_withCK_(NULL),
outputBuf_withCK_(NULL),
rsInputBuffer_(NULL),
isoMapping_((Int32)SQLCHARSETCODE_ISO88591), // ISO_MAPPING=ISO88591
parentQid_(parentQid),
inputAttrs_(NULL),
outputAttrs_(NULL),
explainData_(NULL),
explainDataLen_(0),
flags_(0)
{
if (parentQid_)
{
Int32 len = str_len(parentQid_);
ex_assert( len >= ComSqlId::MIN_QUERY_ID_LEN, "parentQid too short.");
ex_assert( len <= ComSqlId::MAX_QUERY_ID_LEN, "parentQid too long.");
ex_assert( !str_cmp(parentQid_, COM_SESSION_ID_PREFIX, 4),
"invalid parentQid.");
}
}
ExeCliInterface::~ExeCliInterface()
{
dealloc();
}
Lng32 ExeCliInterface::deallocStuff(SQLMODULE_ID * &module,
SQLSTMT_ID * &stmt,
SQLDESC_ID * &sql_src,
SQLDESC_ID * &input_desc,
SQLDESC_ID * &output_desc)
{
if (sql_src)
{
SQL_EXEC_DeallocDesc(sql_src);
NADELETEBASIC(sql_src, heap_);
sql_src = NULL;
}
if (stmt)
{
SQL_EXEC_DeallocStmt(stmt);
NADELETEBASIC(stmt, heap_);
stmt = NULL;
}
if (input_desc)
{
SQL_EXEC_DeallocDesc(input_desc);
NADELETEBASIC(input_desc, heap_);
input_desc = NULL;
}
if (output_desc)
{
SQL_EXEC_DeallocDesc(output_desc);
NADELETEBASIC(output_desc, heap_);
output_desc = NULL;
}
if (module)
{
NADELETEBASIC(module, heap_);
module = NULL;
}
if (rsInputBuffer_)
{
NADELETEBASIC(rsInputBuffer_, heap_);
rsInputBuffer_ = NULL;
}
if (outputAttrs_)
{
NADELETEBASIC(outputAttrs_, heap_);
outputAttrs_ = NULL;
}
if (outputBuf_)
{
NADELETEBASIC(outputBuf_, heap_);
outputBuf_ = NULL;
}
return 0;
}
Lng32 ExeCliInterface::dealloc()
{
return deallocStuff(module_, stmt_, sql_src_, input_desc_, output_desc_);
}
void ExeCliInterface::clearGlobalDiags()
{
SQL_EXEC_ClearDiagnostics(NULL);
}
Lng32 ExeCliInterface::allocStuff(SQLMODULE_ID * &module,
SQLSTMT_ID * &stmt,
SQLDESC_ID * &sql_src,
SQLDESC_ID * &input_desc,
SQLDESC_ID * &output_desc,
const char * stmtName
)
{
Lng32 retcode = 0;
deallocStuff(module, stmt, sql_src, input_desc, output_desc);
clearGlobalDiags();
module = new(heap_) SQLMODULE_ID;
init_SQLMODULE_ID(module);
// Allocate a SQL statement
stmt = new(heap_) SQLSTMT_ID;
if (stmtName)
{
init_SQLSTMT_ID(stmt, SQLCLI_CURRENT_VERSION, stmt_name, module);
stmt->identifier =
new(heap_) char[strlen(stmtName) +1];
strcpy((char*)stmt->identifier, stmtName);
stmt->identifier_len = (Lng32)strlen(stmtName);
}
else
init_SQLSTMT_ID(stmt, SQLCLI_CURRENT_VERSION, stmt_handle, module);
retcode = SQL_EXEC_AllocStmt(stmt, 0);
if (retcode < 0)
return retcode;
// Allocate a descriptor which will hold the SQL statement source
sql_src = new(heap_) SQLSTMT_ID;
init_SQLDESC_ID(sql_src, SQLCLI_CURRENT_VERSION, desc_handle, module);
retcode = SQL_EXEC_AllocDesc(sql_src, 1);
if (retcode < 0)
return retcode;
retcode = SQL_EXEC_SetDescItem(sql_src, 1, SQLDESC_TYPE_FS,
REC_BYTE_V_ANSI, 0);
if (retcode < 0)
return retcode;
// Allocate a descriptor which will hold the SQL statement input
input_desc = new(heap_) SQLSTMT_ID;
init_SQLDESC_ID(input_desc, SQLCLI_CURRENT_VERSION, desc_handle, module);
retcode = SQL_EXEC_AllocDesc(input_desc, 1);
if (retcode < 0)
return retcode;
// Allocate a descriptor which will hold the SQL statement output
output_desc = new(heap_) SQLSTMT_ID;
init_SQLDESC_ID(output_desc, SQLCLI_CURRENT_VERSION, desc_handle, module);
retcode = SQL_EXEC_AllocDesc(output_desc, 1);
if (retcode < 0)
return retcode;
return 0;
}
Lng32 ExeCliInterface::prepare(const char * stmtStr,
SQLMODULE_ID * module,
SQLSTMT_ID * stmt,
SQLDESC_ID * sql_src,
SQLDESC_ID * input_desc,
SQLDESC_ID * output_desc,
char ** outputBuf,
Queue * outputVarPtrList,
char ** inputBuf,
Queue * inputVarPtrList,
char *uniqueStmtId,
Lng32 *uniqueStmtIdLen,
SQL_QUERY_COST_INFO *query_cost_info,
SQL_QUERY_COMPILER_STATS_INFO *comp_stats_info,
NABoolean monitorThis,
NABoolean doNotCachePlan)
{
Lng32 retcode = 0;
ULng32 prepFlags = 0;
SQL_QUERY_COST_INFO local_query_cost_info;
SQL_QUERY_COMPILER_STATS_INFO local_comp_stats_info;
if (monitorThis)
prepFlags |= PREPARE_MONITOR_THIS_QUERY;
if ((currContext_) && (currContext_->getSessionDefaults()))
{
if(currContext_->getSessionDefaults()->callEmbeddedArkcmp())
prepFlags |= PREPARE_USE_EMBEDDED_ARKCMP;
}
if (doNotCachePlan)
{
prepFlags |= PREPARE_NO_TEXT_CACHE;
prepFlags |= PREPARE_DONT_CACHE;
}
retcode = SQL_EXEC_SetDescItem(sql_src, 1, SQLDESC_LENGTH,
strlen(stmtStr) + 1, 0);
if (retcode != SUCCESS)
return retcode;
retcode = SQL_EXEC_SetDescItem(sql_src, 1, SQLDESC_VAR_PTR,
(Long)stmtStr, 0);
if (retcode != SUCCESS)
return retcode;
retcode = SQL_EXEC_SetDescItem(sql_src, 1, SQLDESC_CHAR_SET,
(Int32)SQLCHARSETCODE_UTF8,0);
if (retcode != SUCCESS)
return retcode;
char parentQid[ComSqlId::MAX_QUERY_ID_LEN + 1];
char *pQidPtr = NULL;
if (parentQid_)
{
// The parentQid_ is a const char *, but the CLI doesn't
// want a const char * arg, so convert it safely here.
memset(parentQid, 0, sizeof(parentQid));
memcpy(parentQid, parentQid_, ComSqlId::MAX_QUERY_ID_LEN);
pQidPtr = parentQid;
}
retcode = SQL_EXEC_SetStmtAttr(stmt, SQL_ATTR_PARENT_QID, 0, pQidPtr);
if (retcode < 0)
return retcode;
// set parserflags to indicate that this is an internal query from exeutil
NABoolean flagWasSetHere = FALSE;
if (currContext_)
{
if (((currContext_->getSqlParserFlags() & 0x20000) == 0) &&
(NOT notExeUtilInternalQuery())) // this is an exeutil internal query. This is the default.
{
flagWasSetHere = TRUE;
currContext_->setSqlParserFlags(0x20000); // INTERNAL_QUERY_FROM EXEUTIL
}
}
if (uniqueStmtId == NULL)
retcode = SQL_EXEC_Prepare2(stmt, sql_src,NULL,0,NULL,
(query_cost_info?query_cost_info:&local_query_cost_info),
(comp_stats_info?comp_stats_info:&local_comp_stats_info),
NULL,0,prepFlags);
else
{
prepFlags |= PREPARE_STANDALONE_QUERY;
retcode = SQL_EXEC_Prepare2(stmt, sql_src, NULL, 0, NULL,
(query_cost_info?query_cost_info:&local_query_cost_info),
(comp_stats_info?comp_stats_info:&local_comp_stats_info),
uniqueStmtId, uniqueStmtIdLen, prepFlags);
}
// reset internal exeutil query parserflags if it was set in this method.
if ((currContext_) && (flagWasSetHere))
currContext_->resetSqlParserFlags(0x20000); // INTERNAL_QUERY_FROM EXEUTIL
// return the error code that was returned from SQL_EXEC_Prepare
if (retcode < 0)
return retcode;
// clear diagnostics to reset any warnings.
SQL_EXEC_ClearDiagnostics(NULL);
Lng32 num_input_entries, num_output_entries;
retcode = SQL_EXEC_DescribeStmt(stmt, input_desc, output_desc);
if (retcode != SUCCESS)
return retcode;
retcode = SQL_EXEC_GetDescEntryCount(input_desc, &num_input_entries);
if (retcode != SUCCESS)
return retcode;
retcode = SQL_EXEC_GetDescEntryCount(output_desc, &num_output_entries);
if (retcode != SUCCESS)
return retcode;
numInputEntries_ = num_input_entries;
numOutputEntries_ = num_output_entries;
inputAttrs_ = NULL;
outputAttrs_ = NULL;
if (numInputEntries_ > 0)
inputAttrs_ = (Attrs*) (new(heap_) char[sizeof(Attrs) * numInputEntries_]);
if (numOutputEntries_ > 0)
outputAttrs_ = (Attrs*) (new(heap_) char[sizeof(Attrs) * numOutputEntries_]);
short entry=1;
Lng32 datatype = 0;
Lng32 datacharset = 0;
Lng32 length = 0;
Lng32 null_flag = 0;
Lng32 dataOffset = -1;
Lng32 nullIndOffset = -1;
outputDatalen_ = 0;
inputDatalen_ = 0;
for (; entry <= num_output_entries; entry++)
{
retcode = SQL_EXEC_GetDescItem(output_desc, entry,
SQLDESC_TYPE_FS,
&datatype, 0, 0, 0, 0);
if (retcode != SUCCESS)
return retcode;
retcode = SQL_EXEC_GetDescItem(output_desc, entry,
SQLDESC_OCTET_LENGTH,
&length, 0, 0, 0, 0);
if (retcode != SUCCESS)
return retcode;
retcode = SQL_EXEC_GetDescItem(output_desc, entry,
SQLDESC_NULLABLE,
&null_flag, 0, 0, 0, 0);
if (retcode != SUCCESS)
return retcode;
retcode = SQL_EXEC_GetDescItem(output_desc, entry,
SQLDESC_CHAR_SET,
&datacharset, 0, 0, 0, 0);
if (retcode != SUCCESS)
return retcode;
outputDatalen_ += length;
if (null_flag)
outputDatalen_ += SQL_NULL_HDR_SIZE;
if (datatype == REC_BYTE_V_ASCII ||
datatype == REC_BYTE_V_ASCII_LONG ||
datatype == REC_BYTE_V_DOUBLE)
outputDatalen_ += SQL_VARCHAR_HDR_SIZE;
retcode = SQL_EXEC_GetDescItem(output_desc, entry,
SQLDESC_NULL_IND_OFFSET,
&nullIndOffset, 0, 0, 0, 0);
if (retcode != SUCCESS)
return retcode;
retcode = SQL_EXEC_GetDescItem(output_desc, entry,
SQLDESC_DATA_OFFSET,
&dataOffset, 0, 0, 0, 0);
if (retcode != SUCCESS)
return retcode;
outputAttrs_[entry-1].fsDatatype_ = datatype;
outputAttrs_[entry-1].length_ = length;
outputAttrs_[entry-1].nullFlag_ = null_flag;
outputAttrs_[entry-1].indOffset_ = nullIndOffset;
outputAttrs_[entry-1].varOffset_ = dataOffset;
}
if (outputBuf)
{
if ((*outputBuf == NULL) &&
(outputDatalen_ > 0))
*outputBuf = new (heap_) char[outputDatalen_];
Lng32 curpos = 0;
for (entry=1; entry <= num_output_entries; entry++)
{
retcode = SQL_EXEC_GetDescItem(output_desc, entry,
SQLDESC_NULLABLE,
&null_flag, 0, 0, 0, 0);
if (retcode != SUCCESS)
return retcode;
if (null_flag)
{
retcode = SQL_EXEC_SetDescItem(output_desc, entry,
SQLDESC_IND_PTR,
(Long)&(*outputBuf)[curpos],0);
if (retcode != SUCCESS)
return retcode;
curpos += SQL_NULL_HDR_SIZE;
}
retcode = SQL_EXEC_SetDescItem(output_desc, entry,
SQLDESC_VAR_PTR,
(Long)&(*outputBuf)[curpos],0);
if (retcode != SUCCESS)
return retcode;
retcode = SQL_EXEC_GetDescItem(output_desc, entry,
SQLDESC_OCTET_LENGTH,
&length, 0, 0, 0, 0);
if (outputVarPtrList)
{
outputVarPtrList->insert((char*) &(*outputBuf)[curpos]);
}
curpos += length;
retcode = SQL_EXEC_GetDescItem(output_desc, entry,
SQLDESC_TYPE_FS,
&datatype, 0, 0, 0, 0);
if (retcode != SUCCESS)
return retcode;
retcode = SQL_EXEC_GetDescItem(output_desc, entry,
SQLDESC_CHAR_SET,
&datacharset, 0, 0, 0, 0);
if (retcode != SUCCESS)
return retcode;
if (datatype == REC_BYTE_V_ASCII ||
datatype == REC_BYTE_V_ASCII_LONG ||
datatype == REC_BYTE_V_DOUBLE)
curpos += SQL_VARCHAR_HDR_SIZE;
}
}
entry=1;
inputDatalen_ = 0;
for (; entry <= num_input_entries; entry++)
{
Lng32 alignedLen = 0;
retcode = SQL_EXEC_GetDescItem(input_desc, entry,
SQLDESC_ALIGNED_LENGTH,
&alignedLen, 0, 0, 0, 0);
if (retcode != SUCCESS)
return retcode;
inputDatalen_ += alignedLen;
retcode = SQL_EXEC_GetDescItem(input_desc, entry,
SQLDESC_TYPE_FS,
&datatype, 0, 0, 0, 0);
if (retcode != SUCCESS)
return retcode;
retcode = SQL_EXEC_GetDescItem(input_desc, entry,
SQLDESC_OCTET_LENGTH,
&length, 0, 0, 0, 0);
if (retcode != SUCCESS)
return retcode;
retcode = SQL_EXEC_GetDescItem(input_desc, entry,
SQLDESC_NULLABLE,
&null_flag, 0, 0, 0, 0);
if (retcode != SUCCESS)
return retcode;
retcode = SQL_EXEC_GetDescItem(input_desc, entry,
SQLDESC_NULL_IND_OFFSET,
&nullIndOffset, 0, 0, 0, 0);
if (retcode != SUCCESS)
return retcode;
retcode = SQL_EXEC_GetDescItem(input_desc, entry,
SQLDESC_DATA_OFFSET,
&dataOffset, 0, 0, 0, 0);
if (retcode != SUCCESS)
return retcode;
inputAttrs_[entry-1].fsDatatype_ = datatype;
inputAttrs_[entry-1].length_ = length;
inputAttrs_[entry-1].nullFlag_ = null_flag;
inputAttrs_[entry-1].indOffset_ = nullIndOffset;
inputAttrs_[entry-1].varOffset_ = dataOffset;
}
if (inputBuf)
{
if ((*inputBuf == NULL) &&
(inputDatalen_ > 0))
*inputBuf = new (heap_) char[inputDatalen_];
Lng32 curpos = 0;
for (entry=1; entry <= num_input_entries; entry++)
{
retcode = SQL_EXEC_GetDescItem(input_desc, entry,
SQLDESC_NULL_IND_OFFSET,
&nullIndOffset, 0, 0, 0, 0);
if (retcode != SUCCESS)
return retcode;
retcode = SQL_EXEC_GetDescItem(input_desc, entry,
SQLDESC_DATA_OFFSET,
&dataOffset, 0, 0, 0, 0);
if (retcode != SUCCESS)
return retcode;
if (nullIndOffset >= 0)
{
retcode = SQL_EXEC_SetDescItem(input_desc, entry,
SQLDESC_IND_PTR,
(Long)&(*inputBuf)[nullIndOffset],0);
if (retcode != SUCCESS)
return retcode;
}
retcode = SQL_EXEC_SetDescItem(input_desc, entry,
SQLDESC_VAR_PTR,
(Long)&(*inputBuf)[dataOffset],0);
if (retcode != SUCCESS)
return retcode;
}
}
return 0;
}
Lng32 ExeCliInterface::setupExplainData(SQLMODULE_ID * module,
SQLSTMT_ID * stmt)
{
Lng32 retcode = 0;
if (explainData_)
NADELETEBASIC(explainData_, getHeap());
explainData_ = NULL;
explainDataLen_ = 0;
// get explain fragment.
explainDataLen_ = 50000; // start with 50K bytes
Int32 retExplainLen = 0;
explainData_ = new(getHeap()) char[explainDataLen_+1];
retcode = SQL_EXEC_GetExplainData(stmt,
explainData_, explainDataLen_+1,
&retExplainLen
);
if (retcode == -CLI_GENCODE_BUFFER_TOO_SMALL)
{
NADELETEBASIC(explainData_, getHeap());
explainDataLen_ = retExplainLen;
explainData_ = new(getHeap()) char[explainDataLen_ + 1];
retcode = SQL_EXEC_GetExplainData(stmt,
explainData_, explainDataLen_+1,
&retExplainLen
);
}
if (retcode != SUCCESS)
{
NADELETEBASIC(explainData_, getHeap());
explainData_ = NULL;
explainDataLen_ = 0;
return retcode;
}
explainDataLen_ = retExplainLen;
return retcode;
}
Lng32 ExeCliInterface::setupExplainData()
{
return setupExplainData(module_, stmt_);
}
Lng32 ExeCliInterface::exec(char * inputBuf, Lng32 inputBufLen)
{
Lng32 retcode = 0;
if (! stmt_)
{
return -CLI_STMT_NOT_EXISTS;
}
// set parserflags to indicate that this is an internal query from exeutil
NABoolean flagWasSetHere = FALSE;
if (currContext_)
{
if (((currContext_->getSqlParserFlags() & 0x20000) == 0) &&
(NOT notExeUtilInternalQuery())) // this is an exeutil internal query. This is the default.
{
flagWasSetHere = TRUE;
currContext_->setSqlParserFlags(0x20000); // INTERNAL_QUERY_FROM EXEUTIL
}
}
if ((inputBuf) && (inputBuf_) && (inputDatalen_ > 0) && (inputBufLen > 0))
memcpy(inputBuf_, inputBuf, MINOF(inputDatalen_, inputBufLen));
retcode = SQL_EXEC_Exec(stmt_, input_desc_, 0);
// reset internal exeutil query parserflags if it was set in this method.
if ((currContext_) && (flagWasSetHere))
currContext_->resetSqlParserFlags(0x20000); // INTERNAL_QUERY_FROM EXEUTIL
if (retcode != SUCCESS)
return retcode;
return retcode;
}
Lng32 ExeCliInterface::fetch()
{
Lng32 retcode = 0;
retcode = SQL_EXEC_Fetch(stmt_, output_desc_, 0);
if (retcode != SUCCESS)
return retcode;
return retcode;
}
//if indicator pointer is NULL, do not retrieve the indicator
//the datatype SQLTYPECODE... is added (the others did not work)
Lng32 ExeCliInterface::getPtrAndLen(short entry, char* &ptr, Lng32 &len, short**ind)
{
Long data_addr;
Lng32 datatype = 0;
Lng32 retcode;
Long ind_addr;
retcode = SQL_EXEC_GetDescItem(output_desc_, entry,
SQLDESC_VAR_PTR,
&data_addr, 0, 0, 0, 0);
if (retcode != SUCCESS)
return retcode;
retcode = SQL_EXEC_GetDescItem(output_desc_, entry,
SQLDESC_IND_PTR ,
&ind_addr, 0, 0, 0, 0);
if (retcode != SUCCESS)
return retcode;
if (ind != NULL)
*ind = (short*)ind_addr;
retcode = SQL_EXEC_GetDescItem(output_desc_, entry,
SQLDESC_TYPE,
&datatype, 0, 0, 0, 0);
if (retcode != SUCCESS)
return retcode;
retcode = SQL_EXEC_GetDescItem(output_desc_, entry,
SQLDESC_OCTET_LENGTH,
&len, 0, 0, 0, 0);
if (retcode != SUCCESS)
return retcode;
short *nullIndPtr = (short *)ind_addr;
if (nullIndPtr && *nullIndPtr < 0)
{
// without this test, when "showddl component sql_operations"
// ran some child query which returned a nullable column
// with a SQL NULL value, junk from data_addr was interpreted
// as a length and the caller of this method tried to allocate
// too many bytes.
len = 0;
}
else
if (datatype == REC_BYTE_V_ASCII ||
datatype == REC_BYTE_V_ASCII_LONG ||
datatype == REC_BYTE_V_DOUBLE ||
datatype == SQLTYPECODE_VARCHAR_WITH_LENGTH ||
datatype == SQLTYPECODE_VARCHAR_LONG ||
datatype == SQLTYPECODE_BLOB ||
datatype == SQLTYPECODE_CLOB
)
{
// Depending on value of len, first 2 or 4 bytes of data indicate
// the actual length -- adjust data and length
if (len & 0xFFFF8000)
{
Lng32 VClen;
str_cpy_all((char*)&VClen, (char*)data_addr, sizeof(Lng32));
data_addr += sizeof(Lng32);
len = VClen;
}
else
{
short VClen;
str_cpy_all((char*)&VClen, (char*)data_addr, sizeof(short));
data_addr += sizeof(short);
len = VClen;
}
}
ptr = (char*)data_addr;
return 0;
}
Lng32 ExeCliInterface::getHeadingAndLen(short entry, char* heading, Lng32 &len)
{
Lng32 retcode;
len = 0;
retcode = SQL_EXEC_GetDescItem(output_desc_, entry,
SQLDESC_HEADING,
0, heading,
ComMAX_1_PART_EXTERNAL_UTF8_NAME_LEN_IN_BYTES, &len, 0);
if (retcode != SUCCESS)
return retcode;
if (len == 0)
{
retcode = SQL_EXEC_GetDescItem(output_desc_, entry,
SQLDESC_NAME,
0, heading,
ComMAX_1_PART_EXTERNAL_UTF8_NAME_LEN_IN_BYTES/*CAT_MAX_HEADING_LEN*/, &len, 0);
if (retcode != SUCCESS)
return retcode;
}
return 0;
}
Lng32 ExeCliInterface::getNumEntries(Lng32 &numInput, Lng32 &numOutput)
{
Lng32 retcode = 0;
retcode = SQL_EXEC_GetDescEntryCount(input_desc_, &numInput);
if (retcode != SUCCESS)
return retcode;
retcode = SQL_EXEC_GetDescEntryCount(output_desc_, &numOutput);
if (retcode != SUCCESS)
return retcode;
return retcode;
}
Lng32 ExeCliInterface::getAttributes(short entry, NABoolean forInput,
Lng32 &fsDatatype, Lng32 &length,
Lng32 *indOffset, Lng32 *varOffset)
{
Lng32 retcode = 0;
if (forInput)
{
fsDatatype = inputAttrs_[entry-1].fsDatatype_;
length = inputAttrs_[entry-1].length_;
if (indOffset)
*indOffset = inputAttrs_[entry-1].indOffset_;
if (varOffset)
*varOffset = inputAttrs_[entry-1].varOffset_;
}
else
{
fsDatatype = outputAttrs_[entry-1].fsDatatype_;
length = outputAttrs_[entry-1].length_;
if (indOffset)
*indOffset = outputAttrs_[entry-1].indOffset_;
if (varOffset)
*varOffset = outputAttrs_[entry-1].varOffset_;
}
return retcode;
}
Lng32 ExeCliInterface::getDataOffsets(short entry, Lng32 forInput,
Lng32 *indOffset, Lng32 *varOffset)
{
Lng32 temp;
if (forInput)
{
if (inputAttrs_ && inputAttrs_[entry-1].varOffset_ && inputAttrs_[entry-1].indOffset_)
{
*varOffset = inputAttrs_[entry-1].varOffset_;
*indOffset = inputAttrs_[entry-1].indOffset_;
}
else
{
return getAttributes(entry, forInput, temp, temp,
indOffset, varOffset);
}
}
else
{
return getAttributes(entry, forInput, temp, temp,
indOffset, varOffset);
}
return 0;
}
Lng32 ExeCliInterface::getStmtAttr(char * stmtName, Lng32 attrName,
Lng32 * numeric_value, char * string_value)
{
Lng32 retcode = 0;
SQLMODULE_ID module;
init_SQLMODULE_ID(&module);
char stmtNameBuf[400];
SQLSTMT_ID stmt;
init_SQLSTMT_ID(&stmt, SQLCLI_CURRENT_VERSION, stmt_name, &module);
stmt.identifier = stmtNameBuf;
strcpy((char*)stmt.identifier, stmtName);
stmt.identifier_len = (Lng32)strlen(stmtName);
retcode = SQL_EXEC_GetStmtAttr(&stmt, attrName, numeric_value, string_value,
0, NULL);
return retcode;
}
Lng32 ExeCliInterface::close()
{
Lng32 retcode = 0;
if (stmt_)
{
retcode = SQL_EXEC_CloseStmt(stmt_);
if (retcode != SUCCESS)
return retcode;
}
return retcode;
}
Lng32 ExeCliInterface::executeImmediatePrepare(const char * stmtStr,
char * outputBuf,
Lng32 * outputBufLen,
Int64 * rowsAffected,
NABoolean monitorThis,
char * stmtName
)
{
Lng32 retcode = 0;
if (outputBufLen)
*outputBufLen = 0;
retcode = allocStuff(module_, stmt_, sql_src_, input_desc_, output_desc_,
stmtName);
if (retcode != SUCCESS)
return retcode;
retcode = prepare(stmtStr, module_, stmt_, sql_src_,
input_desc_, output_desc_, &outputBuf,NULL,&inputBuf_,
NULL,NULL,NULL,NULL,NULL,monitorThis);
if (retcode < 0)
{
deallocStuff(module_, stmt_, sql_src_, input_desc_, output_desc_);
return retcode;
}
return 0;
}
Lng32 ExeCliInterface::executeImmediatePrepare2(const char * stmtStr,
char *uniqueStmtId,
Lng32 *uniqueStmtIdLen,
SQL_QUERY_COST_INFO *query_cost_info,
SQL_QUERY_COMPILER_STATS_INFO *comp_stats_info,
char * outputBuf,
Lng32 * outputBufLen,
Int64 * rowsAffected,
NABoolean monitorThis
)
{
Lng32 retcode = 0;
if (outputBufLen)
*outputBufLen = 0;
retcode = allocStuff(module_, stmt_, sql_src_, input_desc_, output_desc_);
if (retcode != SUCCESS)
return retcode;
retcode = prepare(stmtStr, module_, stmt_, sql_src_,
input_desc_, output_desc_, &outputBuf, NULL, NULL, NULL,
uniqueStmtId, uniqueStmtIdLen, query_cost_info, comp_stats_info,monitorThis);
if (retcode < 0)
{
deallocStuff(module_, stmt_, sql_src_, input_desc_, output_desc_);
return retcode;
}
return 0;
}
Lng32 ExeCliInterface::executeImmediateExec(const char * stmtStr,
char * outputBuf,
Lng32 * outputBufLen,
NABoolean nullTerminate,
Int64 * rowsAffected,
ComDiagsArea **diagsArea)
{
Lng32 retcode = 0;
Lng32 diagsCount = 0;
retcode = exec();
if (retcode < 0)
{
deallocStuff(module_, stmt_, sql_src_, input_desc_, output_desc_);
goto ExecReturn;
}
retcode = fetch();
if (retcode < 0)
{
deallocStuff(module_, stmt_, sql_src_, input_desc_, output_desc_);
goto ExecReturn;
}
if ((outputBuf) &&
(outputBufLen))
{
*outputBufLen = 0;
if (retcode != 100)
{
char * ptr;
Lng32 len;
getPtrAndLen(1, ptr, len);
str_cpy_all(outputBuf, ptr, len);
if (nullTerminate)
outputBuf[len] = 0;
*outputBufLen = len;
}
}
Lng32 rc;
if (retcode >= 0)
{
if (rowsAffected)
{
Int64 tmpRowsAffected = 0;
rc = SQL_EXEC_GetDiagnosticsStmtInfo2(NULL, SQLDIAG_ROW_COUNT,
&tmpRowsAffected, NULL,
0, NULL);
if (rc == EXE_NUMERIC_OVERFLOW)
{
GetRowsAffected(rowsAffected);
}
else
*rowsAffected = tmpRowsAffected;
}
rc = SQL_EXEC_GetDiagnosticsStmtInfo2(NULL, SQLDIAG_NUMBER,
&diagsCount, NULL, 0, NULL);
// No need to passback the warnings of SQL_NO_DATA (100)
if (retcode == 100)
diagsCount--;
}
ExecReturn:
if (retcode < 0 || diagsCount > 0)
{
if (diagsArea != NULL)
{
if (*diagsArea == NULL)
*diagsArea = ComDiagsArea::allocate(heap_);
rc = SQL_EXEC_MergeDiagnostics_Internal(**diagsArea);
}
// if diagsArea is not passed in, retain the diagnostics info
// in ContextCli for it to be retrieved later
// But, deallocate the statement
else
{
rc = close();
deallocStuff(module_, stmt_, sql_src_, input_desc_, output_desc_);
return retcode;
}
}
rc = close();
deallocStuff(module_, stmt_, sql_src_, input_desc_, output_desc_);
clearGlobalDiags();
return retcode;
}
// When the globalDiags is not null, errors and warnings are
// passed to the caller. If *globalsDiags points to NULL,
// allocate ComDiagsArea and pass back the error or warnings
// to the caller.
//
// If *globalDiags points to ComDiagsArea already, pass back
// the diagnostics conditions back to the caller after executing
// the stmtStr along with new errors or warnings.
Lng32 ExeCliInterface::executeImmediate(const char * stmtStr,
char * outputBuf,
Lng32 * outputBufLen,
NABoolean nullTerminate,
Int64 * rowsAffected,
NABoolean monitorThis,
ComDiagsArea **globalDiags)
{
Lng32 retcode = 0;
ComDiagsArea * tempDiags = NULL;
if (globalDiags != NULL && *globalDiags != NULL && (*globalDiags)->getNumber() > 0)
{
tempDiags = ComDiagsArea::allocate(heap_);
tempDiags->mergeAfter(**globalDiags);
}
clearGlobalDiags();
outputBuf_ = NULL;
inputBuf_ = NULL;
retcode = executeImmediatePrepare(stmtStr,
(nullTerminate ? outputBuf_ : outputBuf),
outputBufLen,
rowsAffected,monitorThis);
if (retcode < 0)
goto ExecuteImmediateReturn;
retcode = executeImmediateExec(stmtStr,
outputBuf, outputBufLen,
nullTerminate,
rowsAffected,
globalDiags);
ExecuteImmediateReturn:
if ((globalDiags))
{
// Allocate the diagnostics area if needed
// and populate the diagnostics conditions
if (*globalDiags == NULL && retcode != 0 && retcode != 100) {
*globalDiags = ComDiagsArea::allocate(getHeap());
SQL_EXEC_MergeDiagnostics_Internal(**globalDiags);
}
// populate the diagnostics conditons passed in
if (tempDiags)
(*globalDiags)->mergeAfter(*tempDiags);
}
if (tempDiags)
tempDiags->deAllocate();
return retcode;
}
short ExeCliInterface::fetchRowsPrologue(const char * sqlStrBuf,
NABoolean noExec,
NABoolean monitorThis,
char * stmtName)
{
Lng32 retcode;
clearGlobalDiags();
retcode = allocStuff(module_, stmt_, sql_src_, input_desc_, output_desc_,
stmtName);
if (retcode < 0)
{
//ex_assert(0, "Error in fetchRows");
return (short)retcode;
}
outputBuf_ = NULL;
inputBuf_ = NULL;
retcode = prepare(sqlStrBuf, module_, stmt_, sql_src_,
input_desc_, output_desc_, &outputBuf_, NULL,
&inputBuf_, NULL,NULL,NULL,NULL,NULL,monitorThis);
if (retcode < 0)
{
//ex_assert(0, "Error in fetchRows");
return (short)retcode;
}
if (NOT noExec)
{
retcode = exec();
if (retcode < 0)
{
//ex_assert(0, "Error in fetchRows");
return (short)retcode;
}
}
return 0;
}
short ExeCliInterface::fetchRowsEpilogue(const char * sqlStrBuf,
NABoolean noClose)
{
if (NOT noClose)
close();
deallocStuff(module_, stmt_, sql_src_, input_desc_, output_desc_);
if (NOT noClose)
SQL_EXEC_ClearDiagnostics(NULL);
return 0;
}
short ExeCliInterface::initializeInfoList(Queue* &infoList,
NABoolean infoListIsOutputInfo)
{
if (infoList)
{
infoList->position();
while (NOT infoList->atEnd())
{
if (infoListIsOutputInfo)
{
OutputInfo * r = (OutputInfo*)infoList->getCurr();
r->dealloc(getHeap());
}
else
{
char * c = (char*)infoList->getCurr();
NADELETEBASIC(c, getHeap());
}
infoList->advance();
}
NADELETE(infoList, Queue, getHeap());
}
infoList = new(getHeap()) Queue(getHeap());
return 0;
}
short ExeCliInterface::fetchAllRows(Queue * &infoList,
const char * query,
Lng32 inNumOutputEntries,
NABoolean varcharFormat,
NABoolean monitorThis,
NABoolean initInfoList)
{
short rc = 0;
Lng32 numOutputEntries = inNumOutputEntries;
if (initInfoList)
{
rc = initializeInfoList(infoList, TRUE);
if (rc < 0)
{
return rc;
}
}
rc = fetchRowsPrologue(query,FALSE,monitorThis);
if (rc < 0)
{
return rc;
}
NABoolean rowsFound = FALSE;
while ((rc >= 0) &&
(rc != 100))
{
rc = (short)fetch();
if (rc < 0)
{
fetchRowsEpilogue(0, TRUE);
return rc;
}
if (rc == 100)
continue;
rowsFound = TRUE;
if (numOutputEntries == -1)
{
char * ob = new(getHeap()) char[outputDatalen()];
str_cpy_all(ob, outputBuf(),
outputDatalen());
infoList->insert(ob);
}
else
{
if (numOutputEntries == 0)
numOutputEntries = numOutputEntries_;
OutputInfo * oi = new(getHeap()) OutputInfo(numOutputEntries);
for (Int32 j = 0; j < numOutputEntries; j++)
{
char * ptr, *r;
Lng32 len;
Lng32 type;
short nulind=0;
short *indaddr=&nulind;
short **ind=&indaddr;
getAttributes(j+1, FALSE, type, len, NULL, NULL);
getPtrAndLen(j+1, ptr, len, ind);
NABoolean nullableCol = TRUE, isNullVal = FALSE;
if(*ind == NULL) // It is not a nullable value
isNullVal = FALSE;
else
{
if( ((char*)*ind)[0] == -1 ) // NULL value
isNullVal = TRUE;
}
if(isNullVal)
{
oi->insert(j, NULL, 0, type);
}
else
{
NABoolean nullTerminate =
DFS2REC::is8bitCharacter(outputAttrs_[j].fsDatatype_);
r = new(getHeap()) char
[(varcharFormat ? SQL_VARCHAR_HDR_SIZE : 0)
+ len + (nullTerminate ? 1 : 0)];
if (varcharFormat)
{
*(short*)r = (short)len;
str_cpy_all(&r[SQL_VARCHAR_HDR_SIZE], ptr, len);
if (nullTerminate)
r[SQL_VARCHAR_HDR_SIZE + len] = 0;
}
else
{
str_cpy_all(r, ptr, len);
if (nullTerminate)
r[len] = 0;
}
oi->insert(j, r, len, type);
}
}
infoList->insert(oi);
}
} // while
rc = fetchRowsEpilogue(0);
if (rc < 0)
{
return rc;
}
if (NOT rowsFound)
rc = 100;
return rc;
}
short ExeCliInterface::clearExecFetchClose(char * inputBuf,
Lng32 inputBufLen,
// ptr to buf where output values will be copied to.
// Caller need to allocate this.
char * outputBuf,
Lng32 * outputBufLen)
{
Lng32 retcode = 0;
SQL_EXEC_ClearDiagnostics(NULL);
retcode = exec(inputBuf, inputBufLen);
if (retcode < 0)
{
return (short)retcode;
}
retcode = fetch();
if (retcode < 0)
{
return (short)retcode;
}
if ((outputBuf) &&
(outputBufLen))
{
*outputBufLen = 0;
if (retcode != 100)
{
char * currPtr = outputBuf;
for (Int32 j = 0; j < numOutputEntries_; j++)
{
char * ptr;
Lng32 len;
getPtrAndLen(j+1, ptr, len);
str_cpy_all(currPtr, ptr, len);
currPtr += len;
*outputBufLen += len;
}
}
}
close();
if (retcode == 100)
fetchRowsEpilogue(NULL, TRUE);
return (short)retcode;
}
short ExeCliInterface::clearExecFetchCloseOpt(char * inputBuf,
Lng32 inputBufLen,
// ptr to buf where output values will be copied to.
// Caller need to allocate this.
char * outputBuf,
Lng32 * outputBufLen,
Int64 * rowsAffected)
{
Lng32 retcode = 0;
if (inputBuf)
{
if (inputDatalen_ < inputBufLen)
{
// input data will not fit in inputBuf_.
// return error.
return -EXE_STRING_OVERFLOW;
}
str_cpy_all(inputBuf_, inputBuf, inputBufLen);
}
if (rowsAffected)
*rowsAffected = 0;
retcode = SQL_EXEC_ClearExecFetchClose(
stmt_,
(numInputEntries_ > 0 ? input_desc_ : NULL),
(numOutputEntries_ > 0 ? output_desc_ : NULL),
0, 0, 0);
if ((retcode == 0) ||
((retcode >= 0) && (retcode != 100)))
{
if ((numOutputEntries_ > 0) &&
(outputBuf) &&
(outputBufLen))
{
*outputBufLen = 0;
char * currPtr = outputBuf;
for (Int32 j = 0; j < numOutputEntries_; j++)
{
char * ptr;
Lng32 len;
getPtrAndLen(j+1, ptr, len);
str_cpy_all(currPtr, ptr, len);
currPtr += len;
*outputBufLen += len;
}
if (rowsAffected)
{
*rowsAffected = 1;
}
} // values being returned
else if (rowsAffected)
{
Lng32 tmpRowsAffected = 0;
retcode = SQL_EXEC_GetDiagnosticsStmtInfo2(NULL, SQLDIAG_ROW_COUNT,
&tmpRowsAffected, NULL,
0, NULL);
if(retcode == EXE_NUMERIC_OVERFLOW) // rowsAffected > LONG_MAX
{
GetRowsAffected(rowsAffected);
}
else
*rowsAffected = (Int64)tmpRowsAffected;
} // rowsAffected
}
return (short)retcode;
}
Lng32 ExeCliInterface::executeImmediateCEFC(const char * stmtStr,
char * inputBuf,
Lng32 inputBufLen,
char * outputBuf,
Lng32 * outputBufLen,
Int64 * rowsAffected
)
{
Lng32 retcode = 0;
clearGlobalDiags();
outputBuf_ = NULL;
inputBuf_ = NULL;
retcode = executeImmediatePrepare(stmtStr,
outputBuf,
outputBufLen,
rowsAffected);
if (retcode < 0)
goto ExecuteImmediateCEFCReturn;
retcode = clearExecFetchCloseOpt(inputBuf, inputBufLen, NULL, NULL, rowsAffected);
ExecuteImmediateCEFCReturn:
return retcode;
}
Lng32 ExeCliInterface::cwrsAllocStuff(SQLMODULE_ID * &module,
SQLSTMT_ID * &stmt,
SQLDESC_ID * &sql_src,
SQLDESC_ID * &input_desc,
SQLDESC_ID * &output_desc,
SQLDESC_ID * &rs_input_maxsize_desc,
const char * stmtName
)
{
Lng32 retcode = 0;
retcode = cwrsDeallocStuff(module,
stmt,
sql_src,
input_desc,
output_desc,
rs_input_maxsize_desc);
if (retcode < 0)
{
return (short)retcode;
}
retcode = allocStuff(module,
stmt,
sql_src,
input_desc,
output_desc);
if (retcode < 0)
{
return (short)retcode;
}
// Allocate a descriptor to set input array maximum size
rs_input_maxsize_desc = new(heap_) SQLSTMT_ID;
init_SQLDESC_ID(rs_input_maxsize_desc, SQLCLI_CURRENT_VERSION, desc_handle, module);
retcode = SQL_EXEC_AllocDesc(rs_input_maxsize_desc, 1);
if (retcode < 0)
return retcode;
retcode = SQL_EXEC_SetDescItem(rs_input_maxsize_desc, 1, SQLDESC_TYPE,
SQLTYPECODE_INTEGER, NULL);
if (retcode < 0)
return retcode;
retcode = SQL_EXEC_SetDescItem( rs_input_maxsize_desc,
1, // entry #1, attr value.
SQLDESC_VAR_PTR, // what to set - host var addr
(long) &rsMaxsize_, // Notice that output from CLI
// will be read from host var
// rowset_size.
NULL);
retcode = SQL_EXEC_SetStmtAttr(stmt,
SQL_ATTR_INPUT_ARRAY_MAXSIZE,
rsMaxsize_,
NULL);
return retcode;
}
Lng32 ExeCliInterface::cwrsDeallocStuff(
SQLMODULE_ID * &module,
SQLSTMT_ID * &stmt,
SQLDESC_ID * &sql_src,
SQLDESC_ID * &input_desc,
SQLDESC_ID * &output_desc,
SQLDESC_ID * &rs_input_maxsize_desc)
{
deallocStuff(module, stmt, sql_src, input_desc, output_desc);
if (rs_input_maxsize_desc)
{
SQL_EXEC_DeallocDesc(rs_input_maxsize_desc);
NADELETEBASIC(rs_input_maxsize_desc, heap_);
rs_input_maxsize_desc = NULL;
}
return 0;
}
Lng32 ExeCliInterface::cwrsPrepare(const char * stmtStr,
Lng32 rs_maxsize, NABoolean monitorThis)
{
Lng32 retcode = 0;
rsMaxsize_ = rs_maxsize;
retcode = cwrsAllocStuff(module_, stmt_, sql_src_,
input_desc_, output_desc_,
rs_input_maxsize_desc_);
if (retcode != SUCCESS)
return retcode;
retcode = prepare(stmtStr, module_, stmt_, sql_src_,
input_desc_, output_desc_, NULL,NULL,NULL,NULL,
NULL,NULL,NULL,NULL,monitorThis);
if (retcode < 0)
{
cwrsDeallocStuff(module_, stmt_, sql_src_,
input_desc_, output_desc_,
rs_input_maxsize_desc_);
return retcode;
}
numQuadFields_ = numInputEntries_;// + 1;
quadFields_ = (SQLCLI_QUAD_FIELDS*)
new (heap_) char[sizeof(SQLCLI_QUAD_FIELDS) * numQuadFields_];
rsInputBuffer_ = new(heap_) char[rsMaxsize_ * inputDatalen_];
Lng32 fsDatatype;
Lng32 length;
Lng32 indOffset = 0;
Lng32 varOffset = 0;
quadFields_[0].var_layout = 0;
quadFields_[0].var_ptr = (void *)&currRSrow_;
quadFields_[0].ind_layout = 0;
quadFields_[0].ind_ptr = NULL;
Lng32 currOffset = 0;
for (Lng32 entry = 2; entry <= numInputEntries_; entry++)
{
getAttributes(entry, TRUE,
fsDatatype, length,
&indOffset, &varOffset);
quadFields_[entry-1].var_layout = length;
quadFields_[entry-1].var_ptr = (void*)&rsInputBuffer_[currOffset];
quadFields_[entry-1].ind_layout = 0;
quadFields_[entry-1].ind_ptr = NULL;
currOffset += length * rsMaxsize_;
}
currRSrow_ = 0;
return 0;
}
Lng32 ExeCliInterface::cwrsExec(
char * inputRow,
Int32 inputRowLen,
Int64 * rowsAffected)
{
Lng32 retcode = 0;
Int32 rowset_status[1]; // Has no functionality currently.
//However it is part of RowsetSetDesc API
if ((inputRow) && (currRSrow_ < rsMaxsize_))
{
Lng32 fsDatatype;
Lng32 length;
Lng32 indOffset = 0;
Lng32 varOffset = 0;
for (Lng32 entry = 2; entry <= numInputEntries_; entry++)
{
getAttributes(entry, TRUE,
fsDatatype, length,
&indOffset, &varOffset);
str_cpy_all((char*)((long)(quadFields_[entry-1].var_ptr) +
currRSrow_*length),
&inputRow[varOffset], length);
}
currRSrow_++;
return 0;
}
if ((inputRow == NULL) && (currRSrow_ == 0))
return 0;
retcode = SQL_EXEC_SETROWSETDESCPOINTERS(input_desc_,
currRSrow_,
rowset_status,
1,
numQuadFields_,
quadFields_);
if (retcode < 0)
return retcode;
retcode = exec();
if (retcode < 0)
return retcode;
retcode = fetch();
if (retcode < 0)
return retcode;
if (retcode >= 0)
{
if (rowsAffected)
{
Lng32 tmpRowsAffected = 0;
retcode = SQL_EXEC_GetDiagnosticsStmtInfo2(NULL, SQLDIAG_ROW_COUNT,
&tmpRowsAffected, NULL,
0, NULL);
if(retcode == EXE_NUMERIC_OVERFLOW) // rowsAffected > LONG_MAX
{
GetRowsAffected(rowsAffected);
}
else
*rowsAffected = (Int64)tmpRowsAffected;
retcode = 0;
}
}
retcode = close();
currRSrow_ = 0;
// current input row has not been moved to the rowset buffer.
// move the input row to the rowset buffer
return cwrsExec(inputRow, inputRowLen, rowsAffected);
}
Lng32 ExeCliInterface::cwrsClose(Int64 * rowsAffected)
{
Lng32 retcode = 0;
if (rowsAffected)
*rowsAffected = 0;
retcode = cwrsExec(NULL, 0, rowsAffected);
Lng32 retcode2 = cwrsDeallocStuff(module_, stmt_, sql_src_,
input_desc_, output_desc_,
rs_input_maxsize_desc_);
return retcode;
}
Lng32 ExeCliInterface::rwrsPrepare(const char * stmtStr, Lng32 rs_maxsize,NABoolean monitorThis)
{
Lng32 retcode = 0;
rsMaxsize_ = rs_maxsize;
retcode = allocStuff(module_, stmt_, sql_src_,
input_desc_, output_desc_);
if (retcode != SUCCESS)
return retcode;
/*
retcode = SQL_EXEC_SetStmtAttr(stmt_,
SQL_ATTR_INPUT_ARRAY_MAXSIZE,
rsMaxsize_,
NULL);
if (retcode != SUCCESS)
return retcode;
*/
retcode = prepare(stmtStr, module_, stmt_, sql_src_,
input_desc_, output_desc_, NULL,NULL,NULL,NULL,NULL,
NULL,NULL,NULL,monitorThis);
if (retcode < 0)
{
deallocStuff(module_, stmt_, sql_src_,
input_desc_, output_desc_);
return retcode;
}
rsInputBuffer_ = new(heap_) char[rsMaxsize_ * inputDatalen_];
retcode = SQL_EXEC_SetDescItem(input_desc_,0,SQLDESC_ROWSET_TYPE, 3, 0);
retcode = SQL_EXEC_SetDescItem(input_desc_,0,SQLDESC_ROWWISE_ROWSET_PTR,
(long)rsInputBuffer_, 0);
retcode = SQL_EXEC_SetDescItem(input_desc_,0,SQLDESC_ROWWISE_ROWSET_ROW_LEN,
inputDatalen_, 0);
currRSrow_ = 0;
return 0;
}
Lng32 ExeCliInterface::rwrsExec(
char * inputRow,
Int32 inputRowLen,
Int64 * rowsAffected)
{
Lng32 retcode = 0;
clearGlobalDiags();
if (rowsAffected)
*rowsAffected = 0;
if ((inputRow) && (currRSrow_ < rsMaxsize_))
{
str_cpy_all(&rsInputBuffer_[currRSrow_ * inputDatalen_],
inputRow, inputRowLen);
currRSrow_++;
return 0;
}
if ((inputRow == NULL) && (currRSrow_ == 0))
return 0;
retcode = SQL_EXEC_SetDescItem(input_desc_, 0, SQLDESC_ROWWISE_ROWSET_SIZE,
currRSrow_, 0);
retcode = exec();
if (retcode < 0)
return retcode;
retcode = fetch();
if (retcode < 0)
return retcode;
Lng32 cliRetcode = -1;
if (retcode >= 0)
{
cliRetcode = retcode;
if (rowsAffected)
{
Lng32 tmpRowsAffected = 0;
retcode = SQL_EXEC_GetDiagnosticsStmtInfo2(NULL, SQLDIAG_ROW_COUNT,
&tmpRowsAffected, NULL,
0, NULL);
if(retcode == EXE_NUMERIC_OVERFLOW) // rowsAffected > LONG_MAX
{
GetRowsAffected(rowsAffected);
}
else
*rowsAffected = (Int64)tmpRowsAffected;
retcode = 0;
}
}
currRSrow_ = 0;
return retcode;
}
Lng32 ExeCliInterface::rwrsClose()
{
Lng32 retcode = 0;
retcode = rwrsExec(NULL, 0, NULL);
close();
deallocStuff(module_, stmt_, sql_src_,
input_desc_, output_desc_);
return retcode;
}
short ExeCliInterface::prepareAndExecRowsPrologue(const char * sqlInitialStrBuf,
char * sqlSecondaryStrBuf,
Queue* initialOutputVarPtrList,
Queue* secondaryOutputVarPtrList,
Int64 &rowsAffected,
NABoolean monitorThis)
{
Lng32 retcode = 0;
SQL_EXEC_ClearDiagnostics(NULL);
retcode = allocStuff(module_, stmt_, sql_src_, input_desc_, output_desc_);
if (retcode < 0)
return (short)retcode;
// Prepare
outputBuf_ = NULL;
inputBuf_ = NULL;
retcode = prepare(sqlInitialStrBuf, module_, stmt_, sql_src_,
input_desc_, output_desc_, &outputBuf_,
initialOutputVarPtrList, NULL,NULL,NULL,NULL,
NULL,NULL,monitorThis);
if (retcode < 0)
return (short)retcode;
retcode = allocStuff(moduleWithCK_, stmtWithCK_, sql_src_withCK_,
input_desc_withCK_, output_desc_withCK_);
if (retcode < 0)
return (short)retcode;
// Prepare
outputBuf_withCK_ = NULL;
retcode = prepare(sqlSecondaryStrBuf, moduleWithCK_, stmtWithCK_, sql_src_withCK_,
input_desc_withCK_, output_desc_withCK_, &outputBuf_withCK_,
secondaryOutputVarPtrList,NULL,NULL,NULL,NULL,
NULL,NULL,monitorThis);
if (retcode < 0)
return (short)retcode;
// Ensure the input entries have the correct character set type
retcode = setCharsetTypes();
if (retcode < 0)
return (short)retcode;
retcode = SQL_EXEC_Exec(stmt_, input_desc_, 0);
if (retcode < 0)
return (short)retcode;
Lng32 cliRetcode = -1;
retcode = SQL_EXEC_Fetch(stmt_, output_desc_, 0);
if (retcode < 0)
return (short)retcode;
if (retcode >= 0) // we continue for warnings (retcode > 0)
// and NO errors or warnings (retcode == 0)
{
cliRetcode = retcode; // save the retcode from cli fetch.
setOutputPtrsAsInputPtrs(initialOutputVarPtrList, 0);
Int64 tmpRowsAffected = 0;
retcode = SQL_EXEC_GetDiagnosticsStmtInfo2(NULL, SQLDIAG_ROW_COUNT,
&tmpRowsAffected, NULL,
0, NULL);
if(retcode == EXE_NUMERIC_OVERFLOW) // rowsAffected > LONG_MAX
{
GetRowsAffected(&rowsAffected);
}
else
rowsAffected = tmpRowsAffected;
}
SQL_EXEC_ClearDiagnostics(NULL);
retcode = SQL_EXEC_CloseStmt(stmt_);
if (retcode < 0)
return (short)retcode;
// return the return code from the cli fetch if it succeded.
if (cliRetcode != -1)
return (short) cliRetcode;
else
return (short) retcode;
}
short ExeCliInterface::execContinuingRows(Queue * continuingOutputVarPtrList,
Int64 &rowsAffected)
{
Lng32 retcode = 0;
SQL_EXEC_ClearDiagnostics(NULL);
retcode = SQL_EXEC_Exec(stmtWithCK_, input_desc_withCK_, 0);
if (retcode < 0)
return (short)retcode;
Lng32 cliRetcode = -1;
retcode = SQL_EXEC_Fetch(stmtWithCK_, output_desc_withCK_, 0);
if (retcode < 0)
return (short)retcode;
if (retcode >= 0)
{
cliRetcode = retcode; // save the retcode from cli fetch.
setOutputPtrsAsInputPtrs(continuingOutputVarPtrList, 0);
Int64 tmpRowsAffected = 0;
retcode = SQL_EXEC_GetDiagnosticsStmtInfo2(NULL, SQLDIAG_ROW_COUNT,
&tmpRowsAffected, NULL,
0, NULL);
if(retcode == EXE_NUMERIC_OVERFLOW) // rowsAffected > LONG_MAX
{
GetRowsAffected(&rowsAffected);
}
else
rowsAffected = tmpRowsAffected;
}
retcode = SQL_EXEC_CloseStmt(stmtWithCK_);
if (retcode < 0)
return (short)retcode;
// return the return code from the cli fetch if it succeded.
if (cliRetcode != -1)
return (short) cliRetcode;
else
return (short) retcode;
}
Lng32 ExeCliInterface::setCharsetTypes()
{
Lng32 retcode = 0;
Lng32 num_input_entries = 0;
// Obtain the number of entries
retcode = SQL_EXEC_GetDescEntryCount(input_desc_withCK_, &num_input_entries);
if (retcode < 0)
return (short)retcode;
Lng32 data_charset = 0;
for (Lng32 i = 1; i <= num_input_entries; i++)
{
retcode = SQL_EXEC_GetDescItem(output_desc_withCK_,
i,
SQLDESC_CHAR_SET,
&data_charset, 0, 0, 0, 0);
if (retcode < 0)
return (short)retcode;
if (data_charset != SQLCHARSETCODE_UNKNOWN)
{
retcode = SQL_EXEC_SetDescItem(input_desc_withCK_,
i,
SQLDESC_CHAR_SET,
data_charset, 0);
if (retcode < 0)
return (short)retcode;
}
}
return (short)retcode;
}
void ExeCliInterface::setOutputPtrsAsInputPtrs(Queue* outputVarPtrList,
SQLDESC_ID * target_inputDesc)
{
// Process the queue
Int32 j = 1;
outputVarPtrList->position();
while (NOT outputVarPtrList->atEnd())
{
char * entry = (char*)outputVarPtrList->getCurr();
SQL_EXEC_SetDescItem(input_desc_withCK_, j++,
SQLDESC_VAR_PTR,
(Long)entry, 0);
outputVarPtrList->advance();
}
return;
}
Lng32 ExeCliInterface::prepareAndExecRowsEpilogue()
{
Lng32 retcode = 0;
retcode = close();
deallocStuff(module_, stmt_, sql_src_, input_desc_, output_desc_);
if (stmtWithCK_)
{
retcode = SQL_EXEC_CloseStmt(stmtWithCK_);
}
deallocStuff(moduleWithCK_, stmtWithCK_,
sql_src_withCK_, input_desc_withCK_, output_desc_withCK_);
SQL_EXEC_ClearDiagnostics(NULL);
return 0;
}
Lng32 ExeCliInterface::beginWork()
{
return executeImmediate("begin work;");
}
Lng32 ExeCliInterface::commitWork()
{
return executeImmediate("commit work;");
}
Lng32 ExeCliInterface::rollbackWork()
{
return executeImmediate("rollback work;");
}
Lng32 ExeCliInterface::autoCommit(NABoolean v)
{
if (v)
return executeImmediate("set transaction autocommit ON;");
else
return executeImmediate("set transaction autocommit OFF;");
}
Lng32 ExeCliInterface::beginXn()
{
return SQL_EXEC_Xact(SQLTRANS_BEGIN, 0);
}
Lng32 ExeCliInterface::commitXn()
{
return SQL_EXEC_Xact(SQLTRANS_COMMIT, 0);
}
Lng32 ExeCliInterface::rollbackXn()
{
return SQL_EXEC_Xact(SQLTRANS_ROLLBACK, 0);
}
Lng32 ExeCliInterface::statusXn()
{
return SQL_EXEC_Xact(SQLTRANS_STATUS, NULL);
}
Lng32 ExeCliInterface::suspendXn()
{
return SQL_EXEC_Xact(SQLTRANS_SUSPEND, 0);
}
Lng32 ExeCliInterface::resumeXn()
{
return SQL_EXEC_Xact(SQLTRANS_RESUME, 0);
}
Lng32 ExeCliInterface::createContext(char * contextHandle)
{
Lng32 rc = 0;
rc = SQL_EXEC_CreateContext((SQLCTX_HANDLE*)contextHandle, NULL, FALSE);
return rc;
}
Lng32 ExeCliInterface::switchContext(char * contextHandle)
{
Lng32 rc = 0;
rc = SQL_EXEC_SwitchContext(*(SQLCTX_HANDLE*)contextHandle, NULL);
return rc;
}
Lng32 ExeCliInterface::currentContext(char * contextHandle)
{
Lng32 rc = 0;
rc = SQL_EXEC_CurrentContext((SQLCTX_HANDLE*)contextHandle);
return rc;
}
Lng32 ExeCliInterface::deleteContext(char* contextHandle) // in buf contains context handle
{
return SQL_EXEC_DeleteContext(*(SQLCTX_HANDLE*)contextHandle);
}
Lng32 ExeCliInterface::retrieveSQLDiagnostics(ComDiagsArea *toDiags)
{
Lng32 retcode;
ex_assert(toDiags != NULL, "ComDiagsArea is null");
retcode = SQL_EXEC_MergeDiagnostics_Internal(*toDiags);
SQL_EXEC_ClearDiagnostics(NULL);
return retcode;
}
ComDiagsArea *ExeCliInterface::allocAndRetrieveSQLDiagnostics(ComDiagsArea *&toDiags)
{
Lng32 retcode;
NABoolean daAllocated = FALSE;
if (toDiags == NULL) {
toDiags = ComDiagsArea::allocate(heap_);
daAllocated = TRUE;
}
retcode = SQL_EXEC_MergeDiagnostics_Internal(*toDiags);
SQL_EXEC_ClearDiagnostics(NULL);
if (retcode == 0)
return toDiags;
else {
if (daAllocated)
toDiags->decrRefCount();
return NULL;
}
}
Lng32 ExeCliInterface::GetRowsAffected(Int64 *rowsAffected)
{
SQLDESC_ID *rowCountDesc = NULL;
SQLMODULE_ID * module = NULL;
Lng32 retcode = SUCCESS;
NABoolean sqlWarning = FALSE;
SQLDIAG_STMT_INFO_ITEM_ID sqlItem = SQLDIAG_ROW_COUNT;
rowCountDesc = new(heap_) SQLDESC_ID;
rowCountDesc->version = SQLCLI_CURRENT_VERSION;
rowCountDesc->name_mode = desc_handle;
module = new(heap_) SQLMODULE_ID;
rowCountDesc->module = module;
module->module_name = 0;
module->charset = "ISO88591";
module->module_name_len = 0;
module->version = SQLCLI_CURRENT_VERSION;
rowCountDesc->identifier = 0;
rowCountDesc->handle = 0;
// get number of rows affected
retcode = SQL_EXEC_AllocDesc (rowCountDesc, 1);
retcode = SQL_EXEC_SetDescItem(rowCountDesc, 1,
SQLDESC_TYPE_FS, REC_BIN64_SIGNED, 0);
retcode = SQL_EXEC_SetDescItem(rowCountDesc, 1,
SQLDESC_VAR_PTR, (Long)rowsAffected, 0);
Lng32 *temp;
temp = (Lng32 *) &sqlItem;
retcode = SQL_EXEC_GetDiagnosticsStmtInfo(temp, rowCountDesc);
// free up resources
SQL_EXEC_DeallocDesc(rowCountDesc);
return SUCCESS;
} // GetRowsAffected()
Lng32 ExeCliInterface::holdAndSetCQD(const char * defaultName, const char * defaultValue, ComDiagsArea *globalDiags)
{
Lng32 cliRC;
char buf[400];
strcpy(buf, "control query default ");
strcat(buf, defaultName);
strcat(buf, " hold;");
// hold the current value for defaultName
cliRC = executeImmediate(buf, NULL, NULL, TRUE, NULL, 0,&globalDiags);
if (cliRC < 0)
{
return cliRC;
}
// now set the new value for defaultName
strcpy(buf, "control query default ");
strcat(buf, defaultName);
strcat(buf, " '");
strcat(buf, defaultValue);
strcat(buf, "';");
cliRC = executeImmediate(buf, NULL, NULL, TRUE, NULL, 0,&globalDiags);
if (cliRC < 0)
{
return cliRC;
}
return 0;
}
Lng32 ExeCliInterface::restoreCQD(const char * defaultName, ComDiagsArea *globalDiags)
{
Lng32 cliRC;
char buf[400];
// remove this cqd from the cqd array
strcpy(buf, "control query default ");
strcat(buf, defaultName);
strcat(buf, " reset;");
cliRC = executeImmediate(buf, NULL, NULL, TRUE, NULL, 0,&globalDiags);
if (cliRC < 0)
{
return cliRC;
}
// restore the saved cqd default value
strcpy(buf, "control query default ");
strcat(buf, defaultName);
strcat(buf, " restore;");
cliRC = executeImmediate(buf, NULL, NULL, TRUE, NULL, 0,&globalDiags);
if (cliRC < 0)
{
return cliRC;
}
return 0;
}
Lng32 ExeCliInterface::getCQDval(const char * defaultName,
char * val,
ComDiagsArea *globalDiags)
{
Lng32 cliRC;
char buf[400];
strcpy(buf, "cqd showcontrol_show_all 'ON';");
cliRC = executeImmediate(buf);
if (cliRC < 0)
{
return cliRC;
}
char valBuf[4000];
Lng32 valBufLen = 0;
strcpy(buf, "showcontrol default ");
strcat(buf, defaultName);
strcat(buf, ", match full, no header;");
cliRC = executeImmediate(buf, valBuf, &valBufLen);
if (cliRC < 0)
{
strcpy(buf, "cqd showcontrol_show_all 'OFF';");
executeImmediate(buf);
return cliRC;
}
strcpy(val, valBuf);
strcpy(buf, "cqd showcontrol_show_all 'OFF';");
cliRC = executeImmediate(buf);
return 0;
}
Lng32 ExeCliInterface::setCQS(const char * shape, ComDiagsArea *globalDiags)
{
Lng32 cliRC;
cliRC = executeImmediate(shape, NULL, NULL, TRUE, NULL, 0,&globalDiags);
if (cliRC < 0)
{
return cliRC;
}
return 0;
}
Lng32 ExeCliInterface::resetCQS(ComDiagsArea * globalDiags)
{
Lng32 cliRC;
char buf[400];
strcpy(buf, "control query shape cut ");
cliRC = executeImmediate(buf, NULL, NULL, TRUE, NULL, 0,&globalDiags);
if (cliRC < 0)
{
return cliRC;
}
return 0;
}
// methods for routine invocation
Lng32 ExeCliInterface::getRoutine(
/* 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,
/* IN/OUT */ ComDiagsArea *diags)
{
Lng32 retcode = 0;
SQL_EXEC_ClearDiagnostics(NULL);
retcode = SQL_EXEC_GetRoutine(
serializedInvocationInfo,
invocationInfoLen,
serializedPlanInfo,
planInfoLen,
language,
paramStyle,
externalName,
containerName,
externalPath,
librarySqlName,
handle);
if (retcode != 0 && diags)
{
SQL_EXEC_MergeDiagnostics_Internal(*diags);
SQL_EXEC_ClearDiagnostics(NULL);
}
return retcode;
}
Lng32 ExeCliInterface::invokeRoutine(
/* 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,
/* IN/OUT */ ComDiagsArea *diags)
{
Lng32 retcode = 0;
SQL_EXEC_ClearDiagnostics(NULL);
retcode = SQL_EXEC_InvokeRoutine(
handle,
phaseEnumAsInt,
serializedInvocationInfo,
invocationInfoLen,
invocationInfoLenOut,
serializedPlanInfo,
planInfoLen,
planNum,
planInfoLenOut,
inputRow,
inputRowLen,
outputRow,
outputRowLen);
if (retcode != 0 && diags)
{
SQL_EXEC_MergeDiagnostics_Internal(*diags);
SQL_EXEC_ClearDiagnostics(NULL);
}
return retcode;
}
Lng32 ExeCliInterface::getRoutineInvocationInfo(
/* 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,
/* IN/OUT */ ComDiagsArea *diags)
{
Lng32 retcode = 0;
SQL_EXEC_ClearDiagnostics(NULL);
retcode = SQL_EXEC_GetRoutineInvocationInfo(
handle,
serializedInvocationInfo,
invocationInfoMaxLen,
invocationInfoLenOut,
serializedPlanInfo,
planInfoMaxLen,
planNum,
planInfoLenOut);
if (retcode != 0 && diags)
{
SQL_EXEC_MergeDiagnostics_Internal(*diags);
SQL_EXEC_ClearDiagnostics(NULL);
}
return retcode;
}
Lng32 ExeCliInterface::putRoutine(
/* IN */ Int32 handle,
/* IN/OUT */ ComDiagsArea *diags)
{
Lng32 retcode = 0;
SQL_EXEC_ClearDiagnostics(NULL);
retcode = SQL_EXEC_PutRoutine(
handle);
if (retcode != 0 && diags)
{
SQL_EXEC_MergeDiagnostics_Internal(*diags);
SQL_EXEC_ClearDiagnostics(NULL);
}
return retcode;
}