blob: a071f27e632a0efaadccc408cff159ec2062a07a [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: SqlciEnv.C
* RCS: $Id: SqlciEnv.cpp,v 1.2 2007/10/17 00:13:53 Exp $
* Description:
*
* Created: 4/15/95
* Modified: $ $Date: 2007/10/17 00:13:53 $ (GMT)
* Language: C++
* Status: $State: Exp $
*
*
*
*
*****************************************************************************
*/
#include "Platform.h"
#include <ctype.h>
#include <signal.h>
#include <string.h>
#include <unistd.h>
#include "SqlciEnv.h"
#include "SqlciError.h"
#include "SqlciNode.h"
#include "SqlciParser.h"
#include "SqlciCmd.h"
#include "sql_id.h"
#include "SqlciStats.h"
#include "sqlcmd.h"
#include "SQLCLIdev.h"
#include "InputStmt.h"
#include "SqlciRWCmd.h"
#include "SqlciCSCmd.h"
#include "CmpCommon.h"
#include "ComDiags.h"
#include "copyright.h"
#include "EHException.h"
#include "ErrorMessage.h"
#include "ExpError.h"
#include "GetErrorMessage.h"
#include "Int64.h"
#include "NAError.h"
#include "ShowSchema.h"
#include "str.h"
#include "BaseTypes.h"
#include "ComSchemaName.h"
#include "DefaultConstants.h"
#include "ComRtUtils.h"
#include "NLSConversion.h"
Int32 total_opens = 0;
Int32 total_closes = 0;
NAHeap sqlci_Heap((char *) "temp heap", NAMemory::DERIVED_FROM_SYS_HEAP);
ComDiagsArea sqlci_DA(&sqlci_Heap);
ComDiagsArea &SqlciEnv::diagsArea() { return sqlci_DA; }
extern SqlciEnv * global_sqlci_env ; // Global sqlci_env for break key handling purposes.
#define MXCI_DONOTISSUE_ERRMSGS -1
static char brkMessage[] = "Break.";
CRITICAL_SECTION g_CriticalSection;
CRITICAL_SECTION g_InterruptCriticalSection;
// We'll jump into this function from the interruptHandler routine...
// This function never exits.
static void ThrowBreakException()
{
EnterCriticalSection(&g_CriticalSection);
SQLCI_EXCEPTION_EPILOGUE("Sqlci ThrowBreak");
throw EHBreakException();
}
BOOL CtrlHandler(DWORD ctrlType) {
if (Sqlci_PutbackChar == LOOK_FOR_BREAK) // see InputStmt.cpp
Sqlci_PutbackChar = FOUND_A_BREAK;
breakReceived =1;
sqlci_DA << DgSqlCode(SQLCI_BREAK_RECEIVED, DgSqlCode::WARNING_);
switch (ctrlType) {
case CTRL_C_EVENT:
case CTRL_BREAK_EVENT:
if (TryEnterCriticalSection(&g_CriticalSection))
{
Lng32 eCode = SQL_EXEC_Cancel(0);
if (eCode ==0) {
sqlci_DA << DgSqlCode( -SQL_Canceled, DgSqlCode::WARNING_);
LeaveCriticalSection(&g_CriticalSection);
}
else { // retry
switch (-eCode) {
case CLI_CANCEL_REJECTED:
{
sqlci_DA << DgSqlCode(SQLCI_BREAK_REJECTED, DgSqlCode::WARNING_);
//sqlci_DA << DgSqlCode(SQLCI_COMMAND_NOT_CANCELLED, DgSqlCode::WARNING_);
SqlciEnv s;
s.displayDiagnostics();
sqlci_DA.clear();
//breakReceived = 0;
LeaveCriticalSection(&g_CriticalSection);
}
break;
default:
{
sqlci_DA << DgSqlCode(SQLCI_BREAK_ERROR, DgSqlCode::WARNING_);
SqlciEnv s;
s.displayDiagnostics();
sqlci_DA.clear();
LeaveCriticalSection(&g_CriticalSection);
}
break;
}
}
}
return TRUE;
break;
case CTRL_CLOSE_EVENT:
case CTRL_LOGOFF_EVENT:
case CTRL_SHUTDOWN_EVENT:
if (TryEnterCriticalSection(&g_CriticalSection))
{
Lng32 eCode = SQL_EXEC_Cancel(0);
if (eCode ==0) {
sqlci_DA << DgSqlCode( -SQL_Canceled, DgSqlCode::WARNING_);
LeaveCriticalSection(&g_CriticalSection);
}
else { // retry
switch (-eCode) {
case CLI_CANCEL_REJECTED:
{
SqlciEnv s;
s.displayDiagnostics();
sqlci_DA.clear();
LeaveCriticalSection(&g_CriticalSection);
}
break;
default:
{
sqlci_DA << DgSqlCode(SQLCI_BREAK_ERROR, DgSqlCode::WARNING_);
SqlciEnv s;
s.displayDiagnostics();
sqlci_DA.clear();
LeaveCriticalSection(&g_CriticalSection);
}
break;
}
}
}
return TRUE;
break;
default:
return FALSE;
}
}
// The signal interrupt handler. When break is hit, this function
// will be called.
#pragma nowarn(770) // warning elimination
void interruptHandler (Int32 signalType)
{
void (*intHandler_addr) (Int32);
intHandler_addr = interruptHandler;
Lng32 retcode = 0; // for return of success or failure from handleBreak methods in MACL and RW.
UInt32 recoverNeeded = 0;
signal(SIGINT, intHandler_addr); // arm the signal for break.
// This is for the Break key abend problem in Outside View for NSK. Instead of SIGINT,
// SIGQUIT is being sent by the TELSRV people to OSS. We catch it right here.
if (TryEnterCriticalSection(&g_CriticalSection))
{
Lng32 eCode = SQL_EXEC_Cancel(0);
if (eCode ==0) {
LeaveCriticalSection(&g_CriticalSection);
}
else { // retry
switch (-eCode) {
case CLI_CANCEL_REJECTED:
{
SqlciEnv s;
s.displayDiagnostics();
sqlci_DA.clear();
LeaveCriticalSection(&g_CriticalSection);
}
break;
default:
{
sqlci_DA << DgSqlCode(SQLCI_BREAK_ERROR, DgSqlCode::WARNING_);
SqlciEnv s;
s.displayDiagnostics();
sqlci_DA.clear();
LeaveCriticalSection(&g_CriticalSection);
}
break;
}
}
}
}
void setupForSockets()
{
return;
}
void cleanupSockets()
{
}
void SqlciEnv::welcomeMessage()
{
COPYRIGHT_BANNER_1(cout, COPYRIGHT_SQLCI_PRODNAME_H);
}
SqlciEnv::SqlciEnv(short serv_type, NABoolean macl_rw_flag)
{
ole_server = serv_type;
logfile = new Logfile;
sqlci_stmts = new SqlciStmts(50);
prepared_stmts = new SqlciList<PrepStmt>;
param_list = new SqlciList<Param>;
pattern_list = new SqlciList<Param>;
define_list = new SqlciList<Define>;
envvar_list = new SqlciList<Envvar>;
cursorList_ = new SqlciList<CursorStmt>;
sqlci_stats = new SqlciStats();
terminal_charset_ = CharInfo::ISO88591;
iso_mapping_charset_ = CharInfo::ISO88591;
default_charset_ = CharInfo::ISO88591;
infer_charset_ = FALSE;
lastDmlStmtStatsType_ = SQLCLIDEV_NO_STATS;
lastExecutedStmt_ = NULL;
statsStmt_ = NULL;
lastAllocatedStmt_ = NULL;
defaultCatalog_ = NULL;
defaultSchema_ = NULL;
doneWithPrologue_ = FALSE;
noBanner_ = FALSE;
setListCount(MAX_LISTCOUNT);
resetSpecialError();
defaultCatAndSch_ = NULL;
userNameFromCommandLine_ = "";
report_env = new SqlciRWEnv(); // initialize the report writer environment variable
cs_env = new SqlciCSEnv(); // initialize the macl environment variable.
// A break flag macl_rw_flag was added to the constructor in order for the SqlciEnv
// constructor not to call the MACL & Report Writer Constructors
// when the SqlciEnv constructor is called after a break key is hit.
// 64-bit: no more report writer and macl
/*
// if (macl_rw_flag) {
// jzLng32 retcode = RW_MXCI_Constructor(report_env->rwEnv(), this);
// if (retcode == ERR)
// SqlciError (SQLCI_RW_UNABLE_TO_GET_CONSTRUCTOR,(ErrorParam *) 0 );
//
// jzLng32 maclretcode = CS_MXCI_Constructor(cs_env->csEnv());
// if (maclretcode == CSERROR)
// SqlciError (SQLCI_CS_UNABLE_TO_GET_CONSTRUCTOR,(ErrorParam *) 0 );
// constructorFlag_ = TRUE;
// }
// else
*/
constructorFlag_ = FALSE;
setMode(SqlciEnv::SQL_); // Set the mode initially to be SQL
showShape_ = FALSE;
eol_seen_on_input = -1;
obey_file = 0;
prev_err_flush_input = 0;
logCommands_ = FALSE;
deallocateStmt_ = FALSE ; // Always set to FALSE.Set to TRUE only in global_sqlci_env if needed.
// Note that interactive_session is overwritten in SqlciEnv::run(infile) ...
// Executing on NT
if ((Int32)cin.tellg() == EOF)
interactive_session = -1; // Std. input is terminal keyboard
else
interactive_session = 0;
cin.clear(); // Always clear() bad results from any tellg()
// Special case for QA testing
// ---------------------------
// If sqlci has been started via an exec, ALWAYS deem it to be interactive.
// Since there is no easy way to determine if we have been exec'ed, we will
// use an environment variable to decide this. Just the existence of this
// variable is enough and the value is immaterial.
if (getenv("QA_TEST_WITH_EXEC")) interactive_session = -1;
#ifndef NDEBUG
// Ensure that SQLCI sqlcode is same as in ExpError.h
ComASSERT(SQL_Canceled == -ABS(EXE_CANCELED));
#endif
prepareOnly_ = NULL;
executeOnly_ = NULL;
}
SqlciEnv::~SqlciEnv()
{
delete logfile;
delete sqlci_stmts;
delete prepared_stmts;
delete param_list;
delete pattern_list;
delete cursorList_;
delete define_list;
delete envvar_list;
delete sqlci_stats;
sqlci_stmts = 0;
// Report Writer and MACL Destructors has to be called only if the SqlciEnv constructor
// called the MACL and RW constructors.
if (constructorFlag_){
// 64-bit: no more report writer
// jzLng32 retcode = RW_MXCI_Destructor(report_env->rwEnv(), this);
// if (retcode == ERR)
// SqlciError (SQLCI_RW_UNABLE_TO_GET_DESTRUCTOR,(ErrorParam *) 0 );
// 64-bit: no more macl
// jzLng32 maclretcode = CS_MXCI_Destructor(cs_env->csEnv());
// if (maclretcode == CSERROR)
// SqlciError (SQLCI_CS_UNABLE_TO_GET_DESTRUCTOR,(ErrorParam *) 0 );
}
}
void SqlciEnv::autoCommit()
{
// Queries issued from SQLCI are COMMITted at the end of execution,
// that is, if a transaction was started by the executor to execute it
// then that transaction is ended. This is the default behavior.
// It could be overridden by either a BEGIN WORK statement or
// a SET TRANSACTION AUTOCOMMIT OFF statement.
//
//
// This function is called during the initialization phase of MXCI
// (SqlciEnv_prologue_to_run). Use specialERROR_ as a flag indicating that
// the querry being executed is invoke during MXCI's initialization phase and
// that any errors will be fatal.
SqlCmd::executeQuery("SET TRANSACTION AUTOCOMMIT ON;", this);
// Should an error occur, exit MXCI.
if (!specialError_)
{
char *noexit = getenv("SQL_MXCI_NO_EXIT_ON_COMPILER_STARTUP_ERROR");
if (!noexit)
exit(EXIT_FAILURE);
}
}
void SqlciEnv::readonlyCursors()
{
// All select stmts issued from sqlci are READONLY.
// They cannot be later updated/deleted using a cursor
// 'upd/del where current of' stmt.
//
//
// This function is called during the initialization phase of MXCI
// (SqlciEnv_prologue_to_run). Use specialERROR_ as a flag indicating that
// the querry being executed is invoke during MXCI's initialization phase and
// that any errors will be fatal.
SqlCmd::executeQuery("CONTROL QUERY DEFAULT READONLY_CURSOR 'TRUE';", this);
if (!specialError_)
{
char *noexit = getenv("SQL_MXCI_NO_EXIT_ON_COMPILER_STARTUP_ERROR");
if (!noexit)
exit(EXIT_FAILURE);
}
}
void SqlciEnv::pertableStatistics()
{
// Turn on pertable statistics. This will make queries issued
// from sqlci to collect pertable statistics and will be the
// same behavior as sql/mp.
//
// This function is called during the initialization phase of MXCI
// (SqlciEnv_prologue_to_run). Use specialERROR_ as a flag indicating that
// the querry being executed is invoke during MXCI's initialization phase and
// that any errors will be fatal.
char * buf = new char[300];
sprintf(buf, "select variable_info from table(statistics(null, cast(? as char(256) character set iso88591)))");
SqlCmd sqlCmd(SqlCmd::DML_TYPE, buf);
if (!statsStmt_)
{
statsStmt_ = new PrepStmt("__SQLCI_GET_STATS__");
short retcode = sqlCmd.do_prepare(this, statsStmt_, sqlCmd.get_sql_stmt(), FALSE);
}
char *collectionType = getenv("SQLMX_REGRESS");
if (collectionType == NULL)
{
strcpy(buf, "SET SESSION DEFAULT STATISTICS_VIEW_TYPE 'PERTABLE';");
SqlCmd::executeQuery(buf, this);
if (!specialError_)
{
char *noexit = getenv("SQL_MXCI_NO_EXIT_ON_COMPILER_STARTUP_ERROR");
if (!noexit)
exit(EXIT_FAILURE);
}
}
delete [] buf;
}
void SqlciEnv::generateExplain()
{
// Turn explain generation ON by default from mxci.
//
// This function is called during the initialization phase of MXCI
// (SqlciEnv_prologue_to_run). Use specialERROR_ as a flag indicating that
// the querry being executed is invoke during MXCI's initialization phase and
// that any errors will be fatal.
SqlCmd::executeQuery("CONTROL QUERY DEFAULT GENERATE_EXPLAIN 'ON';", this);
if (!specialError_)
{
char *noexit = getenv("SQL_MXCI_NO_EXIT_ON_COMPILER_STARTUP_ERROR");
if (!noexit)
exit(EXIT_FAILURE);
}
}
void SqlciEnv::datatypeSupport()
{
// Can handle tinyint datatype
SqlCmd::executeQuery("CONTROL QUERY DEFAULT TRAF_TINYINT_SUPPORT 'ON';", this);
SqlCmd::executeQuery("CONTROL QUERY DEFAULT TRAF_TINYINT_RETURN_VALUES 'ON';", this);
SqlCmd::executeQuery("CONTROL QUERY DEFAULT TRAF_TINYINT_INPUT_PARAMS 'ON';", this);
// can handle largeint unsigned datatype
SqlCmd::executeQuery("CONTROL QUERY DEFAULT TRAF_LARGEINT_UNSIGNED_IO 'ON';", this);
// can handle boolean datatype
SqlCmd::executeQuery("CONTROL QUERY DEFAULT TRAF_BOOLEAN_IO 'ON';", this);
if (!specialError_)
{
exit(EXIT_FAILURE);
}
}
void SqlciEnv::sqlmxRegress()
{
char * regr = getenv("SQLMX_REGRESS");
if (regr)
{
char buf[1000];
str_sprintf(buf, "set envvar sqlmx_regress %s;", regr);
SqlCmd::executeQuery(buf, this);
if (!specialError_)
{
char *noexit = getenv("SQL_MXCI_NO_EXIT_ON_COMPILER_STARTUP_ERROR");
if (!noexit)
exit(EXIT_FAILURE);
}
str_sprintf(buf, "cqd sqlmx_regress 'ON';");
SqlCmd::executeQuery(buf, this);
if (!specialError_)
{
char *noexit = getenv("SQL_MXCI_NO_EXIT_ON_COMPILER_STARTUP_ERROR");
if (!noexit)
exit(EXIT_FAILURE);
}
}
}
static void SqlciEnv_prologue_to_run(SqlciEnv *sqlciEnv)
{
if (sqlciEnv->doneWithPrologue())
return;
if (NOT sqlciEnv->noBanner())
sqlciEnv->welcomeMessage();
setupForSockets();
// If a user name was specified on the command line, call CLI to set
// the database user identity.
//
// *** NOTE: This should always be sqlci's first CLI interaction
// *** because CLI treats this operation as the beginning of a new
// *** session with the compiler. Previous state in the compiler is
// *** not guaranteed to persist after this interaction.
//
sqlciEnv->setUserIdentityInCLI();
// Suppress console messages
sqlciEnv->setSpecialError(MXCI_DONOTISSUE_ERRMSGS, NULL);
sqlciEnv->autoCommit();
sqlciEnv->readonlyCursors();
sqlciEnv->pertableStatistics();
sqlciEnv->generateExplain();
sqlciEnv->datatypeSupport();
sqlciEnv->sqlmxRegress();
// see catman/CatWellKnownTables.cpp for this envvar need.
char * ltmi = getenv("LOB_TEST_METADATA_INIT");
if (ltmi)
{
SqlCmd::executeQuery("CONTROL QUERY DEFAULT CAT_DISTRIBUTE_METADATA 'OFF';", sqlciEnv);
}
sqlciEnv->resetSpecialError();
// Enable break handling.
SQL_EXEC_BreakEnabled_Internal (TRUE);
const char* initCmd = NULL;
if (initCmd) {
NAString cmd(initCmd);
TrimNAStringSpace(cmd);
size_t len = cmd.length();
if (len > 1) { // ignore if empty or ';' or '0' or '1' or ...
if (cmd[len-1] != ';')
cmd += ';';
SqlCmd::executeQuery(cmd, sqlciEnv);
}
}
// indicate that the caller is sqlci
SqlCmd::executeQuery("CONTROL QUERY DEFAULT IS_SQLCI 'ON';", sqlciEnv);
// Protect our startup CQDs and SET SCHEMA (from any SQL_MXCI_INITIALIZATION)
// from being RESET. User may still manually alter them, of course.
//
SqlCmd::executeQuery("CONTROL QUERY DEFAULT * RESET RESET;", sqlciEnv);
// tell CLI that datetime & interval values are to be input/output in internal format.
SqlCmd::executeQuery("SET SESSION DEFAULT INTERNAL_FORMAT_IO 'ON';", sqlciEnv);
// get the defaults
Define::getDefaults(sqlciEnv->defaultSubvol());
// get sqlmx_terminal_charset if environment variable exists
const char *termCS = getenv("SQLMX_TERMINAL_CHARSET");
if (termCS) {
SetTerminalCharset setTermCS((char*)termCS);
setTermCS.process(sqlciEnv);
}
// get the DEFAULT_CHARSET CQD default attribute
sqlciEnv->retrieveDefaultCharsetViaShowControlDefault();
// get the INFER_CHARSET CQD default attribute
sqlciEnv->retrieveInferCharsetViaShowControlDefault();
// undo the CQD set by DDOL while retrieving the other CQDs
SqlCmd::executeQuery("CONTROL QUERY DEFAULT SHOWCONTROL_SHOW_ALL RESET;", sqlciEnv);
sqlciEnv->setDoneWithPrologue(TRUE);
}
// sqlci run with input coming in at SQLCI prompt
void SqlciEnv::run()
{
// This function is called during the initialization phase of MXCI
// (SqlciEnv_prologue_to_run). Use specialERROR_ as a flag indicating that
// the querry being executed is invoke during MXCI's initialization phase and
// that any errors will be fatal. Should an error occur, exit MXCI.
SqlciEnv_prologue_to_run(this);
// tell CLI that this user session has started.
SqlCmd::executeQuery("SET SESSION DEFAULT SQL_SESSION 'BEGIN';", this);
// Initialize lifetime objects
InputStmt * input_stmt = NULL;
Int32 retval;
void (*intHandler_addr) (Int32);
intHandler_addr = interruptHandler;
do
{
retval = executeCommands(input_stmt);
}
while (retval != 0);
DeleteCriticalSection(&g_CriticalSection);
DeleteCriticalSection(&g_InterruptCriticalSection);
cleanupSockets();
}
// sqlci run with input coming in as a parameter.
void SqlciEnv::runWithInputString(char * input_string)
{
// This function is called during the initialization phase of MXCI
// (SqlciEnv_prologue_to_run). Use specialERROR_ as a flag indicating that
// the querry being executed is invoke during MXCI's initialization phase and
// that any errors will be fatal. Should an error occur, exit MXCI.
SqlciEnv_prologue_to_run(this);
SqlCmd::executeQuery("SET SESSION DEFAULT SQL_SESSION 'BEGIN';", this);
// Initialize lifetime objects
InputStmt * input_stmt;
Int32 retval;
void (*intHandler_addr) (Int32);
intHandler_addr = interruptHandler;
InputStmt dummyIS(this);
input_stmt = new InputStmt(&dummyIS, input_string);
retval = executeCommands(input_stmt);
if (retval == 0)
{
}
DeleteCriticalSection(&g_CriticalSection);
DeleteCriticalSection(&g_InterruptCriticalSection);
cleanupSockets();
}
// sqlci run with input coming in from an infile specified at command line
void SqlciEnv::run(char * in_filename, char * input_string)
{
if ((! in_filename) && (input_string))
{
runWithInputString(input_string);
return;
}
interactive_session = 0; // overwrite value from ctor!
// This function is called during the initialization phase of MXCI
// (SqlciEnv_prologue_to_run). Use specialERROR_ as a flag indicating that
// the querry being executed is invoke during MXCI's initialization phase and
// that any errors will be fatal. Should an error occur, exit MXCI.
SqlciEnv_prologue_to_run(this);
SqlCmd::executeQuery("SET SESSION DEFAULT SQL_SESSION 'BEGIN';", this);
Int32 retval = 0;
SqlciNode * sqlci_node = 0;
// input is from a file given at command line (SQLCI -i<filename>).
// Create an "OBEY filename" command and process it.
char * command = new char[10 + strlen(in_filename)];
strcpy(command, "OBEY ");
strcat(command, in_filename);
strcat(command, ";");
sqlci_parser(command, command, &sqlci_node,this);
delete [] command;
void (*intHandler_addr) (Int32);
intHandler_addr = interruptHandler;
if (sqlci_node)
{
retval = sqlci_node->process(this);
delete sqlci_node;
sqlci_node = NULL;
displayDiagnostics();
sqlci_DA.clear(); // Clear the DiagnosticsArea for the next command...
}
if (!retval) // EXIT not seen in the obey file
{
// create an EXIT command
char command[10];
strcpy(command, "exit;");
get_logfile()->WriteAll(">>exit;");
sqlci_parser(command, command, &sqlci_node,this);
if (sqlci_node)
{
retval = sqlci_node->process(this);
delete sqlci_node;
sqlci_node = NULL;
displayDiagnostics();
sqlci_DA.clear();
}
}
DeleteCriticalSection(&g_CriticalSection);
DeleteCriticalSection(&g_InterruptCriticalSection);
cleanupSockets();
} // run (in_filename)
Int32 SqlciEnv::executeCommands(InputStmt *& input_stmt)
{
Int32 retval = 0;
Int32 ignore_toggle = 0;
SqlciNode * sqlci_node = 0;
NABoolean inputPassedIn = (input_stmt ? TRUE : FALSE);
try
{
while (!retval)
{
total_opens = 0;
total_closes = 0;
// This is new'd here, deleted when history buffer fills up,
// in SqlciStmts::add/StmtEntry::set
if (NOT inputPassedIn)
input_stmt = new InputStmt(this);
Int32 read_error = 0;
if (NOT inputPassedIn)
read_error = input_stmt->readStmt(NULL/*i.e. input is stdin*/);
prev_err_flush_input = 0;
if (cin.eof() || read_error == -99)
{
// allow the other thread to process
Sleep(50); // milliseconds
if (!input_stmt->isEmpty())
{
// Unterminated statement in input file (redirected stdin).
// Make the parser emit an error message.
if (!isInteractiveSession())
input_stmt->display((UInt16)0);
input_stmt->logStmt();
input_stmt->syntaxErrorOnEof();
displayDiagnostics();
sqlci_DA.clear();
}
char command[10];
strcpy(command, ">>exit;");
if (!isInteractiveSession())
get_logfile()->WriteAll(command);
else if (get_logfile()->IsOpen())
#pragma nowarn(1506) // warning elimination
get_logfile()->Write(command, strlen(command));
#pragma warn(1506) // warning elimination
sqlci_parser(&command[2], &command[2], &sqlci_node,this);
if (sqlci_node)
{
retval = sqlci_node->process(this);
delete sqlci_node;
sqlci_node = NULL;
}
}
else
{
if (!isInteractiveSession())
input_stmt->display((UInt16)0);
if (logCommands())
get_logfile()->setNoLog(FALSE);
input_stmt->logStmt();
if (logCommands())
get_logfile()->setNoLog(TRUE);
if (!input_stmt->sectionMatches())
{
Int32 ignore_stmt = input_stmt->isIgnoreStmt();
if (ignore_stmt)
ignore_toggle = ~ignore_toggle;
if (ignore_stmt || ignore_toggle || input_stmt->ignoreJustThis())
{
// ignore until stmt following the untoggling ?ignore
sqlci_DA.clear();
}
else
{
getSqlciStmts()->add(input_stmt);
if (!read_error)
{
retval = sqlci_parser(input_stmt->getPackedString(),
input_stmt->getPackedString(),
&sqlci_node, this);
if (sqlci_node)
{
retval = sqlci_node->process(this);
delete sqlci_node;
sqlci_node = NULL;
if (retval == SQL_Canceled)
retval = 0;
} else {
// pure MXCI synatax error. Reset retval
retval = 0;
}
}
if (retval > 0)
{
if (!eol_seen_on_input)
{
prev_err_flush_input = -1;
}
retval = 0;
}
} // else
}// if
} // else
if ( read_error == -20)
{
sqlci_DA << DgSqlCode(SQLCI_BREAK_RECEIVED, DgSqlCode::WARNING_);
}
if (read_error == SqlciEnv::MAX_FRAGMENT_LEN_OVERFLOW && !eolSeenOnInput() )
setPrevErrFlushInput();
displayDiagnostics();
sqlci_DA.clear(); // Clear the DiagnosticsArea for the next command...
if (total_opens != total_closes)
{
char buf[100];
sprintf(buf, "total opens = %d, total closes = %d", total_opens, total_closes);
#pragma nowarn(1506) // warning elimination
get_logfile()->WriteAll(buf, strlen(buf));
#pragma warn(1506) // warning elimination
}
// Delete the stmt if not one of those we saved on the history list
if (!input_stmt->isInHistoryList())
delete input_stmt;
if (inputPassedIn)
retval = 1;
} // while
if (retval == SQL_Canceled)
return SQL_Canceled;
else
return 0;
}
catch(EHBreakException&)
{
sqlci_DA << DgSqlCode(SQLCI_BREAK_RECEIVED, DgSqlCode::WARNING_);
displayDiagnostics();
sqlci_DA.clear(); // Clear the DiagnosticsArea for the next command...
if (sqlci_node)
delete sqlci_node;
sqlci_node = NULL;
cin.clear();
// NOTE: EnterCriticalSection has been done in ThrowBreakException()
LeaveCriticalSection(&g_CriticalSection);
return -1;
}
catch(...)
{
return 1;
}
} // executeCommands
// returns -1, if a transaction is active; 0, otherwise.
// Optionally returns the transaction identifier, if transid is passed in.
short SqlciEnv::statusTransaction(Int64 * transid)
{
// if a transaction is active, get the transid by calling the CLI procedure.
SQLDESC_ID transid_desc; // added for multi charset module names
SQLMODULE_ID module;
init_SQLCLI_OBJ_ID(&transid_desc);
init_SQLMODULE_ID(&module);
module.module_name = 0;
transid_desc.module = &module;
transid_desc.name_mode = desc_handle;
HandleCLIErrorInit();
Lng32 rc = SQL_EXEC_AllocDesc(&transid_desc, 1);
HandleCLIError(rc, this);
Int64 transid_;
rc = SQL_EXEC_SetDescItem(&transid_desc, 1, SQLDESC_VAR_PTR,
(Long)&transid_, 0);
if (rc)
SQL_EXEC_DeallocDesc(&transid_desc);
HandleCLIError(rc, this);
rc = SQL_EXEC_Xact(SQLTRANS_STATUS, &transid_desc);
if (rc == 0)
{
if (transid) *transid = transid_; // return transID if arg was passed in.
rc = -1; // transaction is active.
}
else
rc = 0;
SQL_EXEC_DeallocDesc(&transid_desc);
return (short)rc;
}
//
void SqlciEnv::displayDiagnostics()
{
NADumpDiags(cout, &sqlci_DA,
TRUE/*newline*/, FALSE/*comment-style*/,
get_logfile()->GetLogfile());
}
void SqlciEnv::setPrepareOnly(char * prepareOnly)
{
if (prepareOnly_)
delete prepareOnly_;
prepareOnly_ = NULL;
if (prepareOnly)
{
prepareOnly_ = new char[strlen(prepareOnly)+1];
strcpy(prepareOnly_, prepareOnly);
delete executeOnly_;
executeOnly_ = NULL;
}
}
void SqlciEnv::setExecuteOnly(char * executeOnly)
{
if (executeOnly_)
delete executeOnly_;
executeOnly_ = NULL;
if (executeOnly)
{
executeOnly_ = new char[strlen(executeOnly)+1];
strcpy(executeOnly_, executeOnly);
delete prepareOnly_;
prepareOnly_ = NULL;
}
}
void callback_storeSchemaInformation(SqlciEnv *sqlci_env, Lng32 err,
const char *cat, const char *sch)
{
if (sqlci_env->defaultCatalog())
delete sqlci_env->defaultCatalog();
if (sqlci_env->defaultSchema())
delete sqlci_env->defaultSchema();
sqlci_env->defaultCatalog() = new char[strlen(cat) + 1];
sqlci_env->defaultSchema() = new char[strlen(sch) + 1];
strcpy(sqlci_env->defaultCatalog(), cat);
strcpy(sqlci_env->defaultSchema(), sch);
}
void SqlciEnv::updateDefaultCatAndSch()
{
setSpecialError(ShowSchema::DiagSqlCode(), callback_storeSchemaInformation);
SqlCmd::executeQuery(ShowSchema::ShowSchemaStmt(), this);
resetSpecialError();
}
/////////////////////////////////////////
// Processing of Report Writer class.
// the constructor and destructor are
// defined here. Set the Report Writer
// mode and Select In Progress mode to be
// FALSE at this time. Also instantiate
// the Interface executor here.
/////////////////////////////////////////
SqlciRWEnv::SqlciRWEnv()
{
rwEnv_ = NULL;
rwSelect_ = FALSE;
rwExe_ = new SqlciRWInterfaceExecutor();
// Any memory required by RW should be derived from
// system heap only. RW should not do any memory
// allocation or deallocation on its own. All memory
// must be got by calling methods on this pointer
// provided by MXCI.
heap_ = new NAHeap((char *) "reportwriter_heap",
NAMemory::DERIVED_FROM_SYS_HEAP);
}
SqlciRWEnv::~SqlciRWEnv()
{
}
/////////////////////////////////////////
// Processing of MACL class.
// the constructor and destructor are
// defined here. Set the Report Writer
// mode and Select In Progress mode to be
// FALSE at this time. Also instantiate
// the Interface executor here.
/////////////////////////////////////////
SqlciCSEnv::SqlciCSEnv()
{
csEnv_ = NULL;
csExe_ = new SqlciCSInterfaceExecutor();
}
SqlciCSEnv::~SqlciCSEnv()
{
}
// This is the command which will show the user
// which mode they are in.
void SqlciEnv::showMode(ModeType mode_)
{
switch (mode_)
{
case SQL_:
cout << "The current mode is SQL mode." << endl;
break;
case REPORT_:
cout << "The current mode is REPORT WRITER mode." << endl;
break;
case MXCS_:
cout << "The current mode is MXCS mode." << endl;
break;
default:
break;
}
}
////////////////////////////////////////
// Processing of the ENV command.
////////////////////////////////////////
Env::Env(char * argument_, Lng32 arglen_)
: SqlciCmd(SqlciCmd::ENV_TYPE, argument_, arglen_)
{}
void callback_Env_showSchema(SqlciEnv *sqlci_env, Lng32 err,
const char *cat, const char *sch)
{
sqlci_env->defaultCatAndSch().setCatalogNamePart (NAString(cat));
sqlci_env->defaultCatAndSch().setSchemaNamePart (NAString(sch));
}
short Env::process(SqlciEnv *sqlci_env)
{
// ## Should any of this text come from the message file,
// ## i.e. from a translatable file for I18N?
// When adding new variables, please keep the information in
// alphabetic order
Logfile *log = sqlci_env->get_logfile();
log->WriteAll("----------------------------------");
log->WriteAll("Current Environment");
log->WriteAll("----------------------------------");
bool authenticationEnabled = false;
bool authorizationEnabled = false;
bool authorizationReady = false;
bool auditingEnabled = false;
Int32 rc = sqlci_env->getAuthState(authenticationEnabled,
authorizationEnabled,
authorizationReady,
auditingEnabled);
// TDB: add auditing state
log->WriteAllWithoutEOL("AUTHENTICATION ");
if (authenticationEnabled)
log->WriteAll("enabled");
else
log->WriteAll("disabled");
log->WriteAllWithoutEOL("AUTHORIZATION ");
if (authorizationEnabled)
log->WriteAll("enabled");
else
log->WriteAll("disabled");
log->WriteAllWithoutEOL("CURRENT DIRECTORY ");
// NT_PORT (bv 10/24/96) Added NA_MAX_PATH here and in common/Platform.h
log->WriteAll(getcwd((char *)NULL, NA_MAX_PATH));
log->WriteAllWithoutEOL("LIST_COUNT ");
char buf[100];
Int32 len = sprintf(buf, "%u", sqlci_env->getListCount());
if (len-- > 0)
if (buf[len] == 'L' || buf[len] == 'l')
buf[len] = '\0';
log->WriteAll(buf);
if (log->IsOpen())
{
log->WriteAllWithoutEOL("LOG FILE ");
log->WriteAll(log->Logname());
}
else
{
log->WriteAll("LOG FILE");
}
log->WriteAllWithoutEOL("MESSAGEFILE ");
const char *mf = GetErrorMessageFileName();
log->WriteAll(mf ? mf : "");
#if 0
log->WriteAllWithoutEOL("ISO88591 MAPPING ");
log->WriteAll(CharInfo::getCharSetName(sqlci_env->getIsoMappingCharset()));
log->WriteAllWithoutEOL("DEFAULT CHARSET ");
log->WriteAll(CharInfo::getCharSetName(sqlci_env->getDefaultCharset()));
log->WriteAllWithoutEOL("INFER CHARSET ");
log->WriteAll((sqlci_env->getInferCharset())?"ON":"OFF");
#endif
// ## These need to have real values detected from the env and written out:
// "US English" is more "politically correct" than "American English".
//
log->WriteAllWithoutEOL("MESSAGEFILE LANG US English\n");
log->WriteAllWithoutEOL("MESSAGEFILE VRSN ");
char vmsgcode[10];
sprintf(vmsgcode, "%d", SQLERRORS_MSGFILE_VERSION_INFO);
#pragma nowarn(1506) // warning elimination
Error vmsg(vmsgcode, strlen(vmsgcode), Error::ENVCMD_);
#pragma warn(1506) // warning elimination
vmsg.process(sqlci_env);
ComAnsiNamePart defaultCat;
ComAnsiNamePart defaultSch;
sqlci_env->getDefaultCatAndSch (defaultCat, defaultSch);
CharInfo::CharSet TCS = sqlci_env->getTerminalCharset();
CharInfo::CharSet ISOMAPCS = sqlci_env->getIsoMappingCharset();
if(TCS !=
CharInfo::UTF8
) {
NAString dCat = defaultCat.getExternalName();
NAString dSch = defaultSch.getExternalName();
charBuf cbufCat((unsigned char*)dCat.data(), dCat.length());
charBuf cbufSch((unsigned char*)dSch.data(), dSch.length());
NAWcharBuf* wcbuf = 0;
Int32 errorcode = 0;
wcbuf = csetToUnicode(cbufCat, 0, wcbuf, CharInfo::UTF8, errorcode);
NAString* tempstr;
if (errorcode != 0){
tempstr = new NAString(defaultCat.getExternalName().data());
}
else {
tempstr = unicodeToChar(wcbuf->data(),wcbuf->getStrLen(), TCS, NULL, TRUE);
TrimNAStringSpace(*tempstr, FALSE, TRUE); // trim trailing blanks
}
log->WriteAllWithoutEOL("SQL CATALOG ");
log->WriteAll(tempstr->data());
// Default Schema
wcbuf = 0; // must 0 out to get next call to allocate memory.
wcbuf = csetToUnicode(cbufSch, 0, wcbuf, CharInfo::UTF8, errorcode);
if (errorcode != 0){
tempstr = new NAString(defaultSch.getExternalName().data());
}
else {
tempstr = unicodeToChar(wcbuf->data(),wcbuf->getStrLen(), TCS, NULL, TRUE);
TrimNAStringSpace(*tempstr, FALSE, TRUE); // trim trailing blanks
}
log->WriteAllWithoutEOL("SQL SCHEMA ");
log->WriteAll(tempstr->data());
}
else
{
log->WriteAllWithoutEOL("SQL CATALOG ");
log->WriteAll(defaultCat.getExternalName());
log->WriteAllWithoutEOL("SQL SCHEMA ");
log->WriteAll(defaultSch.getExternalName());
}
// On Linux we include the database user name and user ID in the
// command output
NAString username;
rc = sqlci_env->getExternalUserName(username);
log->WriteAllWithoutEOL("SQL USER CONNECTED ");
if (rc >= 0)
log->WriteAll(username.data());
else
log->WriteAll("?");
rc = sqlci_env->getDatabaseUserName(username);
log->WriteAllWithoutEOL("SQL USER DB NAME ");
if (rc >= 0)
log->WriteAll(username.data());
else
log->WriteAll("?");
Int32 uid = 0;
rc = sqlci_env->getDatabaseUserID(uid);
log->WriteAllWithoutEOL("SQL USER ID ");
if (rc >= 0)
sprintf(buf, "%d", (int) uid);
else
strcpy(buf, "?");
log->WriteAll(buf);
log->WriteAllWithoutEOL("TERMINAL CHARSET ");
log->WriteAll(CharInfo::getCharSetName(sqlci_env->getTerminalCharset()));
Int64 transid;
if (sqlci_env->statusTransaction(&transid))
{
// transaction is active.
char transid_str[20];
convertInt64ToAscii(transid, transid_str);
log->WriteAllWithoutEOL("TRANSACTION ID ");
log->WriteAll(transid_str);
log->WriteAll("TRANSACTION STATE in progress");
}
else
{
log->WriteAll("TRANSACTION ID ");
log->WriteAll("TRANSACTION STATE not in progress");
}
if (log->isVerbose())
log->WriteAll("WARNINGS on");
else
log->WriteAll("WARNINGS off");
return 0;
}
void SqlciEnv::getDefaultCatAndSch (ComAnsiNamePart & defaultCat, ComAnsiNamePart & defaultSch)
{
defaultCatAndSch_ = new ComSchemaName;
setSpecialError(ShowSchema::DiagSqlCode(), callback_Env_showSchema);
SqlCmd::executeQuery(ShowSchema::ShowSchemaStmt(), this);
resetSpecialError();
defaultCat = defaultCatAndSch_->getCatalogNamePart();
defaultSch = defaultCatAndSch_->getSchemaNamePart();
delete defaultCatAndSch_;
defaultCatAndSch_ = NULL;
}
// Retrieve the external database user ID from CLI
Int32 SqlciEnv::getExternalUserName(NAString &username)
{
HandleCLIErrorInit();
char buf[1024] = "";
Int32 rc = SQL_EXEC_GetSessionAttr(SESSION_EXTERNAL_USER_NAME,
NULL,
buf, 1024, NULL);
HandleCLIError(rc, this);
if (rc >= 0)
username = buf;
if (username.length() == 0)
username = "user not connected";
return rc;
}
// Retrieve the database user ID from CLI
Int32 SqlciEnv::getDatabaseUserID(Int32 &uid)
{
HandleCLIErrorInit();
Int32 localUID = 0;
Int32 rc = SQL_EXEC_GetSessionAttr(SESSION_DATABASE_USER_ID,
&localUID,
NULL, 0, NULL);
HandleCLIError(rc, this);
if (rc >= 0)
uid = localUID;
return rc;
}
// Retrieve the database user ID from CLI
Int32 SqlciEnv::getAuthState(bool &authenticationEnabled,
bool &authorizationEnabled,
bool &authorizationReady,
bool &auditingEnabled)
{
HandleCLIErrorInit();
Int32 localUID = 0;
Int32 rc = SQL_EXEC_GetAuthState(authenticationEnabled,
authorizationEnabled,
authorizationReady,
auditingEnabled);
HandleCLIError(rc, this);
return rc;
}
// Retrieve the database user name from CLI. This will be the
// USER_NAME column from a USERS row not the EXTERNAL_USER_NAME
// column.
Int32 SqlciEnv::getDatabaseUserName(NAString &username)
{
HandleCLIErrorInit();
char buf[1024] = "";
Int32 rc = SQL_EXEC_GetSessionAttr(SESSION_DATABASE_USER_NAME,
NULL,
buf, 1024, NULL);
HandleCLIError(rc, this);
if (rc >= 0)
username = buf;
if (rc != 0)
SQL_EXEC_ClearDiagnostics(NULL);
return rc;
}
CharInfo::CharSet SqlciEnv::retrieveIsoMappingCharsetViaShowControlDefault()
{
this->iso_mapping_charset_ = CharInfo::ISO88591;
return this->iso_mapping_charset_;
}
CharInfo::CharSet SqlciEnv::retrieveDefaultCharsetViaShowControlDefault()
{
this->default_charset_ = CharInfo::ISO88591;
return this->default_charset_;
}
NABoolean SqlciEnv::retrieveInferCharsetViaShowControlDefault()
{
this->infer_charset_ = FALSE;
return this->infer_charset_;
}
void SqlciEnv::setUserNameFromCommandLine(const char *s)
{
userNameFromCommandLine_ = s;
userNameFromCommandLine_.strip();
}
// If a user name was specified on the command line, call CLI to set
// the database user identity.
void SqlciEnv::setUserIdentityInCLI()
{
if (userNameFromCommandLine_.length() > 0)
{
// Within this function we do not want CLI errors to be
// fatal. Setting specialError_ to 0 ensures they are not. We also
// save the current value of specialError_ and restore if after
// the CLI calls.
Lng32 previousSpecialError = specialError_;
specialError_ = 0;
HandleCLIErrorInit();
Lng32 sqlcode =
SQL_EXEC_SetSessionAttr_Internal(SESSION_DATABASE_USER_NAME,
0,
(char *) userNameFromCommandLine_.data());
HandleCLIError(sqlcode, this);
if (sqlcode >= 0)
printf("\nDatabase user: %s\n\n", userNameFromCommandLine_.data());
if (sqlcode != 0)
SQL_EXEC_ClearDiagnostics(NULL);
specialError_ = previousSpecialError;
}
else
{
// Call CLI to retrieve the current user identity. This is only
// done to see if CLI generates errors or warnings that we should
// display. For example, CLI was not able to establish a default
// user identity, perhaps metadata is corrupt, we should display
// that information.
Int32 uid = 0;
getDatabaseUserID(uid);
}
}