LmResult LmRoutineCppObj::dealloc(ComDiagsArea *diagsArea)
{
  LmResult result = LM_OK;

  delete invocationInfo_;
  invocationInfo_ = NULL;

  for (CollIndex i=0; i<planInfos_.getUsedLength(); i++)
    if (planInfos_.used(i))
      delete planInfos_[i];
  planInfos_.clear();

  if (paramRow_)
    {
      NADELETEBASIC(paramRow_, collHeap());
      paramRow_ = NULL;
    }

  if (inputRows_)
    {
      for (int i=0; i<numInputTables_; i++)
        if (inputRows_[i])
          NADELETEBASIC((inputRows_[i]), collHeap());
      NADELETEBASIC(inputRows_, collHeap());
      inputRows_ = NULL;
    }
  if (outputRow_)
    {
      // actually allocated buffer started where the wall starts
      NADELETEBASIC((outputRow_ - WALL_STRING_LEN), collHeap());
      outputRow_ = NULL;
    }

  try
    {
      // delete the interface object, the virtual destructor may call user code
      delete interfaceObj_;
    }
  catch (tmudr::UDRException e)
    {
      *diagsArea << DgSqlCode(-LME_UDR_METHOD_ERROR)
                 << DgString0("destructor")
                 << DgString1(getNameForDiags())
                 << DgString2(e.getMessage().c_str());
      result = LM_ERR;
    }
  catch (...)
    {
      *diagsArea << DgSqlCode(-LME_UDR_METHOD_ERROR)
                 << DgString0("destructor")
                 << DgString1(getNameForDiags())
                 << DgString2("General exception.");
      result = LM_ERR;
    }

  interfaceObj_ = NULL;

  return result;
}
LmHandle loadDll(
  const char   *containerName,
  const char   *externalPath,
  LmHandle     extLoader,
  ComUInt32    *containerSize,
  ComDiagsArea *da,
  NAMemory *heap)
{
#ifdef LMCOMMON_CANNOT_CALL_DLOPEN
  *da << DgSqlCode(-LME_INTERNAL_ERROR)
      << DgString0(": dlopen() is not supported");
  *da << DgSqlCode(-LME_DLL_CONT_NOT_FOUND)
      << DgString0(containerName)
      << DgString1(externalPath);
  return NULL;
#else
  char *libraryName = NULL;
  if (str_len(externalPath) == 0)
    externalPath = ".";
  libraryName = new (heap)
	  char[str_len(externalPath) + str_len(containerName) + 2];
  sprintf(libraryName, "%s/%s", externalPath, containerName);

  // TBD: For now, set container size to 0. Need to see how to get
  // the actual size
  if (containerSize)
    *containerSize = 0;

  // extLoader is an object of LmCLoader class. It's not used to
  // load the library. We can simply load the DLL.
  LmHandle container = NULL;
  const char *operation = "dlopen";
  container = (LmHandle) dlopen(libraryName, RTLD_NOW | RTLD_GLOBAL);

  LM_DEBUG3("%s(%s) returned 0x%08x\n", operation, libraryName, container);
  
  if (container == NULL)
  {
    *da << DgSqlCode(-LME_DLL_CONT_NOT_FOUND)
        << DgString0(containerName)
        << DgString1(externalPath);
    addDllErrors(*da, operation, FALSE);
  }

  NADELETEBASIC(libraryName, heap);
  return container;
#endif // LMCOMMON_CANNOT_CALL_DLOPEN
}
void addDllErrors(ComDiagsArea &diags,
                  const char *operation,
                  NABoolean isWarningOnly)
{
  Int32 errorCode = 0;
  Int32 errorDetail = 0;
  char *errorString = (char *)"";


#ifndef LMCOMMON_CANNOT_CALL_DLOPEN
  // dlresultcode() is not applicable to Linux
  errorString = dlerror();
#endif


  // Remove trailing period and linefeed characters from the message
  // string
  ComUInt32 msglen = 0;
  while (errorString && (msglen = strlen(errorString)) > 0)
  {
    ComUInt32 idx = msglen - 1;
    if (errorString[idx] == '\n' || errorString[idx] == '\r' ||
        errorString[idx] == '.')
      errorString[idx] = 0;
    else
      break;
  }

  diags << DgSqlCode((isWarningOnly ? LME_DLFCN_ERROR : -LME_DLFCN_ERROR))
        << DgString0(operation)
        << DgInt0(errorCode)
        << DgInt1(errorDetail)
        << DgString1(errorString);

}
// match a terminal symbol t
void ExtQualModuleNames::match(tokenType t)
{
  if (nextToken() == t) { // matches t. all is OK.
    currentTokenCode_ = scanner(); // get next token
  }
  else {
    *mxCUMptr << FAIL << DgSqlCode(-2212) << DgString0(tokenString(t))
              << DgString1(currentTokenString());
  }
}
LmResult LmRoutineCppObj::validateWall(char *userBuf,
                                       int userBufLen,
                                       ComDiagsArea *da,
                                       const char *bufferName)
{
  if (memcmp(userBuf - WALL_STRING_LEN, WALL_STRING, WALL_STRING_LEN) != 0)
    {
      if (da)
        *da << DgSqlCode(LME_BUFFER_OVERWRITE)
            << DgString0(invocationInfo_->getUDRName().data())
            << DgString1(bufferName)
            << DgString2("beginning");
      else
        throw tmudr::UDRException(
             38900,
             "UDR %s overwrote space before its %s buffer",
             invocationInfo_->getUDRName().data(),
             bufferName);
    }

  if (memcmp(userBuf + userBufLen, WALL_STRING, WALL_STRING_LEN) != 0)
    {
      if (da)
        *da << DgSqlCode(LME_BUFFER_OVERWRITE)
            << DgString0(invocationInfo_->getUDRName().data())
            << DgString1(bufferName)
            << DgString2("end");
      else
        throw tmudr::UDRException(
             38900,
             "UDR %s overwrote space after its %s buffer",
             invocationInfo_->getUDRName().data(),
             bufferName);
    }

  return LM_OK;
}
void ExFastExtractTcb::updateWorkATPDiagsArea(const char *file, 
                                              int line, const char *msg)
{
    ComDiagsArea *da = workAtp_->getDiagsArea();
    if(!da)
    {
      da = ComDiagsArea::allocate(getHeap());
      workAtp_->setDiagsArea(da);
    }
   
    *da << DgSqlCode(-1001)
        << DgString0(file)
        << DgInt0(line)
        << DgString1(msg);
}
// LCOV_EXCL_START :cnu
Int32 ValidateAnsiList::validate( const char *value,  
				const NADefaults *nad,
			 Int32 attrEnum,
			 Int32 errOrWarn,
				float *) const
{
  // Validate using a copy of "*value"
  char tempStr[1000];  // max length of ATTR_VALUE 
  if ( strlen(value) >= 1000 ) return FALSE;  // just in case
  if ( strlen(value) == 0 ) return TRUE;  // empty string ATTR_VALUE is OK
  strcpy(tempStr, value);

  // prepare to extract the partitions/tokens from the default string
  const char *token, *sep = " ,:" ;
  token = strtok( tempStr, sep );
  
  // iterate thru list of volume names; return false iff any name is invalid
  // (Also an appropriate error/warning would be issued.)
  while ( token != NULL ) {
    NAString tokenObj(token);
    Int32 countPeriods = 0, inBetween = 0;
    NABoolean anyError = tokenObj.isNull() ;
    // check three part ANSI name
    for (Int32 i = 0; !anyError && i < (Int32)tokenObj.length() ; i++ ) {
      if ( ComSqlText.isDigit(token[i]) ||
	   ComSqlText.isSimpleLatinLetter(token[i]) ) inBetween++;
      else {
	if ( ComSqlText.getPeriod() == token[i] &&  // it is a period
	     countPeriods++ < 2 ) {
	  if ( inBetween == 0 ) anyError = TRUE; // no CATALOG or SCHEMA
	  else inBetween = 0 ; // start counting the next ( SCHEMA or NAME )
	}
	else anyError = TRUE;
      }
    }
    if ( countPeriods != 2 || inBetween == 0 ) anyError = TRUE;

    if ( anyError ) {
      if (errOrWarn)
	*CmpCommon::diags() << DgSqlCode(ERRWARN(2055)) << DgString0(token) 
			    << DgString1("INVALID QUALIFIED NAME");
      return FALSE;
    }
    token = strtok( NULL, sep );
  }

  return TRUE;
}
// validate parameter for MV_AGE
Int32 ValidateMVAge::validate( const char *value,
                               const NADefaults *nad,
                               Int32 attrEnum,
                               Int32 errOrWarn,
                               float *alreadyHaveFloat ) const
{
  Int32 isOK = FALSE;
  float number=0;
  char textChars[20];

  if (strlen(value) < 15)
  {
    if (sscanf(value, "%f %s", &number, textChars) == 2)
    {
      const NAString text(textChars);
      if (!text.compareTo("Seconds", NAString::ignoreCase))
      {
	isOK = TRUE;
      }
      else if (!text.compareTo("Minutes", NAString::ignoreCase))
      {
	isOK = TRUE;
      }
      else if (!text.compareTo("Hours", NAString::ignoreCase))
      {
	isOK = TRUE;
      }
      else if (!text.compareTo("Days", NAString::ignoreCase))
      {
	isOK = TRUE;
      }
    }
  }

  if (!isOK)
  {
    if (errOrWarn)
      *CmpCommon::diags() << DgSqlCode(ERRWARN(2055))
          << DgString0(value)
          << DgString1(nad->lookupAttrName(attrEnum, errOrWarn));
  }
  
  return isOK;
}
Int32 ValidateRoleNameList::validate( const char *value,   
				const NADefaults *nad,
			 Int32 attrEnum,
			 Int32 errOrWarn,
				float *) const
{
  // Validate a list of role names.  Based on ValidateAnsiList
  // List format:  comma separated list of role names which use either . or _ 
  //  example:  "role.user1", "ROLE.user2", "role_user3"
  // SeaQuest example:  DB__Root, DB__Services, db_role12, db_user3

  // Validate using a copy of "*value"
  char tempStr[1000];  // max length of ATTR_VALUE 
  if ( strlen(value) >= 1000 ) return FALSE;  // just in case
  if ( strlen(value) == 0 ) return TRUE;  // empty string ATTR_VALUE is OK
  strcpy(tempStr, value);

  // prepare to extract the role names/tokens from the default string
  const char *token, *sep = " ," ;
  token = strtok( tempStr, sep );
  
  // iterate thru list of role names; return false iff any name is invalid
  // (Also an appropriate error/warning would be issued.)
  while ( token != NULL ) {
    NAString tokenObj(token);
    Lng32 sqlcode = ToInternalIdentifier(tokenObj, TRUE /*upCase*/,
                                         FALSE /*acceptCircumflex*/,
                                         0 /*toInternalIdentifierFlags*/);
    if (sqlcode && ABS(sqlcode) != 3128)
    {
      // 3004 A delimited identifier must contain at least one character.
      // 3118 Identifier too long.
      // 3127 Illegal character in identifier $0~string0.
      // 3128 $1~string1 is a reserved word.
      if (errOrWarn)
	*CmpCommon::diags() << DgSqlCode(ERRWARN(2055)) << DgString0(token) 
			    << DgString1("INVALID AUTHORIZATION IDENTIFIER");
    }
    token = strtok( NULL, sep );
  }

  return TRUE;
}
// validate OVERRIDE_SCHEMA FROM_SCHEMA:TO_SCHEMA setting
// format validation for xxx:yyy
Int32 ValidateOverrideSchema::validate( const char *value,
                                    const NADefaults *nad,
                                    Int32 attrEnum,
                                    Int32 errOrWarn,
                                    float *flt ) const
{
  NABoolean ok = TRUE;
  Int32 len = strlen(value);

  if (len == 0)                             // empty is ok
    return ok;

  NAString fromSchema, toSchema;

  extractOverrideSchemas(value, fromSchema, toSchema);

  if ( (fromSchema.isNull()) || (toSchema.isNull()) )
    ok = FALSE;  
  else
  {
    ComSchemaName targetSchema(toSchema);
    if (!targetSchema.isValid())
      ok = FALSE;
    else
      if (fromSchema!="*")  // reserve * for wildcard operation
      {
        ComSchemaName sourceSchema(fromSchema);
        if (!sourceSchema.isValid())
          ok = FALSE; 
      }
  }
 
  if (!ok && errOrWarn)
    *CmpCommon::diags() << DgSqlCode(ERRWARN(2055))
	<< DgString0(value)
	<< DgString1(nad->lookupAttrName(attrEnum, errOrWarn));

  return ok;

}
// validate REPLICATE_IO_VERSION setting
// setting may be schema or catalog.schema
Int32 ValidateReplIoVersion::validate( const char *value,
                                    const NADefaults *nad,
                                    Int32 attrEnum,
                                    Int32 errOrWarn,
                                    float *alreadyHaveFloat ) const
{
  Int32 isValid = FALSE;
  float flt;
  Int32 min;

  if (alreadyHaveFloat)
    flt = *alreadyHaveFloat;
  else {
    isValid = nad->validateFloat(value, flt, attrEnum, SilentIfSYSTEM);
    if (isValid == SilentIfSYSTEM) return SilentIfSYSTEM;
  }

  if (alreadyHaveFloat || isValid) 
  {
    if (Get_SqlParser_Flags(INTERNAL_QUERY_FROM_EXEUTIL))
       min = 1;
    else
       min = min_; 
    if (flt >= min && flt <= max_)
       return TRUE;                            // valid
  }

  if (alreadyHaveFloat) *alreadyHaveFloat = (float)min_;

  if (errOrWarn)
    *CmpCommon::diags() << DgSqlCode(ERRWARN(2055))
        << DgString0(value)
        << DgString1(nad->lookupAttrName(attrEnum, errOrWarn));

  return FALSE;

}
// validate PUBLIC_SCHEMA_NAME setting
// setting may be schema or catalog.schema
Int32 ValidatePublicSchema::validate( const char *value,
                                    const NADefaults *nad,
                                    Int32 attrEnum,
                                    Int32 errOrWarn,
                                    float *flt ) const
{
  NABoolean ok = TRUE;
  Int32 len = strlen(value);

  if (len == 0)                             // empty is ok
    return ok;

  ComSchemaName pubSchema(value);
  if (!pubSchema.isValid())
    ok = FALSE;
 
  if (!ok && errOrWarn)
    *CmpCommon::diags() << DgSqlCode(ERRWARN(2055))
	<< DgString0(value)
	<< DgString1(nad->lookupAttrName(attrEnum, errOrWarn));

  return ok;

}
Int32 ValidateCollationList::validate(const char *value,
				    const NADefaults *nad,
				    Int32 attrEnum,
				    Int32 errOrWarn,
				    float *) const
{
  if (errOrWarn) {
    CMPASSERT(nad && attrEnum);
    errOrWarn = +1;			// warnings only (else silent)
  }

  // Cast away constness on various private members which are really implicit
  // arguments (the validate method by itself vs. from insertIntoCDB).
  ValidateCollationList *ncThis = (ValidateCollationList *)this;

  #ifndef NDEBUG
    if (getenv("NCHAR_DEBUG")) ncThis->formatRetry_ = TRUE;
  #endif

  // If cdb is NULL, we are validating only; if nonNULL, we are inserting.
  CollationDB *cdb = ncThis->cdb_;
  const ComMPLoc   *defaultMPLoc  = NULL;
  const SchemaName *defaultSchema = NULL;
  if (cdb) {
    CMPASSERT(sdb_);
    defaultMPLoc  = &SqlParser_MPLOC;
    defaultSchema = &sdb_->getDefaultSchema();
  }

  // Make our own copy of the value string data,
  // on which we can safely cast away const-ness for the loop,
  // which chops the list up into individual names by replacing
  // (in place, i.e. w/o additional copying)
  // each semicolon with a string-terminating nul.
  NAString collNAS(value);
  char *collList = (char *)collNAS.data();

  while (*collList) {

    // SYNTAX OF THE MP_COLLATIONS LIST:
    //
    // The list may look like any of these:
    //	''		(empty)
    //	'collname'
    //	'c1; sv.c2; $v.sv.c3; \s.$v.sv.c4'
    //	'c1; sv.c2; $v.sv.c3; \s.$v.sv.c4;'
    //	' = c1; =sv.c2;=$v.sv.c3;\s.$v.sv.c4;'
    // We also ignore pathologies like
    //	'   '  or  '=========;;;;;===;    ; =  = == =; ; ; '
    //
    // The '=' flags the following collation name as one that has a 1:1 mapping,
    // i.e. its CPRULES.CHARACTERISTICS == 'O',
    // i.e. in Rel1 it allows only equality comparisons
    //      (SQL '=', '<>', DISTINCT, GROUP BY),
    // although no other operations
    // (other predicates, ordering, MIN/MAX, partitioning)
    // would be disallowed -- the column wouldn't even be updatable,
    // but it could be at least read and appear in some limited other places.
    //
    // The absence of a '=' means the collation's CHARACTERISTICS == 'N',
    // and in Rel1 we cannot support *any* comparisons, predicates, MIN/MAX,
    // ordering, partitioning, on it --
    // it's basically just a name attached to a column,
    // but the intent was to allow the column to be at least readable.
    //
    // See ReadTableDef and NATable to see if MP COLLATEd column support
    // is or is not currently being enabled.

    // Find the next semicolon separator outside of delim-ident quotes,
    // or find end of string.
    // Set collStr to be the fragment up to (excluding) the semicolon or zero;
    // set collList to be the rest of itself (after the semicolon).
    //
// LCOV_EXCL_START :mp
    char *s = collList;
    for (NABoolean quoted = FALSE; *s; s++) {
      if (*s == '"')
	quoted = !quoted;
      else if (*s == ';' && !quoted)
	break;
    }
    char sep = *s;			// sep is either ';' or '\0'
    *s = '\0';
    NAString collStr(collList);
    collList = sep ? ++s : s;		// get past ';' OR stay on final '\0'
    
    CollationInfo::CollationFlags flags = CollationInfo::ALL_CMP_ILLEGAL;

    TrimNAStringSpace(collStr);		// remove leading/trailing blanks
    size_t i = 0, n = collStr.length();
    while (i < n)
      if (collStr[i] == '=' || collStr[i] == ' ')
	i++;				// get past leading '=' (and blanks)
      else
        break;
    if (i) {				// an '=' was seen, EQ_NE_CMP is LEGAL
      flags = CollationInfo::ORDERED_CMP_ILLEGAL;
      collStr.remove(0, i);
    }

    if (!collStr.isNull()) {
      NABoolean ok = FALSE;
      NABoolean nsk = formatNSK_;
      NABoolean retry = formatRetry_;

      retry_as_other_format:

	if (nsk) {
	  ComMPLoc collMP(collStr, ComMPLoc::FILE);
	  if (collMP.isValid(ComMPLoc::FILE)) {
	    ok = TRUE;
	    if (cdb) {
	      ncThis->lastCoInserted_ =
	        cdb->insert(collMP, defaultMPLoc, flags);
	    }
	  }
	}
	else {
	  ComObjectName collMX(collStr);
	  if (collMX.isValid()) {
	    ok = TRUE;
	    if (cdb) {
	      QualifiedName collQN(collMX);
	      ncThis->lastCoInserted_ =
	        cdb->insert(collQN, defaultSchema, flags);
	    }
	  }
	}

      if (ok) ncThis->cntCoParsed_++;

      if (!ok && retry) {
        retry = FALSE;			// Retry only once,
	nsk = !nsk;			// using the other name format.
	goto retry_as_other_format;
      }

      if (!ok && errOrWarn)
	*CmpCommon::diags() << DgSqlCode(ERRWARN(2055))
	    << DgString0(collStr)
	    << DgString1(nad->lookupAttrName(attrEnum, errOrWarn));

// LCOV_EXCL_STOP
    }	// !collStr.isNull()
  } // while

  return TRUE;				// warnings only; all is valid
}
Int32 ValidateNumericRange::validate( const char *value,
				    const NADefaults *nad,
				    Int32 attrEnum,
				    Int32 errOrWarn,
				    float *alreadyHaveFloat) const
{
  Int32 isValid = FALSE, rangeOK = FALSE, multipleOK = FALSE;
  float flt;

  if (alreadyHaveFloat)
    flt = *alreadyHaveFloat;
  else {
    isValid = nad->validateFloat(value, flt, attrEnum, SilentIfSYSTEM);
    if (isValid == SilentIfSYSTEM) return SilentIfSYSTEM;
  }

  if (alreadyHaveFloat || isValid) {

    rangeOK = (min_ <= flt && flt <= max_);
    if (rangeOK) {
      multipleOK = (multiple_ == 0 || ((ULng32)flt) % multiple_ == 0);
      if (multipleOK) {
	return TRUE;				// valid
      }
    }
  }

  if (alreadyHaveFloat) *alreadyHaveFloat = min_;

  if (errOrWarn) {

    *CmpCommon::diags() << DgSqlCode(ERRWARN(2055))
      << DgString0(value)
      << DgString1(nad->lookupAttrName(attrEnum, errOrWarn));

    if (!rangeOK) {
      char minbuf[50], maxbuf[50];
      
      if (type_ == VALID_INT) {
	sprintf(minbuf, "%d", (Lng32)min_);
	

	// A fudge factor of 64 is added for NT/Yos/Neo to include 
	// the precision lost. The value printed is 2147483520, 
	// while values are accepted till 2147483584. 
	sprintf(maxbuf, "%d", (Lng32)max_+64);
     }
      else if (type_ == VALID_UINT) {
	sprintf(minbuf, "%u", (ULng32)min_);
	if (max_ == 2147483520)
	  sprintf(maxbuf, "%u", (ULng32)max_+64);
        else
	  sprintf(maxbuf, "%u", (ULng32)max_);

      }
      else {
	sprintf(minbuf, "%g", min_);
	sprintf(maxbuf, "%g", max_);
      }

      switch (attrEnum)
        {
        case HIVE_INSERT_ERROR_MODE:
          {
            sprintf(minbuf, "%u", 0);
            sprintf(maxbuf, "%u", 3);
          }
          break;
        default:
          {
            // do nothing
          }
        }
      
      NAString range = NAString("[") + minbuf + "," + maxbuf + "]";
      *CmpCommon::diags() << DgSqlCode(ERRWARN(2056)) << DgString0(range);
    }

    if (multiple_ && !multipleOK)
#pragma nowarn(1506)   // warning elimination 
      *CmpCommon::diags() << DgSqlCode(ERRWARN(2057)) << DgInt0(multiple_);
#pragma warn(1506)  // warning elimination 

  }

  return FALSE;					// not valid
}
Int32 ValidatePOSTableSizes::validate(const char *value,
                                    const NADefaults *nad,
                                    Int32 attrEnum,
                                    Int32 errOrWarn,
                                    float *) const
{
  char tempStr[1000];  // max length of ATTR_VALUE

  if ( strlen(value) == 0 ) return TRUE;  // empty string ATTR_VALUE is OK

  if ( strlen(value) > 1000 )
  {
    *CmpCommon::diags() << DgSqlCode(ERRWARN(2055))
                        << DgString0(value)
                        << DgString1(nad->lookupAttrName(attrEnum, errOrWarn));

    return FALSE;
  }

  strcpy(tempStr, value);

  const char *token, *sep = " ,";
  token = strtok(tempStr, sep);

  float initialSize = -1;
  float maxSize = -1;
  ValidateUInt  uint;
  
  if (token != NULL)
  {
    // check if the first value is an unsigned int
    if (!uint.validate(token, nad, attrEnum, -1))
      return FALSE;
    else
    {
      sscanf(token, "%g", &initialSize);
      token = strtok(NULL, sep);
      if (token != NULL)
      {
        // check if the second value is an unsigned int
        if (!uint.validate(token, nad, attrEnum, -1))
          return FALSE;
        else
        {
          // if there is a third value or max table size is smaller than
          // initial table size raise an error
          sscanf(token, "%g", &maxSize);
          token = strtok(NULL, sep);
          if (token != NULL || maxSize < initialSize)
          {
            *CmpCommon::diags() << DgSqlCode(ERRWARN(2055))
              << DgString0(value)
              << DgString1(nad->lookupAttrName(attrEnum, errOrWarn));
  
            if (maxSize < initialSize)
            {
              *CmpCommon::diags() << DgSqlCode(ERRWARN(2077))
                << DgInt0((Lng32)maxSize)
                << DgInt1((Lng32)initialSize);
            }
            return FALSE;
          }
        }
      }
    }
  }
  else
  {
    *CmpCommon::diags() << DgSqlCode(ERRWARN(2055))
                        << DgString0(value)
                        << DgString1(nad->lookupAttrName(attrEnum, errOrWarn));

     return FALSE;
  }

  return TRUE;
}
LmResult LmRoutineCppObj::invokeRoutineMethod(
     /* IN */     tmudr::UDRInvocationInfo::CallPhase phase,
     /* IN */     const char   *serializedInvocationInfo,
     /* IN */     Int32         invocationInfoLen,
     /* OUT */    Int32        *invocationInfoLenOut,
     /* IN */     const char   *serializedPlanInfo,
     /* IN */     Int32         planInfoLen,
     /* IN */     Int32         planNum,
     /* OUT */    Int32        *planInfoLenOut,
     /* IN */     char         *inputParamRow,
     /* IN */     Int32         inputParamRowLen,
     /* OUT */    char         *outputRow,
     /* IN */     Int32         outputRowLen,
     /* IN/OUT */ ComDiagsArea *da)
{
  LmResult result = LM_OK;

  // initialize out parameters
  *invocationInfoLenOut = 0;
  *planInfoLenOut = 0;

  // some parameter checks
  if (invocationInfoLen <= 0 &&
      invocationInfo_ == NULL)
    {
      // we need to have an Invocation info
      *da << DgSqlCode(-LME_OBJECT_INTERFACE_ERROR)
          << DgString0(getNameForDiags())
          << DgString1(tmudr::UDRInvocationInfo::callPhaseToString(
                            tmudr::UDRInvocationInfo::COMPILER_INITIAL_CALL))
          << DgString2("LmRoutineCppObj::invokeRoutineMethod()")
          << DgString3("Missing UDRInvocationInfo");
    }

  try
    {
      if (invocationInfoLen > 0)
        {
          if (invocationInfo_ == NULL)
            invocationInfo_ = new tmudr::UDRInvocationInfo;

          // unpack the invocation info
          invocationInfo_->deserializeObj(serializedInvocationInfo,
                                          invocationInfoLen);
        }

      if (planInfoLen > 0)
        {
          if (!planInfos_.used(planNum))
            planInfos_.insertAt(planNum, new tmudr::UDRPlanInfo(invocationInfo_,
                                                                planNum));

          // unpack the invocation info
          planInfos_[planNum]->deserializeObj(serializedPlanInfo,
                                              planInfoLen);
        }

      // some parameter checks
      if (inputParamRowLen < inputParamRowLen_)
        return LM_ERR;
      // test to do for scalar UDFs
      // if (outputRowLen < invocationInfo_->out().getRecordLength())
      //   return LM_ERR;

      if (inputParamRow && inputParamRowLen_ > 0)
        // copy parameter row
        memcpy(invocationInfo_->par().getRowPtr(), inputParamRow, inputParamRowLen_);

      invocationInfo_->callPhase_ = phase;
      switch (phase)
        {
        case tmudr::UDRInvocationInfo::COMPILER_INITIAL_CALL:
          if (invocationInfo_->getDebugFlags() &
              tmudr::UDRInvocationInfo::PRINT_INVOCATION_INFO_INITIAL)
            invocationInfo_->print();

          if (invocationInfo_->getDebugFlags() &
              tmudr::UDRInvocationInfo::DEBUG_INITIAL_COMPILE_TIME_LOOP)
            if (invocationInfo_->getSessionUser() == ComUser::getRootUserName())
              interfaceObj_->debugLoop();
            else if (da)
              *da << DgSqlCode(1260); // warning, only root user can debug

          interfaceObj_->describeParamsAndColumns(*invocationInfo_);
          break;

        case tmudr::UDRInvocationInfo::COMPILER_DATAFLOW_CALL:
          interfaceObj_->describeDataflowAndPredicates(*invocationInfo_);
          break;

        case tmudr::UDRInvocationInfo::COMPILER_CONSTRAINTS_CALL:
          interfaceObj_->describeConstraints(*invocationInfo_);
          break;

        case tmudr::UDRInvocationInfo::COMPILER_STATISTICS_CALL:
          interfaceObj_->describeStatistics(*invocationInfo_);
          break;

        case tmudr::UDRInvocationInfo::COMPILER_DOP_CALL:
          interfaceObj_->describeDesiredDegreeOfParallelism(
               *invocationInfo_,
               *planInfos_[planNum]);
          break;

        case tmudr::UDRInvocationInfo::COMPILER_PLAN_CALL:
          interfaceObj_->describePlanProperties(*invocationInfo_,
                                                *planInfos_[planNum]);
          break;

        case tmudr::UDRInvocationInfo::COMPILER_COMPLETION_CALL:
          interfaceObj_->completeDescription(*invocationInfo_,
                                             *planInfos_[planNum]);
          if (invocationInfo_->getDebugFlags() &
              tmudr::UDRInvocationInfo::PRINT_INVOCATION_INFO_END_COMPILE)
            {
              invocationInfo_->print();
              printf("\n");
              for (CollIndex i=0; i<planInfos_.getUsedLength(); i++)
                if (planInfos_.used(i))
                  {
                    if (i == planNum)
                      printf("++++++++++ Chosen plan: ++++++++++\n");
                    else
                      printf("-------- Plan not chosen: --------\n");
                    planInfos_[i]->print();
                  }
            }

          break;

        case tmudr::UDRInvocationInfo::RUNTIME_WORK_CALL:
          {
            if (invocationInfo_->getDebugFlags() &
                tmudr::UDRInvocationInfo::PRINT_INVOCATION_INFO_AT_RUN_TIME)
              {
                invocationInfo_->print();
                planInfos_[planNum]->print();
              }

            if ((invocationInfo_->getDebugFlags() &
                 tmudr::UDRInvocationInfo::DEBUG_INITIAL_RUN_TIME_LOOP_ALL) ||
                (invocationInfo_->getDebugFlags() &
                 tmudr::UDRInvocationInfo::DEBUG_INITIAL_RUN_TIME_LOOP_ONE &&
                 invocationInfo_->getMyInstanceNum() == 0))
              interfaceObj_->debugLoop();

            interfaceObj_->processData(*invocationInfo_,
                                       *planInfos_[planNum]);

            if (result == LM_OK)
              {
                if (invocationInfo_->getDebugFlags() & tmudr::UDRInvocationInfo::TRACE_ROWS)
                  printf("(%d) Emitting EOD\n",
                         invocationInfo_->getMyInstanceNum());

                // call emitRow to indicate EOD, something the
                // C interface would do inside the UDF
                SQLUDR_Q_STATE qstate = SQLUDR_Q_EOD;

                (*interfaceObj_->emitRowPtr_)(
                     invocationInfo_->out().getRowPtr(),
                     0,
                     &qstate);
              }
          }
          break;

        default:
          *da << DgSqlCode(-11111)
              << DgString0("Invalid call phase in LmRoutineCppObj::invokeRoutineMethod()");

          result = LM_ERR;
          break;
        
        }

      // return length of updated invocation and plan info for
      // compile-time phases
      if (invocationInfo_ &&
          phase < tmudr::UDRInvocationInfo::RUNTIME_WORK_CALL)
        {
          *invocationInfoLenOut = invocationInfo_->serializedLength();
          if (planInfos_.used(planNum))
            *planInfoLenOut = planInfos_[planNum]->serializedLength();
        }
    }
  catch (tmudr::UDRException e)
    {
      // Check the returned SQLSTATE value and raise appropriate
      // SQL code. Valid SQLSTATE values begin with "38" except "38000"
      const char *sqlState = e.getSQLState();

      if ((strncmp(sqlState, "38", 2) == 0) &&
          (strncmp(sqlState, "38000", 5) != 0))
        {
          *da << DgSqlCode(-LME_CUSTOM_ERROR)
              << DgString0(e.getMessage().c_str())
              << DgString1(sqlState);
          *da << DgCustomSQLState(sqlState);
        }
      else
        {
          *da << DgSqlCode(-LME_UDF_ERROR)
              << DgString0(invocationInfo_->getUDRName().c_str())
              << DgString1(sqlState)
              << DgString2(e.getMessage().c_str());
        }
      result = LM_ERR;
    }
  catch (...)
    {
      *da << DgSqlCode(-LME_OBJECT_INTERFACE_ERROR)
          << DgString0(getNameForDiags())
          << DgString1(invocationInfo_->callPhaseToString(phase))
          << DgString2("LmRoutineCppObj::invokeRoutineMethod()")
          << DgString3("general exception");
      result = LM_ERR;
    }

  invocationInfo_->callPhase_ =
    tmudr::UDRInvocationInfo::UNKNOWN_CALL_PHASE;

  return result;
}
Example #17
0
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;

  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;
  routinePtr = getRoutinePtr(container->getHandle(), externalName);

  const char *operation = "dlsym";
  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_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 
  {
    // 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 LmRoutineCppObj::getRoutineInvocationInfo(
     /* IN/OUT */ char         *serializedInvocationInfo,
     /* IN */     Int32         invocationInfoMaxLen,
     /* OUT */    Int32        *invocationInfoLenOut,
     /* IN/OUT */ char         *serializedPlanInfo,
     /* IN */     Int32         planInfoMaxLen,
     /* IN */     Int32         planNum,
     /* OUT */    Int32        *planInfoLenOut,
     /* IN/OUT */ ComDiagsArea *da)
{
  LmResult result = LM_OK;

  // Retrieve updated invocation and plan info.
  // The invokeRoutineMethod provided the required buffer
  // space, so there is no excuse for having insufficient
  // buffer when calling this, and doing so will raise
  // an exception in the try block below.
  try
    {
      if (invocationInfo_ && invocationInfoMaxLen > 0)
        {
          char *tempiibuf = serializedInvocationInfo;
          int tempiilen   = invocationInfoMaxLen;
          *invocationInfoLenOut = invocationInfo_->serialize(
               tempiibuf, tempiilen);
        }
      else
        *invocationInfoLenOut = 0;

      if (planInfos_.used(planNum) && planInfoMaxLen > 0)
        {
          char *temppibuf = serializedPlanInfo;
          int temppilen   = planInfoMaxLen;
          *planInfoLenOut = planInfos_[planNum]->serialize(
               temppibuf, temppilen);
        }
      else
        *planInfoLenOut = 0;
    }
  catch (tmudr::UDRException e)
    {
      // this UDRException is generated by Trafodion code and
      // it is an internal error to fail serializing the structs,
      // even though the user might have caused it by corrupting
      // these structs
      *da << DgSqlCode(-LME_OBJECT_INTERFACE_ERROR)
          << DgString0(getNameForDiags())
          << DgString1(invocationInfo_->callPhaseToString(invocationInfo_->getCallPhase()))
          << DgString2("LmRoutineCppObj::getRoutineInvocationInfo()")
          << DgString3(e.getMessage().c_str());
      result = LM_ERR;
    }
  catch (...)
    {
      *da << DgSqlCode(-LME_OBJECT_INTERFACE_ERROR)
          << DgString0(getNameForDiags())
          << DgString1(invocationInfo_->callPhaseToString(invocationInfo_->getCallPhase()))
          << DgString2("LmRoutineCppObj::getRoutineInvocationInfo()")
          << DgString3("general exception");
      result = LM_ERR;
    }

  return result;
}
Example #19
0
// print MDFWriter errors to cout
void SQLJFile::printMDFWriterErrors(char *errFileName)
{
  char args[1024], EorW[10];
  Int32  errNum;
  FILE *errFile = fopen(errFileName, "r");
  if (errFile) {
    // accommodate case of MDFWriter dumping more entries into its errFile
    // than can fit into the fixed-size diags area. Do this by feeding
    // and then dumping diags one entry at a time.
    ComDiagsArea *myDiags = ComDiagsArea::allocate(mxCUMptr->heap());
    while (fscanf(errFile, "%s %d ", EorW, &errNum) != EOF) {
      size_t sLen = 0;
      if (fgets(args, 1024, errFile) == NULL) { // fgets got EOF or an error
        args[0] = 0; // empty string
        *mxCUMptr << FAIL;
      }
      else { // fgets got something
        sLen = strlen(args);
        // chop off terminating newline
        if (args[sLen-1] == '\n') {
          args[sLen-1] = 0;
        }
        if (sLen >= 1023) { // diagnostic msg is too long
          // toss rest of line
          Int32 nxtCh;
          do {
            nxtCh = fgetc(errFile);
          } while (nxtCh != '\n' && nxtCh != EOF);
        }
      }
      if (!myDiags) { // no diags
        *mxCUMptr << FAIL;
        if (sLen >= 1023) { // diagnostic msg is too long
          cerr << "Diagnostic message is over 1023 characters long." << endl;
        }
        // echo error file entry to cerr
        cerr << EorW << " " << errNum << " " << args << endl;
      }
      else {
        if (sLen >= 1023) { // diagnostic msg is too long
          *mxCUMptr << WARNING;
          *myDiags << DgSqlCode(2237);
        }
        switch (errNum) {
        case 2224:
        case 2225:
        case 2226:
          *mxCUMptr << FAIL; 
          *myDiags << DgSqlCode(-errNum);
          break;
        case 2227:
        case 2228:
        case 2230:
          *mxCUMptr << FAIL;
          *myDiags << DgSqlCode(-errNum) << DgString0(args);
          break;
        case 2229:
          *mxCUMptr << ERROR;
          *myDiags << DgSqlCode(-errNum) << DgString0(args);
          break;
        default:
          *mxCUMptr << (EorW[0]=='E' ? ERROR :
                        (EorW[0]=='W' ? WARNING : FAIL));
          *myDiags << DgSqlCode(-2231) << DgInt0(errNum) 
                   << DgString0(EorW) << DgString1(args);
          break;
        } // end switch
        NADumpDiags(cerr, myDiags, TRUE);
        myDiags->clear();
      } // end if
    } // end while
    if (myDiags) {
      myDiags->decrRefCount();
    }
    fclose(errFile);
  }
  else {
    *mxCUMptr << FAIL << DgSqlCode(-2218) << DgString0(errFileName);
  }
  // clean up temporary file (MDFWriter errors)
  remove(errFileName);
}
// static helper function to generate one list of disks
// (returns an array of ExScratchDiskDrive objects)
static ExScratchDiskDrive * genScratchDriveList(const NAString &def,
						Lng32 &numDrives,
						Generator *generator,
						const char *defName)
{
  ExScratchDiskDrive *result = NULL;

  // temporary
  //  numDrives = 0;
  //  return result;
  // end temporary

  const char *str = def.data();
  if (!*str)
    {
      numDrives = 0;
      return result;		// fast return if empty NADefaults val
    }

  // ---------------------------------------------------------------------
  // Convert the strings into a temporary list of ExScratchDiskDrive
  // objects (temporary because we want to make the final list a
  // contiguous array)
  // ---------------------------------------------------------------------
  LIST(ExScratchDiskDrive *) tempList;
  CollHeap *heap = generator->wHeap();
  Space *space = generator->getSpace();

  // ---------------------------------------------------------------------
  // process the NT default
  // ---------------------------------------------------------------------
  while (str && *str)
    {
      Lng32 nodeNum;
      char *driveLetter = new(heap) char[2];

      driveLetter[1] = 0;
      if (ValidateDiskListNT::getNextDriveLetterAndAdvance(
	   str,nodeNum,driveLetter[0]))
	{
	  // syntax error in default, issue a warning (not an error)
	  *CmpCommon::diags() << DgSqlCode(2055)
			      << DgString0(def)
			      << DgString1(defName);
	  // don't continue after a syntax error
	  str = NULL;
	}
      else
	{
	  tempList.insert(new(heap) ExScratchDiskDrive(
	       driveLetter,
	       1, // Thanks to Bill Gates
	       nodeNum));
	}

      NADELETEBASIC(driveLetter, heap);
      driveLetter = NULL;

    }

  // ---------------------------------------------------------------------
  // Calculate total generated space needed and allocate it
  // ---------------------------------------------------------------------
#pragma nowarn(1506)   // warning elimination 
  numDrives = tempList.entries();
#pragma warn(1506)  // warning elimination 
  Lng32 allClusterNamesLen = 0;
  Lng32 allDiskNamesLen = 0;
  char *generatedClusterNames = NULL;
  char *generatedDiskNames = NULL;

  Int32 i=0;
  for (; i<numDrives; i++)
    {
      allClusterNamesLen += tempList[i]->getClusterNameLength()+1;
      allDiskNamesLen += str_len(tempList[i]->getDiskName())+1;
    }

  if (numDrives >0)
      {
	result = new(space) ExScratchDiskDrive[numDrives];
	generatedClusterNames = new(space) char[allClusterNamesLen];
	generatedDiskNames = new(space) char[allDiskNamesLen];
      }

  // ---------------------------------------------------------------------
  // Loop over the temporary list and copy it into the generated space
  // ---------------------------------------------------------------------
  for (i=0; i<numDrives; i++)
    {
      ExScratchDiskDrive *src = tempList[i];
      Lng32 clusterNameLen = src->getClusterNameLength();
      Lng32 diskNameLen = src->getDiskNameLength();
      if (clusterNameLen)
	{
	  str_cpy_all(generatedClusterNames, src->getClusterName(),
		      clusterNameLen);
	  generatedClusterNames[clusterNameLen] = 0;
	  result[i].setClusterName(generatedClusterNames);
	  generatedClusterNames += clusterNameLen+1;
	}
      else
	{
	  result[i].setClusterName(NULL);
	}
      result[i].setClusterNameLength(clusterNameLen);
      result[i].setClusterNumber(src->getClusterNumber());
      result[i].setNodeNumber(src->getNodeNumber());
      str_cpy_all(generatedDiskNames, src->getDiskName(), diskNameLen);
      generatedDiskNames[diskNameLen] = 0;
      result[i].setDiskName(generatedDiskNames);
      result[i].setDiskNameLength(diskNameLen);
      generatedDiskNames += diskNameLen+1;
    }
  return result;
}
Example #21
0
NABoolean CmpSqlSession::validateVolatileQualifiedName(QualifiedName &inName)
{
  if (NOT Get_SqlParser_Flags(ALLOW_VOLATILE_SCHEMA_IN_TABLE_NAME))
    {
      if (NOT inName.getCatalogName().isNull())
	{
	  // cannot be a 3-part name
	  *CmpCommon::diags() << DgSqlCode(-4192);
	  return FALSE;
	}
      
      if (NOT inName.getSchemaName().isNull())
	{
	  // validate that the schemaName part is the currentUserName
	  if (inName.getSchemaName() != externalUserName_)
	    {
	      *CmpCommon::diags() << DgSqlCode(-4191) <<
		DgString0(inName.getSchemaName()) <<
		DgString1(externalUserName_);
	      return FALSE;
	    }
	}
    }
  else
    {
      // Volatile schema name is allowed.
      // Make sure that it is a valid volatile 3 part name.
      if ((NOT inName.getCatalogName().isNull()) &&
	  (NOT inName.getSchemaName().isNull()))
	{
	  // move to a temp to upcase
	  ComSchemaName csn(inName.getSchemaName());
	  
	  ULng32 len = 
	    MINOF(strlen(csn.getSchemaNamePartAsAnsiString().data()),
		  strlen(COM_VOLATILE_SCHEMA_PREFIX));
	  NAString upSch(csn.getSchemaNamePartAsAnsiString().data());
	  upSch.toUpper();
	  if ((len < strlen(COM_VOLATILE_SCHEMA_PREFIX)) ||
	      (strncmp(upSch.data(), COM_VOLATILE_SCHEMA_PREFIX, len) != 0))
	    {
	      *CmpCommon::diags() << DgSqlCode(-4192);
	      return FALSE;
	    }
	}
      else if (NOT inName.getSchemaName().isNull())
	{
	  // 2 part name
	  // validate that the schemaName part is the currentUserName
	  if (inName.getSchemaName() != externalUserName_)
	    {
	      *CmpCommon::diags() << DgSqlCode(-4191) <<
		DgString0(inName.getSchemaName()) <<
		DgString1(externalUserName_);
	      return FALSE;
	    }
	}
    }

  return TRUE;
}
// static helper function to generate one list of disks
// (returns an array of ExScratchDiskDrive objects)
static ExScratchDiskDrive * genScratchDisks(const NAString &def,
						Lng32 &numDirs,
						Generator *generator,
						const char *defName)
{
  ExScratchDiskDrive *result = NULL;

  // temporary
  //  numDrives = 0;
  //  return result;
  // end temporary

  const char *str = def.data();
  if (!str || str[0]=='\0')
    {
      numDirs = 0;
      return result;		// fast return if empty NADefaults val
    }

  
  // ---------------------------------------------------------------------
  // Convert the strings into a temporary list of ExScratchDiskDrive
  // objects (temporary because we want to make the final list a
  // contiguous array)
  // ---------------------------------------------------------------------
  CollHeap *heap = generator->wHeap();
  Space *space = generator->getSpace();
  LIST(ExScratchDiskDrive *) tempList(heap);
  struct stat st;
  
 
  Lng32 nodeNum;
 
  char *token,*saveptr = NULL;
  //save the pointer to this since token will keep changing.

  char *sep = (char *)":";
  token = strtok_r((char *)str,sep,&saveptr);
  while (token != NULL)
    {
      //validate the directory
      if ((stat(token,&st) != 0 ) &&  !S_ISDIR(st.st_mode) ) //&& (numDirs > MAX_SCRATCH_LOCATIONS))
        {
          // syntax error in default, issue a warning (not an error)
          *CmpCommon::diags() << DgSqlCode(2055)
			      << DgString0(def)
			      << DgString1(defName);
          // don't continue after a syntax error
          str = NULL;
        }
      else
        {
          tempList.insert(new(heap) ExScratchDiskDrive(
                               token,
                               strlen(token) ));
        }
      token = strtok_r(NULL,sep,&saveptr);
    }
      
 
  token  = NULL;
    

  // ---------------------------------------------------------------------
  // Calculate total generated space needed and allocate it
  // ---------------------------------------------------------------------
  numDirs = tempList.entries();
 
  Lng32 allDirNamesLen = 0;
  char *generatedDirNames = NULL;

  Int32 i=0;
  for (; i<numDirs; i++)
    {
      allDirNamesLen += str_len(tempList[i]->getDirName())+1;
    }

  if (numDirs >0)
    {
      result = new(space) ExScratchDiskDrive[numDirs];
      generatedDirNames = new(space) char[allDirNamesLen];
    }

  // ---------------------------------------------------------------------
  // Loop over the temporary list and copy it into the generated space
  // ---------------------------------------------------------------------
  for (i=0; i<numDirs; i++)
    {
      ExScratchDiskDrive *src = tempList[i];
      Lng32 dirNameLen = src->getDirNameLength();
        
      str_cpy_all(generatedDirNames, src->getDirName(), dirNameLen);
      generatedDirNames[dirNameLen] = 0;
      result[i].setDirName(generatedDirNames);
      result[i].setDirNameLength(dirNameLen);
      generatedDirNames += dirNameLen+1;
    }
  return result;
}
ExprNode *
ElemDDLPartitionSystem::bindNode(BindWA * /*pBindWA*/)
{
  //
  // location
  //
  ComLocationName defaultLocName;  // empty object

  if (getLocationName().isNull())
    //
    // location clause not specified (only allowed for primary partition)
    //
    guardianLocation_ =
      defaultLocName.getGuardianFullyQualifiedName();
  else  // LOCATION clause was specified
  {
    ComLocationName locName;         // empty object
    switch (getLocationNameType())
    {
    case ElemDDLLocation::LOCATION_GUARDIAN_NAME :
      locName.copy(getLocationName(),
                   ComLocationName::GUARDIAN_LOCATION_NAME_FORMAT);
      if (NOT locName.isValid())
      {
        // Illegal location name format.
        *SqlParser_Diags << DgSqlCode(-3061) << DgString0(getLocationName());
        guardianLocation_ =
          defaultLocName.getGuardianFullyQualifiedName();
      }
      else  // valid location
        guardianLocation_ =
          locName.getGuardianFullyQualifiedName();
      break;

    case ElemDDLLocation::LOCATION_OSS_NAME :
      locName.copy(getLocationName(),
                   ComLocationName::OSS_LOCATION_NAME_FORMAT);
      if (NOT locName.isValid())
      {
        // Illegal location name format.
        *SqlParser_Diags << DgSqlCode(-3061) << DgString0(getLocationName());
        guardianLocation_ =
          defaultLocName.getGuardianFullyQualifiedName();
      }
      else  // valid location
        guardianLocation_ =
          locName.getGuardianFullyQualifiedName();
      break;

#if 0
      //
      // Currently we do not handle this case
      // The grammar productions don't accept this syntax.
      // So comment out the following code for now.
      //
    case ElemDDLLocation::LOCATION_ENVIRONMENT_VARIABLE :
      {
        NAString envVarName(getLocationName());
        //
        // if the specified OSS environment variable has the
        // dollar sign prefix, removes it.
        //
	    if (envVarName[(size_t) 0] EQU '$')            // NT_PORT FIX SK 07/15/96
        {
          envVarName = envVarName(1/*startpos*/, envVarName.length() - 1);
        }
        const char * pEnvVarValue = getenv((const char *)envVarName);
        NAString locationName;
        if (pEnvVarValue NEQ NULL)
        {
          locationName = pEnvVarValue;
        }
        if (locationName.isNull())
        {
          guardianLocation_ = defaultLocName.
                              getGuardianFullyQualifiedName();
        }
        else
        {
          guardianLocationName = locationName;
          if (guardianLocationName.isValid())
          {
            guardianLocation_ = (guardianLocationName.
                                 getGuardianFullyQualifiedName());
            
          }
          else
          {
            ossLocationName = locationName;
            if (ossLocationName.isValid())
            {
              guardianLocation_ = (ossLocationName.
                                   getGuardianFullyQualifiedName());
            }
            else
            {
              // OSS environment variable $1~string1 contains illegal
              // location name $0~string0.
              *SqlParser_Diags << DgSqlCode(-3061) 
		<< DgString0(locationName)
	        << DgString1(envVarName)
		;
            }
          }
        }
      }
      break;
#endif // 0

    default :
      NAAbort("ElemDDLPartition.C", __LINE__, "internal logic error");
      break;
    }
  }

  markAsBound();
  return this;
}
Example #24
0
ExWorkProcRetcode ExCancelTcb::work()
{

  ExMasterStmtGlobals *masterGlobals = 
     getGlobals()->castToExExeStmtGlobals()->castToExMasterStmtGlobals();

  CliGlobals *cliGlobals = masterGlobals->getCliGlobals();

  while ((qparent_.down->isEmpty() == FALSE) && 
         (qparent_.up->isFull() == FALSE))
  {
    ex_queue_entry *pentry_down = qparent_.down->getHeadEntry();
  
    switch (step_)
    {
      case NOT_STARTED:
      {
        if (pentry_down->downState.request == ex_queue::GET_NOMORE)
          step_ = DONE;
        else
        {
          retryCount_ = 0;
          // Priv checking is done during compilation. To support 
          // REVOKE, prevent a prepared CANCEL/SUSPEND/ACTIVATE
          // that was compiled more than 1 second ago from executing 
          // by raising the 8734 error to force an AQR. 
          Int64 microSecondsSinceCompile = NA_JulianTimestamp() - 
              masterGlobals->getStatement()->getCompileEndTime();

          if (microSecondsSinceCompile > 1000*1000)
          {

            ComDiagsArea *diagsArea =
              ComDiagsArea::allocate(getGlobals()->getDefaultHeap());
            *diagsArea << DgSqlCode(-CLI_INVALID_QUERY_PRIVS);
            reportError(diagsArea);
            step_ = DONE;
            break;
          }
          
          // Figure out which MXSSMP broker to use.
          if (cancelTdb().getAction() == ComTdbCancel::CancelByPname)
          {
            int nid = -1;
            int rc = msg_mon_get_process_info(cancelTdb().getCancelPname(),
                                &nid, &pid_);
            switch (rc)
            {
              case XZFIL_ERR_OK:
                cpu_ = (short) nid;
                break;
              case XZFIL_ERR_NOTFOUND:
              case XZFIL_ERR_BADNAME:
              case XZFIL_ERR_NOSUCHDEV:
                {
                  ComDiagsArea *diagsArea =
                    ComDiagsArea::allocate(getGlobals()->getDefaultHeap());

                  *diagsArea << DgSqlCode(-EXE_CANCEL_PROCESS_NOT_FOUND);
                  *diagsArea << DgString0(cancelTdb().getCancelPname());
                  reportError(diagsArea);

                  step_ = DONE;
                  break;
                }
              default:
                {
                  char buf[200];
                  str_sprintf(buf, "Unexpected error %d returned from "
                                   "msg_mon_get_process_info", rc);
                  ex_assert(0, buf);
                }
            }
            if (step_ != NOT_STARTED)
              break;
          }
          else if  (cancelTdb().getAction() == ComTdbCancel::CancelByNidPid)
          {
            cpu_ = (short) cancelTdb().getCancelNid();
            pid_ = cancelTdb().getCancelPid();

            // check that process exists, if not report error.
            char processName[MS_MON_MAX_PROCESS_NAME];
            int rc = msg_mon_get_process_name(cpu_, pid_, processName);
            if (XZFIL_ERR_OK == rc)
              ; // good. nid & pid are valid.
            else
            {
              if ((XZFIL_ERR_NOTFOUND  != rc) &&
                  (XZFIL_ERR_BADNAME   != rc) &&
                  (XZFIL_ERR_NOSUCHDEV != rc))
              {
                // Log rc in case it needs investigation later.
               char buf[200];
               str_sprintf(buf, "Unexpected error %d returned from "
                                "msg_mon_get_process_name", rc);
               SQLMXLoggingArea::logExecRtInfo(__FILE__, __LINE__,
                                               buf, 0);
              }
              char nid_pid_str[32];
              str_sprintf(nid_pid_str, "%d, %d", cpu_, pid_);
              ComDiagsArea *diagsArea =
                    ComDiagsArea::allocate(getGlobals()->getDefaultHeap());

              *diagsArea << DgSqlCode(-EXE_CANCEL_PROCESS_NOT_FOUND);
              *diagsArea << DgString0(nid_pid_str);
              reportError(diagsArea);

              step_ = DONE;
              break;
            }
          }
          else
          {
            char * qid = cancelTdb().qid_;
            Lng32 qid_len = str_len(qid);

            // This static method is defined in SqlStats.cpp.  It side-effects
            // the nodeName and cpu_ according to the input qid.
            if (getMasterCpu(
                  qid, qid_len, nodeName_, sizeof(nodeName_) - 1, cpu_) == -1)
            {
              ComDiagsArea *diagsArea =
                ComDiagsArea::allocate(getGlobals()->getDefaultHeap());

              *diagsArea << DgSqlCode(-EXE_RTS_INVALID_QID);

              reportError(diagsArea);

              step_ = DONE;
              break;
            }
          }

          // Testpoints for hard to reproduce problems:
          bool fakeError8028 = false;
          fakeError8028 = (getenv("HP_FAKE_ERROR_8028") != NULL);
          if ((cliGlobals->getCbServerClass() == NULL) || fakeError8028)
          {
            ComDiagsArea *diagsArea = 
              ComDiagsArea::allocate(getGlobals()->getDefaultHeap());

            *diagsArea << DgSqlCode(-EXE_CANCEL_PROCESS_NOT_FOUND);
            *diagsArea << DgString0("$ZSM000");

            reportError(diagsArea);

            step_ = DONE;
            break;
          }

          ComDiagsArea *diagsArea = NULL;
          bool fakeError2024 = false;
          fakeError2024 = (getenv("HP_FAKE_ERROR_2024") != NULL);
        
          if (fakeError2024)
          {
            cbServer_ = NULL;
            diagsArea =
                  ComDiagsArea::allocate(getGlobals()->getDefaultHeap());
            if (getenv("HP_FAKE_ERROR_8142"))
            {
               *diagsArea << DgSqlCode(-8142);
               *diagsArea << DgString0(__FILE__);
               *diagsArea << DgString1("cbServer_ is NULL");
            }
            else
               *diagsArea << DgSqlCode(-2024);
          }
          else
            cbServer_ = cliGlobals->getCbServerClass()->allocateServerProcess(
                      &diagsArea, 
                      cliGlobals->getEnvironment()->getHeap(),
                      nodeName_,
                      cpu_,
                      IPC_PRIORITY_DONT_CARE,
                      FALSE,  // usesTransactions 
                      TRUE,   // waitedCreation
                      2       // maxNowaitRequests -- cancel+(1 extra).
                      );


          if (cbServer_ == NULL || cbServer_->getControlConnection() == NULL)
          {
            ex_assert(diagsArea != NULL, 
                      "allocateServerProcess failed, but no diags");

            // look for SQLCode 2024 
            // "*** ERROR[2024] Server Process $0~string0 
            // is not running or could not be created. Operating System 
            // Error $1~int0 was returned."
            // Remap to cancel-specfic error 8028.
            if (diagsArea->contains(-2024)  &&
                cancelTdb().actionIsCancel())
            {
              diagsArea->deleteError(diagsArea->returnIndex(-2024));
              reportError(diagsArea, true, EXE_CANCEL_PROCESS_NOT_FOUND, 
                          nodeName_, cpu_);
            }
            else
              reportError(diagsArea);

            step_ = DONE;
            break;
          }

          // the reportError method was not called -- see break above.
          if (diagsArea != NULL)
            diagsArea->decrRefCount();

          //Create the stream on the IpcHeap, since we don't dispose 
          // of it immediately.  We just add it to the list of completed 
          // messages in the IpcEnv, and it is disposed of later.

          cancelStream_  = new (cliGlobals->getIpcHeap())
                CancelMsgStream(cliGlobals->getEnvironment(), this);

          cancelStream_->addRecipient(cbServer_->getControlConnection());

        }

        step_ = SEND_MESSAGE;

        break;
      }  // end case NOT_STARTED

#pragma warning (disable : 4291)

      case SEND_MESSAGE:
      {
        RtsHandle rtsHandle = (RtsHandle) this;

        if (cancelTdb().actionIsCancel())
        {
          Int64 cancelStartTime = JULIANTIMESTAMP();

          Lng32 firstEscalationInterval = cliGlobals->currContext()->
                    getSessionDefaults()->getCancelEscalationInterval();

          Lng32 secondEscalationInterval = cliGlobals->currContext()->
                    getSessionDefaults()->getCancelEscalationMxosrvrInterval();

          NABoolean cancelEscalationSaveabend = cliGlobals->currContext()->
                    getSessionDefaults()->getCancelEscalationSaveabend();

          bool cancelLogging = (TRUE == cliGlobals->currContext()->
                    getSessionDefaults()->getCancelLogging());

          CancelQueryRequest *cancelMsg = new (cliGlobals->getIpcHeap()) 
            CancelQueryRequest(rtsHandle, cliGlobals->getIpcHeap(), 
                      cancelStartTime,
                      firstEscalationInterval,
                      secondEscalationInterval,
                      cancelEscalationSaveabend,
                      cancelTdb().getCommentText(),
                      str_len(cancelTdb().getCommentText()),
                      cancelLogging,
                      cancelTdb().action_ != ComTdbCancel::CancelByQid,
                      pid_,
                      cancelTdb().getCancelPidBlockThreshold());

#pragma warning (default : 4291)

          *cancelStream_ << *cancelMsg;

          cancelMsg->decrRefCount();
        }
        else if (ComTdbCancel::Suspend == cancelTdb().action_)
        {

          bool suspendLogging = (TRUE == cliGlobals->currContext()->
                    getSessionDefaults()->getSuspendLogging());

#pragma warning (disable : 4291)
          SuspendQueryRequest * suspendMsg = new (cliGlobals->getIpcHeap()) 
            SuspendQueryRequest(rtsHandle, cliGlobals->getIpcHeap(),
                                ComTdbCancel::Force ==
                                cancelTdb().forced_,
                                suspendLogging);
#pragma warning (default : 4291)

          *cancelStream_ << *suspendMsg;

          suspendMsg->decrRefCount();
        }
        else
        {
          ex_assert(
            ComTdbCancel::Activate == cancelTdb().action_,
            "invalid action for ExCancelTcb");

          bool suspendLogging = (TRUE == cliGlobals->currContext()->
                    getSessionDefaults()->getSuspendLogging());

#pragma warning (disable : 4291)
          ActivateQueryRequest * activateMsg = new (cliGlobals->getIpcHeap()) 
            ActivateQueryRequest(rtsHandle, cliGlobals->getIpcHeap(),
                                 suspendLogging);
#pragma warning (default : 4291)

          *cancelStream_ << *activateMsg;

          activateMsg->decrRefCount();
        }

        if ((cancelTdb().getAction() != ComTdbCancel::CancelByPname) &&
            (cancelTdb().getAction() != ComTdbCancel::CancelByNidPid))
        {
          char * qid = cancelTdb().qid_;
          Lng32 qid_len = str_len(qid);

#pragma warning (disable : 4291)
          RtsQueryId *rtsQueryId = new (cliGlobals->getIpcHeap())
                           RtsQueryId( cliGlobals->getIpcHeap(), qid, qid_len);
#pragma warning (default : 4291)

          *cancelStream_ << *rtsQueryId;
          rtsQueryId->decrRefCount();
        }

        // send a no-wait request to the cancel broker.
        cancelStream_->send(FALSE);

        step_ = GET_REPLY;    
        // Come back when I/O completes.
        return WORK_OK; 

        break;
      }  // end case SEND_MESSAGE

      case GET_REPLY:
      {

        // Handle general IPC error.
        bool fakeError201 = false;
        fakeError201 = (getenv("HP_FAKE_ERROR_201") != NULL);
        if ((cbServer_->getControlConnection()->getErrorInfo() != 0) ||
            fakeError201)
        {
          ComDiagsArea *diagsArea = 
            ComDiagsArea::allocate(getGlobals()->getDefaultHeap());

          cbServer_->getControlConnection()->
              populateDiagsArea( diagsArea, getGlobals()->getDefaultHeap());

          if (fakeError201)
          {
            *diagsArea << DgSqlCode(-2034) << DgInt0(201)
                       << DgString0("I say") << DgString1("control broker");
          }

          if (diagsArea->contains(-8921))
          {
            // Should not get timeout error 8921. Get a core-file
            // of the SSMP and this process too so that this can be
            // debugged.
            cbServer_->getControlConnection()->
              dumpAndStopOtherEnd(true, false);
            genLinuxCorefile("Unexpected timeout error");
          }

          reportError(diagsArea);

          step_ = DONE;
          break;
        }

        // See if stream has the reply yet.
        if (!cancelStream_->moreObjects())
          return WORK_OK; 

#pragma warning (disable : 4291)

        ControlQueryReply *reply = new (cliGlobals->getIpcHeap()) 
              ControlQueryReply(INVALID_RTS_HANDLE, cliGlobals->getIpcHeap());

#pragma warning (default : 4291)

        *cancelStream_ >> *reply;

        if (reply->didAttemptControl())
        {
          // yeaah!
          cancelStream_->clearAllObjects();
        }
        else
        {
          if (cancelStream_->moreObjects() &&
              cancelStream_->getNextObjType() == IPC_SQL_DIAG_AREA)
          {
            ComDiagsArea *diagsArea = 
              ComDiagsArea::allocate(getGlobals()->getDefaultHeap());

            *cancelStream_ >> *diagsArea;
            cancelStream_->clearAllObjects();

            if ( retryQidNotActive_ &&
                (diagsArea->mainSQLCODE() == -EXE_SUSPEND_QID_NOT_ACTIVE) &&
                (++retryCount_ <= 60))
            {
              SQLMXLoggingArea::logExecRtInfo(__FILE__, __LINE__, 
                                             "Retrying error 8672.", 0);
              DELAY(500);
              diagsArea->decrRefCount();
              step_ = SEND_MESSAGE;
              break;
            }

            reportError(diagsArea);
          }
          else 
            ex_assert(0, "Control failed, but no diagnostics.");
        }

        step_ = DONE;
        break;
      }
      case DONE: 
      {
        if (cancelStream_)
        {
          cancelStream_->addToCompletedList();
          cancelStream_ = NULL;
        }
        if (cbServer_)
        {
          cbServer_->release();
          cbServer_ = NULL;
        }

        ex_queue_entry * up_entry = qparent_.up->getTailEntry();
        up_entry->copyAtp(pentry_down);
        up_entry->upState.parentIndex = pentry_down->downState.parentIndex;
        up_entry->upState.downIndex = qparent_.down->getHeadIndex();     
        up_entry->upState.setMatchNo(1);
        up_entry->upState.status = ex_queue::Q_NO_DATA;
        qparent_.up->insert();

        qparent_.down->removeHead();

        step_ = NOT_STARTED;
        break;
      }
      default:
        ex_assert( 0, "Unknown step_.");
    }
//
// Set private data members corresponding to the SG options
// specified in a file option or load option phrases in a SG
// clause.  This method also looks for duplicate phrases.
//
void
ElemDDLSGOptions::setSGOpt(ElemDDLNode * pSGOpt)
{
  switch(pSGOpt->getOperatorType())
  {
    
 
    case ELM_SG_OPT_START_VALUE_ELEM :
    if (isStartValueSpec_)
    {
      // cout << "*** Error *** Duplicate options in sg option list.
      if (ieType_ == SG_INTERNAL)
        *SqlParser_Diags << DgSqlCode(-3427)
                         << DgString0("START WITH")
		         << DgString1("IDENTITY column");
      else
        *SqlParser_Diags << DgSqlCode(-3427)
                         << DgString0("START WITH")
		         << DgString1("sequence generator");
    }
    isStartValueSpec_ = TRUE;
    startValue_ =
      pSGOpt->castToElemDDLSGOptionStartValue()->getValue();
    break;

    case ELM_SG_OPT_INCREMENT_ELEM :
    if (isIncrementSpec_)
    {
      // cout << "*** Error *** Duplicate options in sg option list.
      if (ieType_ == SG_INTERNAL)
        *SqlParser_Diags << DgSqlCode(-3427)
                         << DgString0("INCREMENT BY")
		         << DgString1("IDENTITY column");
      else
        *SqlParser_Diags << DgSqlCode(-3427)
                         << DgString0("INCREMENT BY")
		         << DgString1("sequence generator");
    }
    isIncrementSpec_ = TRUE;
    increment_ =
      pSGOpt->castToElemDDLSGOptionIncrement()->getValue();
    break;

    case ELM_SG_OPT_MIN_VALUE_ELEM :
    if (isMinValueSpec_)
    {
      // cout << "*** Error *** Duplicate options in sg option list.
      if (ieType_ == SG_INTERNAL)
        *SqlParser_Diags << DgSqlCode(-3427)
                         << DgString0("MINVALUE")
		         << DgString1("IDENTITY column");
      else
        *SqlParser_Diags << DgSqlCode(-3427)
                         << DgString0("MINVALUE")
		         << DgString1("sequence generator");
    }
    isMinValueSpec_ = TRUE;
    minValue_ =
      pSGOpt->castToElemDDLSGOptionMinValue()->getValue();
    isNoMinValue_ =
      pSGOpt->castToElemDDLSGOptionMinValue()->isNoMinValue();
    break;

    case ELM_SG_OPT_MAX_VALUE_ELEM :
    if (isMaxValueSpec_)
    {
      // cout << "*** Error *** Duplicate options in sg option list.
      if (ieType_ == SG_INTERNAL)
        *SqlParser_Diags << DgSqlCode(-3427)
                         << DgString0("MAXVALUE")
		         << DgString1("IDENTITY column");
      else
        *SqlParser_Diags << DgSqlCode(-3427)
                         << DgString0("MAXVALUE")
		         << DgString1("sequence generator");
    }
    isMaxValueSpec_ = TRUE;
    maxValue_ =
      pSGOpt->castToElemDDLSGOptionMaxValue()->getValue();
    isNoMaxValue_ =
      pSGOpt->castToElemDDLSGOptionMaxValue()->isNoMaxValue();
    break;

    case ELM_SG_OPT_CYCLE_OPTION_ELEM :
    if (isCycleSpec_)
    {
      // cout << "*** Error *** Duplicate options in sg option list.
      if (ieType_ == SG_INTERNAL)
        *SqlParser_Diags << DgSqlCode(-3427)
                         << DgString0("CYCLE")
		         << DgString1("IDENTITY column");
      else
        *SqlParser_Diags << DgSqlCode(-3427)
                         << DgString0("CYCLE")
		         << DgString1("sequence generator");
    }
    isCycleSpec_ = TRUE;
    cycle_ =
      pSGOpt->castToElemDDLSGOptionCycleOption()->getValue();
    break;

    case ELM_SG_OPT_CACHE_OPTION_ELEM :
    if (isCacheSpec_)
    {
      // cout << "*** Error *** Duplicate options in sg option list.
      if (ieType_ == SG_INTERNAL)
        *SqlParser_Diags << DgSqlCode(-3427)
                         << DgString0("CACHE")
		         << DgString1("IDENTITY column");
      else
        *SqlParser_Diags << DgSqlCode(-3427)
                         << DgString0("CACHE")
		         << DgString1("sequence generator");
    }
    isCacheSpec_ = TRUE;
    cache_ =
      pSGOpt->castToElemDDLSGOptionCacheOption()->getCacheSize();
    isNoCache_ =
      pSGOpt->castToElemDDLSGOptionCacheOption()->isNoCache();
    break;

    case ELM_SG_OPT_DATATYPE_ELEM :
    if (isDatatypeSpec_)
    {
      // cout << "*** Error *** Duplicate options in sg option list.
      if (ieType_ == SG_INTERNAL)
        *SqlParser_Diags << DgSqlCode(-3427)
                         << DgString0("DATATYPE")
		         << DgString1("IDENTITY column");
      else
        *SqlParser_Diags << DgSqlCode(-3427)
                         << DgString0("DATATYPE")
		         << DgString1("sequence generator");
    }
    isDatatypeSpec_ = TRUE;
    fsDataType_ =
      pSGOpt->castToElemDDLSGOptionDatatype()->getDatatype();
    break;

   case ELM_SG_OPT_RESET_OPTION_ELEM :
    if (isResetSpec_)
    {
      // cout << "*** Error *** Duplicate options in sg option list.
      if (ieType_ == SG_INTERNAL)
        *SqlParser_Diags << DgSqlCode(-3427)
                         << DgString0("RESET")
		         << DgString1("IDENTITY column");
      else
        *SqlParser_Diags << DgSqlCode(-3427)
                         << DgString0("RESET")
		         << DgString1("sequence generator");
    }
    isResetSpec_ = TRUE;
    reset_ = TRUE;
    break;

  default :
    ABORT("internal logic error");
    break;
  }
}  // ElemDDLSGOptions::setSGOpt()
// queryType:  0, create sequence.  1, alter sequence.  2, IDENTITY col.
short ElemDDLSGOptions::validate(short queryType)
{
  char queryTypeStr[40];

  if (queryType == 0)
    strcpy(queryTypeStr, "CREATE SEQUENCE");
  else if (queryType == 1)
    strcpy(queryTypeStr, "ALTER SEQUENCE");
  else
    strcpy(queryTypeStr, "IDENTITY column");

  Int64 minValue = 0;
  Int64 startValue = 0;
  Int64 increment = 0;
  Int64 maxValue = LONG_MAX - 1;

  NAString dtStr;
  if (fsDataType_ != COM_UNKNOWN_FSDT)
    {
      switch (fsDataType_)
        {
        case COM_UNSIGNED_BIN16_FSDT:
          maxValue = USHRT_MAX;
          dtStr = COM_SMALLINT_UNSIGNED_SDT_LIT;
          break;
        case COM_UNSIGNED_BIN32_FSDT:
          maxValue = UINT_MAX;
          dtStr = COM_INTEGER_UNSIGNED_SDT_LIT;
          break;
        case COM_SIGNED_BIN64_FSDT:
          maxValue = LONG_MAX - 1;
          dtStr =  COM_LARGEINT_SIGNED_SDT_LIT;
          break;
        default:
          *CmpCommon::diags() << DgSqlCode(-1510);
          return -1;
        }
    }

  if (queryType == 1) // alter
    {
      if ((isMinValueSpecified()|| isStartValueSpecified()))
        {
          *CmpCommon::diags() << DgSqlCode(-1592)
                              << (isMinValueSpecified() ? DgString0("MINVALUE") : DgString0("START WITH"))
                              << DgString1(queryTypeStr);
          
          return -1;
        }
      
      minValue = getMinValue();
      startValue = getStartValue();
      increment = getIncrement();

      if (isMaxValueSpecified() && (NOT isNoMaxValue()))
        {
          if ((fsDataType_ != COM_UNKNOWN_FSDT) &&
              (getMaxValue() > maxValue))
            {
              *CmpCommon::diags() << DgSqlCode(-1576)
                                  << DgString0("MAXVALUE")
                                  << DgString1(dtStr);
              
              return -1;
            }
        }

      maxValue = getMaxValue();
    } // alter
  else
    {
      if (isResetSpecified())
        {
          *CmpCommon::diags() << DgSqlCode(-1592)
                              << DgString0("RESET") 
                              << DgString1(queryTypeStr);
          
          return -1;
        }
 
      minValue = ((isMinValueSpecified() && (NOT isNoMinValue())) ? 
                  getMinValue() : 1LL); 
      startValue = (isStartValueSpecified() ? getStartValue() : minValue);
      increment = (isIncrementSpecified() ? getIncrement() : 1LL);
    } //else

  if (isMaxValueSpecified() && (NOT isNoMaxValue()))
    {
      if ((fsDataType_ != COM_UNKNOWN_FSDT) &&
          (getMaxValue() > maxValue))
        {
          *CmpCommon::diags() << DgSqlCode(-1576)
                              << DgString0("MAXVALUE")
                              << DgString1(dtStr);
          
          return -1;
        }

      maxValue = getMaxValue();
    }

  if (minValue == 0)
    {
      *CmpCommon::diags() << DgSqlCode(-1571)
			  << DgString0("MINVALUE")
			  << DgString1(queryTypeStr);
      
      return -1;
    }

  if (minValue < 0)
    {
      *CmpCommon::diags() << DgSqlCode(-1572)
			  << DgString0("MINVALUE")
			  << DgString1(queryTypeStr);
      
      return -1;
    }

  if (maxValue == 0)
    {
      *CmpCommon::diags() << DgSqlCode(-1571)
			  << DgString0("MAXVALUE")
			  << DgString1(queryTypeStr);
      
      return -1;
    }

  if (maxValue < 0)
    {
      *CmpCommon::diags() << DgSqlCode(-1572)
			  << DgString0("MAXVALUE")
			  << DgString1(queryTypeStr);
      
      return -1;
    }

  if (increment == 0)
    {
      *CmpCommon::diags() << DgSqlCode(-1571)
			  << DgString0("INCREMENT BY")
			  << DgString1(queryTypeStr);
      
      return -1;
    }

  if (increment < 0)
    {
      *CmpCommon::diags() << DgSqlCode(-1572)
			  << DgString0("INCREMENT BY")
			  << DgString1(queryTypeStr);  
      return -1;
    }

  if (startValue < 0)
    {
      *CmpCommon::diags() << DgSqlCode(-1572)
			  << DgString0("START WITH")
			  << DgString1(queryTypeStr);
      
      return -1;
    }

  if (maxValue <= minValue)
    {
      *CmpCommon::diags() << DgSqlCode(-1570)
			  << DgString0(queryTypeStr);      
      return -1;
    }

  if (startValue > maxValue)
    {
      *CmpCommon::diags() << DgSqlCode(-1573)
			  << DgString0(queryTypeStr);      
      return -1;
    }

  if (startValue < minValue)
    {
      *CmpCommon::diags() << DgSqlCode(-1573)
			  << DgString0(queryTypeStr);      
      return -1;
    }

  if (increment > (maxValue - minValue))
    {
      *CmpCommon::diags() << DgSqlCode(-1575)
			  << DgString0(queryTypeStr);      
      return -1;
    }

  Int64 cache = 0;
  Int64 minVal = MAXOF(startValue, minValue);
  Int64 rangeOfVals = (maxValue-minVal)/increment + 1;

  if (isCacheSpecified())
    cache = getCache();
  else
    cache = MINOF(rangeOfVals, 25);

  if (NOT isNoCache())
    {
      if ((cache <= 1) ||
	  (cache > rangeOfVals))
	{
	  *CmpCommon::diags() << DgSqlCode(-1577)
			      << DgString0(queryTypeStr);	  
	  return -1;
	}
    }
  
  cache = MINOF(rangeOfVals, cache);

  setStartValue(startValue);
  setIncrement(increment);
  setMinValue(minValue);
  setMaxValue(maxValue);
  if (NOT isCacheSpecified())
    setCache(cache);

  return 0;
}
void
ParDDLLikeOptsCreateTable::setLikeOption(ElemDDLLikeOpt * pLikeOption)
{
  ComASSERT(pLikeOption != NULL);
  
  switch (pLikeOption->getOperatorType())
  {
  case ELM_LIKE_OPT_WITHOUT_CONSTRAINTS_ELEM :
    if (isLikeOptWithoutConstraintsSpec_)
    {
      *SqlParser_Diags << DgSqlCode(-3149);

      //  "*** Error *** Duplicate WITHOUT CONSTRAINTS phrases "
      //  << "in LIKE clause" << endl;
    }
    ComASSERT(pLikeOption->castToElemDDLLikeOptWithoutConstraints() != NULL);
    isLikeOptWithoutConstraints_ = TRUE;
    isLikeOptWithoutConstraintsSpec_ = TRUE;
    break;

  case ELM_LIKE_OPT_WITH_HEADINGS_ELEM :
    if (isLikeOptWithHeadingsSpec_)
    {
      *SqlParser_Diags << DgSqlCode(-3150);
      //      cout << "*** Error *** Duplicate WITH HEADING phrases "
      //  << "in LIKE clause" << endl;
    }
    ComASSERT(pLikeOption->castToElemDDLLikeOptWithHeadings() != NULL);
    isLikeOptWithHeadings_ = TRUE;
    isLikeOptWithHeadingsSpec_ = TRUE;
    break;

  case ELM_LIKE_OPT_WITH_HORIZONTAL_PARTITIONS_ELEM :
    if (isLikeOptWithHorizontalPartitionsSpec_)
    {
      *SqlParser_Diags << DgSqlCode(-3151);
      //cout << "*** Error *** Duplicate WITH HORIZONTAL PARTITIONS phrases "
      //  << "in LIKE clause" << endl;
    }
    ComASSERT(pLikeOption->castToElemDDLLikeOptWithHorizontalPartitions() != NULL);
    isLikeOptWithHorizontalPartitions_ = TRUE;
    isLikeOptWithHorizontalPartitionsSpec_ = TRUE;
    break;

  case ELM_LIKE_OPT_WITHOUT_SALT_ELEM :
    if (isLikeOptWithoutSaltSpec_)
    {
      // ERROR[3152] Duplicate WITHOUT SALT phrases were specified
      //             in LIKE clause in CREATE TABLE statement.
      *SqlParser_Diags << DgSqlCode(-3152) << DgString0("SALT");
    }
    if (isLikeOptSaltClauseSpec_)
    {
      // ERROR[3154] The WITHOUT SALT clause is not allowed with the SALT clause.
      *SqlParser_Diags << DgSqlCode(-3154) << DgString0("WITHOUT SALT") << DgString1("SALT");
    }
    ComASSERT(pLikeOption->castToElemDDLLikeOptWithoutSalt() != NULL);
    isLikeOptWithoutSalt_ = TRUE;
    isLikeOptWithoutSaltSpec_ = TRUE;
    break;

  case ELM_LIKE_OPT_SALT_CLAUSE_ELEM:
    {  // braces needed since we declare some variables in this case
      if (isLikeOptSaltClauseSpec_)
      {
        // ERROR[3183] Duplicate SALT clauses were specified.
        *SqlParser_Diags << DgSqlCode(-3183) << DgString0("SALT");
      }
      if (isLikeOptWithoutSaltSpec_)
      {
        // ERROR[3154] The WITHOUT SALT clause is not allowed with the SALT clause.
        *SqlParser_Diags << DgSqlCode(-3154) << DgString0("WITHOUT SALT") << DgString1("SALT");
      }
      ComASSERT(pLikeOption->castToElemDDLLikeSaltClause() != NULL);
      isLikeOptSaltClauseSpec_ = TRUE;
      isLikeOptSaltClause_ = new (PARSERHEAP()) NAString();
      ElemDDLLikeSaltClause * saltClauseWrapper = pLikeOption->castToElemDDLLikeSaltClause();
      const ElemDDLSaltOptionsClause * saltOptions = saltClauseWrapper->getSaltClause();
      saltOptions->unparseIt(*isLikeOptSaltClause_ /* side-effected */);
      isLikeOptWithoutSalt_ = TRUE;  // suppresses any SALT clause from the source table
    }
    break;

  case ELM_LIKE_OPT_WITHOUT_DIVISION_ELEM :
    if (isLikeOptWithoutDivisionSpec_)
    {
      // ERROR[3152] Duplicate WITHOUT DIVISION phrases were specified
      //             in LIKE clause in CREATE TABLE statement.
      *SqlParser_Diags << DgSqlCode(-3152) << DgString0("DIVISION");
    }
    ComASSERT(pLikeOption->castToElemDDLLikeOptWithoutDivision() != NULL);
    isLikeOptWithoutDivision_ = TRUE;
    isLikeOptWithoutDivisionSpec_ = TRUE;
    break;

  case ELM_LIKE_OPT_LIMIT_COLUMN_LENGTH:
    {
      if (isLikeOptLimitColumnLengthSpec_)
      {
        // ERROR[3152] Duplicate LIMIT COLUMN LENGTH phrases were specified
        //             in LIKE clause in CREATE TABLE statement.
        *SqlParser_Diags << DgSqlCode(-3152) << DgString0("LIMIT COLUMN LENGTH");
      }
      ComASSERT(pLikeOption->castToElemDDLLikeLimitColumnLength() != NULL);
      ElemDDLLikeLimitColumnLength * limitColumnLength = 
        pLikeOption->castToElemDDLLikeLimitColumnLength();
      isLikeOptColumnLengthLimit_ = limitColumnLength->getColumnLengthLimit();
      isLikeOptLimitColumnLengthSpec_ = TRUE;
    }
    break;

  case ELM_LIKE_OPT_WITHOUT_ROW_FORMAT_ELEM :
    if (isLikeOptWithoutRowFormatSpec_)
    {
      // ERROR[3152] Duplicate WITHOUT ROW FORMAT phrases were specified
      //             in LIKE clause in CREATE TABLE statement.
      *SqlParser_Diags << DgSqlCode(-3152) << DgString0("ROW FORMAT");
    }
    ComASSERT(pLikeOption->castToElemDDLLikeOptWithoutRowFormat() != NULL);
    isLikeOptWithoutRowFormat_ = TRUE;
    isLikeOptWithoutRowFormatSpec_ = TRUE;
    break;

  default :
    NAAbort("ParDDLLikeOpts.C", __LINE__, "internal logic error");
    break;
  }
} // ParDDLLikeOptsCreateTable::setLikeOption()
void EspNewIncomingConnectionStream::actOnReceive(IpcConnection *connection)
{
  // check for OS errors
  if (getState() == ERROR_STATE)
  {
    ex_assert(FALSE,"Error while receiving first message from client");
  }

  // check for protocol errors
  bool willPassTheAssertion = 
             (getType() == IPC_MSG_SQLESP_DATA_REQUEST OR
              getType() == IPC_MSG_SQLESP_CANCEL_REQUEST) AND
              getVersion() == CurrEspRequestMessageVersion AND
              moreObjects();
  if (!willPassTheAssertion)
  {
    char *doCatchBugCRx = getenv("ESP_BUGCATCHER_CR_NONUMBER");
    if (!doCatchBugCRx ||
        *doCatchBugCRx != '0')
    {
      connection->dumpAndStopOtherEnd(true, false);
      environment_->getControlConnection()->
        castToGuaReceiveControlConnection()->
        getConnection()->dumpAndStopOtherEnd(true, false);
    }
  }

  ex_assert((getType() == IPC_MSG_SQLESP_DATA_REQUEST OR
             getType() == IPC_MSG_SQLESP_CANCEL_REQUEST) AND
	    getVersion() == CurrEspRequestMessageVersion AND
	    moreObjects(),
	    "Invalid first message from client");

  // take a look at the type of the first object in the message
  IpcMessageObjType nextObjType = getNextObjType();
  switch (nextObjType)
  {
    case ESP_OPEN_HDR:
    case ESP_LATE_CANCEL_HDR:
      {
        ExFragKey key;
        Lng32 remoteInstNum;
        NABoolean isParallelExtract = false; 

        // peek at the message header to see for whom it is
        if (nextObjType == ESP_OPEN_HDR)
        {
          ExEspOpenReqHeader reqHdr((NAMemory *) NULL);
	   
	  *this >> reqHdr;
	  key = reqHdr.key_;
	  remoteInstNum = reqHdr.myInstanceNum_;
	  if (reqHdr.getOpenType() == ExEspOpenReqHeader::PARALLEL_EXTRACT) 
          {
            isParallelExtract = true;
	  }
	}
        else
	{
          // note that the late cancel request may or may not
	  // arrive as the first request (only in the former case
	  // will we reach here)
	  ExEspLateCancelReqHeader reqHdr((NAMemory *) NULL);
	   
	  *this >> reqHdr;
	  key = reqHdr.key_;
	  remoteInstNum = reqHdr.myInstanceNum_;
	}

        if (!isParallelExtract) 
        {
          ExFragInstanceHandle handle =
	    espFragInstanceDir_->findHandle(key);

	  if (handle != NullFragInstanceHandle)
	  {
            // the send bottom node # myInstanceNum of this downloaded fragment
            // is the true recipient of this open request
            ex_split_bottom_tcb * receivingTcb =
              espFragInstanceDir_->getTopTcb(handle);
            ex_send_bottom_tcb *receivingSendTcb =
              receivingTcb->getSendNode(remoteInstNum);

            // Check the connection for a co-located client, and if so,
            // tell the split bottom, because it may prefer this send 
            // bottom when using skew buster uniform distribution.
            if (espFragInstanceDir_->
                  getEnvironment()->
                  getMyOwnProcessId(IPC_DOM_GUA_PHANDLE).match(
                    connection->getOtherEnd().getNodeName(),
                    connection->getOtherEnd().getCpuNum()))
              receivingTcb->setLocalSendBottom(remoteInstNum);

            // Portability note for the code above: we pass IPC_DOM_GUA_PHANDLE
            // for IpcEnvironment::getMyOwnProcessId, even though that method
            // can be called with the default param (IpcNetworkDomain 
            // IPC_DOM_INVALID).  In fact it would  probably be better 
            // to call the object without specifying the IpcNetworkDomain so
            // that it can decide for itself what domain it is using.
            // But there is a problem with the Windows implementation
            // of IpcEnvironment::getMyOwnProcessId, it seems to assume
            // that its domain is IPC_DOM_INTERNET and so this will 
            // cause the botch of an assertion that its control connection 
            // (which is type EspGuaControlConnection) can be cast to a 
            // SockControlConnection.  When this problem is fixed, the 
            // IPC_DOM_GUA_PHANDLE param above can be removed.  Also,
            // when this code is ported to run it a domain other than
            // "guardian", it will be necessary to fix this and to
            // fix IpcEnvironment::getMyOwnProcessId to work properly on
            // windows.

            receivingSendTcb->setClient(connection);
            receivingSendTcb->routeMsg(*this);
          }
	  else
	  {
            connection->dumpAndStopOtherEnd(true, false);
	    ex_assert(FALSE,"entry not found, set diagnostics area and reply");
	  }

        } // normal case, not parallel extract

        else 
        {
          // The OPEN request is from a parallel extract consumer. The
          // incoming request contains a user ID which we will compare
          // against the current user ID for this ESP.

          // NOTE: The user ID for the extract security check is
          // currently sent and compared as a C string. On Linux it is
          // possible to send and compare integers which would lead to
          // simpler code. The code to send/compare strings is still
          // used because it works on all platforms.

          char errorStr[150];

	  // check if next msg is of securityInfo type. 
          ex_assert(moreObjects(), "expected object not received");
          ex_assert(getNextObjType() == ESP_SECURITY_INFO,
	            "received message for unknown message type");
          
	  // unpack security info
	  ExMsgSecurityInfo secInfo(environment_->getHeap());
	  *this >> secInfo;

          // Get the auth ID of this ESP in text form and compare it
          // to the auth ID that arrived in the message. Skip this
          // step in the debug build if an environment variable is
          // set.
          NABoolean doAuthIdCheck = TRUE;
          Int32 status = 0;
#ifdef _DEBUG
          const char *envvar = getenv("NO_EXTRACT_AUTHID_CHECK");
          if (envvar && envvar[0])
            doAuthIdCheck = FALSE;
#endif
          if (doAuthIdCheck)
          {
            // Get user ID from ExMsgSecurityInfo -> (secUserID)
            // the user ID is the integer value made into a string
            // Convert it back into its integer value
            short userIDLen = (short) str_len(secInfo.getAuthID());
            Int32 secUserID = str_atoi(secInfo.getAuthID(), userIDLen);

            // Get the current user ID
            Int32 curUserID = ComUser::getSessionUser(); 

            // Report an error if the user ID is not valid
            if (curUserID == NA_UserIdDefault || secUserID == NA_UserIdDefault)
            {
              str_cpy_c(errorStr,
                        "Producer ESP could not authenticate the consumer, "
                        "no valid current user.");
              status = -1;
            }

            // Make sure user id passed in ExMsgSecurityInfo matches
            // the user id associated with the current session

#if defined(_DEBUG)
            NABoolean doDebug = (getenv("DBUSER_DEBUG") ? TRUE : FALSE);
            if (doDebug)
              printf("[DBUSER:%d] ESP extract user ID: "
                     "local [%d], msg [%d]\n",
                     (int) getpid(), curUserID, secUserID);
#endif

              // Compare user ID, Report an error, if comparison fails
              if (curUserID != secUserID)
              {
                str_cpy_c(errorStr,
                          "Producer ESP could not authenticate the consumer, "
                          "user named passed in ExMsgSecurityInfo is not the "
                          "current user");
                status = -1;
              }

          } // if (doAuthIdCheck)
		   
          // get the split bottom TCB that matches the securityKey
          ex_split_bottom_tcb *receivingTcb = NULL;
          if (status == 0) 
          {
            receivingTcb = espFragInstanceDir_->getExtractTop(secInfo.getSecurityKey());
            if (receivingTcb == NULL) 
            {
              str_cpy_c(errorStr, "Producer ESP could not locate extract node");
              status = -1;
            }
          }

	  // get the sendBottom TCB if not already connected to a client
	  ex_send_bottom_tcb *receivingSendTcb = NULL;
	  if (status == 0)
	  {
	    receivingSendTcb = receivingTcb->getConsumerSendBottom();
	    if (receivingSendTcb == NULL) 
	    {
	      str_cpy_c(errorStr, "Producer ESP already connected to a client");
	      status = -1;
	    }
	  }

          // send the error message to the consumer 
	  if (status != 0) 
	  {
            clearAllObjects();
            setType(IPC_MSG_SQLESP_DATA_REPLY);

            NAMemory *heap = environment_->getHeap();

	    IpcMessageObj* baseObj =
	      new(heap)IpcMessageObj(IPC_SQL_DIAG_AREA, CurrEspReplyMessageVersion);
	    *this << *baseObj;

	    // prepare proper error message
	    char phandle[100];
	    MyGuaProcessHandle myHandle;
            myHandle.toAscii(phandle, 100);

	    ComDiagsArea *diags = ComDiagsArea::allocate(heap);
            *diags << DgSqlCode(-EXE_PARALLEL_EXTRACT_OPEN_ERROR)
                   << DgString0(phandle)
                   << DgString1(errorStr);
	    *this  << *diags;

	    diags->decrRefCount();

            send(TRUE /* TRUE indicates waited */);
          }

          // if everything okay, then make the connection
	  if (status == 0) 
          {
            receivingSendTcb->setClient(connection);
            receivingSendTcb->routeMsg(*this);
          }
        } // parallel extract case
      } // open or cancel header
LmResult LmRoutineCSql::invokeRoutine(void *inputRow,
				      void *outputRow,
                                      ComDiagsArea *da)
{
  ComUInt32 argc = numSqlParam_;
  ComUInt32 i = 0;
  short *udrInd = (short *) ind_.getBuffer();

  // Code handles UDF functions with upto 32 parameters.
  LM_ASSERT1(argc <= 32, "Parameters more than 32 are not allowed.");

  // 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;

  ComUInt32 numIn = 0;
  ComUInt32 numOut = 0;

  // Build the argument vector
  if (callType_ != SQLUDR_CALLTYPE_FINAL)
  {
    for (i = 0; i < argc; i++)
    {
      LmParameter &p = lmParams_[i];
      LM_ASSERT1(p.direction() != COM_INOUT_COLUMN,
	         "INOUT parameters are not supported for C routines");

      if (p.isIn())
      {
        numIn++;

        // Set the input null indicator
	NABoolean nullVal = p.isNullInput((char *) inputRow);
        udrInd[i] = (nullVal ? SQLUDR_NULL : SQLUDR_NOTNULL);

        // Make a copy of the input value
        if (! nullVal)
        {
          char *inData = ((char *) inputRow) + p.inDataOffset();
          char *inCopy = data_[i];
          ComUInt32 inBytes = p.inSize();

          switch (p.fsType())
          {
            case COM_FCHAR_FSDT:
            {
              // CHAR(N) CHARACTER SET ISO88591
              memcpy(inCopy, inData, inBytes);
              inCopy[inBytes] = 0;
            }
            break;
            
            case COM_FCHAR_DBL_FSDT:
            {
              // CHAR(N) CHARACTER SET UCS2
              memcpy(inCopy, inData, inBytes);
              inCopy[inBytes] = 0;
              inCopy[inBytes + 1] = 0;
            }
            break;

            case COM_VCHAR_FSDT:
            case COM_VCHAR_DBL_FSDT:
            {
              // VARCHAR(N) CHARACTER SET ISO88591
              // VARCHAR(N) CHARACTER SET UCS2
              SQLUDR_VC_STRUCT *vc = (SQLUDR_VC_STRUCT *) inCopy;
	      ComUInt32 inDataLen = p.actualInDataSize(inputRow);
	      memcpy(&(vc->length), &inDataLen, 4);
              memcpy(vc->data, inData, inDataLen);
            }
            break;

            case COM_SIGNED_BIN16_FSDT:
            case COM_UNSIGNED_BIN16_FSDT:
            {
              // SMALLINT [UNSIGNED]
              // NUMERIC 0 <= precision <= 4
              memcpy(inCopy, inData, 2);
            }
            break;

            case COM_SIGNED_BIN32_FSDT:
            case COM_UNSIGNED_BIN32_FSDT:
            case COM_FLOAT32_FSDT:
            {
              // INTEGER [UNSIGNED]
              // REAL
              // NUMERIC 5 <= precision <= 9
              memcpy(inCopy, inData, 4);
            }
            break;

            case COM_SIGNED_BIN64_FSDT:
            case COM_FLOAT64_FSDT:
            {
              // LARGEINT
              // FLOAT
              // DOUBLE PRECISION
              // NUMERIC 10 <= precision <= 18
              memcpy(inCopy, inData, 8);
            }
            break;

            case COM_SIGNED_DECIMAL_FSDT:
            case COM_UNSIGNED_DECIMAL_FSDT:
            case COM_DATETIME_FSDT:
            case COM_SIGNED_NUM_BIG_FSDT:
            case COM_UNSIGNED_NUM_BIG_FSDT:
	    {
              // DECIMAL [UNSIGNED]
	      // DATE, TIME, TIMESTAMP
              // NUMERIC precision > 18
	      memcpy(inCopy, inData, inBytes);
	      inCopy[inBytes] = '\0';
	    }
	    break;

            default:
            {
              char msg[256];
              sprintf(msg, "Unknown parameter type: %d", p.fsType());
              LM_ASSERT1(0, msg);
            }
            break;
            
          } // switch (p.fsType())
        } // if not null
      } // if (isInput)

      else
      {
        numOut++;

        // Set the output null indicator
        udrInd[i] = SQLUDR_NOTNULL;

        // Initialize the output buffer
        char *outData = (char *)outputRow +  p.outDataOffset();
        char *outCopy = data_[i];
        ComUInt32 outBytes = p.outSize();
        
        switch (p.fsType())
        {
          case COM_FCHAR_FSDT:
          {
            // CHAR(N) CHARACTER SET ISO88591
            memset(outCopy, ' ', outBytes);
            outCopy[outBytes] = 0;
          }
          break;

          case COM_FCHAR_DBL_FSDT:
          {
            // CHAR(N) CHARACTER SET UCS2
            NAWchar *wOutCopy = (NAWchar *) outCopy;
            ComUInt32 outChars = outBytes / sizeof(NAWchar);
            wc_str_pad(wOutCopy, outChars); // pads with space by default
            wOutCopy[outChars] = 0;
          }
          break;

          case COM_VCHAR_FSDT:
          case COM_VCHAR_DBL_FSDT:
          {
            // VARCHAR(N) CHARACTER SET ISO88591
            // VARCHAR(N) CHARACTER SET UCS2
            SQLUDR_VC_STRUCT *vc = (SQLUDR_VC_STRUCT *) outCopy;
            vc->length = outBytes;
            memset(vc->data, 0, outBytes);
          }
          break;

          case COM_SIGNED_BIN16_FSDT:
          case COM_UNSIGNED_BIN16_FSDT:
          {
            // SMALLINT [UNSIGNED]
            // NUMERIC 0 <= precision <= 4
            memset(outCopy, 0, 2);
          }
          break;
          
          case COM_SIGNED_BIN32_FSDT:
          case COM_UNSIGNED_BIN32_FSDT:
          case COM_FLOAT32_FSDT:
          {
            // INTEGER [UNSIGNED]
            // REAL
            // NUMERIC 5 <= precision <= 9
            memset(outCopy, 0, 4);
          }
          break;
          
          case COM_SIGNED_BIN64_FSDT:
          case COM_FLOAT64_FSDT:
          {
            // LARGEINT
            // FLOAT
            // DOUBLE PRECISION
            // NUMERIC 10 <= precision <= 18
            memset(outCopy, 0, 8);
          }
          break;

          case COM_SIGNED_DECIMAL_FSDT:
          case COM_UNSIGNED_DECIMAL_FSDT:
	  case COM_DATETIME_FSDT:
          case COM_SIGNED_NUM_BIG_FSDT:
          case COM_UNSIGNED_NUM_BIG_FSDT:
	  {
            // DECIMAL [UNSIGNED]
	    // DATE, TIME, TIMESTAMP
            // NUMERIC precision > 18
	    memset(outCopy, ' ', outBytes);
            outCopy[outBytes] = 0;
	  }
	  break;

          default:
          {
            char msg[256];
            sprintf(msg, "Unknown parameter type value: %d", p.fsType());
            LM_ASSERT1(0, msg);
          }
          break;
          
        } // switch (p.fsType())
      } // if (isInput) else ...
    } // for each parameter
  } // if this is not a FINAL call
  
  else
  {
    // This is a FINAL call. Set all null indicators to SQLUDR_NULL
    // and zero out data buffers.
    for (i = 0; i < argc; i++)
    {
      udrInd[i] = SQLUDR_NULL;
      LmCBuffer &cBuf = cBuf_[i];
      cBuf.set(0);
    }
  }

  // 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');

  // Now we can call the routine body...
  ComSInt32 rc = SQLUDR_INVOKE(routine_, argc, data_, udrInd,
                               sqlState_, msgText_, callType_,
                               stateArea_, udrInfo_);
  
  // Set the call type for the next invocation to NORMAL if this is
  // an INITIAL call
  if (callType_ == SQLUDR_CALLTYPE_INITIAL)
  {
    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;
  }

  LmResult lmResult = LM_OK;

  if (rc != SQLUDR_ERROR)
  {
    // Copy data and null indicator to caller's output buffers
    for (i = numIn; i < argc && lmResult == LM_OK; i++)
    {
      LmParameter &p = lmParams_[i];
      NABoolean isOutput = (p.direction() == COM_OUTPUT_COLUMN ? TRUE : FALSE);
      if (isOutput)
      {
        // Look at the returned null indicator. Raise an error if the
        // routine returned an invalid null indicator.
        NABoolean isNull = TRUE;
        switch(udrInd[i])
        {
          case SQLUDR_NOTNULL:
            isNull = FALSE;
            break;

          case SQLUDR_NULL:
            break;

          default:
          {
            *da << DgSqlCode(-LME_UDF_INVALID_DATA)
                << DgString0(getNameForDiags())
                << DgInt0((Lng32) i + 1)
                << DgString1("Invalid null indicator");
            lmResult = LM_ERR;
          }
          break;
        }

        // Write the null indicator into the output row
        if (lmResult == LM_OK)
          p.setNullOutput((char *) outputRow, isNull);

	// If value is not NULL, set data.
        if (lmResult == LM_OK && !isNull)
        {
          char *outData = ((char *)outputRow) + p.outDataOffset();
          char *outCopy = data_[i];
          ComUInt32 outBytes = p.outSize();

          switch (p.fsType())
          {
            case COM_FCHAR_FSDT:
            case COM_FCHAR_DBL_FSDT:
            {
              // CHAR(N) CHARACTER SET ISO88591
              // CHAR(N) CHARACTER SET UCS2
              p.setOutChar(outputRow, outCopy, outBytes);
            }
            break;

            case COM_VCHAR_FSDT:
            case COM_VCHAR_DBL_FSDT:
            {
              // VARCHAR(N) CHARACTER SET ISO88591
              // VARCHAR(N) CHARACTER SET UCS2
              SQLUDR_VC_STRUCT *vc = (SQLUDR_VC_STRUCT *) outCopy;
              if (vc->length > outBytes)
              {
                char msg[100];
                sprintf(msg, "VARCHAR length should not exceed %d",
                        outBytes);
                *da << DgSqlCode(-LME_UDF_INVALID_DATA)
                    << DgString0(getNameForDiags())
                    << DgInt0((Lng32) i + 1)
                    << DgString1(msg);
                lmResult = LM_ERR;
              }
              else
              {
                p.setOutChar(outputRow, vc->data, vc->length);
              }
            }
            break;

            case COM_SIGNED_BIN16_FSDT:
            case COM_UNSIGNED_BIN16_FSDT:
            {
              // SMALLINT [UNSIGNED]
              // NUMERIC 0 <= precision <= 4
              memcpy(outData, outCopy, 2);
            }
            break;

            case COM_SIGNED_BIN32_FSDT:
            case COM_UNSIGNED_BIN32_FSDT:
            case COM_FLOAT32_FSDT:
            {
              // INTEGER [UNSIGNED]
              // REAL
              // NUMERIC 5 <= precision <= 9
              memcpy(outData, outCopy, 4);
            }
            break;

            case COM_SIGNED_BIN64_FSDT:
            case COM_FLOAT64_FSDT:
            {
              // LARGEINT
              // FLOAT
              // DOUBLE PRECISION
              // NUMERIC 10 <= precision <= 18
              memcpy(outData, outCopy, 8);
            }
            break;

            case COM_SIGNED_DECIMAL_FSDT:
            case COM_UNSIGNED_DECIMAL_FSDT:
	    case COM_DATETIME_FSDT:
            case COM_SIGNED_NUM_BIG_FSDT:
            case COM_UNSIGNED_NUM_BIG_FSDT:
            {
	      // DECIMAL [UNSIGNED]
	      // DATE, TIME, TIMESTAMP
              // NUMERIC precision > 18
	      p.setOutChar(outputRow, outCopy, outBytes);
	    }
	    break;

            default:
            {
              char msg[256];
              sprintf(msg, "Unknown parameter type value: %d", p.fsType());
              LM_ASSERT1(0, msg);
            }
            break;
            
          } // switch (p.fsType())
        } // if (lmResult == LM_OK && !isNull)
      } // if (isOutput)
    } // for each LmParameter
  } // if (rc != SQLUDR_ERROR)
  
  if (lmResult == LM_OK && rc != SQLUDR_SUCCESS)
  {
    sqlState_[SQLUDR_SQLSTATE_SIZE - 1] = 0;
    lmResult = processReturnStatus(rc, da);
  }

  return lmResult;

} // LmRoutineCSql::invokeRoutine
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;
}