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:         SqlciRWCmd.cpp
   * Description:  Methods to process commands that interact with SQL/CLI and RW.
   *               
   *               
   * Created:      6/6/2003
   * Language:     C++
   * Status:       
   *
   *
   *
   *
   *****************************************************************************
   */
  
  #include "Platform.h"
  #include "SQLTypeDefs.h"
  #include "SqlciRWCmd.h"
  #include "SqlciError.h"
  #include "sqlcmd.h"
  #include "SqlciEnv.h"
  #include "Formatter.h"
  #include "exp_clause_derived.h"
  #include "exp_datetime.h"
  #include "unicode_char_set.h"
  #include "RWInterface.h"
  
  extern SqlciEnv * global_sqlci_env; // global sqlci_env for break key handling purposes.
  void ReportWriterError ( ErrorValue *e )
  {
  #pragma nowarn(1506)  // warning elimination
    //Note: when C++ compiler bug is fixed, use constructor/destructor to
    //manage memory allocation/deallocation automatically
  
    ErrorParam *ep1 = new ErrorParam (e->charparam1_);
    ErrorParam *ep2 = new ErrorParam (e->charparam2_); 
    ErrorParam *ep3 = new ErrorParam (e->charparam3_); 
    ErrorParam *ep4 = new ErrorParam (e->intparam1_); 
    ErrorParam *ep5 = new ErrorParam (e->intparam2_); 
    ErrorParam *ep6 = new ErrorParam (e->intparam3_);
  
    SqlciError2 (e->errorCode_,
         ep1,
         ep2,
         ep3,
         ep4,
         ep5,
         ep6,
          (ErrorParam *) 0);
  
    delete ep1;
    delete ep2;
    delete ep3;
    delete ep4;
    delete ep5;
    delete ep6;
  #pragma warn(1506)  // warning elimination
  }
  
  void SetError ( ErrorValue *e, Lng32 errorCode)
  {
      e->errorCode_ = errorCode;
      e->charparam1_= NULL;
      e->charparam2_= NULL;
      e->charparam3_= NULL;
      e->intparam1_= -1;
      e->intparam2_= -1;
      e->intparam3_= -1;
  }
  ///////////////////////////////////////////////////////////////////////
  //
  // This is the base class for RW commands.
  // This class is not constructed by the parser.
  //
  ///////////////////////////////////////////////////////////////////////
  
  SqlciRWCmd::SqlciRWCmd(const report_cmd_type cmd_type_)
                    : SqlciNode(SqlciNode::REPORT_CMD_TYPE),
                      cmd_type(cmd_type_)
  {
  };
  
  SqlciRWCmd::~SqlciRWCmd()
  {
  };
  
  ///////////////////////////////////////////////////////////////////
  // this class is created by sqlci parser when a LIST command
  // ("LIST FIRST <N>", ...etc) is seen.
  //
  // The class is constructed with the list type and the number of
  // rows specified in it.
  //
  // ListType values:
  // List First:  FIRST_
  // List Next:   NEXT_
  // List All:    ALL_
  // Cancel:      END_
  //
  // numRows: number of rows specified in the List command.
  //          -1, if 'list all' is specified.
  //
  //////////////////////////////////////////////////////////////////
  SqlciRWListCmd::SqlciRWListCmd(ListType type, Lng32 listCount, NABoolean listCountSet)
       : SqlciRWCmd(LIST_TYPE),
         type_(type), listCount_(listCount),
         listCountSet_(listCountSet)
  {
  }
  
  SqlciRWListCmd::~SqlciRWListCmd()
  {
  }
  
  short SqlciRWListCmd::process(SqlciEnv * sqlci_env)
  {
    short rc = 0;
  
    SqlciRWInterfaceExecutor::ExecutionState state = SqlciRWInterfaceExecutor::INITIAL_;
    switch (type_)
      {
      case FIRST_:
        state = SqlciRWInterfaceExecutor::LIST_FIRST_;
        if (sqlci_env->getListCount() != SqlciEnv::MAX_LISTCOUNT
            && !listCountSet_)
  #pragma nowarn(1506)   // warning elimination 
          listCount_ = sqlci_env->getListCount();
  #pragma warn(1506)  // warning elimination 
        else if (listCountSet_ == FALSE)
          listCount_ = 0;
        break;
  
      case NEXT_:
        state = SqlciRWInterfaceExecutor::LIST_NEXT_;
        if (sqlci_env->getListCount() != SqlciEnv::MAX_LISTCOUNT
          && !listCountSet_)
  #pragma nowarn(1506)   // warning elimination 
          listCount_ = sqlci_env->getListCount();
  #pragma warn(1506)  // warning elimination 
        else if (listCountSet_ == FALSE)
          listCount_ = 0;
  
        if (sqlci_env->sqlciRWEnv()->rwExe()->resetListFlag())
  	{
  	  // display warning indicating that reset was done.
  	  ErrorValue err;
  	  err.errorCode_ = SQLCI_RW_RESET_LIST;
            err.charparam1_= NULL;
            err.charparam2_= NULL;
            err.charparam3_= NULL;
            err.intparam1_= -1;
            err.intparam2_= -1;
            err.intparam3_= -1;
  	  ReportWriterError(&err);
  
  	  // and reset the list to start at the beginning.
  	  state = SqlciRWInterfaceExecutor::LIST_FIRST_;
  	}
        break;
  
      case ALL_:
        state = SqlciRWInterfaceExecutor::LIST_ALL_;
        sqlci_env->sqlciRWEnv()->setSelectInProgress(FALSE); 
        break;
  
      }
  
    sqlci_env->sqlciRWEnv()->rwExe()->setResetListFlag(FALSE);
  
    sqlci_env->sqlciRWEnv()->rwExe()->setState(state);
    
    sqlci_env->sqlciRWEnv()->rwExe()->setListCount(listCount_);
  
    rc = sqlci_env->sqlciRWEnv()->rwExe()->process(sqlci_env);
  
    return rc;
  }
  
  //////////////////////////////////////////////////////////////////////////////
  //
  // This class is constructed by the parser when a CANCEL is seen.
  // This cancels any select in progress command, then gets out of RW
  // prompt and into mxci prompt.
  //
  //////////////////////////////////////////////////////////////////////////////
  SqlciRWCancelCmd::SqlciRWCancelCmd()
       : SqlciRWCmd(CANCEL_TYPE)
  {
  }
  
  SqlciRWCancelCmd::~SqlciRWCancelCmd()
  {
  }
  
  short SqlciRWCancelCmd::process(SqlciEnv * sqlci_env)
  {
    short rc = 0;
  
    sqlci_env->sqlciRWEnv()->rwExe()->setState(SqlciRWInterfaceExecutor::CANCEL_);
    
    rc = sqlci_env->sqlciRWEnv()->rwExe()->process(sqlci_env);
    sqlci_env->sqlciRWEnv()->setSelectInProgress(FALSE); 
    return rc;
  }
  
  
  //////////////////////////////////////////////////////////////////////////////
  //
  // This class is constructed by the parser when a report writer query is seen.
  // These are the queries which are to be passed to RW without any
  // interpretation by sqlci.
  //
  //////////////////////////////////////////////////////////////////////////////
  SqlciRWQueryCmd::SqlciRWQueryCmd(char * rwCmd, Lng32 rwCmdLen)
       : SqlciRWCmd(RW_QUERY_TYPE)
  {
    rwCmdLen_ = rwCmdLen;
    if (rwCmd)
      {
        rwCmd_ = new char[strlen(rwCmd)+1];
        strcpy(rwCmd_, rwCmd);
      }
    else
      rwCmd_ = 0;
  }
  
  SqlciRWQueryCmd::~SqlciRWQueryCmd()
  {
    if (rwCmd_)
      delete rwCmd_;
  }
  
  short SqlciRWQueryCmd::process(SqlciEnv * sqlci_env)
  {
    short rc = 0;
  
    sqlci_env->sqlciRWEnv()->rwExe()->setRWCmd(rwCmd_, rwCmdLen_);
  
    sqlci_env->sqlciRWEnv()->rwExe()->setState(SqlciRWInterfaceExecutor::SEND_QUERY_TO_RW_);
  
    rc = sqlci_env->sqlciRWEnv()->rwExe()->process(sqlci_env);
  
    return rc;
  }
  
  ////////////////////////////////////////////////////////////////////
  //
  // This class is constructed by parser when a RW Select command is
  // seen. This is the select query that follows a 'set list_count'
  // command.
  //
  ////////////////////////////////////////////////////////////////////
  SqlciRWSelectCmd::SqlciRWSelectCmd(char * selectCmd)
       : SqlciRWCmd(SELECT_TYPE)
  {
    if (selectCmd)
      {
        selectCmd_ = new char[strlen(selectCmd)+1];
        strcpy(selectCmd_, selectCmd);
      }
    else
      selectCmd_ = 0;
  }
  
  SqlciRWSelectCmd::~SqlciRWSelectCmd()
  {
    if (selectCmd_)
      delete selectCmd_;
  }
  
  short SqlciRWSelectCmd::process(SqlciEnv * sqlci_env)
  {
    short rc = 0;
  
    sqlci_env->sqlciRWEnv()->rwExe()->setSelectCmd(selectCmd_);
  
    sqlci_env->sqlciRWEnv()->rwExe()->setState(SqlciRWInterfaceExecutor::PREPARE_);
  
    sqlci_env->sqlciRWEnv()->rwExe()->setResetListFlag(FALSE);
  
    rc = sqlci_env->sqlciRWEnv()->rwExe()->process(sqlci_env);
    return rc;
  }
  
  ////////////////////////////////////////////////////////////////////
  //
  // This class is constructed by parser when a RW execute command is
  // seen. This is the execute of a prepared select query that follows 
  // a 'set list_count' command.
  //
  ////////////////////////////////////////////////////////////////////
  SqlciRWExecuteCmd::SqlciRWExecuteCmd(char * stmtName, char * usingParamStr)
       : SqlciRWCmd(EXECUTE_TYPE)
  {
    if (stmtName)
      {
        stmtName_ = new char[strlen(stmtName)+1];
        strcpy(stmtName_, stmtName);
      }
    else
      stmtName_ = 0;
  
    if (usingParamStr)
      {
        usingParamStr_ = new char[strlen(usingParamStr) + 1];
        strcpy(usingParamStr_, usingParamStr);
      }
    else
      {
        usingParamStr_ = NULL;
      }
  }
  
  SqlciRWExecuteCmd::~SqlciRWExecuteCmd()
  {
    if (stmtName_)
      delete stmtName_;
  
    if (usingParamStr_)
      delete usingParamStr_;
  }
  
  short SqlciRWInterfaceExecutor::setUsingParamInfo(char * usingParamStr)
  {
    short rc = 0;
  
    numUsingParams_ = 0;
    if (usingParamStr)
      {
        if (! usingParams_)
  	usingParams_ = new char * [MAX_NUM_UNNAMED_PARAMS];
  
        for (Int32 i = numUsingParams_; i > 0; )
  	delete usingParams_[--i];
  
        rc = (short)Execute::storeParams(usingParamStr, numUsingParams_,
  				       usingParams_);
      }
  
    return rc;
  }
  
  short SqlciRWExecuteCmd::process(SqlciEnv * sqlci_env)
  {
    short rc = 0;
  
    PrepStmt * prepStmt = sqlci_env->get_prep_stmts()->get(stmtName_);
    if (! prepStmt)
      {
        sqlci_env->diagsArea() << DgSqlCode(-SQLCI_STMT_NOT_FOUND)
  			     << DgString0(stmtName_);
  
        return 0;
      }
  
    sqlci_env->sqlciRWEnv()->rwExe()->setExecutePrepStmt(prepStmt);
    sqlci_env->sqlciRWEnv()->rwExe()->setExecuteCmd(stmtName_);
  
    if (usingParamStr_)
      {
        rc = 
  	sqlci_env->sqlciRWEnv()->rwExe()->setUsingParamInfo(usingParamStr_);
        if (rc)
  	return 0;
      }
  
    sqlci_env->sqlciRWEnv()->rwExe()->setState(SqlciRWInterfaceExecutor::SELECT_STARTED_);
  
    sqlci_env->sqlciRWEnv()->rwExe()->setResetListFlag(FALSE);
  
    rc = sqlci_env->sqlciRWEnv()->rwExe()->process(sqlci_env);
    sqlci_env->sqlciRWEnv()->setSelectInProgress(TRUE);
  
    return rc;
  }
  
  ////////////////////////////////////////////////////////////////////////
  //
  // This class is the execution engine to process the RW select command.
  // It contains all the methods and other information that is needed to
  // interact with RW (mxci calling RW) when a select command is processed.
  //
  // It is constructed during SqlciRWSelectCmd::process and is 'alive'
  // as long as that 'select is in progress'. The globals RWEnv points to this
  // class.
  //
  ////////////////////////////////////////////////////////////////////////
  
  SqlciRWInterfaceExecutor::SqlciRWInterfaceExecutor()
       : selectCmd_(NULL),
         executeStmtName_(NULL),
         usingParams_(NULL), numUsingParams_(0),
         rwCmd_(NULL), rwCmdLen_(0),
         inputRow_(NULL), inputRowLen_(0),
         outputRow_(NULL), outputRowLen_(0),
         listCount_(0), currCount_(0),
         cursorOpened_(FALSE),
         prepStmt_(NULL),
         flags_(0),
         state_(INITIAL_)
  {
  }
  
  void SqlciRWInterfaceExecutor::setSelectCmd(char * selectCmd)
  {
    if (selectCmd_)
      delete selectCmd_;
    selectCmd_ = NULL;
  
    if (executeStmtName_)
      delete executeStmtName_;
    executeStmtName_ = NULL;
  
    if (selectCmd)
      {
        selectCmd_ = new char[strlen(selectCmd)+1];
        strcpy(selectCmd_, selectCmd);
      }
    else
      selectCmd_ = 0;
    
    state_ = INITIAL_;
  }
  
  void SqlciRWInterfaceExecutor::setExecuteCmd(char * executeStmtName)
  {
    if (selectCmd_)
      delete selectCmd_;
    selectCmd_ = NULL;
  
    if (executeStmtName_)
      delete executeStmtName_;
  
    if (executeStmtName)
      {
        executeStmtName_ = new char[strlen(executeStmtName)+1];
        strcpy(executeStmtName_, executeStmtName);
      }
    else
      executeStmtName_ = 0;
    
    state_ = INITIAL_;
  }
  
  void SqlciRWInterfaceExecutor::setRWCmd(char * rwCmd, Lng32 rwCmdLen)
  {
    if (rwCmd_)
      delete rwCmd_;
  
    rwCmdLen_ = rwCmdLen;
    
    if (rwCmd)
      {
        rwCmd_ = new char[strlen(rwCmd)+1];
        strcpy(rwCmd_, rwCmd);
      }
    else
      rwCmd_ = 0;
  }
  
  SqlciRWInterfaceExecutor::~SqlciRWInterfaceExecutor()
  {
    if (selectCmd_)
      delete selectCmd_;
  
    if (executeStmtName_)
      delete executeStmtName_;
  }
  
  //////////////////////////////////////////////////////////////////////////
  // Returns the next state of the state machine based on the retcode
  // and the nextState.
  // 'retcode' is of type RetStatus in RWInterface.h.
  //
  // If retcode is ERROR, then next state of error is returned.
  // If the nextState sent in is different than the current state, state_,
  // then it overrides the retcode state and is returned.
  // Otherwise, the state based on retcode is returned.
  //
  //////////////////////////////////////////////////////////////////////////
  SqlciRWInterfaceExecutor::ExecutionState SqlciRWInterfaceExecutor::getNextState(
       Lng32 retcode,
       SqlciRWInterfaceExecutor::ExecutionState nextState)
  {
    ExecutionState state;
  
    if (retcode == ERR)
      state = RW_ERROR_;
    else if (state_ != nextState)
      state = nextState;
    else
      {
        switch (retcode)
  	{
  	case SEND_QUERY:
  	  state = GET_INPUT_FROM_SQLCI_;
  	  break;
  	  
  	case SEND_INPUT_ROW:
  	  state = FETCH_;
  	  break;
  	  
  	case GET_OUTPUT_ROW:
  	  state = GET_OUTPUT_ROW_FROM_RW_;
  	  break;
  	  
  	case DONE:
  	  state = CLOSE_;
  	  break;
  
  	case RESET_LIST:
  	  state = RESET_LIST_;
  	  break;
  
  	default:
  	  state = state_;
  	  break;
  	  
  	}
      }
  
    return state;
  }
  
  Lng32 SqlciRWInterfaceExecutor::printOutputRow(SqlciEnv * sqlci_env,
  					      char * outputBuf,
  					      Lng32 outputBufLen)
  {
    Logfile *log = sqlci_env->get_logfile();
  
    log->WriteAll(outputBuf, outputBufLen, 0);
  
    return 0;
  }
  
  static NABoolean isSqlError(Lng32 sqlRetcode)
  {
    if (sqlRetcode < 0)
      return TRUE;
    else
      return FALSE;
  }
  
  short SqlciRWInterfaceExecutor::open(SqlciEnv * sqlci_env)
  {
    short rc;
  
  #ifdef _DEBUG
        if (getenv("SHOW_RW_STATE"))
  	{
  	  char buf[40];
  	  strcpy(buf, "OPEN_");
  	  cout << "State " << buf << endl;
  	}
  #endif
  
    // close cursor. TBD: add SqlCmd::close() call to do this.
    // Ignore error, stmt may already be closed.
    SQL_EXEC_CloseStmt(prepStmt_->getStmt());
    SQL_EXEC_ClearDiagnostics(prepStmt_->getStmt());
    
    // open the stmt
    rc = SqlCmd::doExec(sqlci_env,
  		      prepStmt_->getStmt(),
  		      prepStmt_,
  		      numUsingParams_,
  		      usingParams_);
  
    currCount_ = 0;
  
    cursorOpened_ = TRUE;
  
    return rc;
  }
  
  void SqlciRWInterfaceExecutor::Close(SqlciEnv *sqlci_env)
  {
    if (prepStmt_)
      SQL_EXEC_CloseStmt(prepStmt_->getStmt());
  
    SQL_EXEC_ClearDiagnostics(NULL);
  	
    // Deallocate, if selectCmd. This call also
    // deallocates the passed prepStmt_.
    if ((selectCmd_) &&(prepStmt_))
    {
      SqlCmd::deallocate(sqlci_env, prepStmt_);
      prepStmt_ = NULL;
      // make sure that this is reset so we dont deallocate
      // it again in interrupt handler if the break key is hit.
      global_sqlci_env->resetDeallocateStmt(); 
    }
  
    cursorOpened_ = FALSE;
  
  }
  
  short SqlciRWInterfaceExecutor::process(SqlciEnv * sqlci_env)
  {
    short retcode = 0;
    Lng32 sqlRetcode = 0;
    Lng32 rwRetcode = 0;
  
    NABoolean done = FALSE;
  
  // 64-bit: no more report writer
    assert(0);
  
    return retcode;
  }
  
  /////////////////////////////////////////////////////////////////////
  // These methods are called by RW to extract information about
  // an input row.
  /////////////////////////////////////////////////////////////////////
  Lng32 MXCI_RW_getMaxColumns (void *sqlciEnv, Lng32 &max, ErrorValue* &e)
  {
    SqlciEnv * sqlci_env = (SqlciEnv *)sqlciEnv;
    
    PrepStmt * prepStmt = sqlci_env->sqlciRWEnv()->rwExe()->prepStmt();
    if (! prepStmt)
    {
      // populate 'e', stmt doesn't exist. TBD.
      if (e == NULL)
      {
        e = new ErrorValue;
      }
      SetError(e, -SQLCI_STMT_NOT_FOUND);
      ReportWriterError(e);
      return ERR;
    }
  
    max = prepStmt->numOutputEntries();
  
    return SUCCESS;
  }
  
  //////////////////////////////////////////////////////////////////////
  Lng32 MXCI_RW_getColInfo (void *sqlciEnv, Lng32 column, 
  			 AttributeDetails* &entry, ErrorValue* &e)
  {
    SqlciEnv * sqlci_env = (SqlciEnv *)sqlciEnv;
  
    PrepStmt * prepStmt = sqlci_env->sqlciRWEnv()->rwExe()->prepStmt();
  
    if (! prepStmt)
    {
      if (e == NULL)
      {
        e = new ErrorValue;
      }
      SetError(e, -SQLCI_STMT_NOT_FOUND);
      ReportWriterError(e);
      return ERR;
    }
     
  
    if ((column <= 0) ||
        (column > prepStmt->numOutputEntries()))
    {
      if (e == NULL)
      {
        e = new ErrorValue;
      }
      SetError(e, -SQLCI_WRONG_COLUMN_VALUE);
      ReportWriterError(e);
      return ERR;
      
    }
  
    if (entry == NULL)
    {
        // allocate entry here. 
        // How will this get deallocated? TBD.
        entry = new AttributeDetails;
    }
  
    PrepEntry * outputEntry = prepStmt->outputEntries()[column-1];
  
    entry->dataType_ = outputEntry->datatype();
    entry->length_ = outputEntry->length();
    entry->precision_ = outputEntry->precision();
    entry->scale_ = outputEntry->scale();
    entry->nullable_ = outputEntry->nullFlag();
    entry->headingLen_ = outputEntry->headingLen();
    entry->heading_ = outputEntry->heading();
    entry->output_ = outputEntry->outputName();
    entry->outputLen_ = outputEntry->outputNameLen();
    entry->tableName_ = outputEntry->tableName();
    entry->tableLen_ = outputEntry->tableLen();
  
    
    entry->displayLen_ = Formatter::display_length(entry->dataType_,
  						 entry->length_,
  						 entry->precision_,
  						 entry->scale_,
                                                   outputEntry->charsetEnum(),
                                                   0,
                                                   (SqlciEnv *) sqlciEnv,
                                                   NULL);
  
    if (entry->dataType_ == REC_DATETIME)
      {
        entry->dateTimeCode_ = outputEntry->precision();
        entry->precision_ = 0; // not used for datetime
      }
    else if (entry->dataType_ >= REC_MIN_INTERVAL && 
  	   entry->dataType_ <= REC_MAX_INTERVAL) 
      {
        entry->leadPrecision_ = outputEntry->precision();
      }
    else if (DFS2REC::isAnyCharacter(entry->dataType_))
      {
        entry->charSet_ = outputEntry->charset();
  	  
        entry->collation_ = 0; //TBD
      }
  
    return SUCCESS;
  }
  
  //////////////////////////////////////////////////////////////////////////
  #pragma nowarn(770)  // warning elimination
  Lng32 MXCI_RW_getColAddr (void *sqlciEnv, Lng32 column, char *input_row, 
                            Lng32 len, char* &ptr, ErrorValue* &e)
  {
    Lng32 retcode = 0;
  
    SqlciEnv * sqlci_env = (SqlciEnv *)sqlciEnv;
  
    PrepStmt * prepStmt = sqlci_env->sqlciRWEnv()->rwExe()->prepStmt();
    if (! prepStmt)
      // populate 'e', stmt doesn't exist. TBD.
    {
      if (e == NULL)
      {
        e = new ErrorValue;
      }
      SetError(e, -SQLCI_STMT_NOT_FOUND);
      ReportWriterError(e);
      return ERR;
      
    }
  
    if ((column <= 0) ||
        (column > prepStmt->numOutputEntries()))
      // populate 'e', incorrect column value. TBD.
    {
      if (e == NULL)
      {
        e = new ErrorValue;
      }
      SetError(e, -SQLCI_WRONG_COLUMN_VALUE);
      ReportWriterError(e);
      return ERR;
    }
  
    PrepEntry * outputEntry = prepStmt->outputEntries()[column-1];
    SQLDESC_ID * output_desc = prepStmt->getOutputDesc();
  
    // the address of the data row.
    // Should be the same as the 'input_row' address passed in.
    char * outputData = prepStmt->outputData();
    if (outputData != input_row)
      return ERR;
  
    Long data_addr = 0;
    Long ind_data_addr = 0;
    
    retcode = SQL_EXEC_GetDescItem(output_desc, column,
  				 SQLDESC_VAR_PTR,
  				 &data_addr, 0, 0, 0, 0);
   
    retcode = SQL_EXEC_GetDescItem(output_desc, column,
  				 SQLDESC_IND_PTR,
  				 &ind_data_addr, 0, 0, 0, 0);
    if (outputEntry->nullFlag())
      data_addr = ind_data_addr;
  
    ptr = (char*)data_addr;
  
    return SUCCESS;
  }
  #pragma warn(770)  // warning elimination
  
  //////////////////////////////////////////////////////////////////////////
  // This method formats the input datetime value to the specified datetime
  // format.
  // The input value is in external (string) format.
  //////////////////////////////////////////////////////////////////////////
  #pragma nowarn(770)  // warning elimination
  Lng32 MXCI_RW_convertToDateFormat(void * sqlciEnv, 
  				 char* srcPtr, AttributeDetails* srcEntry,
  				 char *tgtPtr, AttributeDetails* tgtEntry, 
  				 DateTimeFormat format, ErrorValue* &e)
  {
    Lng32 rc;
  
    Int32 dtFormat;
    switch (format)
      {
      case DEFAULT:
        dtFormat = ExpDatetime::DATETIME_FORMAT_DEFAULT; break;
      case USA:
        dtFormat = ExpDatetime::DATETIME_FORMAT_USA; break;
      case EUROPEAN:
        dtFormat = ExpDatetime::DATETIME_FORMAT_EUROPEAN; break;
      default:
        assert(0);
        return ERR;
      }
  
    rc =  ExpDatetime::convAsciiDatetimeToASCII(srcPtr,
  					      srcEntry->dateTimeCode_,
  					      srcEntry->scale_,
  					      srcEntry->length_,
  					      tgtPtr,
  					      tgtEntry->length_,
  					      format,
  					      NULL,
  					      NULL);
    if (rc)
      {
        if (e == NULL)
  	{
  	  e = new ErrorValue;
  	}
        SetError(e, SQLCI_CONV_RESULT_FAILED);
        ReportWriterError(e);
        return ERR;
      }
    else
      return SUCCESS;
  }
  #pragma warn(770)  // warning elimination
  
  /////////////////////////////////////////////////////////////////////////////////////
  Lng32 MXCI_RW_allocateHeap (void* sqlciEnv, Lng32 len, char* &ptr)
  {
  
    SqlciEnv * sqlci_env = (SqlciEnv *)sqlciEnv;
    
    NAHeap *h = sqlci_env->sqlciRWEnv()->rwHeap();
    void *p = NULL;
  
    if (h)
      p = h->allocateMemory(len, TRUE);
   
    if (p)
    {
      ptr = (char *)p;
      return SUCCESS;
    }
    else
      return ERR;
  }
  
  ///////////////////////////////////////////////////////////////////////////////////////
  
  Lng32 MXCI_RW_deallocateHeap (void* sqlciEnv, Lng32 len, char* ptr)
  {
  
    SqlciEnv * sqlci_env = (SqlciEnv *)sqlciEnv;
    
    if (len != 0)
    {
      sqlci_env->sqlciRWEnv()->rwHeap()->deallocateMemory((void*)ptr);
      return SUCCESS;
    }
    else
      return ERR;
  }
  
  
  ////////////////////////////////////////////////////////////////////////////////////////
  
  Lng32 MXCI_RW_unicodeConvertToUpper (void *sqlciEnv, char *input_char, Lng32 num_of_input_bytes,
       char *output_char, Lng32& num_of_output_bytes, ErrorValue* &e)
  {
    //SqlciEnv * sqlci_env = (SqlciEnv *)sqlciEnv;
    
    Lng32 length_bytes = num_of_input_bytes;
    
    NAWchar* target = (NAWchar*)output_char;
    NAWchar* source = (NAWchar*)input_char;
    Int32 wc_len = length_bytes/2;
    Int32 actual_len = 0;
    NAWchar* tmpWCP = NULL;
    Int32 maxWideChars = num_of_output_bytes / 2;
  
    if ((((Long)input_char % 2) != 0) || (((Long)output_char % 2) != 0))
    {
      if (e == NULL)
      {
        e = new ErrorValue;
      }
      SetError(e, -SQLCI_RW_BUFFER_UNEVEN_BOUNDARY);
      ReportWriterError(e);
      return ERR;
    }
  
    // the logic in this code is from w:/exp/exp_function_upper_unicode.cpp 
    // in the eval funciton.  Whenever that code changes this has to 
    // change and vice versa.
  
    for (Int32 i = 0; i < wc_len ; i++)
    {
      tmpWCP = unicode_char_set::to_upper_full(source[i]);
      if (tmpWCP)
      {
        if (actual_len + ((tmpWCP[2] ==0) ? 2 : 3) > maxWideChars)
        {
          if (e == NULL)
          {
            e = new ErrorValue;
          }
          SetError(e, -SQLCI_RW_STRING_OVERFLOW);
          ReportWriterError(e);
          return ERR;
        }// end of if
  
        target[actual_len++] = tmpWCP[0];
        target[actual_len++] = tmpWCP[1];
  
        if (tmpWCP[2] != (NAWchar)0)
          target[actual_len++] = tmpWCP[2];
      }
      else
      {
        if (actual_len >= maxWideChars)
        {
          if (e == NULL)
          {
            e = new ErrorValue;
          }
          SetError(e, -SQLCI_RW_STRING_OVERFLOW);
          ReportWriterError(e);
          return ERR;
        }
        target[actual_len++] = unicode_char_set::to_upper(source[i]);
      }// end of else
    } // end of for
  
    num_of_output_bytes = (actual_len * 2);
    return SUCCESS;
  }
  
  ////////////////////////////////////////////////////////////////////////////////////
  
  Lng32 MXCI_RW_unicodeConvertToLower(void *sqlciEnv, char *input_char, Lng32 num_of_input_bytes,
  char *output_char, Lng32& num_of_output_bytes, ErrorValue* &e)
  {
   // SqlciEnv * sqlci_env = (SqlciEnv *)sqlciEnv;
  
    Lng32 len1 = num_of_input_bytes;
    Lng32 buffer_size = num_of_output_bytes/2 ;
    num_of_output_bytes = len1;
  
    NAWchar* target = (NAWchar*)output_char;
    NAWchar* source = (NAWchar*)input_char;
    Int32 wc_len = len1/2;
  
    // the logic in this code is from w:/exp/exp_function_lower_unicode.cpp 
    // in the eval funciton.  Whenever that code changes this has to 
    // change and vice versa.
  
    for (Int32 i = 0; i < wc_len; i++)
    {
      if (i >= buffer_size)
      {
        if (e == NULL)
        {
          e = new ErrorValue;
        }
        SetError(e,-SQLCI_RW_STRING_OVERFLOW);
        ReportWriterError(e);
        return ERR;
      }
      target[i] = unicode_char_set::to_lower(source[i]);
    }
    return SUCCESS;
  }
  
  /////////////////////////////////////////////////////////////////////////////
  /////////////////////////////////////////////////////////////////////////////
  Lng32 MXCI_RW_convDoIt (void *sqlciEnv, char* srcPtr, AttributeDetails* srcEntry,
    char *tgtPtr, AttributeDetails* tgtEntry, short formatting, ErrorValue* &e)
  {
    Lng32 retcode = 0;
    ULng32 convFlags = 0;
  
    if (formatting)
      {
        // if formatting, blankpad target before doing the conversion.
        str_pad (tgtPtr,tgtEntry->displayLen_,' ');
  
        // the formatted target will be left blank padded (blanks to the left).
        convFlags |= CONV_LEFT_PAD;
      }
    else
      convFlags = 0;
  
  
    // SqlciEnv * sqlci_env = (SqlciEnv *)sqlciEnv;
  
    // Check for nullability.  The logic for this code
    // is in w:/exp/exp_conv.cpp::processNulls function
  
    //  Source is nullable 
    if (srcEntry->nullable_)  
      {
        //if data is null - if source data is acutally null
        if ((srcPtr[0] != '\0') || (srcPtr[1] != '\0')) 
          {
            if (formatting)
              {
  	      //if Target is not nullable
  	      if (!(tgtEntry->nullable_)  )
  		{
  		  tgtPtr[0] = '?';
  		  return SUCCESS;  // Conversion has taken place.
  		}
  	      else 
  		{
  		  if (e == NULL)
  		    {
  		      e = new ErrorValue;
  		    }
  		  SetError(e, -SQLCI_RW_INVALID_FORMATTING);
  		  ReportWriterError(e);
  		  return ERR;
  		}
              } // end of formatting
            else // if not formatting
              {
  	      // source is nullable , source is null and target is nullable
  	      if (tgtEntry->nullable_)
  		{
  		  str_pad (tgtPtr,2,'\377');
  		  return SUCCESS;  // Conversion has taken place.
  		}
  	      else
                  {
                    if (e == NULL)
  		    {
  		      e = new ErrorValue;
  		    }
                    SetError(e, -SQLCI_CONV_NULL_TO_NOT_NULL);
                    ReportWriterError(e);
                    return ERR;
                  }
              }// end of else of if not formatting
            
          }// end of source data is null
        
        // source is nullable but the source data is not null
        else 
          {
            srcPtr = (char*)srcPtr + 2; // skip the null indicator bytes
  	  
          } // end of else if source is nullable but source data is not null
        
        //if source is not null and target is nullable
        // set null indicator in target if needed.
        
        if (tgtEntry->nullable_  )
  	{
  	  str_pad (tgtPtr,2,'\0');    // indicate that tgt is not null. Move the ptr by 2 bytes.
  	  tgtPtr = (char*)tgtPtr + 2;
  	}
        
      } // end of source is nullable
  
    char * VCLen = NULL;
    short VCLenSize = 0;
    if (DFS2REC::isAnyVarChar(tgtEntry->dataType_))
      {
        VCLen = tgtPtr;
        VCLenSize = 2;
        tgtPtr = (char*)tgtPtr + VCLenSize;
      }
    
    
    // If the datatype is of time INTERVAL or of type DATETIME, then
    // Set the datatype to _SQLDT_ASCII_F (char)
    // Set the length to the display length.
    // Set the precision to 0.
    // Set the scale to 0.
    
    Lng32 length_;
    Lng32 dataType_;
    Lng32 precision_;
    Lng32 scale_;
    
    if ( srcEntry->dataType_ == _SQLDT_DATETIME  || 
         ( srcEntry->dataType_ >= _SQLDT_INT_Y_Y && srcEntry->dataType_ <= _SQLDT_INT_D_F)
         )
      {
        length_ = srcEntry->displayLen_ ;
        dataType_ = 0;
        precision_ = 0;
        scale_ = 0;
      }
    else
      {
        length_ = srcEntry->length_;
        dataType_ = srcEntry->dataType_;
        precision_ = srcEntry->precision_;
        scale_ = srcEntry->scale_;
      }
    
  
  #pragma warning (disable : 4244)   //warning elimination
  #pragma nowarn(1506)   // warning elimination 
    retcode = convDoIt(srcPtr,
  		     length_,
  		     dataType_,
  		     precision_,
  		     scale_,
  		     tgtPtr,
  		     tgtEntry->length_,
  		     tgtEntry->dataType_, 
  		     tgtEntry->precision_,
  		     tgtEntry->scale_,
  		     VCLen,			//varCharLen
  		     VCLenSize,		//varCharLenSize = 2
  		     0,			//heap
  		     0,		//diagsarea
  		     CONV_UNKNOWN,
  		     0,
  		     convFlags);
  #pragma warn(1506)  // warning elimination 
  #pragma warning (default : 4244)   //warning elimination
    
    
    if (retcode)
      {
        return ERR;
      }
    else
      return SUCCESS;
    
  }
  
  
  
  
  