text: /**********************************************************************
  // @@@ START COPYRIGHT @@@
  //
  // Licensed to the Apache Software Foundation (ASF) under one
  // or more contributor license agreements.  See the NOTICE file
  // distributed with this work for additional information
  // regarding copyright ownership.  The ASF licenses this file
  // to you under the Apache License, Version 2.0 (the
  // "License"); you may not use this file except in compliance
  // with the License.  You may obtain a copy of the License at
  //
  //   http://www.apache.org/licenses/LICENSE-2.0
  //
  // Unless required by applicable law or agreed to in writing,
  // software distributed under the License is distributed on an
  // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  // KIND, either express or implied.  See the License for the
  // specific language governing permissions and limitations
  // under the License.
  //
  // @@@ END COPYRIGHT @@@
  //
  **********************************************************************/
  /* -*-C++-*-
   *****************************************************************************
   *
   * File:         Param.C
   * RCS:          $Id: Param.cpp,v 1.8 1998/08/10 15:34:04  Exp $
   * Description:  
   *
   * Created:      4/15/95
   * Modified:     $ $Date: 1998/08/10 15:34:04 $ (GMT)
   * Language:     C++
   * Status:       $State: Exp $
   *
   *
   *
   *
   *****************************************************************************
   */
  
  #include <stdlib.h>
  #include <wchar.h>
  
  #include "SqlciCmd.h"
  #include "str.h"
  #include "dfs2rec.h"
  #include "exp_clause_derived.h"
  #include "IntervalType.h"
  #include "NLSConversion.h"
  #include "nawstring.h"
  
  short convDoItMxcs(char * source,
  		   Lng32 sourceLen,
  		   short sourceType,
  		   Lng32 sourcePrecision,
  		   Lng32 sourceScale,
  		   char * target,
  		   Lng32 targetLen,
  		   short targetType,
  		   Lng32 targetPrecision,
  		   Lng32 targetScale,
  		   Lng32 flags);
  
  Param::Param(char * name_, SetParam *sp_)
  : name(0),
    value(0),
    display_value(0),
    converted_value(0),
    nullValue_(0),
    inSingleByteForm_(TRUE),
    cs(CharInfo::UnknownCharSet),
    isQuotedStrWithoutCharSetPrefix_(FALSE),
    utf16StrLit_(NULL),
    termCS_(CharInfo::UnknownCharSet)
  {
    if (name_)
      setName(name_);
    if (sp_)
      setValue(sp_);
  }
  
  Param::Param(char * name_, char* value_, CharInfo::CharSet x_)
  : name(0),
    value(0),
    display_value(0),
    converted_value(0),
    nullValue_(0),
    inSingleByteForm_(TRUE),
    cs(CharInfo::UnknownCharSet),
    isQuotedStrWithoutCharSetPrefix_(FALSE),
    utf16StrLit_(NULL),
    termCS_(CharInfo::UnknownCharSet)
  {
    if (name_)
      setName(name_);
    if (value_)
      setValue(value_, x_);
  }
  
  Param::Param(char * name_, NAWchar* value_, CharInfo::CharSet x_)
  : name(0),
    value(0),
    display_value(0),
    converted_value(0),
    nullValue_(0),
    inSingleByteForm_(FALSE),
    cs(CharInfo::UnknownCharSet),
    isQuotedStrWithoutCharSetPrefix_(FALSE),
    utf16StrLit_(NULL),
    termCS_(CharInfo::UnknownCharSet)
  {
    if (name_)
      setName(name_);
    if (value_)
      setValue(value_, x_);
  }
  
  Param::~Param()
  {
    if (name) {
      delete [] name;
      name = 0;
    };
  
    resetValue_();
  }
  
  void Param::setName(const char * name_)
  {
    if (name)
      delete [] name;
  
    name = new char[strlen(name_) + 1];
    strcpy(name, name_);  
  } 
  
  void Param::resetValue_()
  {
    if (value) {
      delete [] value;
      value = 0;
    }
  
    if (display_value) {
      delete [] display_value;
      display_value = 0;
    }
  
    if (converted_value) {
      delete [] converted_value;
      converted_value = 0;
    };
  
    // it is a non-nullable value
    if (nullValue_) {
      delete [] nullValue_;
      nullValue_ = 0;
     }
  
    if (utf16StrLit_ != (NAWchar*)NULL) {
      delete [] utf16StrLit_;
      utf16StrLit_ = (NAWchar*)NULL;
    }
  
    inSingleByteForm_ = TRUE;
    cs = CharInfo::UnknownCharSet;
    isQuotedStrWithoutCharSetPrefix_ = FALSE;
    termCS_ = CharInfo::UnknownCharSet;
  }
  
  void Param::setValue_(const char * value_, CharInfo::CharSet x_)
  {
    cs = x_;
    value = new char[strlen(value_) + 1];
    strcpy(value, value_);
    inSingleByteForm_ = TRUE;
  }
  
  void Param::setValue_(const NAWchar * value_, CharInfo::CharSet x_)
  {
    if (x_ == CharInfo::UNICODE && converted_value) {
      delete [] converted_value;
      converted_value = 0;
    };
  
    cs = x_;
    NAWchar* wvalue = new NAWchar[NAWstrlen(value_) + 1];
    NAWstrcpy(wvalue, value_);
    value = (char*) wvalue;
    inSingleByteForm_ = FALSE;
  }
  
  void Param::setValue(const char * value_, CharInfo::CharSet x_)
  {
    resetValue_();
    setValue_(value_, x_);
  }
  
  void Param::setValue(const NAWchar * value_, CharInfo::CharSet x_)
  {
    resetValue_();
    setValue_(value_, x_);
  }
  
  void Param::setUTF16StrLit (NAWchar *utf16Str)
  {
    if (utf16StrLit_)
      delete [] utf16StrLit_;
  
    utf16StrLit_ = new NAWchar [NAWstrlen(utf16Str) + 1];
    NAWstrcpy(utf16StrLit_, utf16Str);
  }
  
  void Param::setValue(SetParam* sp_)
  {
    resetValue_();
    if ( sp_ -> isInSingleByteForm() ) {
      setValue_(sp_->get_argument(), sp_ -> getCharSet());
    } else {
      setValue_((NAWchar*)(sp_->get_argument()), sp_ -> getCharSet());
    }
    if ( sp_ -> getUTF16ParamStrLit() )
    {
      setUTF16StrLit(sp_ -> getUTF16ParamStrLit());
      isQuotedStrWithoutCharSetPrefix_ = sp_ -> isQuotedStrWithoutCharSetPrefix();
      setTermCharSet(sp_ -> getTermCharSet());
    }
  } 
  
  void Param::makeNull()
  {
    if (nullValue_)
      delete [] nullValue_;
    
    nullValue_ = new char[2];
    *(short *)nullValue_ = -1;
  }
  
  short Param::convertValue(SqlciEnv * sqlci_env, short targetType,
  			  Lng32 &targetLen,
  			  Lng32 targetPrecision,
  			  Lng32 targetScale,
                            Lng32 vcIndLen,
     			  ComDiagsArea* diags) {
  
    // get rid of the old converted value
    if (converted_value) {
      delete [] converted_value;
      converted_value = 0;
    };
  
    short sourceType;
    Lng32 sourceLen;
  
    // set up the source and its length based on the how the value is passed-in.
    if ( isInSingleByteForm() == FALSE ) {
      sourceLen = (Lng32)(NAWstrlen((NAWchar*)value) * BYTES_PER_NAWCHAR);
      switch (getCharSet()) {
        case CharInfo::UNICODE:
          sourceType = REC_NCHAR_F_UNICODE;
          break;
  
        case CharInfo::KANJI_MP:
        case CharInfo::KSC5601_MP:
          sourceType = REC_BYTE_F_ASCII; // KANJI/KSC passed in as NAWchar*
          break;
  
        default:
          return SQL_Error; // error case
      }
    } else {
      sourceLen = (Lng32)strlen(value); // for any source in single-byte format
      sourceType = REC_BYTE_F_ASCII;
    }
  
    char * pParamValue = value;
  
    if ( DFS2REC::isAnyCharacter(targetType) ) {
  
      if (termCS_ == CharInfo::UnknownCharSet)
        termCS_ = sqlci_env->getTerminalCharset();
      if (cs == CharInfo::UnknownCharSet)
      {
        isQuotedStrWithoutCharSetPrefix_ = TRUE;
        cs = termCS_;
      }
  
      // If the target is CHARACTER and param is set as [_cs_prefix]'...', then 
      // make sure the source is assignment compatible with the target.
      CharInfo::CharSet targetCharSet = (CharInfo::CharSet)targetScale;
      if ( targetCharSet == CharInfo::UNICODE )
      {
        if (getUTF16StrLit() == (NAWchar*)NULL)
        {
          utf16StrLit_ = new NAWchar [ sourceLen * 2 + 1 ]; // plenty of room
          Lng32 utf16StrLenInNAWchars =
            LocaleStringToUnicode(cs/*sourceCS*/, /*sourceStr*/value, sourceLen,
                                  utf16StrLit_/*outputBuf*/, sourceLen+1/*outputBufSizeInNAWchars*/,
                                  TRUE /* in - NABoolean addNullAtEnd*/);
          if (sourceLen > 0 && utf16StrLenInNAWchars == 0)
            return SQL_Error;
  
          // ComASSERT(utf16StrLenInNAWchars == NAWstrlen(getUTF16StrLit()));
          // Resize the NAWchar buffer to save space
          NAWchar *pNAWcharBuf = new NAWchar [ utf16StrLenInNAWchars + 1 ];
          NAWstrncpy (pNAWcharBuf, utf16StrLit_, utf16StrLenInNAWchars + 1);
          pNAWcharBuf[utf16StrLenInNAWchars] = NAWCHR('\0'); // play it safe
          delete [] utf16StrLit_;
          utf16StrLit_ = pNAWcharBuf; // do not deallocate pNAWcharBuf
        }
        sourceLen = (Lng32)(NAWstrlen(getUTF16StrLit()) * BYTES_PER_NAWCHAR);
        // check to see if the parameter utf16 string fits in the target
        if ( sourceLen > targetLen )
          return SQL_Error;
  
        pParamValue = (char *)getUTF16StrLit();
        sourceType = REC_NCHAR_F_UNICODE;
      }
  
    } else {
   
      // MP NCHAR (KANJI/KSC) can not be converted to non-character objects
     if ( CharInfo::is_NCHAR_MP(cs) )
        return SQL_Error;
    }
  
  
    switch(targetType) {
    case REC_BOOLEAN:
    case REC_BIN8_SIGNED:
    case REC_BIN8_UNSIGNED:
    case REC_BIN16_SIGNED:
    case REC_BIN16_UNSIGNED:
    case REC_BPINT_UNSIGNED:
    case REC_BIN32_SIGNED:
    case REC_BIN32_UNSIGNED:
    case REC_BIN64_SIGNED:
    case REC_BIN64_UNSIGNED:
    case REC_DECIMAL_UNSIGNED:
    case REC_DECIMAL_LSE:
    case REC_FLOAT32:
    case REC_FLOAT64:
    case REC_BYTE_F_ASCII:
    case REC_BYTE_V_ASCII:
    case REC_BYTE_V_ASCII_LONG:
    case REC_NCHAR_F_UNICODE:
    case REC_NCHAR_V_UNICODE:
    case REC_BLOB:
    case REC_CLOB:
    {
      char *VCLen = NULL;
      short VCLenSize = 0;
      short origTargetType = 0;
      if ((targetType == REC_BLOB) || (targetType == REC_CLOB))
        {       
          // convert the format to a varchar format with 4 bytes of length
          origTargetType = REC_BLOB;
          targetType = REC_BYTE_V_ASCII;
          vcIndLen = sizeof(Int32);
        }
          
      // 5/27/98: added VARCHAR cases
      if ((targetType == REC_BYTE_V_ASCII) || 
          (targetType == REC_BYTE_V_ASCII_LONG) ||
          (targetType == REC_NCHAR_V_UNICODE))       
        {
          // add bytes for variable length field
          VCLenSize = vcIndLen; //sizeof(short);
          VCLen = converted_value = new char[targetLen + VCLenSize];
        } else
        converted_value = new char[targetLen];
  
  
      ex_expr::exp_return_type ok;
      CharInfo::CharSet TCS = sqlci_env->getTerminalCharset();
      CharInfo::CharSet ISOMAPCS = sqlci_env->getIsoMappingCharset();
      
      NAString* tempstr;
      if ( 
           (
                DFS2REC::isAnyCharacter(sourceType) && DFS2REC::isAnyCharacter(targetType) &&
                !(getUTF16StrLit() != NULL && sourceType == REC_NCHAR_F_UNICODE && targetScale == CharInfo::UCS2) &&
                /*source*/cs != targetScale/*i.e., targetCharSet*/
            ) && (origTargetType != REC_BLOB)
           )
           
      {
        charBuf cbuf((unsigned char*)pParamValue, sourceLen);
        NAWcharBuf* wcbuf = 0;
        Int32 errorcode = 0;
        wcbuf = csetToUnicode(cbuf, 0, wcbuf,
                              cs/*sourceCharSet*/
                              , errorcode);
        if (errorcode != 0) return SQL_Error;
        tempstr = unicodeToChar(wcbuf->data(),wcbuf->getStrLen(),
                                targetScale/*i.e., targetCharSet*/
                                );
        if (tempstr == NULL) 
  	return SQL_Error;  //Avoid NULL ptr reference if conversion error
        sourceType = targetType; // we just converted it to the target type
        sourceLen = tempstr->length();
        pParamValue = (char *)tempstr->data();
  
        if ( sourceLen > targetLen )
          return SQL_Error;
      }
      
      ok = convDoIt(pParamValue,
  		  sourceLen, 
  		  sourceType,
  		  0, // source Precision
  		  targetScale, // new charset we converted to
  		  &converted_value[VCLenSize],
  		  targetLen,
  		  targetType,
  		  targetPrecision,
  		  targetScale,
  		  VCLen,
  		  VCLenSize,
  		  0,
  		  &diags);
      
      if ( ok != ex_expr::EXPR_OK)
      {
        // No need to delete allocated memory before return because class member
        // converted_value still points to allocated memory that is deleted in 
        // desctructor.
        return SQL_Error; // error case
      }
      
    };
    break;
  
  
    case REC_DATETIME: {
  
      char *VCLen = NULL;
      short VCLenSize = 0;
      converted_value = new char[targetLen + 1];
  
      UInt32 flags = 0;
      flags |= CONV_NO_HADOOP_DATE_FIX;
  
      ex_expr::exp_return_type ok = convDoIt(value,
  					   sourceLen, 
  					   sourceType,
  					   0, // source Precision
  					   0, // source Scale
  					   converted_value,
  					   targetLen,
  					   targetType,
  					   targetPrecision,
  					   targetScale,
  					   VCLen,
  					   VCLenSize,
  					   0,
  					   &diags,
                                             CONV_UNKNOWN,
                                             NULL,
                                             flags);
      
      if ( ok != ex_expr::EXPR_OK)
        {
  	return SQL_Error; // error case
        }
    };
    break;
  
    case REC_INT_YEAR:
    case REC_INT_MONTH:
    case REC_INT_YEAR_MONTH:
    case REC_INT_DAY:
    case REC_INT_HOUR:
    case REC_INT_DAY_HOUR:
    case REC_INT_MINUTE:
    case REC_INT_HOUR_MINUTE:
    case REC_INT_DAY_MINUTE:
    case REC_INT_SECOND:
    case REC_INT_MINUTE_SECOND:
    case REC_INT_HOUR_SECOND:
    case REC_INT_DAY_SECOND: {
  
      // convert target back to string.
      converted_value = new char[targetLen];
      Lng32 convFlags = CONV_ALLOW_SIGN_IN_INTERVAL;
      short ok = 
        convDoItMxcs(value,
  		   sourceLen, 
  		   sourceType,
  		   0, // source Precision
  		   0, // source Scale
  		   converted_value,
  		   targetLen,
  		   targetType,
  		   targetPrecision,
  		   targetScale,
  		   convFlags);
      
      if ( ok != 0 )
      {
        // No need to delete allocated memory before return because class member
        // converted_value still points to allocated memory that is deleted in 
        // desctructor.
        return SQL_Error; // error case
      }
    };
    break;
  
    case REC_NUM_BIG_UNSIGNED:
    case REC_NUM_BIG_SIGNED:
    {
      converted_value = new char[targetLen];
      short ok = 
        convDoItMxcs(value,
  		   sourceLen, 
  		   sourceType,
  		   0, // source Precision
  		   0, // source Scale
  		   converted_value,
  		   targetLen,
  		   targetType,
  		   targetPrecision,
  		   targetScale,
  		   0);
      
      if ( ok != 0 )
      {
        // No need to delete allocated memory before return because class member
        // converted_value still points to allocated memory that is deleted in 
        // desctructor.
        return SQL_Error; // error case
      }
      
    };
    break;
  
    default:
      break;
    };
  
    return 0;
  }
  
  short Param::contains(const char * value) const
  {
    if (strcmp(name, value) == 0)
      return -1;
    else
      return 0;
  }
    
  char* Param::getDisplayValue(CharInfo::CharSet display_cs) 
  {
    if ( isInSingleByteForm() == FALSE && getCharSet() == CharInfo::UNICODE ) {
         
      if ( display_value == NULL ) 
      {
         NAWchar* wvalue = (NAWchar*)value;
         Lng32 wlen = (Lng32)NAWstrlen(wvalue);
         display_value = new char[wlen+1];
         UnicodeStringToLocale(display_cs, wvalue, wlen, 
                               display_value, wlen+1,
                               TRUE, // add null at end 
                               TRUE  // non-convertable char to ? 
                              );
      }
      return display_value;
  
    } else
     return getValue();
  }
  
  //////////////////////////////////////////////////////////////
  short SetParam::process(SqlciEnv * sqlci_env)
  {
    if (get_arglen() == -1)
      {
        // set param to null value
        Param * param = sqlci_env->get_paramlist()->get(param_name);
        if (param)
  	param->makeNull();
        else
  	{
  	  param = new Param(param_name, (char*)0);
  	  
  	  sqlci_env->get_paramlist()->append(param);
  	  param->makeNull();
  	}
      }
    else
      if (!get_argument())
      {
        /* RESET PARAM command */
        if (!param_name)
  	{
  	  /* RESET all params */
  	  Param * param = sqlci_env->get_paramlist()->getFirst();
  	  while (param)
  	    {
  	      sqlci_env->get_paramlist()->remove(param->getName());
  	      delete param;
  	      param = sqlci_env->get_paramlist()->getNext();
  	    }
  	}
        else
  	{
  	  Param * param = sqlci_env->get_paramlist()->get(param_name);
  	  sqlci_env->get_paramlist()->remove(param_name);
  	  delete param;
  	 }
      } 
    else
      {
        /* SET PARAM command */
        Param * param = sqlci_env->get_paramlist()->get(param_name);
        if (param) {
  	param->setValue(this);
        } else
  	{
  	  param = new Param(param_name, this);
  	  
  	  sqlci_env->get_paramlist()->append(param);
  	}
      }
    
    return 0;
  }
  
  SetParam::~SetParam()
  {
    if (param_name)
      delete [] param_name;
    if (m_convUTF16ParamStrLit)
      delete [] m_convUTF16ParamStrLit;
  }
  
  void SetParam::setUTF16ParamStrLit(const NAWchar * utf16Str, size_t ucs2StrLen)
  {
    if (m_convUTF16ParamStrLit)
    {
      delete [] m_convUTF16ParamStrLit;
      m_convUTF16ParamStrLit = NULL;
    }
    m_convUTF16ParamStrLit = new NAWchar[ucs2StrLen + 1];
    NAWstrncpy(m_convUTF16ParamStrLit, utf16Str, ucs2StrLen);
    m_convUTF16ParamStrLit[ucs2StrLen] = L'\0';
  }
  
  //////////////////////////////////////////////////////////////
  short SetPattern::process(SqlciEnv * sqlci_env)
  {
    if (!get_argument())
      {
        /* RESET PATTERN command */
        if (!pattern_name)
  	{
  	  /* RESET all patterns */
  	  Param * pattern = sqlci_env->get_patternlist()->getFirst();
  	  while (pattern)
  	    {
  	      sqlci_env->get_patternlist()->remove(pattern->getName());
  	      delete pattern;
  	      pattern = sqlci_env->get_patternlist()->getNext();
  	    }
  	}
        else
  	{
  	  Param * pattern = sqlci_env->get_patternlist()->get(pattern_name);
  	  sqlci_env->get_patternlist()->remove(pattern_name);
  	  delete pattern;
  	}
      } 
    else
      {
        /* SET PATTERN command */
        Param * pattern = sqlci_env->get_patternlist()->get(pattern_name);
        if (pattern)
        {
  	pattern->setValue(get_argument(), sqlci_env->getTerminalCharset());
        }
        else
  	{
  	  pattern = new Param(pattern_name, get_argument());
  	  
  	  sqlci_env->get_patternlist()->append(pattern);
  	}
      }
    
    return 0;
  }
  
  SetPattern::~SetPattern()
  {
    if (pattern_name)
      delete [] pattern_name;
  }
  
  