Example #1
0
NARoutine::NARoutine(const QualifiedName   &name,
           const TrafDesc    *routine_desc,
           BindWA                *bindWA,
           Int32                 &errorOccurred,
           NAMemory              *heap)
    : name_                   (name, heap)
    , hashKey_                (name, heap) 
    , language_               (routine_desc->routineDesc()->language)
    , UDRType_                (routine_desc->routineDesc()->UDRType)
    , sqlAccess_              (routine_desc->routineDesc()->sqlAccess)
    , transactionAttributes_  (routine_desc->routineDesc()->transactionAttributes)
    , maxResults_             (routine_desc->routineDesc()->maxResults)
    , stateAreaSize_          (routine_desc->routineDesc()->stateAreaSize)
    , externalFile_           ("", heap)
    , externalPath_           (routine_desc->routineDesc()->libraryFileName, heap)
    , externalName_           ("", heap)
    , librarySqlName_         (routine_desc->routineDesc()->librarySqlName, COM_UNKNOWN_NAME, FALSE, heap) //TODO
    , signature_              (routine_desc->routineDesc()->signature, heap)
    , paramStyle_             (routine_desc->routineDesc()->paramStyle)
    , paramStyleVersion_      (COM_ROUTINE_PARAM_STYLE_VERSION_1)
    , isDeterministic_        (routine_desc->routineDesc()->isDeterministic)
    , isCallOnNull_           (routine_desc->routineDesc()->isCallOnNull )
    , isIsolate_              (routine_desc->routineDesc()->isIsolate)
    , externalSecurity_       (routine_desc->routineDesc()->externalSecurity)
    , isExtraCall_            (FALSE) //TODO
    , hasOutParams_           (FALSE)
    , redefTime_              (0)  //TODO
    , lastUsedTime_           (0)
    , routineSecKeySet_       (heap)
    , passThruDataNumEntries_ (0)
    , passThruData_           (NULL)
    , passThruDataSize_       (0)
    , udfFanOut_              (1) // TODO
    , uecValues_              (heap,0)
    , isUniversal_            (0) // TODO
    , actionPosition_         (0) // TODO
    , executionMode_          (COM_ROUTINE_SAFE_EXECUTION)
    , objectUID_              (routine_desc->routineDesc()->objectUID)
    , dllName_                (routine_desc->routineDesc()->libraryFileName, heap)
    , dllEntryPoint_          (routine_desc->routineDesc()->externalName, heap)
    , sasFormatWidth_         ("", heap) //TODO
    , systemName_             ("", heap) // TODO
    , dataSource_             ("", heap) // TODO
    , fileSuffix_             ("", heap) // TODO
    , schemaVersionOfRoutine_ ((COM_VERSION)0) // TODO
    , objectOwner_            (routine_desc->routineDesc()->owner)
    , schemaOwner_            (routine_desc->routineDesc()->schemaOwner)
    , privInfo_               (NULL)
    , heap_(heap)
{
  char parallelism[5];
  CmGetComRoutineParallelismAsLit(routine_desc->routineDesc()->parallelism, parallelism);
  comRoutineParallelism_ = ((char *)parallelism);

  if (paramStyle_ == COM_STYLE_JAVA_CALL)
  {
    NAString extName(routine_desc->routineDesc()->externalName);
    size_t pos=extName.last('.');
    externalName_ = extName(pos+1, (extName.length()-pos-1)); // method_name
    externalFile_ = extName.remove (pos); // package_name.class_name 
  }
  else
  {
    externalName_ = routine_desc->routineDesc()->externalName;
    if (language_ == COM_LANGUAGE_C ||
        language_ == COM_LANGUAGE_CPP)
      {
        // Split the fully-qualified DLL name into a directory name and
        // simple file name
        ComUInt32 len = dllName_.length();
        if (len > 0)
          {
            size_t lastSlash = dllName_.last('/');
            if (lastSlash == NA_NPOS)
              {
                // No slash was found
                externalPath_ = ".";
                externalFile_ = dllName_;
              }
            else
              {
                // A slash was found. EXTERNAL PATH is everything before the
                // slash. EXTERNAL FILE is everything after.
                externalPath_ = dllName_;
                externalPath_.remove(lastSlash, len - lastSlash);
                externalFile_ = dllName_;
                externalFile_.remove(0, lastSlash + 1);
              }
          }
      } // if (len > 0)
  }

  ComSInt32 colCount = routine_desc->routineDesc()->paramsCount;
  NAColumn *newCol = NULL;
  NAType   *newColType = NULL;
  extRoutineName_ = new (heap) ExtendedQualName( name_, heap );
  extActionName_  = new (heap) NAString(heap);
  intActionName_  = new (heap) ComObjectName(heap);
  params_         = new (heap) NAColumnArray(heap);
  inParams_       = new (heap) NAColumnArray(heap);
  outParams_      = new (heap) NAColumnArray(heap);

  // to compute java signature
  ComFSDataType *paramType = new STMTHEAP ComFSDataType[colCount];
  ComUInt32     *subType   = new STMTHEAP ComUInt32    [colCount];
  ComColumnDirection *direction = new STMTHEAP ComColumnDirection[colCount] ;
  //
  // Construct the CostVectors
  // CQDs are checked at Bind time.
  Int32 initCpuCost = -1;
  Int32 initIOCost = -1;
  Int32 initMsgCost = -1;

  CostScalar initialCpuCost( initCpuCost);
  CostScalar initialIOCost( initIOCost);
  CostScalar initialMsgCost( initMsgCost);

  initialRowCost_.setCPUTime( initCpuCost < 0 ? csMinusOne : initialCpuCost);
  initialRowCost_.setIOTime( initIOCost < 0 ? csMinusOne : initialIOCost);
  initialRowCost_.setMSGTime( initMsgCost < 0 ? csMinusOne : initialMsgCost);

  Int32 normCpuCost = -1;
  Int32 normIOCost = -1;
  Int32 normMsgCost = -1;

  CostScalar normalCpuCost( normCpuCost);
  CostScalar normalIOCost( normIOCost);
  CostScalar normalMsgCost( normMsgCost);

  normalRowCost_.setCPUTime( normCpuCost < 0 ? csMinusOne  : normalCpuCost);
  normalRowCost_.setIOTime( normIOCost < 0 ? csMinusOne  : normalIOCost);
  normalRowCost_.setMSGTime( normMsgCost < 0 ? csMinusOne  : normalMsgCost);

  TrafDesc *params_desc_list  = routine_desc->routineDesc()->params;
  TrafColumnsDesc *param_desc;

  int i = 0;
  while (params_desc_list)
  {
    param_desc = params_desc_list->columnsDesc();

    // Create the new NAType.
    if (NAColumn::createNAType(param_desc->columnsDesc(), (const NATable *)NULL, newColType, heap_))
      {
      errorOccurred = TRUE;
      return;
    }
    if (param_desc->colname && strncmp(param_desc->colname, "#:", 2) == 0)
    {
      memset(param_desc->colname, 0, 2);
    }

    ComParamDirection colDirection = param_desc->paramDirection();
    
    // Create the new NAColumn and insert it into the NAColumnArray
    newCol = new (heap) NAColumn(
         (const char *)UDRCopyString (param_desc->colname, heap)
         , param_desc->colnumber
         , newColType
         , heap
         , NULL   // NATable *
         , USER_COLUMN
         , COM_NO_DEFAULT
         , NULL   // default value
         , UDRCopyString("", heap) // TODO:heading can it have some value
         , param_desc->isUpshifted()
         , FALSE // addedColumn
         , (ComColumnDirection) colDirection
         , param_desc->isOptional()
         , (char *) COM_NORMAL_PARAM_TYPE_LIT
				 );
	
    // We have to check for INOUT in both the
    // if's below
    if ( COM_OUTPUT_PARAM == colDirection ||
	 COM_INOUT_PARAM == colDirection )
    {
      hasOutParams_ = TRUE;
      outParams_->insert (newCol);
      params_->insert (newCol );
    }

    if ( COM_INPUT_PARAM == colDirection ||
	 COM_INOUT_PARAM == colDirection )
    {
      inParams_->insert (newCol);
      if ( COM_INOUT_PARAM != colDirection )
      {
	params_->insert (newCol );
      }    // if not INOUT
    } // if IN or INOUT

    // Gather the param attributes for LM from the paramDefArray previously
    // populated and from the routineparamList generated from paramDefArray.
    paramType[i] = (ComFSDataType)newColType->getFSDatatype();
    subType[i] = 0;  // default

    // Set subType for special cases detected by LM
    switch ( paramType[i] )
    {
      case COM_SIGNED_BIN16_FSDT :
      case COM_SIGNED_BIN32_FSDT :
      case COM_SIGNED_BIN64_FSDT :
      case COM_UNSIGNED_BIN16_FSDT :
      case COM_UNSIGNED_BIN32_FSDT :
      case COM_UNSIGNED_BPINT_FSDT :
        {
          subType[i] = newColType->getPrecision();
          break;
        }

      case COM_DATETIME_FSDT :
      {
        switch ( ((DatetimeType *)newColType)->getSubtype() )
        {
        case DatetimeType::SUBTYPE_SQLDate : subType[i] = 1;      break;
        case DatetimeType::SUBTYPE_SQLTime : subType[i] = 2;      break;
        case DatetimeType::SUBTYPE_SQLTimestamp : subType[i] = 3; break;
        }
      }
    } // end switch paramType[i]

    direction[i] = (ComColumnDirection) colDirection;
    
    params_desc_list = params_desc_list->next;
    i++;
  } // for

  passThruDataNumEntries_ = 0;
  passThruData_ = NULL;
  passThruDataSize_ = NULL;

#define MAX_SIGNATURE_LENGTH 8193
  if ((language_ == COM_LANGUAGE_JAVA)&&(signature_.length() < 2))
    {
      // Allocate buffer for generated signature
      char sigBuf[MAX_SIGNATURE_LENGTH];
      sigBuf[0] = '\0';

      // If the syntax specified a signature, pass that to LanguageManager.
      char* optionalSig = NULL;
      ComBoolean isJavaMain =
        ((str_cmp_ne(externalName_.data(), "main") == 0) ? TRUE : FALSE);

      LmResult createSigResult;
      LmJavaSignature *lmSignature =  new (STMTHEAP) LmJavaSignature(NULL,
                                                                     STMTHEAP);
      createSigResult = lmSignature->createSig(paramType, subType, direction,
                                               colCount, COM_UNKNOWN_FSDT, 0,
                                               maxResults_, optionalSig, 
                                               isJavaMain, sigBuf,
                                               MAX_SIGNATURE_LENGTH,
                                               CmpCommon::diags());
      NADELETE(lmSignature, LmJavaSignature, STMTHEAP);


      // Lm returned error. Lm fills diags area
      if (createSigResult != LM_ERR)
        signature_ = sigBuf;
    }
    
     
  getPrivileges(routine_desc->routineDesc()->priv_desc);

  heapSize_ = (heap ? heap->getTotalSize() : 0);
}
void CmpSeabaseDDL::createSeabaseRoutine(
				      StmtDDLCreateRoutine * createRoutineNode,
				      NAString &currCatName, 
                                      NAString &currSchName)
{
  Lng32 retcode = 0;
 
  ComObjectName routineName(createRoutineNode->getRoutineName());
  ComAnsiNamePart currCatAnsiName(currCatName);
  ComAnsiNamePart currSchAnsiName(currSchName);
  routineName.applyDefaults(currCatAnsiName, currSchAnsiName);
  const NAString catalogNamePart = 
    routineName.getCatalogNamePartAsAnsiString();
  const NAString schemaNamePart = 
    routineName.getSchemaNamePartAsAnsiString(TRUE);
  const NAString objectNamePart = 
    routineName.getObjectNamePartAsAnsiString(TRUE);
  const NAString extRoutineName = routineName.getExternalName(TRUE);
  ComRoutineType rType          = createRoutineNode->getRoutineType();
  ComRoutineLanguage language   = createRoutineNode->getLanguageType();
  ComRoutineParamStyle ddlStyle = createRoutineNode->getParamStyle();
  ComRoutineParamStyle style    = ddlStyle;
  NABoolean isJava              = (language == COM_LANGUAGE_JAVA);

  // Check to see if user has the authority to create the routine
  ExeCliInterface cliInterface(STMTHEAP, NULL, NULL, 
    CmpCommon::context()->sqlSession()->getParentQid());
  Int32 objectOwnerID = SUPER_USER;
  Int32 schemaOwnerID = SUPER_USER;
  ComSchemaClass schemaClass;

  retcode = verifyDDLCreateOperationAuthorized(&cliInterface,
                                               SQLOperation::CREATE_ROUTINE,
                                               catalogNamePart,
                                               schemaNamePart,
                                               schemaClass,
                                               objectOwnerID,
                                               schemaOwnerID);
  if (retcode != 0)
  {
     handleDDLCreateAuthorizationError(retcode,catalogNamePart,schemaNamePart);
     return;
  }
  
  ExpHbaseInterface * ehi = NULL;

  ehi = allocEHI();
  if (ehi == NULL)
    {
      processReturn();
      return;
    }
  
  retcode = existsInSeabaseMDTable(&cliInterface, 
				   catalogNamePart, schemaNamePart, 
                                   objectNamePart, COM_USER_DEFINED_ROUTINE_OBJECT, 
                                   TRUE, FALSE);
  if (retcode < 0)
    {
      deallocEHI(ehi); 
      processReturn();
      return;
    }

  if (retcode == 1) // already exists
    {
      *CmpCommon::diags() << DgSqlCode(-1390)
			  << DgString0(extRoutineName);
      deallocEHI(ehi); 
      processReturn();
      return;
    }

  
  ComObjectName libName(createRoutineNode->
                        getLibraryName().getQualifiedNameAsAnsiString());
  libName.applyDefaults(currCatAnsiName, currSchAnsiName);	
  NAString libCatNamePart = libName.getCatalogNamePartAsAnsiString();
  NAString libSchNamePart = libName.getSchemaNamePartAsAnsiString(TRUE);
  NAString libObjNamePart = libName.getObjectNamePartAsAnsiString(TRUE);
  const NAString extLibraryName = libName.getExternalName(TRUE);
  char externalPath[512] ;
  Lng32 cliRC = 0;
	
  // this call needs to change
  Int64 libUID = getObjectUID(&cliInterface, 
                              libCatNamePart, 
                              libSchNamePart, 
                              libObjNamePart,
                              COM_LIBRARY_OBJECT_LIT);

  if (libUID < 0)
    {
      processReturn();    
      return;
    }

  if (libUID == 0) // does not exist
    {
      *CmpCommon::diags() << DgSqlCode(-1361)
			  << DgString0(extLibraryName);
      deallocEHI(ehi); 
      processReturn();
      return;
    }

  // read the library path name from the LIBRARIES metadata table

  char * buf = new(STMTHEAP) char[200];
  str_sprintf(buf, "select library_filename from %s.\"%s\".%s"
              " where library_uid = %Ld for read uncommitted access",
              getSystemCatalog(), SEABASE_MD_SCHEMA, SEABASE_LIBRARIES, libUID);

  cliRC = cliInterface.fetchRowsPrologue(buf, TRUE/*no exec*/);
  if (cliRC < 0)
    {
      cliInterface.retrieveSQLDiagnostics(CmpCommon::diags());
      deallocEHI(ehi); 
      processReturn();
      return;
    }

  cliRC = cliInterface.clearExecFetchClose(NULL, 0);
  if (cliRC < 0)
    {
      cliInterface.retrieveSQLDiagnostics(CmpCommon::diags());
      deallocEHI(ehi); 
      processReturn();
      return;
    }
  if (cliRC == 100) // did not find the row
    {
      *CmpCommon::diags() << DgSqlCode(-1231)
                          << DgString0(extRoutineName);
      deallocEHI(ehi); 
      processReturn();
      return;
    }

  char * ptr = NULL;
  Lng32 len = 0;
  cliInterface.getPtrAndLen(1, ptr, len);
  str_cpy_all(externalPath, ptr, len);
  externalPath[len] = '\0'; 

  // determine language and parameter styles based on the library
  // type, unless already specified
  if (!createRoutineNode->isLanguageTypeSpecified())
    {
      NAString extPath(externalPath);
      size_t lastDot = extPath.last('.');
      NAString libSuffix;

      if (lastDot != NA_NPOS)
        libSuffix = extPath(lastDot,extPath.length()-lastDot);

      libSuffix.toUpper();

      if (libSuffix == ".JAR")
        {
          isJava = TRUE;
          language = COM_LANGUAGE_JAVA;
        }
      else if (libSuffix == ".SO" ||
               libSuffix == ".DLL")
        {
          // a known C/C++ library, set
          // language and parameter style below
        }
      else
        {
          // language not specified and library name
          // is inconclusive, issue an error
          *CmpCommon::diags() << DgSqlCode( -3284 )
                              << DgString0( externalPath );
          processReturn();
        }
    }

  // set parameter style and also language, if not already
  // specified, based on routine type and type of library
  if (isJava)
    {
      // library is a jar file

      if (rType == COM_PROCEDURE_TYPE)
        // Java stored procedures use the older Java style
        style = COM_STYLE_JAVA_CALL;
      else
        // Java UDFs use the newer Java object style
        style = COM_STYLE_JAVA_OBJ;
    }
  else
    {
      // assume the library is a DLL with C or C++ code
      if (rType == COM_TABLE_UDF_TYPE &&
          (language == COM_LANGUAGE_CPP ||
           !createRoutineNode->isLanguageTypeSpecified()))
        {
          // Table UDFs (TMUDFs) default to the C++ interface
          language = COM_LANGUAGE_CPP;
          style    = COM_STYLE_CPP_OBJ;
        }
      else if (rType == COM_SCALAR_UDF_TYPE &&
               (language == COM_LANGUAGE_C ||
                !createRoutineNode->isLanguageTypeSpecified()))
        {
          // scalar UDFs default to C and SQL parameter style
          language = COM_LANGUAGE_C;
          style    = COM_STYLE_SQL;
        }
      else
        {
          // some invalid combination of routine type, language and
          // library type
          *CmpCommon::diags() << DgSqlCode(-3286);
          processReturn();
          return;
        }
    } // C/C++ DLL

  if (createRoutineNode->isParamStyleSpecified() &&
      ddlStyle != style)
    {
      // An unsupported PARAMETER STYLE was specified
      *CmpCommon::diags() << DgSqlCode(-3280);
      processReturn();
      return;
    }

  NAString externalName;
  if (language == COM_LANGUAGE_JAVA &&
      style == COM_STYLE_JAVA_CALL)
    {
      // the external name is a Java method signature
      externalName = createRoutineNode->getJavaClassName();
      externalName += "." ;
      externalName += createRoutineNode->getJavaMethodName();
    }
  else
    // the external name is a C/C++ entry point or a
    // Java class name
    externalName = createRoutineNode->getExternalName();

  // Verify that current user has authority to create the routine
  // User must be DB__ROOT or have privileges
  if (isAuthorizationEnabled() && !ComUser::isRootUserID())
    {

      // For now, go get privileges directly.  If we ever cache routines, then
      // make sure privileges are stored in the cache.
      NAString privMgrMDLoc;
      CONCAT_CATSCH(privMgrMDLoc, getSystemCatalog(), SEABASE_PRIVMGR_SCHEMA);
      PrivMgrCommands privInterface(privMgrMDLoc.data(), CmpCommon::diags());
      PrivMgrUserPrivs privs;
      PrivStatus retcode = privInterface.getPrivileges(libUID, COM_LIBRARY_OBJECT, 
                                                       ComUser::getCurrentUser(), privs);
      if (retcode != STATUS_GOOD)
        {
          if (CmpCommon::diags()->getNumber(DgSqlCode::ERROR_) == 0)
            SEABASEDDL_INTERNAL_ERROR("checking routine privilege");
          processReturn();
          return;
        }

      // Requester must have USAGE privilege on the library
      NABoolean hasPriv = TRUE;
      if ( !privs.hasUsagePriv() )
        {
          *CmpCommon::diags() << DgSqlCode( -4481 )
                              << DgString0( "USAGE" )
                              << DgString1( extLibraryName.data());
          processReturn();
          return;
        }
    }

  ElemDDLParamDefArray &routineParamArray =
        createRoutineNode->getParamArray();
  Lng32 numParams = routineParamArray.entries();

  if ((createRoutineNode->getRoutineType() == COM_SCALAR_UDF_TYPE) &&
      (numParams > 32))
    {
      *CmpCommon::diags() << DgSqlCode( -1550 )
                          << DgString0( extRoutineName )
                          << DgInt0( numParams );
      deallocEHI(ehi); 
      processReturn();
      return;
    }
#define MAX_SIGNATURE_LENGTH 8193
  // Allocate buffer for generated signature
  char sigBuf[MAX_SIGNATURE_LENGTH];
  sigBuf[0] = '\0';

  if (style == COM_STYLE_JAVA_CALL) 
  {
     // validate routine for Java call based on signature
     Lng32 numJavaParam = 0;
     ComFSDataType *paramType = new ComFSDataType[numParams];
     ComUInt32     *subType   = new ComUInt32    [numParams];
     ComColumnDirection *direction = new ComColumnDirection[numParams];
     NAType *genericType;

     // Gather the param attributes for LM from the paramDefArray previously
     // populated and from the routineparamList generated from paramDefArray.

     for (CollIndex i = 0; (Int32)i < numParams; i++)
     {
       paramType[i] = (ComFSDataType)routineParamArray[i]->getParamDataType()->getFSDatatype();
       subType[i] = 0;  // default
       // Set subType for special cases detected by LM
       switch ( paramType[i] )
       {
         case COM_SIGNED_BIN16_FSDT :
         case COM_SIGNED_BIN32_FSDT :
         case COM_SIGNED_BIN64_FSDT :
         case COM_UNSIGNED_BIN16_FSDT :
         case COM_UNSIGNED_BIN32_FSDT :
         case COM_UNSIGNED_BPINT_FSDT :
         {
           genericType = routineParamArray[i]->getParamDataType() ;
           if (genericType->getTypeName() == LiteralNumeric)
             subType[i] = genericType->getPrecision();
           else
             subType[i] = 0 ;

           break;
         }

         case COM_DATETIME_FSDT :
         {
           genericType = routineParamArray[i]->getParamDataType() ;
           DatetimeType & datetimeType = (DatetimeType &) *genericType;
            if (datetimeType.getSimpleTypeName() EQU "DATE")
              subType[i] = 1 ;
            else if (datetimeType.getSimpleTypeName() EQU "TIME")
              subType[i] = 2;
            else if (datetimeType.getSimpleTypeName() EQU "TIMESTAMP")
              subType[i] = 3;
         }
       } // end switch paramType[i]

       direction[i] = (ComColumnDirection) routineParamArray[i]->getParamDirection();
     }
    
     // If the syntax specified a signature, pass that to LanguageManager.
     NAString specifiedSig( createRoutineNode->getJavaSignature() );
     char* optionalSig;
     if ( specifiedSig.length() == 0 )
       optionalSig = NULL;
     else
       optionalSig = (char *)specifiedSig.data();
     
     ComBoolean isJavaMain =
       ((str_cmp_ne(createRoutineNode->getJavaMethodName(), "main") == 0) ? TRUE : FALSE);

     LmResult createSigResult;
     LmJavaSignature *lmSignature =  new (STMTHEAP) LmJavaSignature(NULL,
                                                                    STMTHEAP);
     createSigResult = lmSignature->createSig(paramType, subType, direction,
                                              numParams, COM_UNKNOWN_FSDT, 0,
                                              createRoutineNode->getMaxResults(), optionalSig, isJavaMain, sigBuf,
                                              MAX_SIGNATURE_LENGTH,
                                              CmpCommon::diags());
     NADELETE(lmSignature, LmJavaSignature, STMTHEAP);
     delete [] paramType;
     delete [] subType;
     delete [] direction;

     // Lm returned error. Lm fills diags area, so no need to worry about diags.
     if (createSigResult == LM_ERR)
     {
       *CmpCommon::diags() << DgSqlCode(-1231)
			  << DgString0(extRoutineName);
       deallocEHI(ehi); 
       processReturn();
       return;
     }

     numJavaParam = (isJavaMain ? 1 : numParams);

     if (validateRoutine(&cliInterface, 
                         createRoutineNode->getJavaClassName(),
                         createRoutineNode->getJavaMethodName(),
                         externalPath,
                         sigBuf,
                         numJavaParam,
                         createRoutineNode->getMaxResults(),
                         optionalSig))
     {
       *CmpCommon::diags() << DgSqlCode(-1231)
                           << DgString0(extRoutineName);
       deallocEHI(ehi); 
       processReturn();
       return;
     }
  }
  else if (style == COM_STYLE_JAVA_OBJ ||
           style == COM_STYLE_CPP_OBJ)
  {
    // validate existence of the C++ or Java class in the library
    Int32 routineHandle = NullCliRoutineHandle;
    NAString externalPrefix(externalPath);
    NAString externalNameForValidation(externalName);
    NAString containerName;

    if (language == COM_LANGUAGE_C || language == COM_LANGUAGE_CPP)
      {
        // separate the actual DLL name from the prefix
        char separator = '/';
        size_t separatorPos = externalPrefix.last(separator);

        if (separatorPos != NA_NPOS)
          {
            containerName = externalPrefix(separatorPos+1,
                                           externalPrefix.length()-separatorPos-1);
            externalPrefix.remove(separatorPos,
                                  externalPrefix.length()-separatorPos);
          }
        else
          {
            // assume the entire string is a local name
            containerName = externalPrefix;
            externalPrefix = ".";
          }
      }
    else
      {
        // For Java, the way the language manager works is that the
        // external path is the fully qualified name of the jar and
        // the container is the class name (external name).  We load
        // the container (the class) by searching in the path (the
        // jar). The external name is the method name, which in this
        // case is the constructor of the class, <init>.

        // leave externalPrevix unchanged, fully qualified jar file
        containerName = externalName;
        externalNameForValidation = "<init>";
      }

    // use a CLI call to validate that the library contains the routine
    if (cliInterface.getRoutine(
             NULL, // No InvocationInfo specified in this step
             0,
             NULL,
             0,
             (Int32) language,
             (Int32) style,
             externalNameForValidation.data(),
             containerName.data(),
             externalPrefix.data(),
             extLibraryName.data(),
             &routineHandle,
             CmpCommon::diags()) != LME_ROUTINE_VALIDATED)
      {
        if (routineHandle != NullCliRoutineHandle)
          cliInterface.putRoutine(routineHandle,
                                  CmpCommon::diags());

        CMPASSERT(CmpCommon::diags()->mainSQLCODE() < 0);
        processReturn();
        return;
      }

    cliInterface.putRoutine(routineHandle,
                            CmpCommon::diags());
  }

  ComTdbVirtTableColumnInfo * colInfoArray = (ComTdbVirtTableColumnInfo*)
    new(STMTHEAP) ComTdbVirtTableColumnInfo[numParams];

  if (buildColInfoArray(&routineParamArray, colInfoArray))
    {
      processReturn();
      return;
    }

  ComTdbVirtTableTableInfo * tableInfo = new(STMTHEAP) ComTdbVirtTableTableInfo[1];
  tableInfo->tableName = NULL,
  tableInfo->createTime = 0;
  tableInfo->redefTime = 0;
  tableInfo->objUID = 0;
  tableInfo->objOwnerID = objectOwnerID;
  tableInfo->schemaOwnerID = schemaOwnerID;
  tableInfo->isAudited = 1;
  tableInfo->validDef = 1;
  tableInfo->hbaseCreateOptions = NULL;
  tableInfo->numSaltPartns = 0;
  tableInfo->rowFormat = COM_UNKNOWN_FORMAT_TYPE;
  tableInfo->objectFlags = 0;

  Int64 objUID = -1;
  if (updateSeabaseMDTable(&cliInterface, 
			   catalogNamePart, schemaNamePart, objectNamePart,
			   COM_USER_DEFINED_ROUTINE_OBJECT,
			   "N",
			   tableInfo,
			   numParams,
			   colInfoArray,
			   0, NULL,
			   0, NULL,
                           objUID))
    {
      deallocEHI(ehi); 
      processReturn();
      return;
    }

  if (objUID == -1)
    {
      deallocEHI(ehi); 
      processReturn();
      return;
    }

  NAString udrType;
  getRoutineTypeLit(createRoutineNode->getRoutineType(), udrType);
  NAString languageType;
  getLanguageTypeLit(language, languageType);
  NAString sqlAccess;
  getSqlAccessLit(createRoutineNode->getSqlAccess(), sqlAccess);
  NAString paramStyle;
  getParamStyleLit(style, paramStyle);
  NAString transactionAttributes;
  getTransAttributesLit(createRoutineNode->getTransactionAttributes(), transactionAttributes);
  NAString parallelism;
  getParallelismLit(createRoutineNode->getParallelism(), parallelism);
  NAString externalSecurity;
  getExternalSecurityLit(createRoutineNode->getExternalSecurity(), externalSecurity);
  NAString executionMode;
  getExecutionModeLit(createRoutineNode->getExecutionMode(), executionMode);
  

  char * query = new(STMTHEAP) char[2000+MAX_SIGNATURE_LENGTH];
  str_sprintf(query, "insert into %s.\"%s\".%s values (%Ld, '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', %d, %d, '%s', '%s', '%s', '%s', '%s', %Ld, '%s' )",
	      getSystemCatalog(), SEABASE_MD_SCHEMA, SEABASE_ROUTINES,
	      objUID,
              udrType.data(),
              languageType.data(),
              createRoutineNode->isDeterministic() ? "Y" : "N" ,
              sqlAccess.data(),
              createRoutineNode->isCallOnNull() ? "Y" : "N" ,
              createRoutineNode->isIsolate() ? "Y" : "N" ,
              paramStyle.data(),
              transactionAttributes.data(),
              createRoutineNode->getMaxResults(),
              createRoutineNode->getStateAreaSize(),
              externalName.data(),
              parallelism.data(),
              createRoutineNode->getUserVersion().data(),
              externalSecurity.data(),
              executionMode.data(),
              libUID,
              sigBuf);
  
  cliRC = cliInterface.executeImmediate(query);
  NADELETEBASIC(query, STMTHEAP);
  if (cliRC < 0)
    {
      cliInterface.retrieveSQLDiagnostics(CmpCommon::diags());
      processReturn();
      return;
    }

  char * query1 = new(STMTHEAP) char[1000];
  str_sprintf(query1, "insert into %s.\"%s\".%s values (%Ld, %Ld)",
	      getSystemCatalog(), SEABASE_MD_SCHEMA, SEABASE_LIBRARIES_USAGE,
	      libUID, objUID);
  
  cliRC = cliInterface.executeImmediate(query1);
  NADELETEBASIC(query1, STMTHEAP);
  if (cliRC < 0)
    {
      cliInterface.retrieveSQLDiagnostics(CmpCommon::diags());
      processReturn();
      return;
    }

  // hope to remove this call soon by setting the valid flag to Y sooner
  if (updateObjectValidDef(&cliInterface, 
			   catalogNamePart, schemaNamePart, objectNamePart,
			   COM_USER_DEFINED_ROUTINE_OBJECT_LIT,
			   "Y"))
    {
      deallocEHI(ehi); 
      processReturn();
      return;
    }

  processReturn();
  return;
}