blob: 32ade6d6d298c1c84b876ce82f375a7245d4724c [file] [log] [blame]
/* -*-C++-*-
**********************************************************************
*
* File: LmLangManagerC.cpp
* Description: Language Manager for C
*
* Created: 05/15/2008
* 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 "LmCommon.h"
#include "LmLangManagerC.h"
#include "LmContManager.h"
#include "LmRoutineC.h"
#include "LmRoutineCSql.h"
#include "LmRoutineCSqlRow.h"
#include "LmRoutineCSqlRowTM.h"
#include "LmRoutineCppObj.h"
#include "LmExtFunc.h"
#include "LmDebug.h"
#include "sqludr.h"
LmLanguageManagerC::LmLanguageManagerC(
LmResult &result,
NABoolean commandLineMode,
ComDiagsArea *diagsArea)
: LmLanguageManager(commandLineMode),
diagsArea_(diagsArea)
{
setRoutineIsActive(FALSE);
contManager_ = new (collHeap()) LmContainerManagerSimple(this);
result = LM_OK;
}
LmLanguageManagerC::~LmLanguageManagerC()
{
delete contManager_;
}
LmResult LmLanguageManagerC::validateRoutine(
ComUInt32 numSqlParam,
ComFSDataType paramType[],
ComUInt32 paramSubType[],
ComColumnDirection direction[],
const char *routineName,
const char *containerName,
const char *externalPath,
char *sigBuf,
ComUInt32 sigLen,
ComFSDataType resultType,
ComUInt32 resultSubType,
ComUInt32 numResultSets,
const char *metaContainerName,
const char *optionalSig,
ComDiagsArea *diagsArea)
{
return LM_OK;
}
LmResult LmLanguageManagerC::getRoutine(
ComUInt32 numSqlParam,
LmParameter parameters[],
ComUInt32 numTableInfo,
LmTableInfo tableInfo[],
LmParameter *returnValue,
ComRoutineParamStyle paramStyle,
ComRoutineTransactionAttributes transactionAttrs,
ComRoutineSQLAccess sqlAccessMode,
const char *parentQid,
ComUInt32 inputRowLen,
ComUInt32 outputRowLen,
const char *sqlName,
const char *externalName,
const char *routineSig,
const char *containerName,
const char *externalPath,
const char *librarySqlName,
const char *currentUserName,
const char *sessionUserName,
ComRoutineExternalSecurity externalSecurity,
Int32 routineOwnerId,
LmRoutine **handle,
LmHandle getNextRowPtr,
LmHandle emitRowPtr,
ComUInt32 maxResultSets,
ComDiagsArea *diagsArea)
{
*handle = NULL;
LmContainer *container = NULL;
LmResult result = LM_OK;
const char *operation = "dlsym";
ComDiagsArea *da = (diagsArea != NULL) ? diagsArea : diagsArea_;
// Get the requested container from the CM.
result = contManager_->getContainer(containerName, externalPath,
&container, da);
if (result == LM_ERR)
return LM_ERR;
// Get a handle to the requested routine
LmHandle routinePtr = NULL;
if (paramStyle != COM_STYLE_CPP_OBJ)
{
routinePtr = getRoutinePtr(container->getHandle(), externalName);
if (routinePtr == NULL)
{
char *libraryName = new (collHeap())
char[str_len(externalPath) + str_len(containerName) + 2];
sprintf(libraryName, "%s/%s", externalPath, containerName);
*da << DgSqlCode(-LME_DLL_METHOD_NOT_FOUND)
<< DgString0(externalName)
<< DgString1(libraryName);
addDllErrors(*da, operation, FALSE);
NADELETEBASIC(libraryName, collHeap());
return LM_ERR;
}
}
// allocate an LM handle for the external method.
LmRoutine *routineHandle = NULL;
if (paramStyle == COM_STYLE_SQL)
{
routineHandle =
new (collHeap()) LmRoutineCSql(sqlName,
externalName,
librarySqlName,
numSqlParam,
(char *)routineSig,
maxResultSets,
transactionAttrs,
sqlAccessMode,
externalSecurity,
routineOwnerId,
parentQid,
inputRowLen,
outputRowLen,
currentUserName,
sessionUserName,
parameters,
this,
routinePtr,
container,
da);
}
else if (paramStyle == COM_STYLE_SQLROW)
{
routineHandle =
new (collHeap()) LmRoutineCSqlRow(sqlName,
externalName,
librarySqlName,
numSqlParam,
(char *)routineSig,
maxResultSets,
transactionAttrs,
sqlAccessMode,
externalSecurity,
routineOwnerId,
parentQid,
inputRowLen,
outputRowLen,
currentUserName,
sessionUserName,
parameters,
this,
routinePtr,
container,
da);
}
else if (paramStyle == COM_STYLE_SQLROW_TM)
{
routineHandle =
new (collHeap()) LmRoutineCSqlRowTM(sqlName,
externalName,
librarySqlName,
numSqlParam,
numTableInfo,
tableInfo,
(char *)routineSig,
maxResultSets,
transactionAttrs,
sqlAccessMode,
externalSecurity,
routineOwnerId,
parentQid,
inputRowLen,
outputRowLen,
currentUserName,
sessionUserName,
parameters,
this,
routinePtr,
getNextRowPtr,
emitRowPtr,
container,
da);
}
else if (paramStyle == COM_STYLE_CPP_OBJ)
{
// need to call getObjRoutine for this parameter style
LM_ASSERT(0);
}
else
{
// XXX LM_ASSERT(0);
char *paramStyleMsg = new (collHeap())
char[100];
sprintf(paramStyleMsg, "Unknown ParameterStyle(%d)", paramStyle);
*da << DgSqlCode(-LME_VALIDATION_FAILED)
<< DgString0(externalName)
<< DgString1(paramStyleMsg);
addDllErrors(*da, operation, FALSE);
}
// Verify the handle.
if (routineHandle == NULL)
{
// DiagsArea is already filled
if (container)
contManager_->putContainer(container);
return LM_ERR;
}
else
{
*handle = routineHandle;
return LM_OK;
}
}
LmResult LmLanguageManagerC::getObjRoutine(
const char *serializedInvocationInfo,
int serializedInvocationInfoLen,
const char *serializedPlanInfo,
int serializedPlanInfoLen,
ComRoutineLanguage language,
ComRoutineParamStyle paramStyle,
const char *externalName,
const char *containerName,
const char *externalPath,
const char *librarySqlName,
LmRoutine **handle,
ComDiagsArea *da)
{
LmResult result;
tmudr::UDRInvocationInfo *invocationInfo = NULL;
tmudr::UDRPlanInfo *planInfo = NULL;
LmContainer *container = NULL;
*handle = NULL;
// Get the requested container from the CM.
result = contManager_->getContainer(containerName,
externalPath,
&container,
da);
if (result == LM_ERR)
return LM_ERR;
// search the DLL for the method that creates the tmudr::UDRInterface object
LmHandle factoryMethodPtr = getRoutinePtr(container->getHandle(), externalName);
tmudr::UDR *interfacePtr = NULL;
if (factoryMethodPtr == NULL)
{
*da << DgSqlCode(-LME_DLL_METHOD_NOT_FOUND)
<< DgString0(externalName)
<< DgString1(containerName);
addDllErrors(*da, "dlsym", FALSE);
return LM_ERR;
}
try
{
if (serializedInvocationInfoLen > 0)
{
// unpack invocation and plan infos
invocationInfo = new tmudr::UDRInvocationInfo;
invocationInfo->deserializeObj(serializedInvocationInfo,
serializedInvocationInfoLen);
}
if (serializedPlanInfoLen > 0)
{
planInfo = new tmudr::UDRPlanInfo(invocationInfo, 0);
planInfo->deserializeObj(serializedPlanInfo,
serializedPlanInfoLen);
}
tmudr::CreateInterfaceObjectFunc fPtr =
reinterpret_cast<tmudr::CreateInterfaceObjectFunc>(factoryMethodPtr);
// call the factory method
interfacePtr = (*fPtr)();
if (interfacePtr == NULL)
{
*da << DgSqlCode(-LME_FACTORY_METHOD)
<< DgString0(externalName)
<< DgString1(containerName)
<< DgString2("Factory method returned NULL");
result = LM_ERR;
}
}
catch (tmudr::UDRException e)
{
*da << DgSqlCode(-LME_FACTORY_METHOD)
<< DgString0(externalName)
<< DgString1(containerName)
<< DgString2(e.getMessage().data());
result = LM_ERR;
}
catch (...)
{
*da << DgSqlCode(-LME_FACTORY_METHOD)
<< DgString0(externalName)
<< DgString1(containerName)
<< DgString2("General exception");
result = LM_ERR;
}
if (result == LM_OK && invocationInfo != NULL)
{
// create the language manager routine, which will take
// ownership of the interface object
ComRoutineTransactionAttributes transactionAttrs = COM_NO_TRANSACTION_REQUIRED;
ComRoutineSQLAccess sqlAccessMode = COM_NO_SQL;
ComRoutineExternalSecurity externalSecurity = COM_ROUTINE_EXTERNAL_SECURITY_DEFINER;
// for now we don't allow a choice, once we do we need to translate enums
LM_ASSERT(invocationInfo->sqlTransactionType_ ==
tmudr::UDRInvocationInfo::REQUIRES_NO_TRANSACTION);
LM_ASSERT(invocationInfo->sqlAccessType_ ==
tmudr::UDRInvocationInfo::CONTAINS_NO_SQL);
LM_ASSERT(invocationInfo->sqlRights_ ==
tmudr::UDRInvocationInfo::INVOKERS_RIGHTS);
*handle =
new (collHeap()) LmRoutineCppObj(invocationInfo,
planInfo,
interfacePtr,
invocationInfo->getUDRName().c_str(),
externalName,
librarySqlName,
0,
transactionAttrs,
sqlAccessMode,
externalSecurity,
0, // routine owner id is 0 for now
this,
container,
da);
}
else
{
// In the error or validation case, get rid of the allocated info.
// invocationInfoLen will be 0 in the validation case, where
// we return LM_OK and NULL for the routine when validation is
// successful.
if (interfacePtr)
delete interfacePtr;
if (invocationInfo)
delete invocationInfo;
if (planInfo)
delete planInfo;
if (container)
contManager_->putContainer(container);
}
return result;
}
LmResult LmLanguageManagerC::putRoutine(
LmRoutine *routine,
ComDiagsArea *diagsArea)
{
if (routine == NULL)
return LM_OK;
// make a final call or the equivalent, if needed
LmResult result = routine->handleFinalCall();
// De-ref the container.
if (routine->container())
contManager_->putContainer(routine->container());
// De-allocate the handle.
delete routine;
return result;
}
LmResult LmLanguageManagerC::invokeRoutine(
LmRoutine *handle,
void *inputRow,
void *outputRow,
ComDiagsArea *diagsArea)
{
LmRoutine *routine = (LmRoutine *) handle;
LM_ASSERT(routine);
LmResult result = LM_OK;
if (routine->getParamStyle() == COM_STYLE_CPP_OBJ)
{
LmRoutineCppObj *cppRoutine = static_cast<LmRoutineCppObj *>(routine);
tmudr::UDRInvocationInfo *invocationInfo = cppRoutine->getInvocationInfo();
Int32 dummy1, dummy2;
// this path is only used for the run-time call, where we
// have already received the UDRInvocationInfo/UDRPlanInfo
result = cppRoutine->invokeRoutineMethod(
tmudr::UDRInvocationInfo::RUNTIME_WORK_CALL,
NULL, // invocation info already there
0,
&dummy1, // expecting no updated invocation info
NULL, // plan info is already there or not used
0,
0,
&dummy2, // expecting no updated plan info
(char *) inputRow,
invocationInfo->par().getRecordLength(),
(char *) outputRow,
invocationInfo->out().getRecordLength(),
diagsArea);
}
else
result = routine->invokeRoutine(inputRow, outputRow, diagsArea);
return result;
}
LmHandle LmLanguageManagerC::createLoader(
const char *externalPath,
ComDiagsArea *da)
{
return new (collHeap()) LmCLoader();
}
void LmLanguageManagerC::deleteLoader(LmHandle loader)
{
// This function deletes LmCLoader object
LmCLoader *cLoader = (LmCLoader *) loader;
delete cLoader;
}
LmHandle LmLanguageManagerC::loadContainer(
const char *containerName,
const char *externalPath,
LmHandle extLoader,
ComUInt32 *containerSize,
ComDiagsArea *da)
{
return loadDll(containerName, externalPath, extLoader,
containerSize, da, collHeap());
}
void LmLanguageManagerC::unloadContainer(LmHandle containerHandle)
{
unloadDll(containerHandle, diagsArea_);
}
LmResult LmLanguageManagerC::getSystemProperty(
const char *key,
char *value,
ComUInt32 bufferLen,
ComBoolean &propertyIsSet,
ComDiagsArea *diagsArea)
{
// TBD: Need to update this with getenv() function call
propertyIsSet = FALSE;
return LM_OK;
}
LmResult LmLanguageManagerC::setSystemProperty(
const char *key,
const char *value,
ComDiagsArea *diagsArea)
{
// TBD: Need to update this with setenv() function call
return LM_OK;
}
LmCLoader::LmCLoader()
{
}
LmCLoader::~LmCLoader()
{
}