| /* -*-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() |
| { |
| } |