blob: d2b5176aa765470e5858503eac2ef99315cc3a39 [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: SqlCmd.C
* RCS: $Id: SqlCmd.cpp,v 1.1 2007/10/09 19:40:29 Exp $
* Description:
*
*
* Created: 4/15/95
* Modified: $ $Date: 2007/10/09 19:40:29 $ (GMT)
* Language: C++
* Status: $State: Exp $
*
*
*
*
*****************************************************************************
*/
#include "Platform.h"
#include <ctype.h>
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sstream>
#include <unistd.h>
#include "ComAnsiNamePart.h"
#include "ComGuardianFileNameParts.h"
#include "ComASSERT.h"
#include "Formatter.h"
#include "SqlciStats.h"
#include "NAString.h"
#include "ErrorMessage.h" // NAWriteConsole
#include "IntervalType.h" // NAType::convertTypeToText etc.
#include "SqlciError.h"
#include "SQLCLIdev.h"
#include "sqlcmd.h"
#include "sql_id.h"
#include "ComSqlId.h"
#include "ComRtUtils.h"
#define CAT_MAX_HEADING_LEN 132
#define CM_GUA_ENAME_LEN 36
#include "dfs2rec.h"
#include "ex_error.h"
#include "str.h"
#include "stringBuf.h"
#include "charinfo.h"
#include "NLSConversion.h"
#include "nawstring.h"
#include "SqlciList_templ.h"
#include "ComCextMisc.h"
#include "ComCextdecs.h"
#include "ComQueue.h"
#include "ExExeUtilCli.h"
extern SqlciEnv * global_sqlci_env; // global sqlci_env for break key handling purposes.
extern ComDiagsArea sqlci_DA;
extern NAHeap sqlci_Heap;
extern BOOL WINAPI CtrlHandler (DWORD signalType);
const Lng32 BREAK_ERROR = -999;
const Int32 MAX_MSGTEXT_LEN = 4096;
const Int32 MAX_OTHERBUF_LEN = ComAnsiNamePart::MAX_IDENTIFIER_EXT_LEN+1+1;
// These should come from a SQL Message Text (immudefs) file! ##
#define UNLOADED_MESSAGE "--- %ld row(s) unloaded."
#define LOADED_MESSAGE "--- %ld row(s) loaded."
#define SELECTED_MESSAGE "--- %d row(s) selected."
#define SELECTED_BUT_MESSAGE "--- %d row(s) selected (but none displayed)."
#define SELECTED_FIRST_ROW_DISPLAY_MESSAGE "--- %d row(s) selected (and first row displayed)."
#define INSERTED_MESSAGE "--- %ld row(s) inserted."
#define UPDATED_MESSAGE "--- %ld row(s) updated."
#define DELETED_MESSAGE "--- %ld row(s) deleted."
#define OP_COMPLETE_MESSAGE "--- SQL operation complete."
#define OP_COMPLETED_ERRORS "--- SQL operation failed with errors."
#define OP_COMPLETED_WARNINGS "--- SQL operation completed with warnings."
#define PREPARED_MESSAGE "--- SQL command prepared."
#define LISTCOUNT_MESSAGE " LIST_COUNT was reached."
#define CATAPI "CREATE TANDEM_CAT_REQUEST&"
// These static variables and global functions, in conjunction with their
// callers, have as one goal to nicely format blank lines for sqlci output
// (output to screen and to logfile -- which should be identical):
// We want single blank lines to enhance legibility; we never want two
// blank non-data lines in a row.
static Lng32 worstcode;
static NABoolean lastLineWasABlank;
// remember the number of rows affected by an SQL statement
// before resetting the diagnostics info
static Int64 rowsAffected;
#define Succ_or_Warn (retcode == SQL_Success || (retcode >= 0 && retcode != SQL_Eof))
void HandleCLIErrorInit()
{
ComASSERT(SQL_Error < SQL_Warning && SQL_Warning < SQL_Eof);
worstcode = SQL_Eof;
lastLineWasABlank = FALSE;
}
void SqlCmd::clearCLIDiagnostics()
{
SQLSTMT_ID dummy_stmt;
SQLMODULE_ID module;
init_SQLMODULE_ID(&module);
init_SQLSTMT_ID(&dummy_stmt,
SQLCLI_CURRENT_VERSION,
stmt_handle,
&module
);
SQL_EXEC_ClearDiagnostics(&dummy_stmt);
}
volatile Int32 breakReceived = 0;
void HandleCLIError(SQLSTMT_ID *stmt, Lng32 &error, SqlciEnv *sqlci_env,
NABoolean displayErr, NABoolean * isEOD,
Int32 prepcode)
{
Int32 diagsCondCount = 0;
if (error == 100)
diagsCondCount = getDiagsCondCount(stmt);
// Get Warnings only when there are 2 or more conditions.
// One condition is for the error code 100 and the others are the actual warnings
NABoolean getWarningsWithEOF = (diagsCondCount > 1);
HandleCLIError(error, sqlci_env, displayErr, isEOD, prepcode, getWarningsWithEOF);
}
void HandleCLIError(Lng32 &error, SqlciEnv *sqlci_env,
NABoolean displayErr, NABoolean * isEOD,
Int32 prepcode, NABoolean getWarningsWithEOF)
{
if (error == 100)
{
if (isEOD != NULL)
*isEOD = 1;
if (! getWarningsWithEOF) {
SqlCmd::clearCLIDiagnostics();
return;
}
}
if (isEOD)
*isEOD = 0;
if (error == BREAK_ERROR)
{
DWORD dwd = 0;
CtrlHandler(dwd);
}
else
#define MXCI_DONOTISSUE_ERRMSGS -1
if (error != 0)
{
Logfile *log = sqlci_env->get_logfile();
if (error != SQL_Eof)
worstcode = error;
SQLMODULE_ID module;
init_SQLMODULE_ID(&module);
SQLDESC_ID cond_desc;
init_SQLDESC_ID(&cond_desc, SQLCLI_CURRENT_VERSION, desc_handle,
&module);
// Get the total number of conditions and # of rows affected
Int32 total_conds = 0;
Int64 rows_affected = 0;
SQL_EXEC_AllocDesc(&cond_desc,2);
SQL_EXEC_SetDescItem(&cond_desc, 1, SQLDESC_TYPE_FS,
REC_BIN32_SIGNED, 0);
SQL_EXEC_SetDescItem(&cond_desc, 1, SQLDESC_VAR_PTR,
(Long) &total_conds, 0);
SQL_EXEC_SetDescItem(&cond_desc, 2, SQLDESC_TYPE_FS,
REC_BIN64_SIGNED, 0);
SQL_EXEC_SetDescItem(&cond_desc, 2, SQLDESC_VAR_PTR,
(Long) &rows_affected, 0);
Lng32 stmt_items[2];
stmt_items[0] = SQLDIAG_NUMBER;
stmt_items[1] = SQLDIAG_ROW_COUNT;
SQL_EXEC_GetDiagnosticsStmtInfo(stmt_items, &cond_desc);
// remember # of rows affected in a global variable
rowsAffected += rows_affected;
// Attach msgtext variable with the output descriptor
SQLMODULE_ID module2;
init_SQLMODULE_ID(&module2);
SQLDESC_ID msg_desc;
init_SQLDESC_ID(&msg_desc, SQLCLI_CURRENT_VERSION, desc_handle,
&module2);
SQLDIAG_COND_INFO_ITEM cond_info_item[4];
short SQLCode;
char msgtext[MAX_MSGTEXT_LEN];
char otherbuf[MAX_OTHERBUF_LEN];
NABoolean getCondInfo = log->isVerbose();
NABoolean showSQLSTATE = !!getenv("SHOW_SQLSTATE");
short num_output_entries = 2;
if (showSQLSTATE)
num_output_entries = 3;
// total_conds can be 1 (Executor error) or 2 (Compile error, the second
// sqlcode being 8822 "Unable to prepare the stmt").
Lng32 specialErr =
(ABS(error) == ABS(sqlci_env->specialError()) && total_conds <= 2) ?
ABS(error) : 0;
if (specialErr)
{
ComASSERT(total_conds > 0);
total_conds = 1;
getCondInfo = TRUE;
showSQLSTATE = FALSE;
num_output_entries = 3;
lastLineWasABlank = TRUE;
}
SQL_EXEC_AllocDesc(&msg_desc, num_output_entries);
// Set up to receive Message text.
SQL_EXEC_SetDescItem(&msg_desc, 1, SQLDESC_TYPE_FS,
REC_BYTE_F_ASCII, 0);
SQL_EXEC_SetDescItem(&msg_desc, 1, SQLDESC_LENGTH,
MAX_MSGTEXT_LEN, 0);
SQL_EXEC_SetDescItem(&msg_desc, 1, SQLDESC_VAR_PTR,
(Long) &msgtext, 0);
cond_info_item[0].item_id = SQLDIAG_MSG_TEXT;
cond_info_item[0].cond_number_desc_entry = 1;
// set up to receive sqlcode
SQL_EXEC_SetDescItem(&msg_desc, 2, SQLDESC_TYPE_FS,
REC_BIN16_SIGNED, 0);
SQL_EXEC_SetDescItem(&msg_desc, 2, SQLDESC_VAR_PTR,
(Long) &SQLCode, 0);
cond_info_item[1].item_id = SQLDIAG_SQLCODE;
cond_info_item[1].cond_number_desc_entry = 2;
//
if (showSQLSTATE || specialErr)
{
SQL_EXEC_SetDescItem(&msg_desc, 3, SQLDESC_TYPE_FS,
REC_BYTE_F_ASCII, 0);
SQL_EXEC_SetDescItem(&msg_desc, 3, SQLDESC_LENGTH,
MAX_OTHERBUF_LEN, 0);
SQL_EXEC_SetDescItem(&msg_desc, 3, SQLDESC_VAR_PTR,
(Long) &otherbuf, 0);
cond_info_item[2].item_id = SQLDIAG_RET_SQLSTATE;
cond_info_item[2].cond_number_desc_entry = 3;
if (specialErr)
{
// "msgtext" is really cat-name; "otherbuf" will contain schema-name.
cond_info_item[0].item_id = SQLDIAG_CATALOG_NAME;
cond_info_item[2].item_id = SQLDIAG_SCHEMA_NAME;
}
}
Int32 curr_cond = 1;
SQL_EXEC_SetDescEntryCount(&cond_desc, 1);
SQL_EXEC_SetDescItem(&cond_desc, 1, SQLDESC_VAR_PTR,
(Long) &curr_cond, 0);
if (!(error == SQL_Success))
{
if (total_conds)
{
// Start with a blank line -- cf. NADumpDiags(GetErrorMessage.C)
if (!lastLineWasABlank)
{
SQL_EXEC_GetDiagnosticsCondInfo(cond_info_item,
&cond_desc, &msg_desc);
if ((SQLCode != 100) &&
((SQLCode < 0) || (SQLCode > 0 && getCondInfo )))
{
if (displayErr) // || (SQLCode > 0))
{
log->WriteAll("");
// The error text(s) we are about to emit
// each have two lines,
// the second of which is a blank.
lastLineWasABlank = TRUE;
}
}
}
}
// Loop through total number of conditions, and print out
// the error message text. This loop should emulate
// NADumpDiags (GetErrorMessage.C) as much as possible.
for (; curr_cond <= total_conds; curr_cond++)
{
SQL_EXEC_GetDiagnosticsCondInfo(cond_info_item,
&cond_desc, &msg_desc);
// do not output no data warning 100.
// do not output warning message if it's printed during preparation
// on Linux.
if ((SQLCode == 100) || (SQLCode == prepcode))
{
if ((isEOD) && (SQLCode == 100)) // 100: SQL_Eof
*isEOD = 1;
continue;
}
//if 'set warnings off' set
if ((SQLCode < 0) || (SQLCode > 0 && getCondInfo ))
{
if (msgtext[0] == '\0') // an empty message
{
strcpy(msgtext, "*** ERROR[15000] Unexpected Error: Message text missing");
}
CharInfo::CharSet TCS = sqlci_env->getTerminalCharset();
CharInfo::CharSet ISOMAPCS = sqlci_env->getIsoMappingCharset();
if(
TCS != CharInfo::UTF8/*msgcharset*/
)
{
charBuf cbuf((unsigned char*)msgtext, strlen(msgtext));
NAWcharBuf* wcbuf = 0;
Int32 errorcode = 0;
wcbuf = csetToUnicode(cbuf, 0, wcbuf, CharInfo::UTF8/*msgcharset*/, errorcode);
NAString* tempstr;
if (errorcode == 0){
tempstr = unicodeToChar(wcbuf->data(),wcbuf->getStrLen(), TCS, NULL, TRUE);
TrimNAStringSpace(*tempstr, FALSE, TRUE); // trim trailing blanks
strcpy(msgtext, tempstr->data());
}
}
if (specialErr && sqlci_env->specialHandler())
{
sqlci_env->specialHandler()(sqlci_env, error, msgtext, otherbuf);
}
else
{
// ## Kludge for "error" 20109. Internationalization problem...!
const char *outtext = msgtext;
size_t pfxl = strlen("*** ERROR[20109] ");
#if defined(USE_WCHAR)
if (wcsncmp(msgtext, L"*** ERROR[20109] ", pfxl) == 0)
#else
if (strncmp(msgtext, "*** ERROR[20109] ", pfxl) == 0)
#endif
outtext += pfxl;
#ifdef USE_WCHAR
if (showSQLSTATE)
{
$$do something here$$
}
if (displayErr)// || (SQLCode > 0))
log->WriteAll((NAWchar*)outtext, NAWstrlen((NAWchar*)outtext));
#else // not wide, so don't use NAWxxx
//
// Rather than returning from the first executable statements in
// HandleCLIError, a couple of breakReceived conditional checks are
// performed to suppress the outputting of error messages after a
// break key was encountered. This allows MXCI to have more control
// of issuing (future break processing enhancements) warning and
// error messages during break key processing.
if (! breakReceived)
{
if (showSQLSTATE)
{
if (displayErr)// || (SQLCode > 0))
{
log->WriteAllWithoutEOL("*** SQLSTATE: ");
log->WriteAll(otherbuf);
}
}
if (displayErr)// || (SQLCode > 0))
log->WriteAll(outtext);
if (sqlci_env->specialError() ==
MXCI_DONOTISSUE_ERRMSGS)
{
sqlci_env->resetSpecialError();
curr_cond = curr_cond + total_conds;
}
} // breakReceived
#endif
// write out a blank line after error message
if (! breakReceived)
{
if (displayErr)// || (SQLCode > 0))
log->WriteAll("");
} // breakReceived
}
}
} // for
}
if (displayErr)// || (SQLCode > 0))
SqlCmd::clearCLIDiagnostics();
SQL_EXEC_DeallocDesc(&cond_desc);
SQL_EXEC_DeallocDesc(&msg_desc);
// delete (cond_desc);
// delete (msg_desc);
} // error != 0
// Check if Ctrl+break occured... nk
if ( sqlci_env->diagsArea().mainSQLCODE() == SQLCI_BREAK_RECEIVED)
error = SQL_Canceled;
} // HandleCLIError
void handleLocalError(ComDiagsArea *diags, SqlciEnv *sqlci_env)
{
Logfile *log = sqlci_env->get_logfile();
// Here the variable worstcode has to be set to SQL_Error in
// case of an error and SQL_Warning in case of a warning.
// which might have been caused due to a param processing error/warning.
// Usually this variable gets set in the HandleCLIError() function,
// when HandleCLIError() is called with a error after a CLI call.
// Soln :10-021203-3433
if (diags->getNumber(DgSqlCode::ERROR_)) {
worstcode = SQL_Error;
}
else if (diags->getNumber(DgSqlCode::WARNING_)) {
worstcode = SQL_Warning;
}
if (!lastLineWasABlank) log->WriteAllWithoutEOL("");
lastLineWasABlank = TRUE;
ostringstream errMsg;
NADumpDiags(errMsg, diags, TRUE/*newline*/, 0, NULL, log->isVerbose(),
sqlci_env->getTerminalCharset());
errMsg << ends;
log->WriteAllWithoutEOL(errMsg.str().c_str());
}
Int64 getRowsAffected(SQLSTMT_ID *stmt)
{
Int32 rc;
rc = SQL_EXEC_GetDiagnosticsStmtInfo2(stmt,
SQLDIAG_ROW_COUNT, &rowsAffected,
NULL, 0, NULL);
if (rc == 0)
return rowsAffected;
else
return -1;
}
Int32 getDiagsCondCount(SQLSTMT_ID *stmt)
{
Int32 rc;
Int32 diagsCondCount;
rc = SQL_EXEC_GetDiagnosticsStmtInfo2(stmt,
SQLDIAG_NUMBER, &diagsCondCount,
NULL, 0, NULL);
if (rc >= 0)
return diagsCondCount;
else
return 0;
}
static char * upshiftStr(char * inStr, char * outStr, UInt32 len)
{
for (UInt32 i = 0; i < len; i++)
{
outStr[i] = toupper(inStr[i]);
}
return outStr;
}
char * SqlCmd::replacePattern(SqlciEnv * sqlci_env, char * str)
{
if (str == NULL)
return NULL;
UInt32 len = strlen(str);
char upperStr[20];
// if SET PATTERN or RESET PATTERN, do not replace pattern.
UInt32 s = 0;
if (len >= strlen("SET PATTERN"))
{
if (strncmp(upshiftStr(str, upperStr, 3), "SET", 3) == 0)
s = 3;
}
else if (len >= strlen("RESET PATTERN"))
{
if (strncmp(upshiftStr(str, upperStr, 5), "RESET", 5) == 0)
s = 5;
}
if (s > 0) // SET or RESET found
{
// skip blanks
while ((s <= len) &&
(str[s] == ' '))
s++;
if (s < len)
{
if ((len - s) >= strlen("PATTERN"))
{
if (strncmp(upshiftStr(&str[s], upperStr, 7), "PATTERN", 7) == 0)
return str;
}
}
}
// preprocess the argument and replace the pattern: <definename >
// (< and > are included) with the value of define/env-var "definename".
enum State { CONSUME_CHAR, QUOTE_SEEN,
LPATTERN_SEEN, RPATTERN_SEEN };
UInt32 outstr_len = 500 + len;
char * outstr = new char[outstr_len];
char * patternText = new char[100];
UInt32 i = 0;
UInt32 j = 0;
UInt32 k = 0;
NABoolean skipChar = FALSE;
NABoolean inSingleQuote = FALSE;
State state = CONSUME_CHAR;
NABoolean patternSeen = FALSE;
while (i <= len)
{
skipChar = TRUE;
switch (state)
{
case CONSUME_CHAR:
if (str[i] == '\'')
{
state = QUOTE_SEEN;
inSingleQuote=TRUE;
}
if (str[i] == '"')
{
state = QUOTE_SEEN;
inSingleQuote = FALSE;
}
else if ((str[i] == '$') && ((i+1) < len) && (str[i+1] == '$'))
{
i+=2;
state = LPATTERN_SEEN;
skipChar = FALSE;
}
break;
case QUOTE_SEEN:
if (str[i] == '\'')
{
// If in a single quote, make sure this quote is the true end
if (inSingleQuote)
{
// If string contains two single quotes, can skip - not the end
if (((i+1) < len) && (str[i+1] == '\''))
{
outstr[k] = str[i]; // skip over quote
i++;
k++;
}
// The quote mark actually signifies the end of the quote
else
state = CONSUME_CHAR;
}
// else: Double quote found, so continue, not the end
}
if (str[i] == '"')
{
// If in a double quote, make sure this quote is the true end
if (!inSingleQuote)
{
//If string contains two double quotes, can skip - not the end
if (((i+1) < len) && (str[i+1] == '\''))
{
outstr[k] = str[i]; // skip over quote
i++;
k++;
}
// The double quote mark signifies the end of the quote
else
state = CONSUME_CHAR;
}
// else: single quote found, so continue - not the end
}
break;
case LPATTERN_SEEN:
patternSeen = TRUE;
if ((str[i] == '$') && ((i+1) < len) && (str[i+1] == '$'))
{
i+=2;
state = RPATTERN_SEEN;
}
else
{
patternText[j++] = str[i];
i++;
}
skipChar = FALSE;
break;
case RPATTERN_SEEN:
// find value of pattern and replace
patternText[j] = '\0';
Param * pattern
= sqlci_env->get_patternlist()->get(patternText);
char * patternValue = NULL;
if (pattern == NULL)
{
// if an env var is present with this name, use it
patternValue = getenv(patternText);
}
else
{
patternValue = pattern->getValue();
}
if (patternValue)
{
strncpy((char *)&outstr[k], patternValue, strlen(patternValue));
k += strlen(patternValue);
//special note: the total length of outstr should be smaller
//than outstr_len. if the condition below becomes false,
//increase outstr_len at the top of the function
ComASSERT(k <= outstr_len);
}
j = 0;
skipChar = FALSE;
state = CONSUME_CHAR;
break;
}
if (skipChar)
{
outstr[k] = str[i];
i++;
k++;
}
} // while
outstr[k] = '\0';
delete [] patternText;
if (NOT patternSeen)
{
delete [] outstr;
return str;
}
else
return outstr;
}
SqlCmd::SqlCmd(const sql_cmd_type cmd_type_, const char * argument_)
: SqlciNode(SqlciNode::SQL_CMD_TYPE),
cmd_type(cmd_type_)
{
if (argument_)
{
sql_stmt = new char[strlen(argument_)+1];
strcpy(sql_stmt, argument_);
}
else
sql_stmt = 0;
}
SqlCmd::~SqlCmd()
{
if (sql_stmt)
delete [] sql_stmt;
}
short SqlCmd::showShape(SqlciEnv *sqlci_env, const char *query)
{
if ((!query) ||
(strncmp(query, "SHOWSHAPE", 9) == 0))
return 0;
char * buf = new char[strlen("SHOWSHAPE ") + strlen(query) + 1];
strcpy(buf, "SHOWSHAPE ");
strcat(buf, query);
DML dml(buf, DML_SHOWSHAPE_TYPE, "__SQLCI_DML_SHOWSHAPE__");
short retcode = dml.process(sqlci_env);
delete buf;
if (retcode)
return retcode;
return 0;
}
short SqlCmd::updateRepos(SqlciEnv * sqlci_env, SQLSTMT_ID * stmt, char * queryId)
{
Lng32 retcode = 0;
// get explain fragment.
Lng32 explainDataLen = 50000; // start with 50K bytes
Int32 retExplainLen = 0;
char * explainData = new char[explainDataLen + 1];
retcode = SQL_EXEC_GetExplainData(stmt,
explainData, explainDataLen+1,
&retExplainLen
);
if (retcode == -CLI_GENCODE_BUFFER_TOO_SMALL)
{
delete explainData;
explainDataLen = retExplainLen;
explainData = new char[explainDataLen + 1];
SqlCmd::clearCLIDiagnostics();
retcode = SQL_EXEC_GetExplainData(stmt,
explainData, explainDataLen+1,
&retExplainLen
);
}
if (retcode < 0)
{
delete explainData;
HandleCLIError(retcode, sqlci_env);
return retcode;
}
explainDataLen = retExplainLen;
// update repository
ExeCliInterface cliInterface;
SQL_EXEC_SetParserFlagsForExSqlComp_Internal(0x20000);
char * queryBuf = new char[4000];
Int64 ts = NA_JulianTimestamp();
str_sprintf(queryBuf, "insert into %s.\"%s\".%s (instance_id, tenant_id, host_id, exec_start_utc_ts, query_id, explain_plan) values (0,0,0, CONVERTTIMESTAMP(%ld), '%s', '' ) ",
TRAFODION_SYSCAT_LIT, SEABASE_REPOS_SCHEMA, REPOS_METRIC_QUERY_TABLE,
ts, queryId);
retcode = cliInterface.executeImmediatePrepare(queryBuf);
if (retcode < 0)
{
HandleCLIError(retcode, sqlci_env);
goto label_return;
}
retcode = cliInterface.clearExecFetchClose(explainData, explainDataLen);
if (retcode < 0)
{
HandleCLIError(retcode, sqlci_env);
goto label_return;
}
retcode = SQL_EXEC_StoreExplainData(
&ts, queryId,
explainData, explainDataLen);
if (retcode < 0)
{
HandleCLIError(retcode, sqlci_env);
goto label_return;
}
label_return:
SQL_EXEC_ResetParserFlagsForExSqlComp_Internal(0x20000);
delete explainData;
delete queryBuf;
return retcode;
}
short SqlCmd::cleanupAfterError(Lng32 retcode,
SqlciEnv * sqlci_env,
SQLSTMT_ID * stmt,
SQLDESC_ID *sql_src,
SQLDESC_ID *output_desc,
SQLDESC_ID *input_desc,
NABoolean resetLastExecStmt)
{
// if retcode < 0, it is an error.
// Clean up and return.
if (retcode < 0)
{
SQL_EXEC_DeallocDesc(input_desc);
SQL_EXEC_DeallocDesc(output_desc);
SQL_EXEC_DeallocDesc(sql_src);
SQL_EXEC_DeallocStmt(stmt);
if (global_sqlci_env->getDeallocateStmt())
global_sqlci_env->resetDeallocateStmt();
delete (SQLMODULE_ID*)output_desc->module;
delete (SQLMODULE_ID*)input_desc->module;
delete (SQLMODULE_ID*)sql_src->module;
delete (SQLMODULE_ID*)stmt->module;
delete input_desc;
delete output_desc;
delete sql_src;
delete [] stmt->identifier;
delete stmt;
if (resetLastExecStmt)
sqlci_env->lastExecutedStmt() = NULL;
SqlCmd::clearCLIDiagnostics();
return (short)SQL_Error;
}
return 0;
}
short SqlCmd::do_prepare(SqlciEnv * sqlci_env,
PrepStmt * prep_stmt,
char * sqlStmt,
NABoolean resetLastExecStmt,
Lng32 rsIndex,
Int32 *prepcode,
Lng32 *statisticsType)
{
if (sqlci_env->showShape())
{
showShape(sqlci_env, sqlStmt);
}
SQLSTMT_ID *stmt = new SQLSTMT_ID;
SQLDESC_ID *sql_src = new SQLDESC_ID;
SQLDESC_ID *output_desc = new SQLDESC_ID;
SQLDESC_ID *input_desc = new SQLDESC_ID;
memset (stmt, 0, sizeof(SQLSTMT_ID));
memset (sql_src, 0, sizeof(SQLDESC_ID));
memset (output_desc, 0, sizeof(SQLDESC_ID));
memset (input_desc, 0, sizeof(SQLDESC_ID));
SQLMODULE_ID * module = new SQLMODULE_ID;
stmt->module = module;
init_SQLMODULE_ID(module);
module = new SQLMODULE_ID;
sql_src->module = module;
init_SQLMODULE_ID(module);
module = new SQLMODULE_ID;
input_desc->module = module;
init_SQLMODULE_ID(module);
module = new SQLMODULE_ID;
output_desc->module = module;
init_SQLMODULE_ID(module);
SqlCmd::clearCLIDiagnostics();
Lng32 retcode = 0;
// replace any user defined pattern in the sql query
// char * str = replacePattern(sqlci_env, sqlStmt);
char * str = sqlStmt;
prep_stmt->set(str, NULL, stmt, 0, NULL, 0, NULL);
char *stmtName = prep_stmt->getStmtName();
// Bookkeeping for stored procedure result sets
NABoolean isResultSet = (rsIndex > 0 ? TRUE : FALSE);
NABoolean skipPrepare = isResultSet;
if (!isResultSet)
HandleCLIErrorInit();
/* allocate a statement */
stmt->version = SQLCLI_CURRENT_VERSION;
stmt->name_mode = stmt_name;
char * identifier = new char[strlen(stmtName) + 1];
stmt->identifier_len = strlen(stmtName);
str_cpy_all(identifier,stmtName, stmt->identifier_len);
identifier[stmt->identifier_len] = 0;
stmt->identifier = identifier;
stmt->handle = 0;
if (!isResultSet)
{
retcode = SQL_EXEC_AllocStmt(stmt, 0);
HandleCLIError(retcode, sqlci_env);
}
else
{
SQLSTMT_ID callStmt;
SQLMODULE_ID module;
init_SQLMODULE_ID(&module);
init_SQLSTMT_ID(&callStmt, SQLCLI_CURRENT_VERSION, stmt_name, &module);
char *callStmtName = sqlci_env->lastExecutedStmt()->getStmtName();
callStmt.identifier_len = (Lng32) strlen(callStmtName);
callStmt.identifier = callStmtName;
retcode = SQL_EXEC_AllocStmtForRS(&callStmt, rsIndex, stmt);
// Statement allocation may have failed simply because the RS
// index is out of range or because the parent statement is not a
// CALL. That can be tolerated and in response we are going to
// return early.
if (retcode == -8909 || // Parent stmt is not a CALL
retcode == -8916) // RS index out of range
{
SqlCmd::clearCLIDiagnostics();
}
else
{
HandleCLIError(retcode, sqlci_env);
}
}
// Statement allocation failed. If errors needed to be reported to
// the console, that has already happened. We can cleanup and
// return.
if (retcode < 0)
{
return cleanupAfterError(retcode, sqlci_env, stmt, sql_src,
output_desc, input_desc, resetLastExecStmt);
}
if (!isResultSet)
{
global_sqlci_env->setDeallocateStmt();
global_sqlci_env->setLastAllcatedStmt(stmt);
}
/* allocate a descriptor which will hold the sql statement source */
sql_src->version = SQLCLI_CURRENT_VERSION;
sql_src->name_mode = desc_handle;
sql_src->identifier = 0;
sql_src->identifier_len = 0;
sql_src->handle = 0;
retcode = SQL_EXEC_AllocDesc(sql_src, 1);
HandleCLIError(retcode, sqlci_env);
retcode = SQL_EXEC_SetDescItem(sql_src, 1, SQLDESC_TYPE_FS,
REC_BYTE_V_ANSI, 0);
retcode = SQL_EXEC_SetDescItem(sql_src, 1, SQLDESC_CHAR_SET_NAM,
0, (char*)CharInfo::getCharSetName(sqlci_env->getTerminalCharset()));
retcode = SQL_EXEC_SetDescItem(sql_src, 1, SQLDESC_VAR_PTR, (Long)str, 0);
HandleCLIError(retcode, sqlci_env);
retcode = SQL_EXEC_SetDescItem(sql_src, 1, SQLDESC_LENGTH, strlen(str) + 1, 0);
HandleCLIError(retcode, sqlci_env);
SQL_QUERY_COST_INFO queryCostInfo;
SQL_QUERY_COMPILER_STATS_INFO queryCompStatsInfo;
char uniqueQueryIdBuf[400];
Lng32 uniqueQueryIdLenBuf = 399;
char * uniqueQueryIdPtr = uniqueQueryIdBuf;
Lng32 * uniqueQueryIdLenPtr = &uniqueQueryIdLenBuf;
if (!skipPrepare)
{
/* prepare it */
// Get cost and set unique query id as well
strcpy(uniqueQueryIdBuf, " ");
ULng32 prepFlags = 0;
if ((stmt->identifier_len > 0) &&
(strncmp(stmt->identifier, "__SQLCI_DML_", strlen("__SQLCI_DML_")) == 0))
{
prepFlags |=PREPARE_STANDALONE_QUERY;
}
prepFlags |=PREPARE_USE_EMBEDDED_ARKCMP; // mxosrvr needs to set this too.
retcode = SQL_EXEC_Prepare2(stmt, sql_src,
NULL, 0, NULL,
&queryCostInfo,
&queryCompStatsInfo,
uniqueQueryIdPtr,
uniqueQueryIdLenPtr,
prepFlags
);
// save returned query id in prep_stmt
if (prep_stmt->uniqueQueryId())
{
delete prep_stmt->uniqueQueryId();
prep_stmt->uniqueQueryIdLen() = 0;
}
if (*uniqueQueryIdLenPtr > 0)
{
prep_stmt->uniqueQueryIdLen() = *uniqueQueryIdLenPtr;
prep_stmt->uniqueQueryId() = new char[prep_stmt->uniqueQueryIdLen() + 1];
memcpy(prep_stmt->uniqueQueryId(), uniqueQueryIdPtr,
prep_stmt->uniqueQueryIdLen());
prep_stmt->uniqueQueryId()[prep_stmt->uniqueQueryIdLen()] = 0;
}
if (prepcode != NULL)
*prepcode = retcode;
HandleCLIError(retcode, sqlci_env);
// if SQL_EXEC_Prepare returned a value < 0, it is an error.
// Clean up and return.
if (retcode < 0)
{
return cleanupAfterError(retcode, sqlci_env, stmt, sql_src,
output_desc, input_desc, resetLastExecStmt);
}
} // if (!skipPrepare)
// Statistics Collection Type
if (statisticsType != NULL)
*statisticsType = queryCompStatsInfo.statsCollectionType;
delete (SQLMODULE_ID *)input_desc->module;
delete (SQLMODULE_ID *)output_desc->module;
input_desc->module = output_desc->module = NULL;
// find the statement type
if (!skipPrepare)
{
retcode = SQL_EXEC_GetStmtAttr(stmt, SQL_ATTR_QUERY_TYPE,
&prep_stmt->queryType(),
NULL, 0, NULL);
HandleCLIError(retcode, sqlci_env);
Lng32 subqueryType;
retcode = SQL_EXEC_GetStmtAttr(stmt, SQL_ATTR_SUBQUERY_TYPE,
&subqueryType, NULL, 0, NULL);
HandleCLIError(retcode, sqlci_env);
prep_stmt->setSubqueryType(subqueryType);
}
else if (isResultSet)
prep_stmt->queryType() = SQL_SP_RESULT_SET;
init_SQLDESC_ID(input_desc, SQLCLI_CURRENT_VERSION, desc_handle);
init_SQLDESC_ID(output_desc, SQLCLI_CURRENT_VERSION, desc_handle);
/* allocate an input descriptor to send values. */
retcode = SQL_EXEC_AllocDesc(input_desc, 500);
HandleCLIError(retcode, sqlci_env);
/* allocate an output descriptor to retrieve values. */
retcode = SQL_EXEC_AllocDesc(output_desc, 500);
HandleCLIError(retcode, sqlci_env);
// An undocumented environment variable can be used to select WIDE
// descriptors. A WIDE descriptor is only meaningful for a CALL
// statement and describes all input and output values together in a
// single descriptor.
if (getenv("SQLCI_DESCRIBE_WIDE"))
{
SQL_EXEC_SetDescItem(input_desc, 1, SQLDESC_DESCRIPTOR_TYPE,
DESCRIPTOR_TYPE_WIDE, 0);
SQL_EXEC_SetDescItem(output_desc, 1, SQLDESC_DESCRIPTOR_TYPE,
DESCRIPTOR_TYPE_WIDE, 0);
}
/* describe the input/output entries into the input/output descriptor */
Lng32 num_input_entries = 0, num_output_entries = 0;
retcode = SQL_EXEC_DescribeStmt(stmt, input_desc, output_desc);
if (retcode < 0)
{
// This is a stored procedure result set without a valid query
// plan. It could be that we just went beyond the end of the
// collection of results for the current CALL statement. That is
// OK and is not an error to report to the console. It just means
// our result set processing should end so we cleanup and
// return. If some other error was encountered, that is unexpected
// and we will report it to the user, then cleanup and return.
if (isResultSet && retcode == -8915)
SqlCmd::clearCLIDiagnostics();
else
HandleCLIError(retcode, sqlci_env);
SqlCmd::clearCLIDiagnostics();
return cleanupAfterError(retcode, sqlci_env, stmt, sql_src,
output_desc, input_desc, resetLastExecStmt);
}
else if (retcode != 8818)
{
HandleCLIError(retcode, sqlci_env);
}
else
{
SqlCmd::clearCLIDiagnostics();
retcode = SQL_EXEC_GetDescEntryCount(input_desc, &num_input_entries);
HandleCLIError(retcode, sqlci_env);
retcode = SQL_EXEC_GetDescEntryCount(output_desc, &num_output_entries);
HandleCLIError(retcode, sqlci_env);
if (num_input_entries > 500)
{
retcode = SQL_EXEC_DeallocDesc(input_desc);
HandleCLIError(retcode, sqlci_env);
retcode = SQL_EXEC_AllocDesc(input_desc, num_input_entries);
HandleCLIError(retcode, sqlci_env);
retcode = SQL_EXEC_DescribeStmt(stmt, input_desc, NULL);
HandleCLIError(retcode, sqlci_env);
}
if (num_output_entries > 500)
{
retcode = SQL_EXEC_DeallocDesc(output_desc);
HandleCLIError(retcode, sqlci_env);
retcode = SQL_EXEC_AllocDesc(output_desc, num_output_entries);
HandleCLIError(retcode, sqlci_env);
retcode = SQL_EXEC_DescribeStmt(stmt, NULL, output_desc);
HandleCLIError(retcode, sqlci_env);
}
}
retcode = SQL_EXEC_GetDescEntryCount(input_desc, &num_input_entries);
HandleCLIError(retcode, sqlci_env);
retcode = SQL_EXEC_GetDescEntryCount(output_desc, &num_output_entries);
HandleCLIError(retcode, sqlci_env);
if (breakReceived)
{
delete sql_src;
delete input_desc;
delete output_desc;
return SQL_Canceled;
}
prep_stmt->set(str, sql_src, stmt,
num_input_entries, input_desc,
num_output_entries, output_desc);
addOutputInfoToPrepStmt(sqlci_env, prep_stmt);
if (resetLastExecStmt)
{
sqlci_env->lastExecutedStmt() = NULL;
sqlci_env->lastDmlStmtStatsType() = SQLCLIDEV_NO_STATS;
}
return 0;
}
void SqlCmd::addOutputInfoToPrepStmt(SqlciEnv *sqlci_env,
PrepStmt *prep_stmt)
{
if (!prep_stmt)
return;
Lng32 num_output_entries = prep_stmt->numOutputEntries();
SQLDESC_ID *output_desc = prep_stmt->getOutputDesc();
if (num_output_entries > 0)
{
Lng32 retcode = 0;
// space where actual data is returned
char * output_data = 0;
Lng32 output_data_len = 0;
Lng32 output_buflen = 0;
Lng32 datatype = 0;
Lng32 length = 0;
Lng32 precision = 0;
Lng32 scale = 0;
Lng32 null_flag = 0;
Lng32 charsetEnum = 0;
Lng32 curpos = 0;
prep_stmt->outputEntries() = new PrepEntry * [num_output_entries];
short entry=1;
for (; entry <= num_output_entries; entry++)
{
retcode = SQL_EXEC_GetDescItem(output_desc, entry,
SQLDESC_TYPE_FS,
&datatype, 0, 0, 0, 0);
HandleCLIError(retcode, sqlci_env);
retcode = SQL_EXEC_GetDescItem(output_desc, entry,
SQLDESC_OCTET_LENGTH,
&length, 0, 0, 0, 0);
HandleCLIError(retcode, sqlci_env);
if (datatype >= REC_MIN_INTERVAL && datatype <= REC_MAX_INTERVAL) {
retcode = SQL_EXEC_GetDescItem(output_desc, entry,
SQLDESC_INT_LEAD_PREC,
&precision, 0, 0, 0, 0);
HandleCLIError(retcode, sqlci_env);
retcode = SQL_EXEC_GetDescItem(output_desc, entry,
SQLDESC_PRECISION,
&scale, 0, 0, 0, 0);
HandleCLIError(retcode, sqlci_env);
} else if (datatype == REC_DATETIME) {
retcode = SQL_EXEC_GetDescItem(output_desc, entry,
SQLDESC_DATETIME_CODE,
&precision, 0, 0, 0, 0);
HandleCLIError(retcode, sqlci_env);
retcode = SQL_EXEC_GetDescItem(output_desc, entry,
SQLDESC_PRECISION,
&scale, 0, 0, 0, 0);
HandleCLIError(retcode, sqlci_env);
} else {
retcode = SQL_EXEC_GetDescItem(output_desc, entry,
SQLDESC_PRECISION,
&precision, 0, 0, 0, 0);
HandleCLIError(retcode, sqlci_env);
retcode = SQL_EXEC_GetDescItem(output_desc, entry,
SQLDESC_SCALE,
&scale, 0, 0, 0, 0);
HandleCLIError(retcode, sqlci_env);
if (DFS2REC::isAnyCharacter(datatype)) {
retcode = SQL_EXEC_GetDescItem(output_desc, entry,
SQLDESC_CHAR_SET,
&charsetEnum, 0, 0, 0, 0);
HandleCLIError(retcode, sqlci_env);
}
}
retcode = SQL_EXEC_GetDescItem(output_desc, entry,
SQLDESC_NULLABLE,
&null_flag, 0, 0, 0, 0);
HandleCLIError(retcode, sqlci_env);
char heading[CAT_MAX_HEADING_LEN+1];
Lng32 heading_len;
char outputName[CAT_MAX_HEADING_LEN+1];
Lng32 output_name_len;
char tableName[CM_GUA_ENAME_LEN+1];
Lng32 table_name_len;
ComASSERT(ComAnsiNamePart::MAX_IDENTIFIER_EXT_LEN >=
(Int32) CAT_MAX_HEADING_LEN);
ComASSERT(ComAnsiNamePart::MAX_IDENTIFIER_EXT_LEN >=
(Int32) CM_GUA_ENAME_LEN);
/////////////////////////////////////////////////////////
// If user specified heading is present, display it.
// Otherwise display the name of the column or expression
// that was used in the select list.
/////////////////////////////////////////////////////////
retcode = SQL_EXEC_GetDescItem(output_desc, entry,
SQLDESC_HEADING,
0, heading,
CAT_MAX_HEADING_LEN, &heading_len, 0);
HandleCLIError(retcode, sqlci_env);
retcode = SQL_EXEC_GetDescItem(output_desc, entry,
SQLDESC_NAME,
0, outputName,
CAT_MAX_HEADING_LEN, &output_name_len, 0);
if (heading_len == 0) // heading not present.
{
strncpy(heading, outputName, output_name_len);
heading_len = output_name_len;
HandleCLIError(retcode, sqlci_env);
}
retcode = SQL_EXEC_GetDescItem(output_desc, entry,
SQLDESC_TABLE_NAME,
0, tableName,
CM_GUA_ENAME_LEN, &table_name_len, 0);
HandleCLIError(retcode, sqlci_env);
Lng32 alignedLen;
retcode = SQL_EXEC_GetDescItem(output_desc, entry,
SQLDESC_ALIGNED_LENGTH,
&alignedLen, 0, 0, 0, 0);
HandleCLIError(retcode, sqlci_env);
output_data_len += alignedLen;
if (DFS2REC::isAnyCharacter(datatype))
{
Lng32 isCaseInsensitive = 0;
retcode = SQL_EXEC_GetDescItem(output_desc, entry,
SQLDESC_CASEINSENSITIVE,
&isCaseInsensitive, NULL,
0, NULL, 0);
HandleCLIError(retcode, sqlci_env);
}
// add space to display the returned data.
Lng32 out_buflen_this_col = 0;
Lng32 display_len = Formatter::display_length(
datatype, length, precision, scale, charsetEnum,
heading_len, sqlci_env, &out_buflen_this_col);
output_buflen += out_buflen_this_col +
((entry < num_output_entries) ? Formatter::BLANK_SEP_WIDTH : 0);
prep_stmt->outputEntries()[entry-1] =
new PrepEntry(datatype, length, scale, precision,
null_flag,
heading, heading_len,
outputName, output_name_len, display_len,
out_buflen_this_col, charsetEnum, tableName, table_name_len);
}
// allocate space to hold the returned data
output_data = new char[output_data_len];
// set var_ptr and ind_ptr
curpos = 0;
for (entry=1; entry <= num_output_entries; entry++)
{
PrepEntry * outputEntry = prep_stmt->outputEntries()[entry-1];
Lng32 dataOffset;
Lng32 nullIndOffset;
retcode = SQL_EXEC_GetDescItem(output_desc, entry,
SQLDESC_NULL_IND_OFFSET,
&nullIndOffset, 0, 0, 0, 0);
HandleCLIError(retcode, sqlci_env);
retcode = SQL_EXEC_GetDescItem(output_desc, entry,
SQLDESC_DATA_OFFSET,
&dataOffset, 0, 0, 0, 0);
HandleCLIError(retcode, sqlci_env);
if (nullIndOffset >= 0)
{
retcode = SQL_EXEC_SetDescItem(output_desc, entry,
SQLDESC_IND_PTR,
(Long)&output_data[nullIndOffset],0);
HandleCLIError(retcode, sqlci_env);
}
retcode = SQL_EXEC_SetDescItem(output_desc, entry,
SQLDESC_VAR_PTR,
(Long)&output_data[dataOffset],0);
}
prep_stmt->outputDatalen() = output_data_len;
prep_stmt->outputData() = output_data;
// Allocate space to hold the formatted row that will be displayed.
// The 'extraOutputBuf' multiplier is used ONLY for the
// buffer allocation itself and NOT for the recorded length
// (otherwise, headers get screwed up!).
// It is calculated ONLY the first several PREPAREs in SQLCI,
// so as to minimize its overhead --
// a getenv of SQL_MXCI_SHOW_NONPRINTING.
static Int32 prepCnt = 0;
static Lng32 extraOutputBuf;
if (prepCnt < 5) {
prepCnt++;
if (Formatter::getShowNonprintingReplacementChar(TRUE) ==
Formatter::HEX_EXPANSION_ON)
extraOutputBuf = Formatter::HEX_BUFSIZ_MULTIPLIER;
else
extraOutputBuf = 1;
}
prep_stmt->outputBuflen() = output_buflen;
prep_stmt->outputBuf() = new char[extraOutputBuf * output_buflen + 1];
} // if (num_output_entries > 0)
}
short SqlCmd::doDescribeInput(SqlciEnv * sqlci_env,
SQLSTMT_ID * stmt,
PrepStmt * prep_stmt,
Lng32 num_input_entries,
Int32 numUnnamedParams,
char ** unnamedParamArray,
CharInfo::CharSet* unnamedParamCharSetArray)
{
Lng32 retcode = 0;
Int32 num_named_params = 0;
SqlciList<Param> *unnamed_param_list = NULL;
ComDiagsArea *diags = NULL;
SQLDESC_ID * input_desc = prep_stmt->getInputDesc();
char * aligned_input_data = 0;
Lng32 aligned_input_data_len = 0;
NABoolean canAlign = TRUE;
// if input params present, then assign their values to the dataptr
// field of the descriptor.
if (num_input_entries > 0)
{
short datatype;
Lng32 returned_len;
Lng32 length = 0;
Lng32 precision;
Lng32 scale;
Lng32 unnamed;
Lng32 vcIndLen = -1;
CharInfo::CharSet charset = CharInfo::CHARSET_MIN;
char param_name[ComAnsiNamePart::MAX_IDENTIFIER_EXT_LEN+1];
prep_stmt->inputEntries() = new PrepEntry * [num_input_entries];
for (short entry=1; entry <= num_input_entries; entry++)
{
Lng32 temp;
retcode = SQL_EXEC_GetDescItem(input_desc, entry,
SQLDESC_TYPE_FS,
&temp, 0, 0, 0, 0);
datatype = (short) temp;
HandleCLIError(retcode, sqlci_env);
retcode = SQL_EXEC_GetDescItem(input_desc, entry,
SQLDESC_OCTET_LENGTH,
&length, 0, 0, 0, 0);
HandleCLIError(retcode, sqlci_env);
Lng32 alignedLen = 0;
retcode = SQL_EXEC_GetDescItem(input_desc, entry,
SQLDESC_ALIGNED_LENGTH,
&alignedLen, 0, 0, 0, 0);
HandleCLIError(retcode, sqlci_env);
aligned_input_data_len += alignedLen;
// check if parameter is unnamed
// note: not implemented in executor yet
// if parameter is unnamed, SQLDESC_UNNAMED = 1
retcode = SQL_EXEC_GetDescItem(input_desc, entry,
SQLDESC_UNNAMED,
&unnamed, 0, 0, 0, 0);
HandleCLIError(retcode, sqlci_env);
Lng32 whatToPutIntoPrecision = SQLDESC_PRECISION;
Lng32 whatToPutIntoScale = SQLDESC_SCALE;
if (datatype >= REC_MIN_INTERVAL && datatype <= REC_MAX_INTERVAL) {
whatToPutIntoPrecision = SQLDESC_INT_LEAD_PREC;
whatToPutIntoScale = SQLDESC_PRECISION;
} else if (datatype == REC_DATETIME) {
whatToPutIntoPrecision = SQLDESC_DATETIME_CODE;
whatToPutIntoScale = SQLDESC_PRECISION;
} else if ( DFS2REC::isAnyCharacter(datatype) ) {
retcode = SQL_EXEC_GetDescItem(input_desc, entry,
SQLDESC_CHAR_SET,
&temp, 0, 0, 0, 0);
HandleCLIError(retcode, sqlci_env);
charset = (CharInfo::CharSet)temp;
if ( DFS2REC::isSQLVarChar(datatype))
{
retcode = SQL_EXEC_GetDescItem(input_desc, entry,
SQLDESC_VC_IND_LENGTH,
&vcIndLen, 0, 0, 0, 0);
HandleCLIError(retcode, sqlci_env);
}
}
retcode = SQL_EXEC_GetDescItem(input_desc, entry,
whatToPutIntoPrecision,
&precision, 0, 0, 0, 0);
HandleCLIError(retcode, sqlci_env);
retcode = SQL_EXEC_GetDescItem(input_desc, entry,
whatToPutIntoScale,
&scale, 0, 0, 0, 0);
HandleCLIError(retcode, sqlci_env);
retcode = SQL_EXEC_GetDescItem(input_desc, entry,
SQLDESC_NAME,
0, param_name,
ComAnsiNamePart::MAX_IDENTIFIER_EXT_LEN,
&returned_len, 0);
HandleCLIError(retcode, sqlci_env);
param_name[returned_len] = 0;
// kludge: until executor recognizes unnamed parameters,
// if length of parameter name is zero, parameter is unnamed
NABoolean isUnnamed = !returned_len;
Param *param = NULL;
if (!isUnnamed) {
num_named_params++;
// lookup this param in the sqlci param-list
param = sqlci_env->get_paramlist()->get(param_name);
}
else if (isUnnamed) {
short entryOffset = entry - num_named_params;
sprintf(param_name, "(UNNAMED_%hd)", entryOffset);
if (numUnnamedParams > 0) {
if (entryOffset <= numUnnamedParams) {
if ( unnamedParamCharSetArray ) {
if ( unnamedParamCharSetArray[entryOffset-1] == CharInfo::UNICODE ) {
Int32 len = (Int32)strlen(unnamedParamArray[entryOffset-1]);
NAWchar* wstrBuf = new NAWchar[len+1];
LocaleStringToUnicode(sqlci_env->getTerminalCharset(),
unnamedParamArray[entryOffset-1], len,
wstrBuf, len+1, TRUE);
param = new Param(param_name, wstrBuf, CharInfo::UNICODE);
delete [] wstrBuf;
} else {
param = new Param(param_name,
unnamedParamArray[entryOffset-1],
unnamedParamCharSetArray[entryOffset-1]);
}
} else
param = new Param(param_name,
unnamedParamArray[entryOffset-1]);
// If it we do a new Param() above that means that
// it is an unnamed param and we have to add it to a
// list which will then be deallocated later. This is
// for Soln 10-031203-1717.
if (! unnamed_param_list)
unnamed_param_list = new SqlciList<Param>;
unnamed_param_list->append(param);
//the parameter value is NULL, so set the nullValue_ field
//in the param
if (!param->getValue())
param->makeNull();
} // unnamed param found in Execute's USING list
}
} // isUnnamed
if (param)
{
if (param->isNull()) {
retcode = SQL_EXEC_SetDescItem(input_desc, entry,
SQLDESC_IND_PTR,
(Long)(param->getNullValue()),
0);
}
else {
NABoolean error = FALSE;
Lng32 inLength = length;
Int32 previousEntry = 0;
if (diags != NULL)
previousEntry = diags->getNumber(DgSqlCode::ERROR_);
if ( DFS2REC::isAnyCharacter(datatype) )
scale = (Lng32)charset; // pass in target charset in argument 'scale'
retcode = param->convertValue(sqlci_env, datatype, length,
precision, scale, vcIndLen, diags);
Int32 newestEntry = 0;
if (diags != NULL)
newestEntry = diags->getNumber(DgSqlCode::ERROR_);
//if the convertValue gets a string overflow warning, convert
//it to error for non characters and it remains warning for characters
if (newestEntry > previousEntry) {
if (diags->getErrorEntry(newestEntry)->getSQLCODE() == EXE_STRING_OVERFLOW ){
if (!DFS2REC::isAnyCharacter(datatype)) {
diags->negateCondition(newestEntry-1);
error = TRUE;
}
}
}
// If convertValue did not return any errors continue on this path
if ((retcode >= 0) && !error) {
if (length != inLength){
// the length of input is different than what cli
// returned. Change the length in the descriptor.
retcode = SQL_EXEC_SetDescItem(input_desc, entry,
SQLDESC_LENGTH,
length,
0);
canAlign = FALSE;
}
retcode = SQL_EXEC_SetDescItem(input_desc, entry,
SQLDESC_VAR_PTR,
(Long)(param->getConvertedValue()),
0);
HandleCLIError(retcode, sqlci_env);
retcode = SQL_EXEC_SetDescItem(input_desc, entry,
SQLDESC_IND_PTR,
0, 0);
}
// If convertValue failed and DID return an error the retcode
// will be < 0 and it will follow this code path.
else {
char tgttype[100];
Lng32 charSet;
Lng32 collation;
retcode = SQL_EXEC_GetDescItem( input_desc
, entry
, SQLDESC_CHAR_SET
,&charSet
, 0
, 0
, 0
, 0
);
HandleCLIError(retcode, sqlci_env);
retcode = SQL_EXEC_GetDescItem( input_desc
, entry
, SQLDESC_COLLATION
,&collation
, 0
, 0
, 0
, 0
);
rec_datetime_field dtStartField = REC_DATE_YEAR;
rec_datetime_field dtEndField = REC_DATE_SECOND;
Lng32 intLeadPrec = SQLInterval::DEFAULT_LEADING_PRECISION;
if (datatype == REC_DATETIME)
{
Lng32 dtCode;
retcode = SQL_EXEC_GetDescItem(input_desc, entry,
SQLDESC_DATETIME_CODE,
&dtCode, 0, 0, 0, 0);
HandleCLIError(retcode, sqlci_env);
// this will get fractional precision
retcode = SQL_EXEC_GetDescItem(input_desc, entry,
SQLDESC_PRECISION,
&precision, 0, 0, 0, 0);
HandleCLIError(retcode, sqlci_env);
if (dtCode == REC_DTCODE_DATE)
{
dtStartField = REC_DATE_YEAR;
dtEndField = REC_DATE_DAY;
}
else if (dtCode == REC_DTCODE_TIME)
{
dtStartField = REC_DATE_HOUR;
dtEndField = REC_DATE_SECOND;
}
else if (dtCode == REC_DTCODE_TIMESTAMP)
{
dtStartField = REC_DATE_YEAR;
dtEndField = REC_DATE_SECOND;
}
}
else if (DFS2REC::isInterval(datatype))
{
getIntervalFields(datatype, dtStartField, dtEndField);
// this will get fractional precision
retcode = SQL_EXEC_GetDescItem(input_desc, entry,
SQLDESC_PRECISION,
&precision, 0, 0, 0, 0);
HandleCLIError(retcode, sqlci_env);
// this will get interval leading precision
retcode = SQL_EXEC_GetDescItem(input_desc, entry,
SQLDESC_INT_LEAD_PREC,
&intLeadPrec, 0, 0, 0, 0);
HandleCLIError(retcode, sqlci_env);
}
NAType::convertTypeToText(tgttype,
datatype, length, precision, scale,
dtStartField, dtEndField,
(short)precision,
(short)intLeadPrec,
FALSE/*upshift*/,
FALSE/*caseinsensitive*/,
(CharInfo::CharSet) charSet,
(CharInfo::Collation) collation,
NULL); // displaydatatype
// All PARAMS are character type.
// #We should single-quote it and double-up any embedded quotes
// #Should be a global func (in NAString.cpp?) for this
NAString srcval(param->getDisplayValue(sqlci_env->getTerminalCharset()));
if (srcval.isNull()) srcval = "''"; // empty string literal
if (diags == NULL)
diags = ComDiagsArea::allocate(&sqlci_Heap);
*diags << DgSqlCode(-SQLCI_PARAM_BAD_CONVERT)
<< DgString0(Param::getExternalName(param_name))
<< DgString1(srcval)
<< DgString2(tgttype);
} // convertValue failed
} // not null param
} // if param
else {
if (diags == NULL)
diags = ComDiagsArea::allocate(&sqlci_Heap);
*diags << DgSqlCode(-SQLCI_PARAM_NOT_FOUND)
<< DgString0(Param::getExternalName(param_name));
}
HandleCLIError(retcode, sqlci_env);
prep_stmt->inputEntries()[entry-1] =
new PrepEntry(datatype, length, scale, precision,
(param ? param->isNull() : 0), // null_flag,
NULL, 0,
param_name, returned_len,
0, 0, 0, NULL, 0);
if (param)
{
if (param->isNull())
prep_stmt->inputEntries()[entry-1]->setIndPtr(
param->getNullValue());
prep_stmt->inputEntries()[entry-1]->setVarPtr(
param->getConvertedValue());
}
} // for num_input_entries
} // if num_input_entries
if (numUnnamedParams > 0 &&
numUnnamedParams > num_input_entries - num_named_params)
{
if (diags == NULL)
diags = ComDiagsArea::allocate(&sqlci_Heap);
// Warning only, so continue processing after this!
*diags << DgSqlCode(+SQLCI_EXTRA_PARAMS_SUPPLIED) // + (i.e. warning)
<< DgInt0(numUnnamedParams)
<< DgInt1(num_input_entries - num_named_params);
}
if (diags != NULL)
{
handleLocalError(diags, sqlci_env);
if (diags->getNumber(DgSqlCode::ERROR_)) {
return SQL_Error;
}
}
if ((num_input_entries > 0) && (canAlign))
{
Lng32 dataOffset = -1;
Lng32 nullIndOffset = -1;
aligned_input_data = new char[aligned_input_data_len];
for (short entry=1; entry <= num_input_entries; entry++)
{
PrepEntry * inputEntry = prep_stmt->inputEntries()[entry-1];
retcode = SQL_EXEC_GetDescItem(input_desc, entry,
SQLDESC_NULL_IND_OFFSET,
&nullIndOffset, 0, 0, 0, 0);
HandleCLIError(retcode, sqlci_env);
retcode = SQL_EXEC_GetDescItem(input_desc, entry,
SQLDESC_DATA_OFFSET,
&dataOffset, 0, 0, 0, 0);
HandleCLIError(retcode, sqlci_env);
if (nullIndOffset >= 0)
{
retcode = SQL_EXEC_SetDescItem(input_desc, entry,
SQLDESC_IND_PTR,
(Long)&aligned_input_data[nullIndOffset],0);
HandleCLIError(retcode, sqlci_env);
if (inputEntry->indPtr())
str_cpy_all(&aligned_input_data[nullIndOffset],
inputEntry->indPtr(), sizeof(short));
else
{
short noNull = 0;
str_cpy_all(&aligned_input_data[nullIndOffset],
(char*)&noNull, sizeof(short));
}
}
retcode = SQL_EXEC_SetDescItem(input_desc, entry,
SQLDESC_VAR_PTR,
(Long)&aligned_input_data[dataOffset],0);
HandleCLIError(retcode, sqlci_env);
if (inputEntry->varPtr())
{
if (DFS2REC::isAnyVarChar(inputEntry->datatype()))
str_cpy_all(&aligned_input_data[dataOffset],
inputEntry->varPtr(),
sizeof(short) + inputEntry->length());
else
str_cpy_all(&aligned_input_data[dataOffset],
inputEntry->varPtr(), inputEntry->length());
}
}
}
return 0;
}
short SqlCmd::doExec(SqlciEnv * sqlci_env,
SQLSTMT_ID * stmt,
PrepStmt * prep_stmt,
Int32 numUnnamedParams,
char ** unnamedParamArray,
CharInfo::CharSet* unnamedParamCharSetArray,
NABoolean handleError)
{
Lng32 retcode = 0;
rowsAffected = 0;
SqlciList<Param> *unnamed_param_list = NULL;
SQLDESC_ID * input_desc = prep_stmt->getInputDesc();
SQLDESC_ID * output_desc = prep_stmt->getOutputDesc();
dml_type stmt_type = prep_stmt->getType();
Lng32 num_input_entries = prep_stmt->numInputEntries();
retcode = doDescribeInput(sqlci_env, stmt, prep_stmt,
num_input_entries,
numUnnamedParams, unnamedParamArray,
unnamedParamCharSetArray);
if (retcode == SQL_Error)
return (short)retcode;
/* execute the statement */
retcode = SQL_EXEC_Exec(stmt, input_desc, 0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0);
if (handleError)
HandleCLIError(retcode, sqlci_env, TRUE);
if (unnamed_param_list)
delete unnamed_param_list;
if (retcode > 0)
getRowsAffected(stmt);
return (short)retcode;
} // SqlCmd::doExec
short SqlCmd::doFetch(SqlciEnv * sqlci_env, SQLSTMT_ID * stmt,
PrepStmt * prep_stmt,
NABoolean firstFetch,
NABoolean handleError,
Int32 prepcode)
{
Lng32 retcode = 0;
// fetch rows till EOF. Note, for statements which do not
// return rows (like, INSERT...), an EOF will be returned
// on the first fetch.
retcode = SQL_EXEC_Fetch(stmt, prep_stmt->getOutputDesc(), 0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0);
NABoolean isEOD = 0;
if (handleError)
HandleCLIError(stmt, retcode, sqlci_env, TRUE, &isEOD,prepcode);
if (isEOD)
retcode = SQL_Eof;
return (short)retcode;
}
short SqlCmd::doClearExecFetchClose(SqlciEnv * sqlci_env,
SQLSTMT_ID * stmt,
PrepStmt * prep_stmt,
Int32 numUnnamedParams,
char ** unnamedParamArray,
CharInfo::CharSet* unnamedParamCharSetArray,
NABoolean handleError)
{
Lng32 retcode = 0;
rowsAffected = 0;
Lng32 num_input_entries = prep_stmt->numInputEntries();
retcode = doDescribeInput(sqlci_env, stmt, prep_stmt,
num_input_entries,
numUnnamedParams, unnamedParamArray,
unnamedParamCharSetArray);
if (retcode == SQL_Error)
return (short)retcode;
retcode = SQL_EXEC_ClearExecFetchClose(
stmt,
((prep_stmt->numInputEntries() > 0)
? prep_stmt->getInputDesc() : NULL),
((prep_stmt->numOutputEntries() > 0)
? prep_stmt->getOutputDesc() : NULL),
0, 0, 0);
Lng32 queryType = prep_stmt->queryType();
if (queryType != SQL_SELECT_UNIQUE)
{
if (retcode == SQL_Success)
retcode = SQL_Eof;
}
if (handleError)
HandleCLIError(retcode, sqlci_env, TRUE);
if (retcode > 0)
getRowsAffected(stmt);
return (short)retcode;
}
short SqlCmd::getHeadingInfo(SqlciEnv * sqlci_env,
PrepStmt * prep_stmt,
char * heading_row,
char * underline)
{
Lng32 retcode = 0;
SQLDESC_ID * output_desc = prep_stmt->getOutputDesc();
Lng32 output_buflen = prep_stmt->outputBuflen();
char * heading = new char[ComAnsiNamePart::MAX_IDENTIFIER_EXT_LEN+1];
Lng32 returned_len;
Lng32 heading_len;
Lng32 curpos = 0;
str_pad(heading_row, output_buflen, ' ');
str_pad(underline, output_buflen, ' ');
Lng32 num_output_entries = prep_stmt->numOutputEntries();
for (short entry=1; entry <= num_output_entries; entry++)
{
/////////////////////////////////////////////////////////
// If user specified heading is present, display it.
// Otherwise display the name of the column or expression
// that was used in the select list.
/////////////////////////////////////////////////////////
retcode = SQL_EXEC_GetDescItem(output_desc, entry,
SQLDESC_HEADING,
0, heading,
CAT_MAX_HEADING_LEN, &returned_len, 0);
HandleCLIError(retcode, sqlci_env);
if (returned_len == 0) // heading not present.
{
retcode = SQL_EXEC_GetDescItem(output_desc, entry,
SQLDESC_NAME,
0, heading,
CAT_MAX_HEADING_LEN, &returned_len, 0);
HandleCLIError(retcode, sqlci_env);
}
heading[returned_len] = 0;
heading_len = prep_stmt->outputEntries()[entry-1]->displayLen();
str_pad(&underline[curpos], (Int32)heading_len, '-');
str_cpy_all(&heading_row[curpos], heading, returned_len);
curpos += heading_len +
((entry < num_output_entries) ? Formatter::BLANK_SEP_WIDTH : 0);
} // for
heading_row[curpos] = 0;
underline[curpos] = 0;
// For long headings, trim trailing spaces
if (curpos > 72)
while (curpos-- && heading_row[curpos] == ' ')
heading_row[curpos] = 0;
delete [] heading;
return 0;
}
short SqlCmd::displayHeading(SqlciEnv * sqlci_env,
PrepStmt * prep_stmt)
{
Lng32 retcode = 0;
Logfile *log = sqlci_env->get_logfile();
if (!lastLineWasABlank) log->WriteAll("");
if (prep_stmt->getType() != DML_DISPLAY_NO_HEADING_TYPE)
{
// Only obtain and display header row if requested
Lng32 output_buflen = prep_stmt->outputBuflen();
char * heading_row = new char[output_buflen + 1];
char * underline = new char[output_buflen + 1];
retcode = getHeadingInfo(sqlci_env, prep_stmt, heading_row, underline);
if (sqlci_env->getTerminalCharset() != CharInfo::UTF8)
{
char * converted_heading_row = new char[output_buflen*4+1];
char *pFirstUntranslatedChar = NULL;
UInt32 outLen = 0;
UInt32 translatedCharCount = 0;
Int32 retCode = UTF8ToLocale ( cnv_version1
, (const char*) heading_row
, (const Int32) strlen(heading_row)
, (const char*) converted_heading_row
, (const Int32) output_buflen*4+1
, (cnv_charset) convertCharsetEnum((Int32)sqlci_env->getTerminalCharset())
, (char* &) pFirstUntranslatedChar
, (UInt32 *) &outLen // unsigned int *output_data_len_p
, (const Int32) TRUE // const int addNullAtEnd_flag
, (const Int32) TRUE // const int allow_invalids
, (UInt32 *) &translatedCharCount // unsigned int * translated_char_cnt_p
, (const char*) NULL // const char *substitution_char_p
);
log->WriteAll(converted_heading_row);
delete [] converted_heading_row;
}
else
log->WriteAll(heading_row);
log->WriteAll(underline);
log->WriteAll("");
delete [] heading_row;
delete [] underline;
}
lastLineWasABlank = TRUE;
return 0;
}
Lng32 SqlCmd::displayRow(SqlciEnv * sqlci_env,
PrepStmt * prep_stmt)
{
NABoolean playItSafeUseTheOldWay = TRUE;
Lng32 retcode = 0;
char * buf = prep_stmt->outputBuf();
SQLDESC_ID * output_desc = prep_stmt->getOutputDesc();
/* print the output */
Lng32 curpos = 0;
Lng32 num_output_entries = prep_stmt->numOutputEntries();
if (playItSafeUseTheOldWay)
for (short entry=1; entry <= num_output_entries; entry++)
{
Long data_addr;
Long ind_data_addr;
retcode = SQL_EXEC_GetDescItem(output_desc, entry,
SQLDESC_VAR_PTR,
&data_addr, 0, 0, 0, 0);
HandleCLIError(retcode, sqlci_env);
retcode = SQL_EXEC_GetDescItem(output_desc, entry,
SQLDESC_IND_PTR,
&ind_data_addr, 0, 0, 0, 0);
HandleCLIError(retcode, sqlci_env);
PrepEntry * outputEntry = prep_stmt->outputEntries()[entry-1];
Formatter::buffer_it(sqlci_env, (char *)data_addr,
outputEntry->datatype(),
outputEntry->length(),
outputEntry->precision(),
outputEntry->scale(),
(char *)ind_data_addr,
outputEntry->displayLen(),
outputEntry->displayBufLen(),
outputEntry->nullFlag(),
&buf[curpos], &curpos,
entry < num_output_entries, //separatorNeeded
TRUE); //checkShowNonPrinting
}
if (buf)
buf[curpos] = 0;
return curpos;
}
short SqlCmd::do_execute(SqlciEnv * sqlci_env,
PrepStmt * prep_stmt,
Int32 numUnnamedParams,
char ** unnamedParamArray,
CharInfo::CharSet* unnamedParamCharSetArray,
Int32 prepcode)
{
Lng32 retcode = 0;
//short ret;
Logfile *log = sqlci_env->get_logfile();
SQLSTMT_ID * stmt = prep_stmt->getStmt();
dml_type stmt_type = prep_stmt->getType();
ULng32 num_rows_returned = 0;
ULng32 listcount = sqlci_env->getListCount();
NABoolean listcountReached = ((listcount == 0) ? TRUE : FALSE);
NABoolean noScreenOutput = (getenv("NO_SCREEN_OUTPUT") ? TRUE : FALSE);
NABoolean displayFirstRow = (getenv("DISPLAY_FIRST_ROW") ? TRUE : FALSE);
Int32 useCout = 0; // Flag which tells LOG::WRITEALL to use COUT
// versus COUT.WRITE.
// Bookkeeping for stored procedure result sets
NABoolean isResultSet = (stmt_type == DML_CALL_STMT_RS_TYPE ? TRUE : FALSE);
char childQueryId[ComSqlId::MAX_QUERY_ID_LEN+1];
Lng32 childQueryIdLen;
SQL_QUERY_COST_INFO childQueryCostInfo;
SQL_QUERY_COMPILER_STATS_INFO childQueryCompilerStatsInfo;
Lng32 queryType = prep_stmt->queryType();
Lng32 subqueryType = prep_stmt->getSubqueryType();
if ((stmt_type == DML_CONTROL_TYPE) &&
((prep_stmt->queryType() == SQL_SELECT_NON_UNIQUE) ||
(prep_stmt->queryType() == SQL_SELECT_UNIQUE)))
stmt_type = DML_SELECT_TYPE;
else if ((stmt_type == DML_DDL_TYPE) &&
(prep_stmt->queryType() == SQL_INSERT_NON_UNIQUE))
stmt_type = DML_INSERT_TYPE;
else if ((stmt_type == DML_DDL_TYPE) &&
((prep_stmt->queryType() == SQL_SELECT_NON_UNIQUE) ||
(prep_stmt->queryType() == SQL_SELECT_UNIQUE)))
stmt_type = DML_SELECT_TYPE;
else if ((stmt_type == DML_DDL_TYPE) &&
(queryType == SQL_EXE_UTIL && subqueryType == SQL_STMT_CTAS))
stmt_type = DML_INSERT_TYPE;
NABoolean firstRowDisplayed = FALSE;
sqlci_env->lastExecutedStmt() = prep_stmt;
NABoolean doCEFC = FALSE; // do ClearExecFetchClose
NABoolean doCTAS = FALSE;
NABoolean doHBL = FALSE;
if (((queryType != SQL_OTHER) &&
(queryType != SQL_UNKNOWN) &&
(queryType != SQL_CAT_UTIL) &&
(queryType != SQL_EXE_UTIL) &&
(queryType != SQL_SELECT_NON_UNIQUE) &&
// (queryType != SQL_SELECT_UNIQUE) &&
(queryType != SQL_CALL_NO_RESULT_SETS) &&
(queryType != SQL_CALL_WITH_RESULT_SETS) &&
(! isResultSet) &&
// (prep_stmt->numOutputEntries() == 0) &&
(! getenv("NO_MXCI_CEFC"))) &&
((queryType == SQL_SELECT_UNIQUE) ||
(prep_stmt->numOutputEntries() == 0)))
{
doCEFC = TRUE;
retcode =
doClearExecFetchClose(sqlci_env,
prep_stmt->getStmt(),
prep_stmt,
numUnnamedParams,
unnamedParamArray,
unnamedParamCharSetArray,
TRUE);
}
if (queryType == SQL_EXE_UTIL && subqueryType == SQL_STMT_CTAS)
doCTAS = TRUE;
if (doCTAS)
{
noScreenOutput = TRUE;
if (getenv("DISPLAY_CTAS_OUTPUT"))
noScreenOutput = FALSE;
}
if (queryType == SQL_EXE_UTIL &&
(subqueryType == SQL_STMT_HBASE_LOAD || subqueryType == SQL_STMT_HBASE_UNLOAD))
doHBL = TRUE;
if (NOT doCEFC)
{
retcode = doExec(sqlci_env,
prep_stmt->getStmt(),
prep_stmt,
numUnnamedParams,
unnamedParamArray,
unnamedParamCharSetArray,
TRUE);
}
NABoolean processedCallWithResultSets = FALSE;
NABoolean firstFetchDone = FALSE;
if (retcode >= 0)
{
// Fetch the first row
if ((NOT doCEFC) && Succ_or_Warn)
{
retcode = doFetch(sqlci_env, prep_stmt->getStmt(), prep_stmt,
TRUE, TRUE,prepcode);
if (Succ_or_Warn)
firstFetchDone = TRUE;
}
// if first row and output entries, print heading.
// don't display heading if DESCRIBE or internal SHOWSHAPE command.
if (Succ_or_Warn && prep_stmt->numOutputEntries() > 0)
{
if (stmt_type != DML_DESCRIBE_TYPE &&
stmt_type != DML_SHOWSHAPE_TYPE &&
stmt_type != DML_DISPLAY_NO_ROWS_TYPE &&
NOT doCTAS &&
NOT doHBL)
displayHeading(sqlci_env, prep_stmt);
}
// We just fetched the first row. Each iteration of the following
// WHILE loop processes one row and then fetches the next.
while (Succ_or_Warn && !listcountReached && !processedCallWithResultSets)
{
num_rows_returned++;
if (prep_stmt->numOutputEntries() > 0)
{
Lng32 curpos = displayRow(sqlci_env, prep_stmt);
// Trim trailing spaces from SHOWDDL and INVOKE ``column'' values,
// and GET RELATED NAMES OF .../ GET VERSION OF ...
// which are really specially formatted variable-length text
// (See CmpDescribe.C).
if (stmt_type == DML_DESCRIBE_TYPE ||
stmt_type == DML_SHOWSHAPE_TYPE ||
stmt_type == DML_DISPLAY_NO_ROWS_TYPE ||
stmt_type == DML_DISPLAY_NO_HEADING_TYPE ||
(doCTAS && NOT noScreenOutput) ||
(doHBL && NOT noScreenOutput))
{
useCout = -1; // use COUT for output versus using COUT.WRITE.
// Move curpos backwards from the end of the string to
// the position of the first non-space character
while (curpos > 0 && prep_stmt->outputBuf()[curpos - 1] == ' ')
curpos--;
// We want to convert a newline-only string ("\n") to
// an empty string ("")
if (curpos == 1 && prep_stmt->outputBuf()[0] == '\n')
curpos--;
// Inject a null terminator
prep_stmt->outputBuf()[curpos] = 0;
}
if (! noScreenOutput)
log->WriteAll(prep_stmt->outputBuf(),curpos,useCout);
else if ((displayFirstRow) &&
(NOT firstRowDisplayed))
{
log->WriteAll(prep_stmt->outputBuf(),curpos,useCout);
firstRowDisplayed = TRUE;
}
// Child QueryId Processing
if (doCTAS && (NOT noScreenOutput))
{
if (strstr(prep_stmt->outputBuf(), "childQidBegin"))
{
Lng32 rc = SQL_EXEC_GetChildQueryInfo(stmt,
childQueryId,
ComSqlId::MAX_QUERY_ID_LEN,
&childQueryIdLen,
&childQueryCostInfo,
&childQueryCompilerStatsInfo);
HandleCLIError(rc, sqlci_env);
if (rc >= 0)
{
childQueryId[childQueryIdLen]='\0';
sprintf(prep_stmt->outputBuf(), "Child Query Id about to execute is %s", childQueryId);
log->WriteAll(prep_stmt->outputBuf(), prep_stmt->outputBuflen(),useCout);
}
}
if (strstr(prep_stmt->outputBuf(), "childQidEnd"))
{
PrepStmt *saved_prep_stmt = prep_stmt;
sqlci_env->getStats()->displayChildQryStats(sqlci_env);
sqlci_env->lastExecutedStmt() = saved_prep_stmt;
}
}
useCout = 0;
lastLineWasABlank = FALSE;
}
// If this is a CALL statement that can return result sets,
// then the CALL has just executed and we now want to display
// all returned result sets
if (queryType == SQL_CALL_WITH_RESULT_SETS &&
retcode >= 0 && !isResultSet)
{
processedCallWithResultSets = TRUE;
NABoolean done = FALSE;
Lng32 rsIndex = 1;
while (!done)
{
// long copyOfWorstcode = worstcode;
DML *rs = new DML("", DML_CALL_STMT_RS_TYPE,
"__SQLCI_DML_SP_RESULT_SET__");
rs->setResultSetIndex(rsIndex);
Lng32 rsProcessingCode = rs->process(sqlci_env);
delete rs;
rsIndex++;
// Not completely sure what to do with the worstcode
// variable now. If errors were encountered while
// displaying the last result set, worstcode will be
// SQL_Error. But if we are going to ignore that error and
// continue processing more result sets, maybe we should
// reset worstcode to the value of copyOfWorstcode. TBD...
//worstcode = copyOfWorstcode;
// Restore last exec stmt pointer
sqlci_env->lastExecutedStmt() = prep_stmt;
// Possible return values: 0, 1, SQL_Canceled
if (rsProcessingCode == 1 ||
(rsProcessingCode < 0 && rsProcessingCode != SQL_Canceled))
{
retcode = rsProcessingCode;
done = TRUE;
}
} // while (!done)
} // End of CALL statement result set loop
if (num_rows_returned == listcount &&
stmt_type != DML_DESCRIBE_TYPE &&
stmt_type != DML_SHOWSHAPE_TYPE)
listcountReached = TRUE;
else if (!processedCallWithResultSets)
{
if (NOT doCEFC)
retcode = doFetch(sqlci_env, stmt, prep_stmt); // get next row
else
retcode = SQL_Eof;
}
} // while getting rows
// close the statement, if an error was not received. The
// statement is already closed in case of an error.
if ((NOT doCEFC) &&
(Succ_or_Warn || retcode == SQL_Eof || retcode == SQL_Canceled))
{
retcode = SQL_EXEC_CloseStmt(stmt);
if (processedCallWithResultSets &&
retcode == -8811) // statement already closed
{
SqlCmd::clearCLIDiagnostics();
retcode = 0;
}
HandleCLIError(retcode, sqlci_env);
}
getRowsAffected(stmt);
} // retcode >= 0
char donemsg[100];
donemsg[0] = '\0';
switch (stmt_type)
{
case DML_UPDATE_TYPE:
case DML_DELETE_TYPE:
case DML_INSERT_TYPE:
case DML_UNLOAD_TYPE:
{
if (stmt_type == DML_UPDATE_TYPE)
sprintf(donemsg, UPDATED_MESSAGE, rowsAffected);
else if (stmt_type == DML_DELETE_TYPE)
sprintf(donemsg, DELETED_MESSAGE, rowsAffected);
else if (stmt_type == DML_INSERT_TYPE)
sprintf(donemsg, INSERTED_MESSAGE, rowsAffected);
else if (stmt_type == DML_UNLOAD_TYPE)
sprintf(donemsg, UNLOADED_MESSAGE, rowsAffected);
}
break;
case DML_CALL_STMT_RS_TYPE:
case DML_SELECT_TYPE:
{
if (! noScreenOutput)
sprintf(donemsg, SELECTED_MESSAGE, num_rows_returned);
else
{
if (displayFirstRow)
sprintf(donemsg, SELECTED_FIRST_ROW_DISPLAY_MESSAGE, num_rows_returned);
else
sprintf(donemsg, SELECTED_BUT_MESSAGE, num_rows_returned);
}
}
break;
case DML_CONTROL_TYPE:
case DML_OSIM_TYPE:
case DML_DISPLAY_NO_HEADING_TYPE:
case DML_DESCRIBE_TYPE:
case DML_DDL_TYPE:
{
if (stmt_type == DML_DDL_TYPE && doHBL )
sprintf(donemsg, LOADED_MESSAGE, rowsAffected);
else if (worstcode == SQL_Success || worstcode == SQL_Eof)
sprintf(donemsg, OP_COMPLETE_MESSAGE);
else if (worstcode < 0)
sprintf(donemsg, OP_COMPLETED_ERRORS);
else
sprintf(donemsg, OP_COMPLETED_WARNINGS);
}
break;
case DML_DISPLAY_NO_ROWS_TYPE:
{
sprintf(donemsg, OP_COMPLETE_MESSAGE);
}
break;
case DML_SHOWSHAPE_TYPE:
{
donemsg[0] = '\0'; // empty
}
break;
default:
{
donemsg[0] = '\0'; // empty
}
break;
}// end of switch stmt
if (listcountReached)
strcat(donemsg, LISTCOUNT_MESSAGE);
if (!lastLineWasABlank)
{
log->WriteAll("");
lastLineWasABlank = TRUE;
}
if (donemsg[0] != '\0')
{
log->WriteAll(donemsg);
lastLineWasABlank = FALSE;
}
if ((retcode < 0) && (retcode != SQL_Canceled))
return SQL_Error;
else
return ((short)retcode);
}
short SqlCmd::executeQuery(const char *query, SqlciEnv *sqlci_env)
{
// -----------------------------------------------------------------------
// Given a SQL query, this procedure invokes the appropriate
// CLI calls to prepare and execute the statement.
// -----------------------------------------------------------------------
Lng32 retcode;
SQLMODULE_ID module;
init_SQLMODULE_ID(&module);
SQLSTMT_ID *stmt = new SQLSTMT_ID;
SQLDESC_ID *sql_src = new SQLDESC_ID;
memset (stmt, 0, sizeof(SQLSTMT_ID));
memset (sql_src, 0, sizeof(SQLDESC_ID));
// Allocate a SQL statement
init_SQLSTMT_ID(stmt, SQLCLI_CURRENT_VERSION, stmt_handle, &module);
retcode = SQL_EXEC_AllocStmt(stmt, 0);
HandleCLIError(retcode, sqlci_env);
// Allocate a descriptor which will hold the SQL statement source
init_SQLDESC_ID(sql_src, SQLCLI_CURRENT_VERSION, desc_handle, &module);
retcode = SQL_EXEC_AllocDesc(sql_src, 1);
HandleCLIError(retcode, sqlci_env);
retcode = SQL_EXEC_SetDescItem(sql_src, 1, SQLDESC_TYPE_FS,
REC_BYTE_V_ANSI, 0);
retcode = SQL_EXEC_SetDescItem(sql_src, 1, SQLDESC_LENGTH,
strlen(query) + 1, 0);
retcode = SQL_EXEC_SetDescItem(sql_src, 1, SQLDESC_CHAR_SET_NAM,
0,(char*)CharInfo::getCharSetName(sqlci_env->getTerminalCharset()));
retcode = SQL_EXEC_SetDescItem(sql_src, 1, SQLDESC_VAR_PTR,
(Long)query, 0);
HandleCLIError(retcode, sqlci_env);
// execute immediate this statement
Int32 prep_flags = 0;
retcode = SQL_EXEC_ExecDirect2(stmt, sql_src,prep_flags, 0, 0);
HandleCLIError(retcode, sqlci_env);
// free up resources
retcode = SQL_EXEC_DeallocDesc(sql_src);
HandleCLIError(retcode, sqlci_env);
retcode = SQL_EXEC_DeallocStmt(stmt);
HandleCLIError(retcode, sqlci_env);
delete stmt;
delete sql_src;
// return ((retcode < 0) ? SQL_Error : retcode);
// avoid compiler warning
return (short)((retcode < 0) ? SQL_Error : retcode);
}
short SqlCmd::setEnviron(SqlciEnv *sqlci_env, Lng32 propagate)
{
short rc = SQL_EXEC_SetEnviron_Internal(propagate);
return rc;
}
DML::DML(const char * argument_, dml_type type_, const char * stmt_name_)
: SqlCmd(SqlCmd::DML_TYPE, argument_), rsIndex_(0)
{
if (stmt_name_)
{
this_stmt_name = new char[strlen(stmt_name_) + 1];
strcpy(this_stmt_name, stmt_name_);
}
else
this_stmt_name = NULL;
type = type_;
}
DML::~DML()
{
}
Prepare::Prepare(char * stmt_name_, char * argument_, dml_type type_)
: SqlCmd(SqlCmd::PREPARE_TYPE, argument_)
{
this_stmt_name = new char[strlen(stmt_name_) + 1];
strcpy(this_stmt_name, stmt_name_);
type = type_;
}
Prepare::~Prepare()
{
delete [] this_stmt_name;
}
DescribeStmt::DescribeStmt(char * stmtName, char * argument) :
SqlCmd(SqlCmd::DESCRIBE_TYPE, argument){
stmtName_ = new char[strlen(stmtName) + 1];
strcpy(stmtName_, stmtName);
}
DescribeStmt::~DescribeStmt(){
delete [] stmtName_;
}
Cursor::Cursor(char * cursorName, CursorOperation operation,
short internalPrepare, char * argument,
NABoolean internalCursor)
: SqlCmd(SqlCmd::CURSOR_TYPE, argument), isHoldable_(FALSE),
resultSetIndex_(0), internalCursor_(internalCursor)
{
cursorName_ = new char[strlen(cursorName) + 1];
strcpy(cursorName_, cursorName);
operation_ = operation;
internalPrepare_ = internalPrepare;
}
Cursor::~Cursor()
{
delete [] cursorName_;
}
Execute::Execute(char * stmt_name_, char * argument_, short flag, SqlciEnv * sqlci_env)
: SqlCmd(SqlCmd::EXECUTE_TYPE, argument_)
{
this_stmt_name = new char[strlen(stmt_name_) + 1];
strcpy(this_stmt_name, stmt_name_);
num_params = 0;
for ( Int32 i=0; i<MAX_NUM_UNNAMED_PARAMS; i++ )
using_param_charsets[i]=CharInfo::UnknownCharSet;
if (flag)
{
Lng32 err = storeParams(argument_, num_params, using_params, using_param_charsets, sqlci_env);
if (err)
setErrorCode(err);
}
}
Execute::~Execute()
{
delete [] this_stmt_name;
for (Int32 i = num_params; i > 0; )
delete [] using_params[--i];
}
/*******************************************************/
/* store unnamed parameters in an array */
/* example: execute <stmt name> using 24, cat, 'dog'; */
/* input: 24, cat, 'dog'; */
/* output: none */
/*******************************************************/
static Lng32 errorParams(Lng32 err,
const char *str0 = NULL, Lng32 int0 = -99)
{
sqlci_DA << DgSqlCode(err) << DgString0(str0) << DgInt0(int0);
return err;
}
Lng32 Execute::storeParams(char* argument_, short &num_params,
char * using_params[],
CharInfo::CharSet using_param_charsets[],
SqlciEnv *sqlci_env)
{
ComASSERT(argument_);
num_params = 0;
// Trim trailing blanks and semicolons
size_t arglen = strlen(argument_);
for (; arglen; arglen--)
if (!isspace((unsigned char)argument_[arglen-1]) && argument_[arglen-1] != ';') // For VS2003
break;
char sentinel = argument_[arglen]; // either ';' or '\0'
argument_[arglen] = '\0'; // now '\0'
// Get past leading blanks
char *args = argument_;
while (*args)
{
NABoolean literal = TRUE; // if this arg is a literal, set it to 1
// otherwise, set it to 0. It's set to 1 as default.
while (isspace((unsigned char)*args)) args++; // For VS2003
if (num_params >= MAX_NUM_UNNAMED_PARAMS)
return errorParams(-SQLCI_NUM_PARAMS_OVERFLOW,
NULL,
MAX_NUM_UNNAMED_PARAMS);
char *errarg = args; // points to a non-blank value
char param[MAX_LEN_UNNAMED_PARAM+1]; // buffer for current value
size_t i = 0; // len(param)+1
if ( using_param_charsets && *args == '_' ) {
char* prefixPtr = args+1;
while ( *prefixPtr ) {
if ( *prefixPtr == '\'' ) {
// check if a valid charset name is found
// upper case the name first
Int32 nameLen = prefixPtr-args-1;
char* upperCaseName = new char[nameLen+1];
Int32 j;
for ( j =0; j<nameLen; j++) {
upperCaseName[j] = (char)TOUPPER(args[j+1]);
}
upperCaseName[j] = 0;
// name lookup
CharInfo::CharSet cs = CharInfo::getCharSetEnum(upperCaseName);
delete [] upperCaseName;
if (CharInfo::isCharSetFullySupported(cs)) {
errarg = args = prefixPtr; // advance the point to true start of the literal
} else {
*prefixPtr= '\0'; // terminate errarg at '\''
return errorParams(-SQLCI_SYNTAX_ERROR, errarg);
}
// fill the charset. If the prefix specifies an unsupported name,
// the cs is CharInfo::UnknownCharSet.
using_param_charsets[num_params] = cs;
break;
}
prefixPtr++;
}
}
switch (*args)
{
case '\'': // Convert 'ab' to ab, 'ab''c' to ab'c
// because basically we want
// USING 'ab' and USING ab
// to be equivalent.
{
char *qseen = errarg; // points to beginning ' of args
while (*args++ &&
i < MAX_LEN_UNNAMED_PARAM)
{
if (*args == '\'')
if (args[1] != '\'')
{ qseen = args++; break; } // ending ' of args
else
param[i++] = *args++; // yes, ++ to skip one ' of ''
else
param[i++] = *args; // no ++ (while does it)
}
if ( CharInfo::UnknownCharSet == using_param_charsets[num_params] )
{
// The character set attribute of a quoted string without a charset prefix is ...
if (sqlci_env != NULL)
using_param_charsets[num_params] = sqlci_env->getTerminalCharset();
else
using_param_charsets[num_params] = CharInfo::UnknownCharSet;
}
else {
// MP KANJI/KSC5601's params should be even in length
if ( CharInfo::is_NCHAR_MP(using_param_charsets[num_params]) &&
i % 2 != 0
) {
*args = '\0'; // terminate errarg
return errorParams(-SQLCI_SYNTAX_ERROR, errarg);
}
}
if (i >= MAX_LEN_UNNAMED_PARAM)
{
*args = '\0'; // terminate errarg
return errorParams(-SQLCI_LEN_PARAM_OVERFLOW,
errarg,
MAX_LEN_UNNAMED_PARAM);
}
if (qseen == errarg)
return errorParams(-SQLCI_INPUT_MISSING_QUOTE,
errarg);
while (isspace((unsigned char)*args)) args++; // go past trailing blanks// For VS2003
if (*args && *args != ',')
{
*++qseen = '\0'; // terminate errarg after end '
return errorParams(-SQLCI_PARAM_QUOTED_BAD_CONCAT,
errarg);
}
}
break;
default: // Copy as is, including embedded squotes and blanks
// (leading blanks were already removed above),
// to param value buffer, until we hit a comma
// (the param value separator).
// Then remove trailing blanks.
//
// ## This is kinda weird, nonAnsi syntax, **AND**
// ## does not at all match the way sqlci_yacc rejects any of
// ## SET PARAM ?p val ue string;
// ## SET PARAM ?p val'ue'str''ing;
// ## Could definitely be fixed here for consistency --
// ## i.e. reject embedded punctuation, esp ' and blanks...
// ##
// ## We do of course accept
// ## USING 'val ue string', 'val''ue''str''''ing';
// ## the same way sqlci_yacc accepts
// ## SET PARAM ?p 'val ue string';
// ## SET PARAM ?p 'val''ue''str''''ing';
// ## so that part's good.
{
for ( ;
*args && *args != ',' && i < MAX_LEN_UNNAMED_PARAM;
args++)
param[i++] = isspace((unsigned char)*args) ? ' ' : *args; // For VS2003
while (isspace((unsigned char)*args)) args++; // go past trailing blanks // For VS2003
if (i >= MAX_LEN_UNNAMED_PARAM)
{
if (*args && *args != ',')
{
*args = '\0'; // terminate errarg
if (&errarg[MAX_LEN_UNNAMED_PARAM+60] < args)
errarg[MAX_LEN_UNNAMED_PARAM+60] = '\0';
return errorParams(-SQLCI_LEN_PARAM_OVERFLOW,
errarg,
MAX_LEN_UNNAMED_PARAM);
}
}
while (i && isspace((unsigned char)param[i-1])) // Here, remove trailing// For VS2003
i--; // blanks from param[].
literal = FALSE;
// ## Yuck, we also allow
// ## USING,,; equiv to USING '','','';
// if (!i) return errorParams(-SQLCI_LEN_PARAM_UNDERFLOW);
}
} // switch *args
if (*args)
{
ComASSERT(*args == ','); // all blanks are past;
args++; // go past the comma
// Convert a final comma (with a blank value "after" it) to a blank,
// to make a final unquoted blank value for our next (and last) while-iter
if (!*args)
*--args = ' ';
}
// dynamically get space for the param value and store it in the array
param[i] = '\0';
//if there's a NULL value and it was not included in quotes, the param
//value is NULL. Otherwise, allocate a space for the param value in
//using_params
if (!literal && !strcmp(param, "NULL"))
using_params[num_params] = NULL;
else {
using_params[num_params] = new char[i+1];
strcpy(using_params[num_params], param);
}
num_params++;
} // while *args
argument_[arglen] = sentinel; // reset back to ';' or '\0'
if (!num_params)
return errorParams(-SQLCI_NUM_PARAMS_UNDERFLOW);
return 0; // no error
}
QueryCacheSt::QueryCacheSt(short option)
: SqlCmd(SqlCmd::QUERYCACHE_TYPE, ""),
option_(option)
{}
short SqlCmd::deallocate(SqlciEnv * sqlci_env, PrepStmt * prep_stmt)
{
Lng32 retcode;
// prepared statement exists. Deallocate it.
retcode = SQL_EXEC_DeallocDesc(prep_stmt->getSqlSrc());
if (prep_stmt->getSqlSrc())
{
if (prep_stmt->getSqlSrc()->module)
delete (SQLMODULE_ID *)prep_stmt->getSqlSrc()->module;
prep_stmt->getSqlSrc()->module = NULL;
}
HandleCLIError(retcode, sqlci_env);
retcode = SQL_EXEC_DeallocDesc(prep_stmt->getInputDesc());
HandleCLIError(retcode, sqlci_env);
retcode = SQL_EXEC_DeallocDesc(prep_stmt->getOutputDesc());
HandleCLIError(retcode, sqlci_env);
retcode = SQL_EXEC_DeallocStmt(prep_stmt->getStmt());
if (prep_stmt->getStmt())
{
if (prep_stmt->getStmt()->module)
delete (SQLMODULE_ID *)prep_stmt->getStmt()->module;
if (prep_stmt->getStmt()->identifier)
delete [] (char *)prep_stmt->getStmt()->identifier;
prep_stmt->getStmt()->identifier = NULL;
}
HandleCLIError(retcode, sqlci_env);
if (prep_stmt)
delete prep_stmt;
prep_stmt = NULL;
return retcode;
}
/////////////////////////////////////////////////////////////////
// ::process() methods
/////////////////////////////////////////////////////////////////
short DML::process(SqlciEnv * sqlci_env)
{
Lng32 retcode = 0, prepcode = 0, retcodeExe = 0;
// Bookkeeping for stored procedure result sets
NABoolean isResultSet = (type == DML_CALL_STMT_RS_TYPE ? TRUE : FALSE);
NABoolean skipStats = isResultSet;
if (!isResultSet)
HandleCLIErrorInit();
char dml_stmt_name[50];
// if this_stmt_name is not NULL, then this method was invoked by
// an sqlci internal method (like stats...etc).
if (! this_stmt_name)
strcpy(dml_stmt_name, "__SQLCI_DML_LAST__"); // generate a dummy name
else
strcpy(dml_stmt_name, this_stmt_name);
PrepStmt * prep_stmt;
if (prep_stmt = sqlci_env->get_prep_stmts()->get(dml_stmt_name))
{
// this statement name should not be present in the list of prepared
// stmts as it is an internal name. If we reach this error, it
// means that someone has prepared a statement with the same
// name as what we used internally. We need to fix our internal
// name.
sqlci_env->diagsArea() << DgSqlCode(-SQLCI_INTERNAL_ERROR);
return 0;
}
prep_stmt = new PrepStmt(dml_stmt_name, type);
if (!skipStats)
sqlci_env->getStats()->startStats(prep_stmt);
NABoolean resetLastExecStmt = (isResultSet ? FALSE : TRUE);
Int32 prepareCode = 0;
Lng32 statisticsType = SQLCLI_NO_STATS;
prepcode = do_prepare(sqlci_env, prep_stmt, get_sql_stmt(),
resetLastExecStmt, rsIndex_,&prepareCode, &statisticsType);
if (statisticsType == SQLCLI_NO_STATS)
skipStats = TRUE;
if (!skipStats)
sqlci_env->getStats()->startExeStats();
if (prepcode >= 0)
{
NABoolean skipExec = FALSE;
char * po = sqlci_env->getPrepareOnly();
char * eo = sqlci_env->getExecuteOnly();
if (!po && !eo)
{
retcodeExe = do_execute(sqlci_env, prep_stmt, 0, NULL, NULL, prepareCode);
}
else
{
// only adding prepareOnly for DML. Other cases could
// be added later.
if ((po) && (strcmp(po, "DML") == 0) &&
((prep_stmt->getType() == DML_SELECT_TYPE) ||
(prep_stmt->getType() == DML_UPDATE_TYPE) ||
(prep_stmt->getType() == DML_INSERT_TYPE) ||
(prep_stmt->getType() == DML_DELETE_TYPE)))
{
// don't execute in this case.
sqlci_env->lastExecutedStmt() = NULL;
Logfile *log = sqlci_env->get_logfile();
if (!lastLineWasABlank) log->WriteAll("");
log->WriteAll(PREPARED_MESSAGE);
}
else
{
retcodeExe = do_execute(sqlci_env, prep_stmt);
}
}
}
if (!skipStats)
{
sqlci_env->getStats()->endExeStats();
sqlci_env->getStats()->endStats(sqlci_env);
}
// if stats were collected for this statement, then do not
// deallocate it. Deallocating the stmt will destroy the stats area
// in executor and a subsequent 'display statistics' command will
// not be able to display stats.
// This statement will be deallocated when the next standalone
// statement is issued from sqlci.
NABoolean deallocStmt = ((prepcode >= 0) ? TRUE : FALSE);
// do not display stats for internal invocations. Do it for user
// entered standalone non-prepared queries only.
if ((this_stmt_name == NULL) && (deallocStmt) &&
(sqlci_env->lastExecutedStmt()) &&
(statisticsType != SQLCLI_NO_STATS))
{
sqlci_env->getStats()->displayStats(sqlci_env);
}
if (deallocStmt)
{
retcode = deallocate(sqlci_env, prep_stmt);
// if the stmt has already been deallocated then
// there is no need to deallocate it in the interrupt handler.
if (!isResultSet)
{
if (! retcode)
global_sqlci_env->resetDeallocateStmt() ;
sqlci_env->lastExecutedStmt() = NULL;
}
}
if ( breakReceived )
{
breakReceived = 0;
if ((prepcode >= 0) && (retcodeExe != SQL_Canceled) && (retcodeExe != SQL_Rejected))
{
sqlci_env->diagsArea() << DgSqlCode(SQLCI_BREAK_RECEIVED, DgSqlCode::WARNING_);
return SQL_Canceled;
}
}
// TEMP TEMP
// Sometimes inserted rows are not being flushed out. That causes selected
// rows to not get returned.
// Temporarily add a one sec delay so it can get flushed out.
// Do this only for regressions run.
if ((prep_stmt) && (prep_stmt->getType() == DML_INSERT_TYPE) &&
(getenv("SQLMX_REGRESS")))
{
//DELAY(100);
}
if ((prepcode >= 0) && (retcodeExe == SQL_Canceled))
{
return (short)retcodeExe;
}
else
{
if (prepcode)
return 1;
else
return 0;
}
} // end DML::process
/////////////////////////////////////////////
// Begin PREPARE
//////////////////////////////////////////////
short Prepare::process(SqlciEnv * sqlci_env)
{
Lng32 retcode;
HandleCLIErrorInit();
PrepStmt * prep_stmt;
if (prep_stmt = sqlci_env->get_prep_stmts()->get(this_stmt_name))
{
// prepared statement exists. Deallocate it.
retcode = SQL_EXEC_DeallocDesc(prep_stmt->getSqlSrc());
HandleCLIError(retcode, sqlci_env);
retcode = SQL_EXEC_DeallocDesc(prep_stmt->getInputDesc());
HandleCLIError(retcode, sqlci_env);
retcode = SQL_EXEC_DeallocDesc(prep_stmt->getOutputDesc());
HandleCLIError(retcode, sqlci_env);
retcode = SQL_EXEC_DeallocStmt(prep_stmt->getStmt());
HandleCLIError(retcode, sqlci_env);
sqlci_env->get_prep_stmts()->remove(this_stmt_name);
}
prep_stmt = new PrepStmt(this_stmt_name, type);
sqlci_env->getStats()->startStats(prep_stmt);
retcode = do_prepare(sqlci_env, prep_stmt, get_sql_stmt());
sqlci_env->getStats()->endStats(sqlci_env);
// if do_prepare was successfull then reset
// the deallocate stmt in global_sqlci_env
// in case of a break.
if (retcode >= 0)
{
global_sqlci_env->resetDeallocateStmt() ;
}
if (retcode >= 0)
{
sqlci_env->get_prep_stmts()->append(prep_stmt);
Logfile *log = sqlci_env->get_logfile();
if (!lastLineWasABlank) log->WriteAll("");
log->WriteAll(PREPARED_MESSAGE);
}
// This is Prepare; no Exe time at all
sqlci_env->getStats()->startExeStats();
sqlci_env->getStats()->endExeStats();
sqlci_env->getStats()->displayStats(sqlci_env);
return 0;
}
// Prepare::process has already set up the PrepStmt by calling
// DescribeStmt CLI call and allocate PrepStmt. Some descriptor items
// has already been extracted from the output descriptor, such as
// type, length, precision, scale.
///////////////////////////////////////////////////////
// Begin DESCRIBESTMT
//////////////////////////////////////////////////////
short DescribeStmt::displayEntries(SqlciEnv *sqlci_env,
SQLDESC_ID *desc, Lng32 numEntries,
Logfile *log)
{
char scratchBuffer[512];
char charVal[ComAnsiNamePart::MAX_IDENTIFIER_EXT_LEN+1];
Lng32 intVal;
Lng32 retcode;
// For each entry produce the following output
//
// [i] NAME "column-name", HEADING "column-heading"
// TYPE n, FS n, LEN n, OCTLEN n, CHARSET n
// PREC n, LPREC n, SCALE n, DTCODE n, NULL n, MODE n, IDX n, ORDPOS n
// CAT "catalog-name", SCH "schema-name", TABLE "table-name"
for (Lng32 entry = 1; entry <= numEntries; entry++)
{
sprintf(scratchBuffer, "[%d] ", entry);
log->WriteAllWithoutEOL(scratchBuffer);
retcode = SQL_EXEC_GetDescItem(desc, entry,
SQLDESC_NAME,
0, charVal,
ComAnsiNamePart::MAX_IDENTIFIER_EXT_LEN,
&intVal, 0);
HandleCLIError(retcode, sqlci_env);
charVal[intVal] = 0;
sprintf(scratchBuffer, "NAME \"%s\", ", charVal);
log->WriteAllWithoutEOL(scratchBuffer);
retcode = SQL_EXEC_GetDescItem(desc, entry,
SQLDESC_HEADING,
0, charVal,
ComAnsiNamePart::MAX_IDENTIFIER_EXT_LEN,
&intVal, 0);
HandleCLIError(retcode, sqlci_env);
charVal[intVal] = 0;
sprintf(scratchBuffer, "HEADING \"%s\"", charVal);
log->WriteAll(scratchBuffer);
// ------------------------------------------------
retcode = SQL_EXEC_GetDescItem(desc, entry,
SQLDESC_TYPE,
&intVal, 0, 0, 0, 0);
HandleCLIError(retcode, sqlci_env);
sprintf(scratchBuffer, " TYPE %d, ", intVal);
log->WriteAllWithoutEOL(scratchBuffer);
retcode = SQL_EXEC_GetDescItem(desc, entry,
SQLDESC_TYPE_FS,
&intVal, 0, 0, 0, 0);
HandleCLIError(retcode, sqlci_env);
sprintf(scratchBuffer, "FS %d, ", intVal);
log->WriteAllWithoutEOL(scratchBuffer);
retcode = SQL_EXEC_GetDescItem(desc, entry,
SQLDESC_LENGTH,
&intVal, 0, 0, 0, 0);
HandleCLIError(retcode, sqlci_env);
sprintf(scratchBuffer, "LEN %d, ", intVal);
log->WriteAllWithoutEOL(scratchBuffer);
retcode = SQL_EXEC_GetDescItem(desc, entry,
SQLDESC_OCTET_LENGTH,
&intVal, 0, 0, 0, 0);
HandleCLIError(retcode, sqlci_env);
sprintf(scratchBuffer, "OCTLEN %d, ", intVal);
log->WriteAllWithoutEOL(scratchBuffer);
retcode = SQL_EXEC_GetDescItem(desc, entry,
SQLDESC_CHAR_SET,
&intVal, 0, 0, 0, 0);
HandleCLIError(retcode, sqlci_env);
sprintf(scratchBuffer, "CHARSET %d", intVal);
log->WriteAll(scratchBuffer);
// ------------------------------------------------
retcode = SQL_EXEC_GetDescItem(desc, entry,
SQLDESC_PRECISION,
&intVal, 0, 0, 0, 0);
HandleCLIError(retcode, sqlci_env);
sprintf(scratchBuffer, " PREC %d, ", intVal);
log->WriteAllWithoutEOL(scratchBuffer);
retcode = SQL_EXEC_GetDescItem(desc, entry,
SQLDESC_INT_LEAD_PREC,
&intVal, 0, 0, 0, 0);
HandleCLIError(retcode, sqlci_env);
sprintf(scratchBuffer, "LPREC %d, ", intVal);
log->WriteAllWithoutEOL(scratchBuffer);
retcode = SQL_EXEC_GetDescItem(desc, entry,
SQLDESC_SCALE,
&intVal, 0, 0, 0, 0);
HandleCLIError(retcode, sqlci_env);
sprintf(scratchBuffer, "SCALE %d, ", intVal);
log->WriteAllWithoutEOL(scratchBuffer);
retcode = SQL_EXEC_GetDescItem(desc, entry,
SQLDESC_DATETIME_CODE,
&intVal, 0, 0, 0, 0);
HandleCLIError(retcode, sqlci_env);
sprintf(scratchBuffer, "DTCODE %d, ", intVal);
log->WriteAllWithoutEOL(scratchBuffer);
retcode = SQL_EXEC_GetDescItem(desc, entry,
SQLDESC_NULLABLE,
&intVal, 0, 0, 0, 0);
HandleCLIError(retcode, sqlci_env);
sprintf(scratchBuffer, "NULL %d, ", intVal);
log->WriteAllWithoutEOL(scratchBuffer);
retcode = SQL_EXEC_GetDescItem(desc, entry,
SQLDESC_PARAMETER_MODE,
&intVal, 0, 0, 0, 0);
HandleCLIError(retcode, sqlci_env);
sprintf(scratchBuffer, "MODE %d, ", intVal);
log->WriteAllWithoutEOL(scratchBuffer);
retcode = SQL_EXEC_GetDescItem(desc, entry,
SQLDESC_PARAMETER_INDEX,
&intVal, 0, 0, 0, 0);
HandleCLIError(retcode, sqlci_env);
sprintf(scratchBuffer, "IDX %d, ", intVal);
log->WriteAllWithoutEOL(scratchBuffer);
retcode = SQL_EXEC_GetDescItem(desc, entry,
SQLDESC_ORDINAL_POSITION,
&intVal, 0, 0, 0, 0);
HandleCLIError(retcode, sqlci_env);
sprintf(scratchBuffer, "ORDPOS %d", intVal);
log->WriteAll(scratchBuffer);
// ------------------------------------------------
retcode = SQL_EXEC_GetDescItem(desc, entry,
SQLDESC_CATALOG_NAME,
0, charVal,
ComAnsiNamePart::MAX_IDENTIFIER_EXT_LEN,
&intVal, 0);
HandleCLIError(retcode, sqlci_env);
charVal[intVal] = 0;
sprintf(scratchBuffer, " CAT \"%s\", ", charVal);
log->WriteAllWithoutEOL(scratchBuffer);
retcode = SQL_EXEC_GetDescItem(desc, entry,
SQLDESC_SCHEMA_NAME,
0, charVal,
ComAnsiNamePart::MAX_IDENTIFIER_EXT_LEN,
&intVal, 0);
HandleCLIError(retcode, sqlci_env);
charVal[intVal] = 0;
sprintf(scratchBuffer, "SCH \"%s\", ", charVal);
log->WriteAllWithoutEOL(scratchBuffer);
retcode = SQL_EXEC_GetDescItem(desc, entry,
SQLDESC_TABLE_NAME,
0, charVal,
ComAnsiNamePart::MAX_IDENTIFIER_EXT_LEN,
&intVal, 0);
HandleCLIError(retcode, sqlci_env);
charVal[intVal] = 0;
sprintf(scratchBuffer, "TABLE \"%s\"", charVal);
log->WriteAll(scratchBuffer);
}
return 0;
}
short DescribeStmt::process(SqlciEnv * sqlci_env)
{
HandleCLIErrorInit();
PrepStmt *prep_stmt;
if (!(prep_stmt = sqlci_env->get_prep_stmts()->get(stmtName_)))
{
sqlci_env->diagsArea() << DgSqlCode(-SQLCI_STMT_NOT_FOUND)
<< DgString0(stmtName_);
return 0;
}
sqlci_env->getStats()->startStats(prep_stmt);
sqlci_env->getStats()->startExeStats();
// meat of the body
Logfile *log = sqlci_env->get_logfile();
SQLDESC_ID * input_desc = prep_stmt->getInputDesc();
SQLDESC_ID * output_desc = prep_stmt->getOutputDesc();
Lng32 num_input_entries = prep_stmt->numInputEntries();
Lng32 num_output_entries = prep_stmt->numOutputEntries();
if (num_input_entries > 0)
{
log->WriteAll("---Describing the INPUT entries---");
displayEntries(sqlci_env, input_desc, num_input_entries, log);
}
if (num_output_entries > 0)
{
log->WriteAll("---Describing the OUTPUT entries---");
displayEntries(sqlci_env, output_desc, num_output_entries, log);
}
// eye marker
sqlci_env->getStats()->endExeStats();
sqlci_env->getStats()->endStats(sqlci_env);
sqlci_env->getStats()->displayStats(sqlci_env);
return 0;
}
short StoreExplain::process(SqlciEnv * sqlci_env)
{
Lng32 retcode;
HandleCLIErrorInit();
PrepStmt * prep_stmt;
if (!(prep_stmt = sqlci_env->get_prep_stmts()->get(get_sql_stmt())))
{
sqlci_env->diagsArea() << DgSqlCode(-SQLCI_STMT_NOT_FOUND)
<< DgString0(get_sql_stmt());
return 0;
}
retcode = updateRepos(sqlci_env, prep_stmt->getStmt(), prep_stmt->uniqueQueryId());
char donemsg[100];
donemsg[0] = '\0';
if (retcode == 0)
sprintf(donemsg, OP_COMPLETE_MESSAGE);
else if (retcode > 0)
sprintf(donemsg, OP_COMPLETED_WARNINGS);
else
sprintf(donemsg, OP_COMPLETED_ERRORS);
Logfile *log = sqlci_env->get_logfile();
if (!lastLineWasABlank)
{
log->WriteAll("");
lastLineWasABlank = TRUE;
}
if (donemsg[0] != '\0')
{
log->WriteAll(donemsg);
lastLineWasABlank = FALSE;
}
return 0;
}
///////////////////////////////////////////
/// Begin Execute
///////////////////////////////////////////
short Execute::process(SqlciEnv * sqlci_env)
{
Lng32 retcode;
HandleCLIErrorInit();
PrepStmt * prep_stmt;
if (!(prep_stmt = sqlci_env->get_prep_stmts()->get(this_stmt_name)))
{
sqlci_env->diagsArea() << DgSqlCode(-SQLCI_STMT_NOT_FOUND)
<< DgString0(this_stmt_name);
return 0;
}
sqlci_env->getStats()->startStats(prep_stmt);
sqlci_env->getStats()->startExeStats();
retcode = do_execute(sqlci_env, prep_stmt,
getNumParams(),
getUnnamedParamArray(),
getUnnamedParamCharSetArray());
sqlci_env->getStats()->endExeStats();
sqlci_env->getStats()->endStats(sqlci_env);
sqlci_env->getStats()->displayStats(sqlci_env);
return 0;
}
//////////////////////////////////////////
// Begin Cursor
//////////////////////////////////////////
// return of -1 is error, cursor operation was not done.
// return of 0 is returned with some cursor/cli operation done.
// retcode contains indication if it succeeded(=0) or failed(!= 0)
short Cursor::declareC(SqlciEnv * sqlci_env, char * donemsg,
Lng32 &retcode)
{
short result = 0;
HandleCLIErrorInit();
if (resultSetIndex_ > 0)
result = declareCursorStmtForRS(sqlci_env, retcode);
else
result = declareCursorStmt(sqlci_env, retcode);
if (donemsg)
{
if (retcode >= 0)
sprintf(donemsg, OP_COMPLETE_MESSAGE);
else
sprintf(donemsg, OP_COMPLETED_ERRORS);
}
// This is Declare; no Exe time at all
sqlci_env->getStats()->startExeStats();
sqlci_env->getStats()->endExeStats();
sqlci_env->getStats()->displayStats(sqlci_env);
return result;
}
// return of -1 is error, cursor operation was not done.
// return of 0 is returned with some cursor/cli operation done.
// retcode contains indication if it succeeded(=0) or failed(!= 0)
short Cursor::declareCursorStmt(SqlciEnv *sqlci_env, Lng32 &retcode)
{
short result = 0;
CursorStmt * cursor;
PrepStmt * prepStmt = NULL;
retcode = SQL_Success;
if (! internalPrepare_)
{
// make sure that the prepared stmt exists.
if (! (prepStmt = sqlci_env->get_prep_stmts()->get(get_sql_stmt())))
{
sqlci_env->diagsArea() << DgSqlCode(-SQLCI_STMT_NOT_FOUND)
<< DgString0(get_sql_stmt());
return -1;
}
}
if (cursor = sqlci_env->getCursorList()->get(cursorName_))
{
cleanupCursorStmt(sqlci_env, cursor);
cursor = NULL;
}
if (internalPrepare_)
{
NAString nameForPrepStmt("__SQLCI_PREPSTMT_FOR_CURSOR_");
nameForPrepStmt += cursorName_;
nameForPrepStmt += "__";
prepStmt = new PrepStmt(nameForPrepStmt.data());
sqlci_env->getStats()->startStats(prepStmt);
// sqlci makes all SELECT's to be readonly by issuing a
// control command at startup time. Since this is an explicit
// DECLARE cursor statement which could later be updated/deleted
// using an "upd/del...where current of" statement, temporarily
// turn the readonly_cursor off. Turn it back on after this
// query has been prepared.
// If this is not an internal prepare, then users will have to
// specify the FOR UPDATE OF clause when they prepare the SELECT.
// Otherwise they will not be able to do a cursor update/delete.
retcode =
executeQuery("CONTROL QUERY DEFAULT READONLY_CURSOR 'FALSE';",
sqlci_env);
if (retcode >= 0) // QSTUFF
{
Lng32 prepcode = do_prepare(sqlci_env, prepStmt, get_sql_stmt());
retcode =
executeQuery("CONTROL QUERY DEFAULT READONLY_CURSOR 'TRUE';",
sqlci_env);
if (retcode >= 0 && prepcode)
retcode = prepcode;
}
sqlci_env->getStats()->endStats(sqlci_env);
}
else
retcode = 0;
ComASSERT(prepStmt);
if (retcode >= 0)
{
// Make a copy of the cursor name
UInt32 nameLen = strlen(cursorName_);
char *identifier = new char[nameLen + 1];
strcpy(identifier, cursorName_);
// Make a statement ID for the new cursor
SQLSTMT_ID *cursorStmtId = new SQLSTMT_ID;
memset(cursorStmtId, 0, sizeof(SQLSTMT_ID));
cursorStmtId->version = SQLCLI_CURRENT_VERSION;
cursorStmtId->name_mode = cursor_name;
cursorStmtId->identifier_len = (Lng32) nameLen;
cursorStmtId->identifier = identifier;
cursorStmtId->handle = 0;
cursorStmtId->module = prepStmt->getStmt()->module;
retcode = SQL_EXEC_AllocStmt(cursorStmtId, prepStmt->getStmt());
HandleCLIError(retcode, sqlci_env);
// QSTUFF: set the holdable cursor flag if necessary
if (isHoldable())
{
Lng32 attrValue = SQL_HOLDABLE;
retcode = SQL_EXEC_SetStmtAttr(cursorStmtId,
SQL_ATTR_CURSOR_HOLDABLE,
attrValue, NULL);
HandleCLIError(retcode, sqlci_env);
if (retcode < 0)
{
Lng32 cleanupRetcode;
cleanupRetcode = SQL_EXEC_DeallocDesc(prepStmt->getSqlSrc());
HandleCLIError(cleanupRetcode, sqlci_env);
cleanupRetcode = SQL_EXEC_DeallocDesc(prepStmt->getInputDesc());
HandleCLIError(cleanupRetcode, sqlci_env);
cleanupRetcode = SQL_EXEC_DeallocDesc(prepStmt->getOutputDesc());
HandleCLIError(cleanupRetcode, sqlci_env);
cleanupRetcode = SQL_EXEC_DeallocStmt(prepStmt->getStmt());
HandleCLIError(cleanupRetcode, sqlci_env);
}
} // if (isHoldable())
if (retcode >= 0)
{
cursor = new CursorStmt(cursorName_, cursorStmtId,
prepStmt, internalPrepare_);
sqlci_env->getCursorList()->append(cursor);
}
else
{
delete [] identifier;
delete cursorStmtId;
}
}
return result;
} // Cursor::declareCursorStmt
// Create a CursorStmt object for a stored procedure result set
// return of -1 is error, cursor operation was not done.
// return of 0 is returned with some cursor/cli operation done.
// retcode contains indication if it succeeded(=0) or failed(!= 0)
short Cursor::declareCursorStmtForRS(SqlciEnv * sqlci_env, Lng32 &retcode)
{
short result = 0; // the return value of this function
PrepStmt *prepStmt = NULL;
CursorStmt *cursor = NULL;
CursorStmt *parentCursor = NULL;
char *nameOfParent = get_sql_stmt();
retcode = SQL_Success;
// This is a stored procedure result set cursor. The
// parent must be another cursor, not a prepared
// statement.
parentCursor = sqlci_env->getCursorList()->get(nameOfParent);
if (!parentCursor)
{
sqlci_env->diagsArea() << DgSqlCode(-SQLCI_STMT_NOT_FOUND)
<< DgString0(nameOfParent);
return -1;
}
if (cursor = sqlci_env->getCursorList()->get(cursorName_))
{
cleanupCursorStmt(sqlci_env, cursor);
cursor = NULL;
}
// Create a PrepStmt for this result set. It will be used later to
// store the column descriptions. It doesn't get used for anything
// else.
NAString nameForPrepStmt("__SQLCI_PREPSTMT_FOR_CURSOR_");
nameForPrepStmt += cursorName_;
nameForPrepStmt += "__";
prepStmt = new PrepStmt(nameForPrepStmt.data());
// Give this PrepStmt instance a dummy name, so that SHOW CURSOR
// has something to display
char buf[100];
sprintf(buf, "Result set %d, child of ", (Lng32) resultSetIndex_);
NAString dummyName(buf);
dummyName += nameOfParent;
// Push values into the PrepStmt instance. Information about the
// output columns will be filled in later. It becomes available only
// after the parent CALL statement executes.
prepStmt->set((char *) dummyName.data(),
NULL, // SQLDESC_ID *sql_src_
NULL, // SQLSTMT_ID *stmt_
0, // Lng32 numInputEntries
NULL, // SQLDESC_ID *input_desc_
0, // Lng32 numOutputEntries
NULL); // SQLDESC_ID *output_desc_
// Make a statement ID for the new result set statement
SQLSTMT_ID *childStmtId = new SQLSTMT_ID;
SQLSTMT_ID *parentStmtId = parentCursor->cursorStmtId();
*childStmtId = *parentStmtId;
childStmtId->name_mode = stmt_handle;
childStmtId->identifier = NULL;
childStmtId->identifier_len = 0;
retcode = SQL_EXEC_AllocStmtForRS(parentStmtId,
resultSetIndex_,
childStmtId);
HandleCLIError(retcode, sqlci_env);
if (retcode >= 0)
{
cursor = new CursorStmt(cursorName_, childStmtId,
prepStmt, FALSE);
cursor->setResultSetIndex(resultSetIndex_);
sqlci_env->getCursorList()->append(cursor);
}
else
delete prepStmt;
return result;
} // Cursor::decalreCursorStmtForRS
// return of -1 is error, cursor operation was not done.
// return of 0 is returned with some cursor/cli operation done.
// retcode contains indication if it succeeded(=0) or failed(!= 0)
short Cursor::open(SqlciEnv * sqlci_env, char * donemsg,
Lng32 &retcode)
{
CursorStmt * cursor;
HandleCLIErrorInit();
retcode = SQL_Success;
if (! (cursor = sqlci_env->getCursorList()->get(cursorName_)))
{
sqlci_env->diagsArea() << DgSqlCode(-SQLCI_STMT_NOT_FOUND)
<< DgString0(cursorName_);
return -1;
}
retcode = doExec(sqlci_env,
cursor->cursorStmtId(),
cursor->prepStmt());
if (retcode >= 0)
{
// If this is a stored procedure result set cursor then we now
// need to DESCRIBE the statement. The DESCRIBE can only be done
// reliably after the CALL statement executes, not necessarily at
// the time the cursor is DECLAREd.
if (cursor->getResultSetIndex() > 0)
{
PrepStmt *p = cursor->prepStmt();
Lng32 num_output_entries = 0;
SQLDESC_ID *output_desc = p->getOutputDesc();
if (!output_desc)
{
output_desc = new SQLDESC_ID;
memset(output_desc, 0, sizeof(SQLDESC_ID));
init_SQLDESC_ID(output_desc,
SQLCLI_CURRENT_VERSION,
desc_handle,
cursor->cursorStmtId()->module);
retcode = SQL_EXEC_AllocDesc(output_desc, 500);
HandleCLIError(retcode, sqlci_env);
}
if (retcode >= 0)
{
retcode = SQL_EXEC_DescribeStmt(cursor->cursorStmtId(),
NULL,
output_desc);
HandleCLIError(retcode, sqlci_env);
}
if (retcode >= 0)
{
retcode = SQL_EXEC_GetDescEntryCount(output_desc,
&num_output_entries);
HandleCLIError(retcode, sqlci_env);
}
if (retcode >= 0)
{
p->setOutputDesc(num_output_entries, output_desc);
addOutputInfoToPrepStmt(sqlci_env, p);
}
else
delete output_desc;
} // if (cursor->getResultSetIndex() > 0)
} // if (retcode >= 0)
if (retcode >= 0)
{
if (donemsg)
sprintf(donemsg, OP_COMPLETE_MESSAGE);
}
else
{
if (donemsg)
sprintf(donemsg, OP_COMPLETED_ERRORS);
}
return 0;
}
// return of -1 is error, cursor operation was not done.
// return of 0 is returned with some cursor/cli operation done.
// retcode contains indication if it succeeded(=0) or failed(!= 0)
short Cursor::fetch(SqlciEnv * sqlci_env,
NABoolean doDisplayRow,
char * donemsg,
Lng32 &retcode)
{
CursorStmt * cursor;
HandleCLIErrorInit();
retcode = SQL_Success;
if (! (cursor = sqlci_env->getCursorList()->get(cursorName_)))
{
sqlci_env->diagsArea() << DgSqlCode(-SQLCI_STMT_NOT_FOUND)
<< DgString0(cursorName_);
return -1;
}
PrepStmt *p = cursor->prepStmt();
if (p && p->numOutputEntries() < 1)
doDisplayRow = FALSE;
retcode = doFetch(sqlci_env,
cursor->cursorStmtId(),
p);
if (Succ_or_Warn)
{
if (doDisplayRow)
{
displayHeading(sqlci_env, p);
displayRow(sqlci_env, p);
Logfile *log = sqlci_env->get_logfile();
log->WriteAll(p->outputBuf());
lastLineWasABlank = FALSE;
}
if (donemsg)
sprintf(donemsg, SELECTED_MESSAGE, 1);
}
else
{
if (donemsg)
sprintf(donemsg, SELECTED_MESSAGE, 0);
}
return 0;
}
// return of -1 is error, cursor operation was not done.
// return of 0 is returned with some cursor/cli operation done.
// retcode contains indication if it succeeded(=0) or failed(!= 0)
short Cursor::close(SqlciEnv * sqlci_env, char * donemsg,
Lng32 &retcode)
{
CursorStmt * cursor;
HandleCLIErrorInit();
retcode = SQL_Success;
if (! (cursor = sqlci_env->getCursorList()->get(cursorName_)))
{
sqlci_env->diagsArea() << DgSqlCode(-SQLCI_STMT_NOT_FOUND)
<< DgString0(cursorName_);
return -1;
}
retcode = SQL_EXEC_CloseStmt(cursor->cursorStmtId());
HandleCLIError(retcode, sqlci_env);
if (retcode > 0)
getRowsAffected(cursor->cursorStmtId());
if (donemsg)
sprintf(donemsg, OP_COMPLETE_MESSAGE);
return 0;
}
// return of -1 is error, cursor operation was not done.
// return of 0 is returned with some cursor/cli operation done.
// retcode contains indication if it succeeded(=0) or failed(!= 0)
short Cursor::dealloc(SqlciEnv * sqlci_env, char * donemsg,
Lng32 &retcode)
{
CursorStmt * cursor;
HandleCLIErrorInit();
retcode = SQL_Success;
if (! (cursor = sqlci_env->getCursorList()->get(cursorName_)))
{
sqlci_env->diagsArea() << DgSqlCode(-SQLCI_STMT_NOT_FOUND)
<< DgString0(cursorName_);
return -1;
}
cleanupCursorStmt(sqlci_env, cursor);
if (donemsg)
sprintf(donemsg, OP_COMPLETE_MESSAGE);
return 0;
}
// Helper function to do all cleanup when a CursorStmt is no longer
// needed.
void Cursor::cleanupCursorStmt(SqlciEnv *sqlci_env, CursorStmt *c)
{
if (!c)
return;
Lng32 retcode = 0;
SQLSTMT_ID *cursorStmtId = c->cursorStmtId();
// Deallocate the underlying SQL statement if this is a stored
// procedure result set
NABoolean isResultSet = (c->getResultSetIndex() > 0 ? TRUE : FALSE);
if (isResultSet && cursorStmtId)
{
retcode = SQL_EXEC_DeallocStmt(cursorStmtId);
HandleCLIError(retcode, sqlci_env);
}
// The PrepStmt for this cursor should be deallocated if either of
// the following are true
// - it was internally prepared
// (e.g. "declare cursor C for select * from t")
// - this is a stored procedure result set
PrepStmt *prepStmt = c->prepStmt();
if (prepStmt && (c->internallyPrepared() || isResultSet))
{
SQLDESC_ID *sqlSrcDesc = prepStmt->getSqlSrc();
SQLDESC_ID *inDesc = prepStmt->getInputDesc();
SQLDESC_ID *outDesc = prepStmt->getOutputDesc();
SQLSTMT_ID *stmtId = prepStmt->getStmt();
if (sqlSrcDesc)
{
retcode = SQL_EXEC_DeallocDesc(sqlSrcDesc);
HandleCLIError(retcode, sqlci_env);
}
if (inDesc)
{
retcode = SQL_EXEC_DeallocDesc(inDesc);
HandleCLIError(retcode, sqlci_env);
}
if (outDesc)
{
retcode = SQL_EXEC_DeallocDesc(outDesc);
HandleCLIError(retcode, sqlci_env);
}
if (stmtId)
{
retcode = SQL_EXEC_DeallocStmt(stmtId);
HandleCLIError(retcode, sqlci_env);
}
}
// Remove c from the cursor list. This will also call the destructor
// for c.
sqlci_env->getCursorList()->remove(c->cursorName());
}
short Cursor::process(SqlciEnv * sqlci_env)
{
short rc = 0;
if ((NOT internalCursor_) &&
(! getenv("SQLCI_CURSOR"))) //## rename this to SQL_MXCI_CURSOR ...
{
sqlci_env->diagsArea() << DgSqlCode(-SQLCI_CURSOR_NOT_SUPPORTED);
return 0;
}
Lng32 retcode = 0;
char donemsg[100];
donemsg[0] = '\0';
switch (operation_)
{
case DECLARE:
rc = declareC(sqlci_env, donemsg, retcode);
break;
case OPEN:
rc = open(sqlci_env, donemsg, retcode);
break;
case FETCH:
rc = fetch(sqlci_env, TRUE, donemsg, retcode);
break;
case CLOSE:
rc = close(sqlci_env, donemsg, retcode);
break;
case DEALLOC:
rc = dealloc(sqlci_env, donemsg, retcode);
break;
}
// All the CURSOR methods return 0 or -1. Write the completion
// message when (rc == 0). In case of rs==-1, the diags is filled with
// error conditions.
if (rc == 0)
{
Logfile *log = sqlci_env->get_logfile();
if (!lastLineWasABlank) log->WriteAll("");
if (donemsg[0] != '\0') log->WriteAll(donemsg);
}
return 0;
}
// unified display_qc to display data as follows:
// CURSIZE MAXSIZE ENTRIES PLANS LOOKUPS HITS HITRATE
// --------- --------- ---------- ---------- ---------- ---------- -------
// 429.49MB 29.49GB 858992 858992 429.496E+7 420.000E+7 97.78%
// hit rate = hits / lookups
static const char * query_cache_query =
" SELECT "
" (CASE WHEN CURRENT_SIZE > 1048575 THEN "
" CONCAT(RTRIM(CAST(CAST(CURRENT_SIZE/1048576 AS NUMERIC(7,2)) AS CHAR(7) CHARACTER SET ISO88591)), _ISO88591'GB') ELSE "
" (CASE WHEN CURRENT_SIZE > 1023 THEN "
" CONCAT(RTRIM(CAST(CAST(CURRENT_SIZE/1024 AS NUMERIC(7,2)) AS CHAR(7) CHARACTER SET ISO88591)), _ISO88591'MB') ELSE "
" CONCAT(RTRIM(CAST(CURRENT_SIZE AS CHAR(7) CHARACTER SET ISO88591)), _ISO88591'KB') "
" END) "
" END) AS CURSIZE, "
" (CASE WHEN MAX_CACHE_SIZE > 1048575 THEN "
" CONCAT(RTRIM(CAST(CAST(MAX_CACHE_SIZE/1048576 AS NUMERIC(7,2)) AS CHAR(7) CHARACTER SET ISO88591)), _ISO88591'GB') ELSE "
" (CASE WHEN MAX_CACHE_SIZE > 1023 THEN "
" CONCAT(RTRIM(CAST(CAST(MAX_CACHE_SIZE/1024 AS NUMERIC(7,2)) AS CHAR(7) CHARACTER SET ISO88591)), _ISO88591'MB') ELSE "
" CONCAT(RTRIM(CAST(MAX_CACHE_SIZE AS CHAR(7) CHARACTER SET ISO88591)), _ISO88591'KB') "
" END) "
" END) AS MAXSIZE, "
" (CASE WHEN NUM_ENTRIES + TEXT_ENTRIES > 9999999 THEN "
" CONCAT(RTRIM(CAST(CAST((NUM_ENTRIES + TEXT_ENTRIES)/10000000 AS NUMERIC(7,3)) "
" AS CHAR(7) CHARACTER SET ISO88591)), _ISO88591'E+7') ELSE "
" CAST(NUM_ENTRIES + TEXT_ENTRIES AS CHAR(7) CHARACTER SET ISO88591) "
" END) AS ENTRIES, "
" (CASE WHEN NUM_PLANS > 9999999 THEN "
" CONCAT(RTRIM(CAST(CAST((NUM_PLANS)/10000000 AS NUMERIC(7,3)) "
" AS CHAR(7) CHARACTER SET ISO88591)), _ISO88591'E+7') ELSE "
" CAST(NUM_PLANS AS CHAR(7) CHARACTER SET ISO88591) "
" END) AS PLANS, "
" (CASE WHEN NUM_LOOKUPS > 9999999 THEN "
" CONCAT(RTRIM(CAST(CAST(NUM_LOOKUPS/10000000 AS NUMERIC(7,3)) AS CHAR(7) CHARACTER SET ISO88591)), _ISO88591'E+7') ELSE "
" CAST(NUM_LOOKUPS AS CHAR(7) CHARACTER SET ISO88591) "
" END) AS LOOKUPS, "
" (CASE WHEN NUM_CACHE_HITS_PARSING + NUM_CACHE_HITS_BINDING + TEXT_CACHE_HITS> 9999999 THEN "
" CONCAT(RTRIM(CAST(CAST((NUM_CACHE_HITS_PARSING + NUM_CACHE_HITS_BINDING + "
" TEXT_CACHE_HITS)/10000000 AS NUMERIC(7,3)) AS CHAR(7) CHARACTER SET ISO88591)), _ISO88591'E+7') ELSE "
" CAST(NUM_CACHE_HITS_PARSING + NUM_CACHE_HITS_BINDING + TEXT_CACHE_HITS AS CHAR(7) CHARACTER SET ISO88591) "
" END) AS HITS, "
" (CASE WHEN NUM_LOOKUPS <=0 THEN _ISO88591'NA' ELSE "
" CONCAT(RTRIM(CAST(CAST(100*(NUM_CACHE_HITS_PARSING + NUM_CACHE_HITS_BINDING + "
" TEXT_CACHE_HITS)/NUM_LOOKUPS AS NUMERIC(6,2)) AS CHAR(6) CHARACTER SET ISO88591)), _ISO88591'%') "
" END) AS HITRATE "
" FROM TABLE(QUERYCACHE()) ";
#define SELECT_LIST1 \
" select " \
" (CASE WHEN ROW_ID > 99999999 THEN _ISO88591'OVERFLOW' ELSE " \
" CAST(ROW_ID AS CHAR(8) CHARACTER SET ISO88591) END) AS ROWID, " \
" SUBSTRING(TEXT, 0, 36) AS TEXT, " \
" (CASE WHEN NUM_HITS > 99999999 THEN _ISO88591'OVERFLOW' ELSE " \
" CAST(NUM_HITS AS CHAR(8) CHARACTER SET ISO88591) END) AS NUMHITS, " \
" (CASE PHASE WHEN _ISO88591'PARSING' THEN _ISO88591'P' WHEN _ISO88591'BINDING' THEN _ISO88591'B' ELSE _ISO88591'T' END) AS PH "
#define FROMQUERYCACHEENTRIES " from table(querycacheentries()) "
static const char * query_cache_ent_query = SELECT_LIST1
",(CASE WHEN COMPILATION_TIME > 99999999 THEN _ISO88591'OVERFLOW' ELSE "
" CAST(COMPILATION_TIME AS CHAR(8) CHARACTER SET ISO88591) END) AS COMPTIME, "
" (CASE WHEN AVERAGE_HIT_TIME > 99999999 THEN _ISO88591'OVERFLOW' ELSE "
" CAST(AVERAGE_HIT_TIME AS CHAR(8) CHARACTER SET ISO88591) END) AS AVGHTIME "
FROMQUERYCACHEENTRIES;
static const char * query_cache_ent_query_notime = SELECT_LIST1
FROMQUERYCACHEENTRIES;
short QueryCacheSt::process(SqlciEnv * sqlci_env)
{
Lng32 retcode;
DML *query;
switch (option_) {
case 0:
default:
{
query = new DML(query_cache_query, DML_CONTROL_TYPE);
}
break;
case 1:
{
query = new DML(query_cache_ent_query, DML_CONTROL_TYPE);
}
break;
case 2:
{
query = new DML(query_cache_ent_query_notime, DML_CONTROL_TYPE);
}
break;
}
retcode = query->process(sqlci_env);
if (query)
delete query;
return (short) retcode;
}
//////////////////////////////////////////
// begin QUIESCE
//////////////////////////////////////////
// Methods for class Quiesce
Quiesce::Quiesce()
: SqlCmd(SqlCmd::QUIESCE_TYPE, NULL)
{
}
Quiesce::~Quiesce()
{
}
short Quiesce::process(SqlciEnv *sqlci_env)
{
if (!getenv("SQLCI_CURSOR"))
{
sqlci_env->diagsArea() << DgSqlCode(-SQLCI_CURSOR_NOT_SUPPORTED);
return 0;
}
Lng32 retcode = SQL_EXEC_Xact(SQLTRANS_QUIESCE, NULL);
cout << endl
<< " SQL_EXEC_Xact(SQLTRANS_QUIESCE, NULL) returned " << retcode
<< endl << endl;
return 0;
}