blob: 824260b80d63daaa77f3ed805a2faa134a42b70c [file] [log] [blame]
/****************************************************************************
* File: LmRoutineCSqlRow.cpp
* Description: LM routine for C routines using parameter style SQLROW
* Created: 08/02/2009
* Language: C++
*
// @@@ START COPYRIGHT @@@
//
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
//
// @@@ END COPYRIGHT @@@
****************************************************************************
*/
#include "LmRoutineCSqlRowTM.h"
#include "LmParameter.h"
#include "LmLangManagerC.h"
// SQLROWTM function declaration
typedef Int32 (*sqlrow_func) (SQLUDR_CHAR *in_data,
SQLUDR_CHAR *rowDataSpace1,
SQLUDR_CHAR *rowDataSpace2,
SQLUDR_EmitRow getRow,
SQLUDR_EmitRow emitRow,
SQLUDR_CHAR sqlstate[6],
SQLUDR_CHAR msgtext[256],
SQLUDR_INT32 calltype,
SQLUDR_STATEAREA *statearea,
SQLUDR_UDRINFO *udrinfo);
SQLUDR_INT32 SQLUDR_INVOKE_SQLROWTM(sqlrow_func func_ptr,
SQLUDR_CHAR *in_data,
SQLUDR_CHAR *rowDataSpace1,
SQLUDR_CHAR *rowDataSpace2,
SQLUDR_GetNextRow getRow,
SQLUDR_EmitRow emitRow,
SQLUDR_CHAR sqlstate[6],
SQLUDR_CHAR msgtext[256],
SQLUDR_INT32 calltype,
SQLUDR_STATEAREA *statearea,
SQLUDR_UDRINFO *udrinfo)
{
return func_ptr(in_data, rowDataSpace1, rowDataSpace2, getRow,
emitRow, sqlstate, msgtext, calltype, statearea, udrinfo);
}
//////////////////////////////////////////////////////////////////////
//
// Class LmRoutineCSqlRow
// If we get errors in creating this object, fill diagsArea and return
// error. Caller is responsbile to cleanup by calling destructor.
//
//////////////////////////////////////////////////////////////////////
LmRoutineCSqlRowTM::LmRoutineCSqlRowTM(
const char *sqlName,
const char *externalName,
const char *librarySqlName,
ComUInt32 numSqlParam,
ComUInt32 numTableInfo,
LmTableInfo *tableInfo,
char *routineSig,
ComUInt32 maxResultSets,
ComRoutineTransactionAttributes transactionAttrs,
ComRoutineSQLAccess sqlAccessMode,
ComRoutineExternalSecurity externalSecurity,
Int32 routineOwnerId,
const char *parentQid,
ComUInt32 inputRowLen,
ComUInt32 outputRowLen,
const char *currentUserName,
const char *sessionUserName,
LmParameter *parameters,
LmLanguageManagerC *lm,
LmHandle routine,
LmHandle getNextRowPtr,
LmHandle emitRowPtr,
LmContainer *container,
ComDiagsArea *diags)
: LmRoutineC(sqlName, externalName, librarySqlName, numSqlParam, routineSig,
maxResultSets,
COM_LANGUAGE_C,
COM_STYLE_SQLROW_TM,
transactionAttrs,
sqlAccessMode,
externalSecurity,
routineOwnerId,
parentQid, inputRowLen, outputRowLen,
currentUserName, sessionUserName,
parameters, lm, routine, container, diags)
{
// Maximum length of getNexTRow row across several input tables.
// This length is used to instantiate input data row as part of
// rowDataSpace1_ in invoke rountine.
ComUInt32 maxInputRowLength = 0;
//Initialize the function pointers for getNextRow and emitRow
getNextRowPtr_ = (SQLUDR_GetNextRow)getNextRowPtr;
emitRowptr_ = (SQLUDR_EmitRow)emitRowPtr;
//The base class LmRoutineC sets up udrInfo details. We need to
//update table info in udrinfo.
udrInfo_->num_table_inputs = numTableInfo;
udrInfo_->table_inputs = (SQLUDR_TABLE_PARAM *)
malloc(numTableInfo * sizeof(SQLUDR_TABLE_PARAM) + 32);
LM_ASSERT(udrInfo_->table_inputs);
memset(udrInfo_->table_inputs, 0, numTableInfo * sizeof(SQLUDR_TABLE_PARAM) + 32);
//Iterate through each table and its params.
for(ComUInt32 i = 0; i < udrInfo_->num_table_inputs; i++)
{
LmTableInfo &lmTInfo = tableInfo[i];
SQLUDR_TABLE_PARAM *udrTInfo = &(udrInfo_->table_inputs[lmTInfo.tabIndex_]);
udrTInfo->table_name = lmTInfo.tableName_;
udrTInfo->num_params = lmTInfo.numInColumns_;
// Allocate space for params
udrTInfo->params = (SQLUDR_PARAM *)
malloc(lmTInfo.numInColumns_ * sizeof(SQLUDR_PARAM) + 32);
LM_ASSERT(udrTInfo->params);
memset(udrTInfo->params, 0, lmTInfo.numInColumns_ * sizeof(SQLUDR_PARAM) + 32);
for(ComUInt32 j = 0; j < udrTInfo->num_params; j++)
{
LmParameter &p = lmTInfo.inColumnParam_[j];
SQLUDR_PARAM &udrColumnInfo = udrTInfo->params[j];
udrColumnInfo.version = SQLUDR_PARAM_CURRENT_VERSION;
udrColumnInfo.datatype =
(SQLUDR_INT16) getAnsiTypeFromFSType(p.fsType());
udrColumnInfo.data_len = (SQLUDR_UINT32) p.inSize();
// The parameter name seen by the routine body will be a pointer
// to the LmParameter's copy of the name.
udrColumnInfo.name = (SQLUDR_CHAR *) p.getParamName();
// Union u1 contains:
// * character_set
// * datetime_code
// * interval_code
// * scale
if (p.isCharacter())
{
udrColumnInfo.u1.character_set =
(SQLUDR_INT16) p.encodingCharSet();
}
else if (p.isDateTime())
{
// For datetime types: ANSI type will be SQLTYPECODE_DATETIME and
// SQLUDR_PARAM stores a code to indicate date, time, or
// timestamp.
udrColumnInfo.u1.datetime_code =
(SQLUDR_INT16) p.getDatetimeCode();
}
else if (p.isInterval())
{
// For interval types: ANSI type will be SQLTYPECODE_INTERVAL and
// SQLUDR_PARAM stores a code to indicate start and end fields.
udrColumnInfo.u1.interval_code =
(SQLUDR_INT16) getIntervalCode(p.fsType());
}
else
{
udrColumnInfo.u1.scale = (SQLUDR_INT16) p.scale();
}
// Union u2 contains:
// * precision
// * collation
if (p.isTimeOrTimestamp())
{
udrColumnInfo.u2.precision = (SQLUDR_INT16) p.getTimePrecision();
}
else if (p.isCharacter())
{
SQLUDR_COLLATION collation = SQLUDR_COLLATION_UNKNOWN;
switch (p.collation())
{
case CharInfo::DefaultCollation:
collation = SQLUDR_COLLATION_DEFAULT;
break;
case CharInfo::CZECH_COLLATION:
collation = SQLUDR_COLLATION_CZECH;
break;
case CharInfo::CZECH_COLLATION_CI:
collation = SQLUDR_COLLATION_CZECH_CI;
break;
case CharInfo::SJIS_COLLATION:
collation = SQLUDR_COLLATION_SJIS;
break;
}
udrColumnInfo.u2.collation = (SQLUDR_INT16) collation;
}
else
{
udrColumnInfo.u2.precision = (SQLUDR_INT16) p.prec();
}
udrColumnInfo.data_offset = (SQLUDR_UINT32) p.inDataOffset();
udrColumnInfo.ind_offset = (SQLUDR_UINT32) p.inNullIndOffset();
udrColumnInfo.vc_ind_offset = (SQLUDR_UINT32) p.inVCLenIndOffset();
udrColumnInfo.vc_ind_len = (SQLUDR_UINT8) p.inVCLenIndSize();
}
if(lmTInfo.rowLength_ > maxInputRowLength)
maxInputRowLength = lmTInfo.rowLength_;
}
rowDataSpace1_ = new (collHeap()) char[maxInputRowLength + 1];
memset(rowDataSpace1_, 0, maxInputRowLength + 1);
rowDataSpace2_ = new (collHeap()) char[outputRowLen + 1];
memset(rowDataSpace2_, 0, outputRowLen + 1);
}
LmRoutineCSqlRowTM::~LmRoutineCSqlRowTM()
{
NADELETEBASIC(rowDataSpace1_, collHeap());
NADELETEBASIC(rowDataSpace2_, collHeap());
}
LmResult LmRoutineCSqlRowTM::invokeRoutine(void *inputRow,
void *outputRow,
ComDiagsArea *da)
{
// We can return early if the caller is requesting a FINAL call but
// not FINAL is necessary because the INITIAL call was never made
if (callType_ == SQLUDR_CALLTYPE_FINAL && !finalCallRequired_)
return LM_OK;
void *param_in_data = NULL;
// If this is not a FINAL call, we need to pass the address of
// the IN and OUT row data pointers to UDF
//
// For the FINAL call (invokeRoutine() during putRoutine()), there
// are no data pointers to be passed down to routine. Only
// statearea_ & udrInfo_ are sent.
if (callType_ != SQLUDR_CALLTYPE_FINAL)
{
param_in_data = inputRow;
}
// Initialize SQLSTATE to all '0' characters and add a null terminator
str_pad(sqlState_, SQLUDR_SQLSTATE_SIZE - 1, '0');
sqlState_[SQLUDR_SQLSTATE_SIZE - 1] = 0;
// Initialize SQL text to all zero bytes
str_pad(msgText_, SQLUDR_MSGTEXT_SIZE, '\0');
// Call the function
Int32 retValue = SQLUDR_INVOKE_SQLROWTM((sqlrow_func) routine_,
(SQLUDR_CHAR *) param_in_data,
(SQLUDR_CHAR *)rowDataSpace1_,
(SQLUDR_CHAR *)rowDataSpace2_,
getNextRowPtr_,
emitRowptr_,
sqlState_,
msgText_,
callType_,
stateArea_,
udrInfo_);
if (callType_ == SQLUDR_CALLTYPE_INITIAL)
{
// Set the call type for next invocation to NORMAL if this is an
// INITIAL call
callType_ = SQLUDR_CALLTYPE_NORMAL;
finalCallRequired_ = TRUE;
}
else if (callType_ == SQLUDR_CALLTYPE_FINAL)
{
// We are done if this is a FINAL call
finalCallRequired_ = FALSE;
return LM_OK;
}
// Check the return value from routine execution
if (retValue != SQLUDR_SUCCESS)
{
sqlState_[SQLUDR_SQLSTATE_SIZE - 1] = 0;
return processReturnStatus(retValue, da);
}
return LM_OK;
}
void LmTableInfo::reset(NAHeap *udrHeap)
{
if(reqSqlBuffer_)
{
udrHeap->deallocateMemory(reqSqlBuffer_);
reqSqlBuffer_ = NULL;
}
if(emitSqlBuffer_)
{
udrHeap->deallocateMemory(emitSqlBuffer_);
emitSqlBuffer_ = NULL;
}
lastReqBuffer_ = FALSE;
}