blob: 2df93b709590dd6f00183a54bbadc12946ad7c97 [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: SqlciRWCmd.cpp
* Description: Methods to process commands that interact with SQL/CLI and RW.
*
*
* Created: 6/6/2003
* Language: C++
* Status:
*
*
*
*
*****************************************************************************
*/
#include "Platform.h"
#include "SQLTypeDefs.h"
#include "SqlciRWCmd.h"
#include "SqlciError.h"
#include "sqlcmd.h"
#include "SqlciEnv.h"
#include "Formatter.h"
#include "exp_clause_derived.h"
#include "exp_datetime.h"
#include "unicode_char_set.h"
#include "RWInterface.h"
extern SqlciEnv * global_sqlci_env; // global sqlci_env for break key handling purposes.
void ReportWriterError ( ErrorValue *e )
{
#pragma nowarn(1506) // warning elimination
//Note: when C++ compiler bug is fixed, use constructor/destructor to
//manage memory allocation/deallocation automatically
ErrorParam *ep1 = new ErrorParam (e->charparam1_);
ErrorParam *ep2 = new ErrorParam (e->charparam2_);
ErrorParam *ep3 = new ErrorParam (e->charparam3_);
ErrorParam *ep4 = new ErrorParam (e->intparam1_);
ErrorParam *ep5 = new ErrorParam (e->intparam2_);
ErrorParam *ep6 = new ErrorParam (e->intparam3_);
SqlciError2 (e->errorCode_,
ep1,
ep2,
ep3,
ep4,
ep5,
ep6,
(ErrorParam *) 0);
delete ep1;
delete ep2;
delete ep3;
delete ep4;
delete ep5;
delete ep6;
#pragma warn(1506) // warning elimination
}
void SetError ( ErrorValue *e, Lng32 errorCode)
{
e->errorCode_ = errorCode;
e->charparam1_= NULL;
e->charparam2_= NULL;
e->charparam3_= NULL;
e->intparam1_= -1;
e->intparam2_= -1;
e->intparam3_= -1;
}
///////////////////////////////////////////////////////////////////////
//
// This is the base class for RW commands.
// This class is not constructed by the parser.
//
///////////////////////////////////////////////////////////////////////
SqlciRWCmd::SqlciRWCmd(const report_cmd_type cmd_type_)
: SqlciNode(SqlciNode::REPORT_CMD_TYPE),
cmd_type(cmd_type_)
{
};
SqlciRWCmd::~SqlciRWCmd()
{
};
///////////////////////////////////////////////////////////////////
// this class is created by sqlci parser when a LIST command
// ("LIST FIRST <N>", ...etc) is seen.
//
// The class is constructed with the list type and the number of
// rows specified in it.
//
// ListType values:
// List First: FIRST_
// List Next: NEXT_
// List All: ALL_
// Cancel: END_
//
// numRows: number of rows specified in the List command.
// -1, if 'list all' is specified.
//
//////////////////////////////////////////////////////////////////
SqlciRWListCmd::SqlciRWListCmd(ListType type, Lng32 listCount, NABoolean listCountSet)
: SqlciRWCmd(LIST_TYPE),
type_(type), listCount_(listCount),
listCountSet_(listCountSet)
{
}
SqlciRWListCmd::~SqlciRWListCmd()
{
}
short SqlciRWListCmd::process(SqlciEnv * sqlci_env)
{
short rc = 0;
SqlciRWInterfaceExecutor::ExecutionState state = SqlciRWInterfaceExecutor::INITIAL_;
switch (type_)
{
case FIRST_:
state = SqlciRWInterfaceExecutor::LIST_FIRST_;
if (sqlci_env->getListCount() != SqlciEnv::MAX_LISTCOUNT
&& !listCountSet_)
#pragma nowarn(1506) // warning elimination
listCount_ = sqlci_env->getListCount();
#pragma warn(1506) // warning elimination
else if (listCountSet_ == FALSE)
listCount_ = 0;
break;
case NEXT_:
state = SqlciRWInterfaceExecutor::LIST_NEXT_;
if (sqlci_env->getListCount() != SqlciEnv::MAX_LISTCOUNT
&& !listCountSet_)
#pragma nowarn(1506) // warning elimination
listCount_ = sqlci_env->getListCount();
#pragma warn(1506) // warning elimination
else if (listCountSet_ == FALSE)
listCount_ = 0;
if (sqlci_env->sqlciRWEnv()->rwExe()->resetListFlag())
{
// display warning indicating that reset was done.
ErrorValue err;
err.errorCode_ = SQLCI_RW_RESET_LIST;
err.charparam1_= NULL;
err.charparam2_= NULL;
err.charparam3_= NULL;
err.intparam1_= -1;
err.intparam2_= -1;
err.intparam3_= -1;
ReportWriterError(&err);
// and reset the list to start at the beginning.
state = SqlciRWInterfaceExecutor::LIST_FIRST_;
}
break;
case ALL_:
state = SqlciRWInterfaceExecutor::LIST_ALL_;
sqlci_env->sqlciRWEnv()->setSelectInProgress(FALSE);
break;
}
sqlci_env->sqlciRWEnv()->rwExe()->setResetListFlag(FALSE);
sqlci_env->sqlciRWEnv()->rwExe()->setState(state);
sqlci_env->sqlciRWEnv()->rwExe()->setListCount(listCount_);
rc = sqlci_env->sqlciRWEnv()->rwExe()->process(sqlci_env);
return rc;
}
//////////////////////////////////////////////////////////////////////////////
//
// This class is constructed by the parser when a CANCEL is seen.
// This cancels any select in progress command, then gets out of RW
// prompt and into mxci prompt.
//
//////////////////////////////////////////////////////////////////////////////
SqlciRWCancelCmd::SqlciRWCancelCmd()
: SqlciRWCmd(CANCEL_TYPE)
{
}
SqlciRWCancelCmd::~SqlciRWCancelCmd()
{
}
short SqlciRWCancelCmd::process(SqlciEnv * sqlci_env)
{
short rc = 0;
sqlci_env->sqlciRWEnv()->rwExe()->setState(SqlciRWInterfaceExecutor::CANCEL_);
rc = sqlci_env->sqlciRWEnv()->rwExe()->process(sqlci_env);
sqlci_env->sqlciRWEnv()->setSelectInProgress(FALSE);
return rc;
}
//////////////////////////////////////////////////////////////////////////////
//
// This class is constructed by the parser when a report writer query is seen.
// These are the queries which are to be passed to RW without any
// interpretation by sqlci.
//
//////////////////////////////////////////////////////////////////////////////
SqlciRWQueryCmd::SqlciRWQueryCmd(char * rwCmd, Lng32 rwCmdLen)
: SqlciRWCmd(RW_QUERY_TYPE)
{
rwCmdLen_ = rwCmdLen;
if (rwCmd)
{
rwCmd_ = new char[strlen(rwCmd)+1];
strcpy(rwCmd_, rwCmd);
}
else
rwCmd_ = 0;
}
SqlciRWQueryCmd::~SqlciRWQueryCmd()
{
if (rwCmd_)
delete rwCmd_;
}
short SqlciRWQueryCmd::process(SqlciEnv * sqlci_env)
{
short rc = 0;
sqlci_env->sqlciRWEnv()->rwExe()->setRWCmd(rwCmd_, rwCmdLen_);
sqlci_env->sqlciRWEnv()->rwExe()->setState(SqlciRWInterfaceExecutor::SEND_QUERY_TO_RW_);
rc = sqlci_env->sqlciRWEnv()->rwExe()->process(sqlci_env);
return rc;
}
////////////////////////////////////////////////////////////////////
//
// This class is constructed by parser when a RW Select command is
// seen. This is the select query that follows a 'set list_count'
// command.
//
////////////////////////////////////////////////////////////////////
SqlciRWSelectCmd::SqlciRWSelectCmd(char * selectCmd)
: SqlciRWCmd(SELECT_TYPE)
{
if (selectCmd)
{
selectCmd_ = new char[strlen(selectCmd)+1];
strcpy(selectCmd_, selectCmd);
}
else
selectCmd_ = 0;
}
SqlciRWSelectCmd::~SqlciRWSelectCmd()
{
if (selectCmd_)
delete selectCmd_;
}
short SqlciRWSelectCmd::process(SqlciEnv * sqlci_env)
{
short rc = 0;
sqlci_env->sqlciRWEnv()->rwExe()->setSelectCmd(selectCmd_);
sqlci_env->sqlciRWEnv()->rwExe()->setState(SqlciRWInterfaceExecutor::PREPARE_);
sqlci_env->sqlciRWEnv()->rwExe()->setResetListFlag(FALSE);
rc = sqlci_env->sqlciRWEnv()->rwExe()->process(sqlci_env);
return rc;
}
////////////////////////////////////////////////////////////////////
//
// This class is constructed by parser when a RW execute command is
// seen. This is the execute of a prepared select query that follows
// a 'set list_count' command.
//
////////////////////////////////////////////////////////////////////
SqlciRWExecuteCmd::SqlciRWExecuteCmd(char * stmtName, char * usingParamStr)
: SqlciRWCmd(EXECUTE_TYPE)
{
if (stmtName)
{
stmtName_ = new char[strlen(stmtName)+1];
strcpy(stmtName_, stmtName);
}
else
stmtName_ = 0;
if (usingParamStr)
{
usingParamStr_ = new char[strlen(usingParamStr) + 1];
strcpy(usingParamStr_, usingParamStr);
}
else
{
usingParamStr_ = NULL;
}
}
SqlciRWExecuteCmd::~SqlciRWExecuteCmd()
{
if (stmtName_)
delete stmtName_;
if (usingParamStr_)
delete usingParamStr_;
}
short SqlciRWInterfaceExecutor::setUsingParamInfo(char * usingParamStr)
{
short rc = 0;
numUsingParams_ = 0;
if (usingParamStr)
{
if (! usingParams_)
usingParams_ = new char * [MAX_NUM_UNNAMED_PARAMS];
for (Int32 i = numUsingParams_; i > 0; )
delete usingParams_[--i];
rc = (short)Execute::storeParams(usingParamStr, numUsingParams_,
usingParams_);
}
return rc;
}
short SqlciRWExecuteCmd::process(SqlciEnv * sqlci_env)
{
short rc = 0;
PrepStmt * prepStmt = sqlci_env->get_prep_stmts()->get(stmtName_);
if (! prepStmt)
{
sqlci_env->diagsArea() << DgSqlCode(-SQLCI_STMT_NOT_FOUND)
<< DgString0(stmtName_);
return 0;
}
sqlci_env->sqlciRWEnv()->rwExe()->setExecutePrepStmt(prepStmt);
sqlci_env->sqlciRWEnv()->rwExe()->setExecuteCmd(stmtName_);
if (usingParamStr_)
{
rc =
sqlci_env->sqlciRWEnv()->rwExe()->setUsingParamInfo(usingParamStr_);
if (rc)
return 0;
}
sqlci_env->sqlciRWEnv()->rwExe()->setState(SqlciRWInterfaceExecutor::SELECT_STARTED_);
sqlci_env->sqlciRWEnv()->rwExe()->setResetListFlag(FALSE);
rc = sqlci_env->sqlciRWEnv()->rwExe()->process(sqlci_env);
sqlci_env->sqlciRWEnv()->setSelectInProgress(TRUE);
return rc;
}
////////////////////////////////////////////////////////////////////////
//
// This class is the execution engine to process the RW select command.
// It contains all the methods and other information that is needed to
// interact with RW (mxci calling RW) when a select command is processed.
//
// It is constructed during SqlciRWSelectCmd::process and is 'alive'
// as long as that 'select is in progress'. The globals RWEnv points to this
// class.
//
////////////////////////////////////////////////////////////////////////
SqlciRWInterfaceExecutor::SqlciRWInterfaceExecutor()
: selectCmd_(NULL),
executeStmtName_(NULL),
usingParams_(NULL), numUsingParams_(0),
rwCmd_(NULL), rwCmdLen_(0),
inputRow_(NULL), inputRowLen_(0),
outputRow_(NULL), outputRowLen_(0),
listCount_(0), currCount_(0),
cursorOpened_(FALSE),
prepStmt_(NULL),
flags_(0),
state_(INITIAL_)
{
}
void SqlciRWInterfaceExecutor::setSelectCmd(char * selectCmd)
{
if (selectCmd_)
delete selectCmd_;
selectCmd_ = NULL;
if (executeStmtName_)
delete executeStmtName_;
executeStmtName_ = NULL;
if (selectCmd)
{
selectCmd_ = new char[strlen(selectCmd)+1];
strcpy(selectCmd_, selectCmd);
}
else
selectCmd_ = 0;
state_ = INITIAL_;
}
void SqlciRWInterfaceExecutor::setExecuteCmd(char * executeStmtName)
{
if (selectCmd_)
delete selectCmd_;
selectCmd_ = NULL;
if (executeStmtName_)
delete executeStmtName_;
if (executeStmtName)
{
executeStmtName_ = new char[strlen(executeStmtName)+1];
strcpy(executeStmtName_, executeStmtName);
}
else
executeStmtName_ = 0;
state_ = INITIAL_;
}
void SqlciRWInterfaceExecutor::setRWCmd(char * rwCmd, Lng32 rwCmdLen)
{
if (rwCmd_)
delete rwCmd_;
rwCmdLen_ = rwCmdLen;
if (rwCmd)
{
rwCmd_ = new char[strlen(rwCmd)+1];
strcpy(rwCmd_, rwCmd);
}
else
rwCmd_ = 0;
}
SqlciRWInterfaceExecutor::~SqlciRWInterfaceExecutor()
{
if (selectCmd_)
delete selectCmd_;
if (executeStmtName_)
delete executeStmtName_;
}
//////////////////////////////////////////////////////////////////////////
// Returns the next state of the state machine based on the retcode
// and the nextState.
// 'retcode' is of type RetStatus in RWInterface.h.
//
// If retcode is ERROR, then next state of error is returned.
// If the nextState sent in is different than the current state, state_,
// then it overrides the retcode state and is returned.
// Otherwise, the state based on retcode is returned.
//
//////////////////////////////////////////////////////////////////////////
SqlciRWInterfaceExecutor::ExecutionState SqlciRWInterfaceExecutor::getNextState(
Lng32 retcode,
SqlciRWInterfaceExecutor::ExecutionState nextState)
{
ExecutionState state;
if (retcode == ERR)
state = RW_ERROR_;
else if (state_ != nextState)
state = nextState;
else
{
switch (retcode)
{
case SEND_QUERY:
state = GET_INPUT_FROM_SQLCI_;
break;
case SEND_INPUT_ROW:
state = FETCH_;
break;
case GET_OUTPUT_ROW:
state = GET_OUTPUT_ROW_FROM_RW_;
break;
case DONE:
state = CLOSE_;
break;
case RESET_LIST:
state = RESET_LIST_;
break;
default:
state = state_;
break;
}
}
return state;
}
Lng32 SqlciRWInterfaceExecutor::printOutputRow(SqlciEnv * sqlci_env,
char * outputBuf,
Lng32 outputBufLen)
{
Logfile *log = sqlci_env->get_logfile();
log->WriteAll(outputBuf, outputBufLen, 0);
return 0;
}
static NABoolean isSqlError(Lng32 sqlRetcode)
{
if (sqlRetcode < 0)
return TRUE;
else
return FALSE;
}
short SqlciRWInterfaceExecutor::open(SqlciEnv * sqlci_env)
{
short rc;
#ifdef _DEBUG
if (getenv("SHOW_RW_STATE"))
{
char buf[40];
strcpy(buf, "OPEN_");
cout << "State " << buf << endl;
}
#endif
// close cursor. TBD: add SqlCmd::close() call to do this.
// Ignore error, stmt may already be closed.
SQL_EXEC_CloseStmt(prepStmt_->getStmt());
SQL_EXEC_ClearDiagnostics(prepStmt_->getStmt());
// open the stmt
rc = SqlCmd::doExec(sqlci_env,
prepStmt_->getStmt(),
prepStmt_,
numUsingParams_,
usingParams_);
currCount_ = 0;
cursorOpened_ = TRUE;
return rc;
}
void SqlciRWInterfaceExecutor::Close(SqlciEnv *sqlci_env)
{
if (prepStmt_)
SQL_EXEC_CloseStmt(prepStmt_->getStmt());
SQL_EXEC_ClearDiagnostics(NULL);
// Deallocate, if selectCmd. This call also
// deallocates the passed prepStmt_.
if ((selectCmd_) &&(prepStmt_))
{
SqlCmd::deallocate(sqlci_env, prepStmt_);
prepStmt_ = NULL;
// make sure that this is reset so we dont deallocate
// it again in interrupt handler if the break key is hit.
global_sqlci_env->resetDeallocateStmt();
}
cursorOpened_ = FALSE;
}
short SqlciRWInterfaceExecutor::process(SqlciEnv * sqlci_env)
{
short retcode = 0;
Lng32 sqlRetcode = 0;
Lng32 rwRetcode = 0;
NABoolean done = FALSE;
// 64-bit: no more report writer
assert(0);
return retcode;
}
/////////////////////////////////////////////////////////////////////
// These methods are called by RW to extract information about
// an input row.
/////////////////////////////////////////////////////////////////////
Lng32 MXCI_RW_getMaxColumns (void *sqlciEnv, Lng32 &max, ErrorValue* &e)
{
SqlciEnv * sqlci_env = (SqlciEnv *)sqlciEnv;
PrepStmt * prepStmt = sqlci_env->sqlciRWEnv()->rwExe()->prepStmt();
if (! prepStmt)
{
// populate 'e', stmt doesn't exist. TBD.
if (e == NULL)
{
e = new ErrorValue;
}
SetError(e, -SQLCI_STMT_NOT_FOUND);
ReportWriterError(e);
return ERR;
}
max = prepStmt->numOutputEntries();
return SUCCESS;
}
//////////////////////////////////////////////////////////////////////
Lng32 MXCI_RW_getColInfo (void *sqlciEnv, Lng32 column,
AttributeDetails* &entry, ErrorValue* &e)
{
SqlciEnv * sqlci_env = (SqlciEnv *)sqlciEnv;
PrepStmt * prepStmt = sqlci_env->sqlciRWEnv()->rwExe()->prepStmt();
if (! prepStmt)
{
if (e == NULL)
{
e = new ErrorValue;
}
SetError(e, -SQLCI_STMT_NOT_FOUND);
ReportWriterError(e);
return ERR;
}
if ((column <= 0) ||
(column > prepStmt->numOutputEntries()))
{
if (e == NULL)
{
e = new ErrorValue;
}
SetError(e, -SQLCI_WRONG_COLUMN_VALUE);
ReportWriterError(e);
return ERR;
}
if (entry == NULL)
{
// allocate entry here.
// How will this get deallocated? TBD.
entry = new AttributeDetails;
}
PrepEntry * outputEntry = prepStmt->outputEntries()[column-1];
entry->dataType_ = outputEntry->datatype();
entry->length_ = outputEntry->length();
entry->precision_ = outputEntry->precision();
entry->scale_ = outputEntry->scale();
entry->nullable_ = outputEntry->nullFlag();
entry->headingLen_ = outputEntry->headingLen();
entry->heading_ = outputEntry->heading();
entry->output_ = outputEntry->outputName();
entry->outputLen_ = outputEntry->outputNameLen();
entry->tableName_ = outputEntry->tableName();
entry->tableLen_ = outputEntry->tableLen();
entry->displayLen_ = Formatter::display_length(entry->dataType_,
entry->length_,
entry->precision_,
entry->scale_,
outputEntry->charsetEnum(),
0,
(SqlciEnv *) sqlciEnv,
NULL);
if (entry->dataType_ == REC_DATETIME)
{
entry->dateTimeCode_ = outputEntry->precision();
entry->precision_ = 0; // not used for datetime
}
else if (entry->dataType_ >= REC_MIN_INTERVAL &&
entry->dataType_ <= REC_MAX_INTERVAL)
{
entry->leadPrecision_ = outputEntry->precision();
}
else if (DFS2REC::isAnyCharacter(entry->dataType_))
{
entry->charSet_ = outputEntry->charset();
entry->collation_ = 0; //TBD
}
return SUCCESS;
}
//////////////////////////////////////////////////////////////////////////
#pragma nowarn(770) // warning elimination
Lng32 MXCI_RW_getColAddr (void *sqlciEnv, Lng32 column, char *input_row,
Lng32 len, char* &ptr, ErrorValue* &e)
{
Lng32 retcode = 0;
SqlciEnv * sqlci_env = (SqlciEnv *)sqlciEnv;
PrepStmt * prepStmt = sqlci_env->sqlciRWEnv()->rwExe()->prepStmt();
if (! prepStmt)
// populate 'e', stmt doesn't exist. TBD.
{
if (e == NULL)
{
e = new ErrorValue;
}
SetError(e, -SQLCI_STMT_NOT_FOUND);
ReportWriterError(e);
return ERR;
}
if ((column <= 0) ||
(column > prepStmt->numOutputEntries()))
// populate 'e', incorrect column value. TBD.
{
if (e == NULL)
{
e = new ErrorValue;
}
SetError(e, -SQLCI_WRONG_COLUMN_VALUE);
ReportWriterError(e);
return ERR;
}
PrepEntry * outputEntry = prepStmt->outputEntries()[column-1];
SQLDESC_ID * output_desc = prepStmt->getOutputDesc();
// the address of the data row.
// Should be the same as the 'input_row' address passed in.
char * outputData = prepStmt->outputData();
if (outputData != input_row)
return ERR;
Long data_addr = 0;
Long ind_data_addr = 0;
retcode = SQL_EXEC_GetDescItem(output_desc, column,
SQLDESC_VAR_PTR,
&data_addr, 0, 0, 0, 0);
retcode = SQL_EXEC_GetDescItem(output_desc, column,
SQLDESC_IND_PTR,
&ind_data_addr, 0, 0, 0, 0);
if (outputEntry->nullFlag())
data_addr = ind_data_addr;
ptr = (char*)data_addr;
return SUCCESS;
}
#pragma warn(770) // warning elimination
//////////////////////////////////////////////////////////////////////////
// This method formats the input datetime value to the specified datetime
// format.
// The input value is in external (string) format.
//////////////////////////////////////////////////////////////////////////
#pragma nowarn(770) // warning elimination
Lng32 MXCI_RW_convertToDateFormat(void * sqlciEnv,
char* srcPtr, AttributeDetails* srcEntry,
char *tgtPtr, AttributeDetails* tgtEntry,
DateTimeFormat format, ErrorValue* &e)
{
Lng32 rc;
Int32 dtFormat;
switch (format)
{
case DEFAULT:
dtFormat = ExpDatetime::DATETIME_FORMAT_DEFAULT; break;
case USA:
dtFormat = ExpDatetime::DATETIME_FORMAT_USA; break;
case EUROPEAN:
dtFormat = ExpDatetime::DATETIME_FORMAT_EUROPEAN; break;
default:
assert(0);
return ERR;
}
rc = ExpDatetime::convAsciiDatetimeToASCII(srcPtr,
srcEntry->dateTimeCode_,
srcEntry->scale_,
srcEntry->length_,
tgtPtr,
tgtEntry->length_,
format,
NULL,
NULL);
if (rc)
{
if (e == NULL)
{
e = new ErrorValue;
}
SetError(e, SQLCI_CONV_RESULT_FAILED);
ReportWriterError(e);
return ERR;
}
else
return SUCCESS;
}
#pragma warn(770) // warning elimination
/////////////////////////////////////////////////////////////////////////////////////
Lng32 MXCI_RW_allocateHeap (void* sqlciEnv, Lng32 len, char* &ptr)
{
SqlciEnv * sqlci_env = (SqlciEnv *)sqlciEnv;
NAHeap *h = sqlci_env->sqlciRWEnv()->rwHeap();
void *p = NULL;
if (h)
p = h->allocateMemory(len, TRUE);
if (p)
{
ptr = (char *)p;
return SUCCESS;
}
else
return ERR;
}
///////////////////////////////////////////////////////////////////////////////////////
Lng32 MXCI_RW_deallocateHeap (void* sqlciEnv, Lng32 len, char* ptr)
{
SqlciEnv * sqlci_env = (SqlciEnv *)sqlciEnv;
if (len != 0)
{
sqlci_env->sqlciRWEnv()->rwHeap()->deallocateMemory((void*)ptr);
return SUCCESS;
}
else
return ERR;
}
////////////////////////////////////////////////////////////////////////////////////////
Lng32 MXCI_RW_unicodeConvertToUpper (void *sqlciEnv, char *input_char, Lng32 num_of_input_bytes,
char *output_char, Lng32& num_of_output_bytes, ErrorValue* &e)
{
//SqlciEnv * sqlci_env = (SqlciEnv *)sqlciEnv;
Lng32 length_bytes = num_of_input_bytes;
NAWchar* target = (NAWchar*)output_char;
NAWchar* source = (NAWchar*)input_char;
Int32 wc_len = length_bytes/2;
Int32 actual_len = 0;
NAWchar* tmpWCP = NULL;
Int32 maxWideChars = num_of_output_bytes / 2;
if ((((Long)input_char % 2) != 0) || (((Long)output_char % 2) != 0))
{
if (e == NULL)
{
e = new ErrorValue;
}
SetError(e, -SQLCI_RW_BUFFER_UNEVEN_BOUNDARY);
ReportWriterError(e);
return ERR;
}
// the logic in this code is from w:/exp/exp_function_upper_unicode.cpp
// in the eval funciton. Whenever that code changes this has to
// change and vice versa.
for (Int32 i = 0; i < wc_len ; i++)
{
tmpWCP = unicode_char_set::to_upper_full(source[i]);
if (tmpWCP)
{
if (actual_len + ((tmpWCP[2] ==0) ? 2 : 3) > maxWideChars)
{
if (e == NULL)
{
e = new ErrorValue;
}
SetError(e, -SQLCI_RW_STRING_OVERFLOW);
ReportWriterError(e);
return ERR;
}// end of if
target[actual_len++] = tmpWCP[0];
target[actual_len++] = tmpWCP[1];
if (tmpWCP[2] != (NAWchar)0)
target[actual_len++] = tmpWCP[2];
}
else
{
if (actual_len >= maxWideChars)
{
if (e == NULL)
{
e = new ErrorValue;
}
SetError(e, -SQLCI_RW_STRING_OVERFLOW);
ReportWriterError(e);
return ERR;
}
target[actual_len++] = unicode_char_set::to_upper(source[i]);
}// end of else
} // end of for
num_of_output_bytes = (actual_len * 2);
return SUCCESS;
}
////////////////////////////////////////////////////////////////////////////////////
Lng32 MXCI_RW_unicodeConvertToLower(void *sqlciEnv, char *input_char, Lng32 num_of_input_bytes,
char *output_char, Lng32& num_of_output_bytes, ErrorValue* &e)
{
// SqlciEnv * sqlci_env = (SqlciEnv *)sqlciEnv;
Lng32 len1 = num_of_input_bytes;
Lng32 buffer_size = num_of_output_bytes/2 ;
num_of_output_bytes = len1;
NAWchar* target = (NAWchar*)output_char;
NAWchar* source = (NAWchar*)input_char;
Int32 wc_len = len1/2;
// the logic in this code is from w:/exp/exp_function_lower_unicode.cpp
// in the eval funciton. Whenever that code changes this has to
// change and vice versa.
for (Int32 i = 0; i < wc_len; i++)
{
if (i >= buffer_size)
{
if (e == NULL)
{
e = new ErrorValue;
}
SetError(e,-SQLCI_RW_STRING_OVERFLOW);
ReportWriterError(e);
return ERR;
}
target[i] = unicode_char_set::to_lower(source[i]);
}
return SUCCESS;
}
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
Lng32 MXCI_RW_convDoIt (void *sqlciEnv, char* srcPtr, AttributeDetails* srcEntry,
char *tgtPtr, AttributeDetails* tgtEntry, short formatting, ErrorValue* &e)
{
Lng32 retcode = 0;
ULng32 convFlags = 0;
if (formatting)
{
// if formatting, blankpad target before doing the conversion.
str_pad (tgtPtr,tgtEntry->displayLen_,' ');
// the formatted target will be left blank padded (blanks to the left).
convFlags |= CONV_LEFT_PAD;
}
else
convFlags = 0;
// SqlciEnv * sqlci_env = (SqlciEnv *)sqlciEnv;
// Check for nullability. The logic for this code
// is in w:/exp/exp_conv.cpp::processNulls function
// Source is nullable
if (srcEntry->nullable_)
{
//if data is null - if source data is acutally null
if ((srcPtr[0] != '\0') || (srcPtr[1] != '\0'))
{
if (formatting)
{
//if Target is not nullable
if (!(tgtEntry->nullable_) )
{
tgtPtr[0] = '?';
return SUCCESS; // Conversion has taken place.
}
else
{
if (e == NULL)
{
e = new ErrorValue;
}
SetError(e, -SQLCI_RW_INVALID_FORMATTING);
ReportWriterError(e);
return ERR;
}
} // end of formatting
else // if not formatting
{
// source is nullable , source is null and target is nullable
if (tgtEntry->nullable_)
{
str_pad (tgtPtr,2,'\377');
return SUCCESS; // Conversion has taken place.
}
else
{
if (e == NULL)
{
e = new ErrorValue;
}
SetError(e, -SQLCI_CONV_NULL_TO_NOT_NULL);
ReportWriterError(e);
return ERR;
}
}// end of else of if not formatting
}// end of source data is null
// source is nullable but the source data is not null
else
{
srcPtr = (char*)srcPtr + 2; // skip the null indicator bytes
} // end of else if source is nullable but source data is not null
//if source is not null and target is nullable
// set null indicator in target if needed.
if (tgtEntry->nullable_ )
{
str_pad (tgtPtr,2,'\0'); // indicate that tgt is not null. Move the ptr by 2 bytes.
tgtPtr = (char*)tgtPtr + 2;
}
} // end of source is nullable
char * VCLen = NULL;
short VCLenSize = 0;
if (DFS2REC::isAnyVarChar(tgtEntry->dataType_))
{
VCLen = tgtPtr;
VCLenSize = 2;
tgtPtr = (char*)tgtPtr + VCLenSize;
}
// If the datatype is of time INTERVAL or of type DATETIME, then
// Set the datatype to _SQLDT_ASCII_F (char)
// Set the length to the display length.
// Set the precision to 0.
// Set the scale to 0.
Lng32 length_;
Lng32 dataType_;
Lng32 precision_;
Lng32 scale_;
if ( srcEntry->dataType_ == _SQLDT_DATETIME ||
( srcEntry->dataType_ >= _SQLDT_INT_Y_Y && srcEntry->dataType_ <= _SQLDT_INT_D_F)
)
{
length_ = srcEntry->displayLen_ ;
dataType_ = 0;
precision_ = 0;
scale_ = 0;
}
else
{
length_ = srcEntry->length_;
dataType_ = srcEntry->dataType_;
precision_ = srcEntry->precision_;
scale_ = srcEntry->scale_;
}
#pragma warning (disable : 4244) //warning elimination
#pragma nowarn(1506) // warning elimination
retcode = convDoIt(srcPtr,
length_,
dataType_,
precision_,
scale_,
tgtPtr,
tgtEntry->length_,
tgtEntry->dataType_,
tgtEntry->precision_,
tgtEntry->scale_,
VCLen, //varCharLen
VCLenSize, //varCharLenSize = 2
0, //heap
0, //diagsarea
CONV_UNKNOWN,
0,
convFlags);
#pragma warn(1506) // warning elimination
#pragma warning (default : 4244) //warning elimination
if (retcode)
{
return ERR;
}
else
return SUCCESS;
}