@@ -2298,6 +2298,10 @@ RETCODE Statement::resolveNames(LateNameInfoList * lnil,
 	      if (retcode != ex_expr::EXPR_OK)
 		{
 		  diagsArea << DgSqlCode(-EXE_CONVERT_STRING_ERROR);
+                  char hexstr[MAX_OFFENDING_SOURCE_DATA_DISPLAY_LEN];
+                  memset(hexstr, 0 , sizeof(hexstr) );
+                  diagsArea << DgString0(stringToHex(hexstr, sizeof(hexstr), source, sourceLen ));
+
 		  return ERROR;  
 		}
 
/**********************************************************************
// @@@ 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:         Statement.C
* Description:  Methods for class Statement.
*
* Created:      7/10/95
* Language:     C++
*
*
*
*
*****************************************************************************
*/

#define _XOPEN_SOURCE_EXTENDED 1
#include "cli_stdh.h"
#undef _XOPEN_SOURCE_EXTENDED       

#include "ComCextdecs.h"
#include "ex_stdh.h"
#include "ex_exe_stmt_globals.h"
#include "ComTdb.h"
#include "ex_tcb.h"
#include "ex_root.h"
#include "ExMeas.h"
#include "ExStats.h"
#include "ExSqlComp.h"
#include "ex_transaction.h"
#include "ex_frag_rt.h"
#include "ComDiags.h"
#include "NAMemory.h"
#include "LateBindInfo.h"
#include "sql_buffer.h"
#include "ex_control.h"
#include "Descriptor.h"  // For call to Descriptor::getCharDataFromCharHostVar(). 
#include "exp_clause_derived.h"
#include "sql_id.h"
#include "ex_error.h"
#include "ComRtUtils.h"
#include "ComDistribution.h"
#include "Cli.h"
#include "Int64.h"
#include "ComSqlId.h"
#include "CmpErrors.h"
#if !defined(__EID) && !defined(ARKFS_OPEN)
#include "ComResWords.h"
#endif

// begin includes for similarity check.
#include "exp_tuple_desc.h"
// end includes for similarity check

#include "TriggerEnable.h" // triggers
# include "ComSmallDefs.h" // MV
# include "ComMvAttributeBitmap.h" // MV

#include "logmxevent.h"


#include "ExUdrServer.h"
#include "wstr.h"
#include "QueryText.h"
#include <wchar.h>

#include "ComAnsiNamePart.h"
#include "ExRsInfo.h"
#include "PortProcessCalls.h"

#if (defined(NA_LINUX) && defined (SQ_NEW_PHANDLE))
#include "nsk/nskport.h"
#include "seabed/ms.h"
#include "seabed/fs.h"
#endif

#ifdef NA_CMPDLL
#include "arkcmp_proc.h"
#include "CmpContext.h"
#endif // NA_CMPDLL

// Printf-style tracing macros for the debug build. The macros are
// no-ops in the release build.
#ifdef NA_DEBUG_C_RUNTIME
#include <stdarg.h>
#define StmtDebug0(s) StmtPrintf((s))
#define StmtDebug1(s,a1) StmtPrintf((s),(a1))
#define StmtDebug2(s,a1,a2) StmtPrintf((s),(a1),(a2))
#define StmtDebug3(s,a1,a2,a3) StmtPrintf((s),(a1),(a2),(a3))
#define StmtDebug4(s,a1,a2,a3,a4) StmtPrintf((s),(a1),(a2),(a3),(a4))
#define StmtDebug5(s,a1,a2,a3,a4,a5) StmtPrintf((s),(a1),(a2),(a3),(a4),(a5))
const char *TransIdToText(Int64 transId)
{
  static char text[256];
  short actualLen;
  short error = TRANSIDTOTEXT(transId, text, 255, &actualLen);
  if (error)
    str_sprintf(text, "(error %d)", (Int32) error);
  else
    text[actualLen] = 0;
  return &text[0];
}
#else
#define StmtDebug0(s)
#define StmtDebug1(s,a1)
#define StmtDebug2(s,a1,a2)
#define StmtDebug3(s,a1,a2,a3)
#define StmtDebug4(s,a1,a2,a3,a4)
#define StmtDebug5(s,a1,a2,a3,a4,a5)
#endif

const char *RetcodeToString(RETCODE r)
{
  switch (r)
  {
    case SUCCESS: return "SUCCESS";
    case SQL_EOF: return "SQL_EOF";
    case ERROR: return "ERROR";
    case WARNING: return "WARNING";
    case NOT_FINISHED: return "NOT_FINISHED";
    default: return ComRtGetUnknownString((Int32) r);
  }
}

#ifdef _DEBUG
#endif  // _DEBUG

class Dealloc
{
  NAHeap *heap_;
  void * addr_;
public:
  Dealloc() : heap_(NULL), addr_(NULL) {}
  ~Dealloc() { if (addr_ != NULL) heap_->deallocateMemory(addr_); }
  NAHeap * setHeap(NAHeap *heap) { return heap_ = heap; }
  void * getAddr(void *addr) { return addr_ = addr; }
};
////////////////////////////////////////////////////////////////////
// class StatementInfo
////////////////////////////////////////////////////////////////////
StatementInfo::StatementInfo()
{
  statement_  = NULL;
  inputDesc_  = NULL;
  outputDesc_ = NULL;
  hashValue_  = 0;
  flags_      = 0;
};

StatementInfo::~StatementInfo()
{
  statement_  = NULL;
  inputDesc_  = NULL;
  outputDesc_ = NULL;
  hashValue_  = 0;
  flags_      = 0;
};

// This function is an internal test mechanism for SPJ result sets
static const char *getProxySyntaxFromEnvironment(CliGlobals *cliGlobals,
                                                 Lng32 rsIndex)
{
  char *stmtText = NULL;


  return stmtText;
}

////////////////////////////////////////////////////////////////////
// class Statement
////////////////////////////////////////////////////////////////////
Statement::Statement(SQLSTMT_ID * statement_id_,
		     CliGlobals * cliGlobals,
                     StatementType stmt_type_,
                     char * cn, Module *module)
  : stmt_state(INITIAL_),
    cliGlobals_(cliGlobals),
    context_(cliGlobals->currContext()),
    clonedFrom_(NULL),
    parentCall_(NULL),
    heap_("Statement Heap",
          context_->exHeap(), 
	  8096  /* 20480 */ /* block size */, 
	  0     /* upperLimit */),
    prevCloseStatement_(NULL),
    nextCloseStatement_(NULL),
    closeSequence_((stmt_type_ == STATIC_STMT) ? 0 : -1)
  , holdable_(SQLCLIDEV_NONHOLDABLE)
  , statementIndex_(0)
  , module_(module)
  , inputArrayMaxsize_(0)   // compile time info for dynamic rowsets
  , rowsetAtomicity_(UNSPECIFIED_)
  , notAtomicFailureLimit_(0)
  , anyTransWasStartedByMe_(FALSE)
  , autoCommitCleared_(FALSE)
  , savedRoVal_(TransMode::READ_WRITE_ )
  , savedRbVal_ (TransMode::ROLLBACK_MODE_NOT_SPECIFIED_ )
  , savedAiVal_( -1 )	       
  , udrSecurity_ (NULL)
  , versionOnEntry_ (COM_VERS_UNKNOWN)
  , versionToUse_ (COM_VERS_UNKNOWN)
  , fetchErrorCode_ (VERSION_NO_ERROR)
  , mxcmpErrorCode_ (VERSION_NO_ERROR)
  , stmtStats_(NULL)
  , extractConsumerQueryTemplate_(NULL)
  , stmtInfo_(NULL)
  , aqrStmtInfo_(NULL)
  , state_(INITIAL_STATE_)  
  , compileStatsArea_(NULL) 
  , spaceObject_(new(context_->exHeap())
    Space(Space::EXECUTOR_SPACE, TRUE, (char *)"Stmt Space"))
  , space_(*spaceObject_)
  , aqrInitialExeStartTime_(-1)
  , compileEndTime_(-1)
{
  cliLevel_ = context_->getNumOfCliCalls();

  space_.setJmpBuf(cliGlobals_->getJmpBuf());
  heap_.setJmpBuf(cliGlobals_->getJmpBuf());

#ifdef NA_DEBUG_C_RUNTIME
  stmtDebug_ = FALSE;
  stmtListDebug_ = FALSE;
  Lng32 numCliCalls = context_->getNumOfCliCalls();

  // We have two printf-style trace mechanisms in the debug build
  //
  // 1. A detailed account of all significant events in the life
  //    of this statement. Enabled by the STMT_DEBUG environment
  //    variable.
  //
  // 2. An account of when this is statement is added to or removed
  //    from any of the context's statement lists. Enabled by the
  //    STMTLIST_DEBUG or STMT_DEBUG environment variable. The code
  //    for this trace is in the ContextCli class. All we do here in
  //    the Statement class is carry a flag indicating whether events
  //    for this instance should be reported.

  // Each trace is enabled on a per-instance basis. We check the
  // environment variables every time through the Statement
  // constructor. Also note that we do NOT enable either trace for
  // statements created internally by SQL/MX code. For those
  // statements, the numCliCalls variable will be greater than one.

  // The commands to create trace output are the StmtDebugX macros
  // above in this source file. In the release build the macros
  // evaluate to a noop.

  if (numCliCalls == 1)
  {
    char *envVar;
    envVar = getenv("STMT_DEBUG");
    if (envVar && envVar[0])
    {
      stmtDebug_ = TRUE;
      stmtListDebug_ = TRUE;
    }
    else
    {
      envVar = getenv("STMTLIST_DEBUG");
      if (envVar && envVar[0])
      {
        stmtListDebug_ = TRUE;
      }
    }
  }
#endif

  StmtDebug1("[BEGIN constructor] %p", this);
  StmtDebug2("  Context address %p, context handle %d",
             context_, (Lng32) context_->getContextHandle());

  clonedStatements = new(&heap_) Queue(&heap_);
  // for now a statement space is allocated from the executor memory
  space_.setParent(context_->exHeap());

  // Set up a space object which might be used during unpacking to allocate
  // additional space for potential upgrading of objects in the plan. This
  // space is derived from heap_, and therefore goes away with it when the
  // statement is destroyed.
  // 
  unpackSpace_ = new(&heap_) Space();
  unpackSpace_->setType(Space::EXECUTOR_SPACE);
  unpackSpace_->setParent(&heap_);

  stmt_type = stmt_type_;

  // Allocate statement-id
  statement_id = (SQLSTMT_ID *)(heap_.allocateMemory(sizeof(SQLSTMT_ID)));
  init_SQLCLI_OBJ_ID(statement_id);

  SQLMODULE_ID* new_module =
       (SQLMODULE_ID *)(heap_.allocateMemory(sizeof(SQLMODULE_ID)));
  init_SQLMODULE_ID(new_module);

  statement_id->module = new_module;
  statement_id->identifier = 0;
  statement_id->handle = 0;
  statement_id->name_mode = statement_id_->name_mode;

  const SQLMODULE_ID* old_module = statement_id_-> module; 

  if(statement_id_->module->module_name)
    {
      Lng32 old_module_nm_len = (Lng32) getModNameLen(old_module);

      char * mn = (char *)(heap_.allocateMemory(old_module_nm_len + 1));
      str_cpy_all(mn,
             statement_id_->module->module_name, old_module_nm_len);

      new_module->module_name_len = old_module_nm_len;
      mn[old_module_nm_len] = 0;
      new_module->module_name = mn;
      StmtDebug1("  Module name: \"%s\"", mn);
    }

  if(statement_id_->identifier)
    {
      Lng32 stmt_name_len = (Lng32) getIdLen(statement_id_);
      char * id =
        (char *)(heap_.allocateMemory(stmt_name_len + 1));

      str_cpy_all(id, statement_id_->identifier, 
		  stmt_name_len);
      statement_id->identifier_len = stmt_name_len;
      id[stmt_name_len] = 0;
      statement_id->identifier = id;
    }
  
  if (context_->aqrInfo() && 
      context_->aqrInfo()->aqrStmtInfo() && 
      (context_->aqrInfo()->aqrStmtInfo()->getSavedStmtHandle() != 0))      
    statement_id->handle=context_->aqrInfo()->aqrStmtInfo()->getSavedStmtHandle();
  else  
    statement_id->handle=(void*)getContext()->getNextStatementHandle();
  StmtDebug1("  New statement handle: %p", statement_id->handle);
    
  default_input_desc = 0;
  default_output_desc = 0;
  
  cursor_name_ = NULL;

  switch (statement_id->name_mode)
  {
  case stmt_handle:
    // nothing to handle for now...
    break;

  case stmt_name:
    // nothing to handle for now...
    break;

  case cursor_name:
    if (cn)
      setCursorName(cn);
    else
      setCursorName(statement_id->identifier);
    break;

  case stmt_via_desc:
  case curs_via_desc:
    {
    SQLDESC_ID tmpDescId;
    if (statement_id->name_mode == stmt_via_desc)
    {
   	init_SQLDESC_ID(&tmpDescId, 
		SQLCLI_CURRENT_VERSION,
		stmt_via_desc,
		statement_id->module,
		statement_id->identifier,
		0,
		SQLCHARSETSTRING_ISO88591,
		(Lng32) getIdLen(statement_id)
    		);
     }
    else
       {
	init_SQLDESC_ID(&tmpDescId,
        SQLCLI_CURRENT_VERSION,
        curs_via_desc,
        statement_id->module,
        statement_id->identifier,
        0,
        SQLCHARSETSTRING_ISO88591,
        (Lng32) getIdLen(statement_id)
        );
	}

    // get the value of the name from the descriptor
    SQLCLI_OBJ_ID* tmpObjId = Descriptor::GetNameViaDesc(&tmpDescId,
           context_,heap_);

    // now that we have used the statement_id->identifier to get the
    // descriptor, we can get rid of it as it won't be used again...
    // NOTE: init_SQLDESC_ID() doesn't make a copy of the identifier so
    //  it isn't safe to free statement_id->identifier until after
    //  the call to GetNameViaDesc().
    if (statement_id->identifier)
    {
      heap_.deallocateMemory((char*)statement_id->identifier);
      statement_id->identifier = 0;
    }

    if (tmpObjId) 
    {
      statement_id->identifier_len = (Lng32) getIdLen(tmpObjId);
      char * id =
        (char *)(heap_.allocateMemory(statement_id->identifier_len + 1));
      if (tmpObjId->identifier) {
        str_cpy_all(id, tmpObjId->identifier,
                    statement_id->identifier_len);
        id[statement_id->identifier_len] = 0;
        // fix memory leak (genesis case 10-981230-3244) 
        // caused by not freeing a non-null tmpString.
        heap_.deallocateMemory((char*)tmpObjId->identifier);
	statement_id->identifier = id;
      }
    
    else
     {
       statement_id->identifier =0;
       statement_id->identifier_len = 0;
     } 
      heap_.deallocateMemory(tmpObjId);
    }

    if(statement_id->identifier == 0)
    {
        // probably an error
    }

    if (statement_id_->name_mode == curs_via_desc)
    {
    // now that the cursor name is set... we don't look in the descriptor
    // again.  The name_mode is now cursor_name *NOT* curs_via_desc.

        setCursorName(statement_id->identifier);
        statement_id->name_mode = cursor_name;
    }
    else
    {
    // now that the statement name is set... we don't look in the descriptor
    // again.  The name_mode is now stmt_name *NOT* stmt_via_desc.

        cursor_name_ = 0;
        statement_id->name_mode = stmt_name;
    }
    }
    break;

  default:
    // error
    break;
  }

#ifdef NA_DEBUG_C_RUNTIME
  switch (statement_id->name_mode)
  {
    case stmt_handle:
      StmtDebug0("  Name mode: stmt_handle");
      break;

    case stmt_name:
      StmtDebug0("  Name mode: stmt_name");
      StmtDebug1("  Statement name: \"%s\"", statement_id->identifier);
      break;

    case cursor_name:
      StmtDebug0("  Name mode: cursor_name");
      StmtDebug1("  Cursor name: \"%s\"", statement_id->identifier);
      break;

    default:
      StmtDebug1("  *** UNKNOWN NAME MODE %d",
                 (Lng32) statement_id->name_mode);
      break;
  }
#endif

  if (statement_id_->version > SQLCLI_STATEMENT_VERSION_1)
    statement_id->tag = statement_id_->tag; 
  else
    statement_id->tag = 0;
  
  currentOfCursorStatement_ = NULL;

  source_str = 0;
  source_length = 0;
  charset_ = SQLCHARSETCODE_ISO88591;

  schemaName_ = NULL;
  schemaNameLength_ = 0;

  recompControlInfo_ = NULL;
  recompControlInfoLen_ = 0;

  root_tdb = 0;
  root_tcb = 0;
  root_tdb_size = 0;

  lnil_ = NULL;
  inputData_ = NULL;
  inputDatalen_ = 0;


  uniqueStmtId_ = NULL;
  uniqueStmtIdLen_ = 0;
  parentQid_ = NULL;
  parentQidSystem_[0] = '\0';

  if (stmt_type_ == STATIC_STMT)
    // STATIC statement. These are already 'prepared'.
    // They are in Close Cursor state.
    setState(CLOSE_);
  
  flags_ = 0;

  setComputeBulkMoveInfo(TRUE);

  statementGlobals_ = 
    new(&heap_) ExMasterStmtGlobals(0, /* fixup will add the real number */
                                    cliGlobals_,
                                    this,
                                    1 /* create gui scheduler */,
                                    &space_,
                                    &heap_);
  
  // set Measure sqlstmt counter flag
  statementGlobals_->setMeasStmtEnabled(cliGlobals_->getMeasStmtEnabled());

  // stored the type in statementGlobals
  if(stmt_type_ == STATIC_STMT){
    statementGlobals_->setStmtType(ExExeStmtGlobals::STATIC);
  }

  if (stmt_type == DYNAMIC_STMT)
    aqrStmtInfo_ = new(&heap_) AQRStatementInfo(&heap_);
  else
    aqrStmtInfo_ = NULL;

  StmtDebug1("[END constructor] %p", this);
  childQueryId_ = NULL;
  childQueryIdLen_ = 0;
  childQueryCostInfo_ = NULL;
  childQueryCompStatsInfo_ = NULL;
} // Statement::Statement

Statement::~Statement()
{
  StmtDebug1("[BEGIN destructor] %p", this);


  dealloc();
  if (compileStatsArea_ != NULL)
  {
    NADELETE(compileStatsArea_, ExStatisticsArea, compileStatsArea_->getHeap());
    compileStatsArea_ = NULL;
  }
  if (statement_id)
    {
      if (statement_id->module)
	{
	  if (statement_id->module->module_name)
	    {
	      heap_.deallocateMemory((char*)statement_id->module->module_name);
	    }
	  heap_.deallocateMemory((char*)statement_id->module);
	  statement_id->module = 0;
	}
      if (statement_id->identifier)
	{
	  heap_.deallocateMemory((char*)statement_id->identifier);
	  statement_id->identifier = 0;
	}
      heap_.deallocateMemory(statement_id);
      statement_id = 0;
    }
  
  if (cursor_name_)
    {
      heap_.deallocateMemory(cursor_name_);
      cursor_name_ = 0;
    }
  
  if (source_str)
    {
      NADELETEBASIC(source_str, context_->exHeap());

      //      heap_.deallocateMemory(source_str);
      source_str = NULL;
    }
  
  // Release the TDB tree. assignRootTdb() does take into account
  // statement cloning and will not actually deallocate memory
  // occupied by the TDB tree if this statement is a clone.
  assignRootTdb(NULL);

  // Delete cloned statements
  // Note: Context should be used to deallocate cloned statements
  //       if the original statement being cloned from is deallocated...
  clonedStatements->position();
  Statement *clone = (Statement *) clonedStatements->getNext();
  for (; clone != NULL; clone = (Statement *) clonedStatements->getNext())
  {
    delete clone;
  }
  
  NADELETE(clonedStatements, Queue, &heap_); 
  
  // Delete child stored procedure result set statements. Note that
  // the context has already removed these child statements from its
  // statement lists before calling this Statement destructor.
  ExRsInfo *rsInfo = getResultSetInfo();
  if (rsInfo)
  {
    ULng32 numChildren = rsInfo->getNumEntries();
    for (ULng32 i = 1; i <= numChildren; i++)
    {
      Statement *rsChild = NULL;
      const char *proxySyntax = NULL;
      NABoolean open = FALSE;
      NABoolean closed = FALSE;
      NABoolean prepared = FALSE;
      NABoolean found = rsInfo->getRsInfo(i, rsChild, proxySyntax,
                                          open, closed, prepared); 
      if (found && rsChild)
        delete rsChild;
    }

    // All the child statements have gone away and this statement is
    // about to go away. We can destroy the ExRsInfo object that was
    // storing information about the children.
    statementGlobals_->deleteResultSetInfo();
  }

  // If this is a stored procedure result set, inform the parent that
  // this child is going away
  if (parentCall_)
  {
    ExRsInfo *rsInfo = parentCall_->getResultSetInfo();
    if (rsInfo)
    {
      StmtDebug1("  About to unbind proxy statement %p ", this);
      rsInfo->unbind(this);
    }
  }

  if (default_input_desc)
    {
      delete default_input_desc;    
      default_input_desc = 0;
    }
  
  if (default_output_desc)
    {
      delete default_output_desc;
      default_output_desc = 0;
    }

  if ( udrSecurity_ )
    {
      if ( udrSecurity_->entries ())
	{
	  for ( UInt32 i=0; i < udrSecurity_->entries (); i++)
	    {
	      delete (*udrSecurity_)[i];
	    }
	    udrSecurity_->clear ();
        } // if udrSecurity_->entries ()
  
      delete udrSecurity_;
      udrSecurity_ = 0;
    } // if udrSecurity_

  StmtDebug1("[END destructor] %p", this);

  if (cliGlobals_->getStatsGlobals() != NULL)
  {
    if (stmtStats_ != NULL)
    {
      short savedPriority, savedStopMode;
      short error = cliGlobals_->getStatsGlobals()->getStatsSemaphore(cliGlobals_->getSemId(),
                    cliGlobals_->myPin(), savedPriority, savedStopMode, FALSE /*shouldTimeout*/);
      ex_assert(error == 0, "getStatsSemaphore() returned an error");
      if (stmtStats_->getMasterStats() != NULL)
	{
	  stmtStats_->getMasterStats()->setStmtState(Statement::DEALLOCATED_);
	  stmtStats_->getMasterStats()->setEndTimes(! stmtStats_->aqrInProgress());
	}
      cliGlobals_->getStatsGlobals()->removeQuery(cliGlobals_->myPin(), stmtStats_);
      cliGlobals_->getStatsGlobals()->releaseStatsSemaphore(cliGlobals_->getSemId(),cliGlobals_->myPin(),
                      savedPriority, savedStopMode);
    }
  }
  else
  {
    if (stmtStats_ != NULL)
    {
      NADELETE(stmtStats_, StmtStats, stmtStats_->getHeap());
    }
  }
  stmtStats_ = NULL;
  if (childQueryId_ != NULL)
  {
    NADELETEBASIC(childQueryId_, &heap_);
    childQueryId_ = NULL;
  }
  if (childQueryCostInfo_ != NULL)
  {
    NADELETEBASIC(childQueryCostInfo_, &heap_);
    childQueryCostInfo_ = NULL;
  }
  if (childQueryCompStatsInfo_ != NULL)
  {   
    NADELETEBASIC(childQueryCompStatsInfo_, &heap_);
    childQueryCompStatsInfo_ = NULL;
  }
  if (spaceObject_ != NULL)
  {
    delete spaceObject_;
    spaceObject_ = NULL;
  }
} // Statement::~Statement

NABoolean Statement::updateInProgress ()
{
  // if there are incomplete insert, delete, update or prepare operations,
  // return TRUE, otherwise return FALSE.
  if (!isPubsubHoldable() 
      )
  {
   if (((getState() == Statement::OPEN_ || 
        getState() == Statement::FETCH_ ||
        getState() == Statement::RELEASE_TRANS_) &&
	(getRootTdb() &&
        (getRootTdb()->updDelInsertQuery() ||
	 getRootTdb()->isEmbeddedUpdateOrDelete()) )
        ) )
     return TRUE;
   }
  return FALSE;
}  

// releaseTransaction is called by Statement::close, Statement::dealloc,
// ContextCli::releaseAllTransactionalRequests and 
// ContextCli::removeFromOpenstatementList.

RETCODE Statement::releaseTransaction(NABoolean allWorkRequests,
				      NABoolean alwaysSendReleaseMsg,
                                      NABoolean statementRemainsOpen)
{
  
  StmtDebug2("[BEGIN releaseTransaction] %p, allWorkRequests = %s",
             this, (allWorkRequests ? "TRUE" : "FALSE"));
  
  // do not send new DML request. 
  statementGlobals_->setNoNewRequest(TRUE);

  if (!statementRemainsOpen               &&  // is holdable cursor?
      root_tcb                            &&
      root_tcb->needsDeregister())
    root_tcb->deregisterCB();

  Int64 cbWaitStartTime = NA_JulianTimestamp();

  statementGlobals_->setNoNewRequest(FALSE);
    
  ExRtFragTable *fragTable = statementGlobals_->getRtFragTable();
  if (fragTable)
    {
      if (root_tcb && root_tcb->fatalErrorOccurred())
        {
          // We can easily get deadlocks from the ESPs at this
          // point, due to producer ESPs' ex_split_bottom_tcb::
          // workState_ set to WAIT_FOR_MORE_REQUESTORS --
          // see solution 10-070108-1544.  This entire statement
          // will soon be deallocated, so place all IpcConnections
          // with pending I/O into the error state.
          fragTable->abandonPendingIOs();
        }
      else
        {
          // For the ESPs, send out the word that we want to get out
          // of the transaction (maybe just temporarily)
	  fragTable->releaseTransaction(allWorkRequests,
					alwaysSendReleaseMsg);
	  
          // Note that for the cancel broker, we have already sent the 
          // finish message -- see the call to deregisterCB in this 
          // method above.
	  
          // wait until the messages have come back
          // (that's all messages if allWorkRequests is set to TRUE,
          // and only the transactional msges if it is FALSE)

	  // how long should we wait for release work reply from esps?
	  // upon timeout we will abort all outstanding I/Os.
	  // some facts below:
	  //
	  //   - default timeout is 15 minutes
	  //   - minimum wait timeout is 5 minutes
	  //   - timeout = -1 means wait indefinitely. but every 2 minutes
	  //     write a timeout message to EMS log.
	  //   - timeout = -2 means that we time out after 2 minutes, then
	  //     abend up to 8 esps that are not responding so we can collect
	  //     saveabend files for debug purpose.
	  //
	  bool waitForever = false;
	  bool abendEsps = false;
	  IpcTimeout timeout = context_->getSessionDefaults()->
                                                getEspReleaseWorkTimeout();
	  if (timeout <= 0)
	    {
	      if (timeout == -1)
		waitForever = true;
	      else if (timeout == -2)
		abendEsps = true;

	      timeout = 2*6000; // 2 minutes
	    }
	  else if (timeout < 5*60)
	    {
	      // minimum timeout is 5 minutes
	      timeout = 5*6000;
	    }
	  else
	    {
	      timeout *= 100;
	    }

          NABoolean hasTimedout;
          while (fragTable->hasOutstandingTransactionalMsges() ||
		 (allWorkRequests && fragTable->hasOutstandingWorkRequests()))
            {
	      if (fragTable->getState() == ExRtFragTable::ERROR)
		{
		  // some error occured
		  context_->diags() << DgSqlCode(-EXE_INTERNAL_ERROR);
		  ComDiagsArea *diagsPtr = statementGlobals_->getDiagsArea();
		  if (diagsPtr)
		    context_->diags().mergeAfter(*diagsPtr);

		  // abort all outstanding I/Os
		  fragTable->abandonPendingIOs();
		  break;
		}

              // wait for an I/O to complete, we know there are some
              // transaction requests that should complete...
              statementGlobals_->getIpcEnvironment()->getAllConnections()->
	        waitOnAll(timeout, FALSE, &hasTimedout);

              if (hasTimedout)
                {
                  // timed out waiting for esp reply. something is wrong.
                  char errMsg[200];
                  str_sprintf(errMsg, "Statement still has %d connections with I/O outstanding - %d trans msgs and %d work reqs.",
			      statementGlobals_->getIpcEnvironment()
                              ->getAllConnections()->getNumPendingIOs(),
			      fragTable->numOutstandingTransactionalMsges(),
			      fragTable->numOutstandingWorkRequests());

		  if (!waitForever)
		    {
		      context_->diags() << DgSqlCode(-EXE_RELEASE_WORK_TIMEOUT)
					<< DgString0(errMsg);

		      if (abendEsps)
			{
			  // abend up to 8 esps so we can collect saveabend
			  // files for debug purpose.
			  CollIndex numEsps = 8;
			  GuaProcessHandle phandles[8];
			  statementGlobals_->getIpcEnvironment()->getAllConnections()->
			    fillInListOfPendingPhandles(phandles, numEsps);

			  char logMsg[300];
			  char *initMsg= (char *)" Executor abended non-responding ESPs ";
			  memset(logMsg, '\0', sizeof logMsg);
			  str_cat(logMsg, initMsg, logMsg);
			  for (CollIndex i = 0; i < numEsps; i++)
			    {
                              // abend esp with saveabend file
                              phandles[i].dumpAndStop(true, true);
			      if (i > 0)
				str_cat(logMsg, ", ", logMsg);
			      phandles[i].toAscii(logMsg + str_len(logMsg), 300 - str_len(logMsg));
			    }
			  str_cat(logMsg, ".", logMsg);

			  context_->diags() << DgString1(logMsg);
			} // if (abendEsps)

		      // abort all outstanding I/Os
		      fragTable->abandonPendingIOs();
		      break;
		    } // if (!waitForever)
		  else
		    {
		      // wait forever. log a warning msg and go back to wait.
		      char logMsg[500];
		      const char *initMsg="Query looping while waiting for release work reply from ESPs ";
		      logMsg[0] = '\0';
		      str_cat(logMsg, initMsg, logMsg);
		      // pins of waited processes are concatenated to logMsg
		      // each pin should be 28 bytes or less
		      statementGlobals_->getIpcEnvironment()->getAllConnections()->
			fillInListOfPendingPins(logMsg + str_len(initMsg),
						300 - str_len(initMsg), 8);
		      str_cat(logMsg, ". ", logMsg);
		      str_cat(logMsg, errMsg, logMsg);
		      SQLMXLoggingArea::logExecRtInfo("Statement.cpp", 0, logMsg, 0);
		    }
                } // if (hasTimedout)
	      else
		{
		  // we did not timeout because some I/O completed first.
		  // now do some work on the fragment dir.
		  if (fragTable->getState() != ExRtFragTable::ERROR)
		    {
		      fragTable->workOnRequests();
		    }
		  else
		    {
		      // some error occured
		      context_->diags() << DgSqlCode(-EXE_INTERNAL_ERROR);
		      ComDiagsArea *diagsPtr = statementGlobals_->getDiagsArea();
		      if (diagsPtr)
			context_->diags().mergeAfter(*diagsPtr);

		      // abort all outstanding I/Os
		      fragTable->abandonPendingIOs();
		      break;
		    }
		}
            } // while (..)
        } // if (root_tcb && ..)
    } // if (fragTable)

  // In most case, the wait loop above will ensure that cancel broker messages
  // are now complete.  However, if there is no fragTable, or there was
  // fatalErrorOccurred or if in the wait loop some problem happened that
  // caused the loop to exit early, then here we must wait for cancel broker
  // to reply to start  and finish message.
  if (root_tcb && !statementRemainsOpen)
    root_tcb->cbMessageWait(cbWaitStartTime);

  // If there is an error either in Context diagsArea or
  // in StatementGlobals_ diagsArea, do not update the end time
  ComDiagsArea *diagsArea = context_->getDiagsArea();
  if (diagsArea->mainSQLCODE() >= 0 && stmtStats_ != NULL &&
    stmtStats_->getMasterStats() != NULL && (! stmtStats_->aqrInProgress())
      && stmtStats_->getMasterStats()->getExeEndTime() == -1)
  {
    Int64 exeEndTime = NA_JulianTimestamp();
    stmtStats_->getMasterStats()->setExeEndTime(exeEndTime);
    stmtStats_->getMasterStats()->setElapsedEndTime(exeEndTime);
  }

  // If this is a CALL statement that can produce result sets (as
  // indicated by a non-NULL return value from getResultSetInfo())
  // then we may need to tell the UDR server to release this
  // transaction.
  ExRsInfo *rsInfo = getResultSetInfo();
  if (rsInfo)
  {
    StmtDebug0("  About to call ExRsInfo::suspendUdrTx()...");
    rsInfo->suspendUdrTx(*statementGlobals_);
    StmtDebug0("  Done");
  }

  // Make sure there are no outstanding transactional UDR requests
  completeUdrRequests(allWorkRequests);

  
  // Ideally, we would want to set this state for all cursors.
  // But we found that setting it for all results in an unnecessary call to
  // removeFromOpenStatementList() when the state is changed from RELEASE_TRANS_ 
  // to CLOSE_ even when the cursor was already closed earlier.
  if (isAnsiHoldable())
    setState(RELEASE_TRANS_);
  else
  if (isPubsubHoldable())
  {
    if (! getRootTdb()->getPsholdUpdateBeforeFetch())
      setState(RELEASE_TRANS_);
  }

  StmtDebug1("[END releaseTransaction] %p", this);
  return SUCCESS;
}

void Statement::releaseEsps(NABoolean closeAllOpens)
{
  if (!statementGlobals_)
    return;

  ExRtFragTable *fragTable = statementGlobals_->getRtFragTable();
  if (!fragTable)
    return;

  fragTable->releaseEsps(closeAllOpens);
	  
  // wait until all release esp replies have come back
  NABoolean hasTimedout;
  IpcTimeout espReleaseTimeout;
  espReleaseTimeout = context_->getEspReleaseTimeout();
  if (espReleaseTimeout != -1)
    espReleaseTimeout *= 6000;
  while (fragTable->hasOutstandingReleaseEspMsges())
    {
      statementGlobals_->getIpcEnvironment()->getAllConnections()->
        waitOnAll(5*6000, FALSE, &hasTimedout);// Wait up to 5 minutes
      if (hasTimedout)
        {
          // not all replied after 5 minutes, something is wrong
          char msg[300];
          str_sprintf(msg, "Timedout! Still have %d release esp messages and %d I/O outstanding.",
                      fragTable->numOutstandingReleaseEspMsges(),
                      statementGlobals_->getIpcEnvironment()
                      ->getAllConnections()->getNumPendingIOs());
          SQLMXLoggingArea::logExecRtInfo("Statement.cpp", 0, msg, 0);
          // abort remaining release esp msgs
          fragTable->abandonPendingIOs();
        } // if (hasTimedout)
    } // while
}

RETCODE Statement::bindTo(Statement * stmt)
{
  StmtDebug2("[BEGIN bindTo] Binding clone %p to master %p",
             this, stmt);

  root_tdb = stmt->root_tdb;
  clonedFrom_ = stmt;
  setState(CLOSE_); // does this work here????
  setCloned();
  stmt->clonedStatements->insert((void *) this);

  StmtDebug0("[END bindTo]");
  return SUCCESS;
}

bool Statement::isOpen()
{
  switch (stmt_state)
  {
    case OPEN_:
    case FETCH_:
    case EOF_:
    case PREPARE_:
    case RELEASE_TRANS_:
    case INITIAL_:
      return true;
    default:
      return false;
  }
}

RETCODE Statement::close(ComDiagsArea &diagsArea, NABoolean inRollback)
{  
  StmtDebug2("[BEGIN close] %p, stmt state %s", this, stmtState(getState()));
  RETCODE rc = SUCCESS;
  NABoolean readyToReturn = FALSE;

  if (!isOpen())
  {
      // trying to close a statement which is already in closed state
      diagsArea << DgSqlCode(- CLI_STMT_NOT_OPEN);
    rc = ERROR;
    readyToReturn = TRUE;
  }

  NABoolean closingEmbeddedIUDCursorPrematurely = FALSE; 

  if (!readyToReturn)
  {
    if ((stmt_state == OPEN_) && 
        (root_tdb && root_tdb->isEmbeddedIUDWithLast1()))
    {
      closingEmbeddedIUDCursorPrematurely = TRUE;
    }

    // Update stmtGlobals transid with current transid.
    // The stmtGlobals transid is used in sending release msg to remote esps.
    // The context transid can be obsolete if the transaction has been 
    // committed/aborted by the user.
    Int64 transid;
    if (!context_->getTransaction()->getCurrentXnId(&transid))
      getGlobals()->castToExExeStmtGlobals()->getTransid() = transid;
    else 
      getGlobals()->castToExExeStmtGlobals()->getTransid() = (Int64)-1;

  // cancel the down request to my child
    if (root_tcb)
    {
      ComDiagsArea *diagsPtr = NULL;

      // pass flag to cancel to collect diags from queue entries 
      // if stmt_state is OPEN_.  This is needed to pick up diags
      // info from failed DDL operations.
      NABoolean pickUpDiags =
        (   // False if DML, true otherwise
           (root_tdb->getQueryType() < ComTdbRoot::SQL_SELECT_UNIQUE)     ||
           (root_tdb->getQueryType() > ComTdbRoot::SQL_DELETE_NON_UNIQUE)
        );

      Int32 rc1 =
      root_tcb->cancel(statementGlobals_, diagsPtr, pickUpDiags);

      StmtDebug1("  root_tcb->cancel() returned %s",
                 RetcodeToString((RETCODE) rc1));
      if (diagsPtr)
	{
	  diagsArea.mergeAfter(*diagsPtr);
	  diagsPtr->decrRefCount();    
          diagsPtr = NULL;
	}
      if (root_tcb->fatalErrorOccurred())
        {
          dealloc();
          space_.freeBlocks();
          statementGlobals_->reAllocate(1);
          setFixupState(0);
        }
    }
  }

  if (!readyToReturn)
  {
    // If this statement has stored procedure result set children,
    // then close each child. Ignore errors encountered while closing
    // the children.
    ExRsInfo *rsInfo = getResultSetInfo();
    if (rsInfo)
    {
      ULng32 numChildren = rsInfo->getNumEntries();
      StmtDebug0("  About to close all result set proxy statements");
      StmtDebug1("  Num RS children: %d", (Lng32) numChildren);

      ComDiagsArea *diagsFromProxy = NULL;

      for (ULng32 i = 1; i <= numChildren && !readyToReturn; i++)
      {
        Statement *proxyStmt = NULL;
        const char *proxySyntax = NULL;
        NABoolean open = FALSE;
        NABoolean closed = FALSE;
        NABoolean prepared = FALSE;
        NABoolean found = rsInfo->getRsInfo(i, proxyStmt, proxySyntax,
                                            open, closed, prepared);

        if (found && proxyStmt && proxyStmt->stmt_state != CLOSE_)
        {
          if (diagsFromProxy == NULL)
            diagsFromProxy = ComDiagsArea::allocate(&heap_);

          RETCODE rcFromProxy = proxyStmt->close(*diagsFromProxy);
          diagsFromProxy->clear();
        }

      } // for each proxy

      if (diagsFromProxy)
        diagsFromProxy->deAllocate();

      StmtDebug0("  About to call ExRsInfo::exitUdrTx()...");
      rsInfo->exitUdrTx(*statementGlobals_);
      StmtDebug0("  Done");
      rsInfo->reset();
    } // if (rsInfo)
  
    // release all work requests for the statement
    if (context_->getSessionDefaults()->getAltpriEsp())
      releaseTransaction(TRUE, TRUE);
    else
      releaseTransaction(TRUE, FALSE);

    setState(CLOSE_);

    if (closingEmbeddedIUDCursorPrematurely)
    {
      diagsArea << DgSqlCode(- CLI_IUD_IN_PROGRESS) << DgString0(getCursorName()->identifier);
      if (rollbackTransaction(diagsArea))
          return ERROR;
    }

    // stop the transaction, if one was started and if we are not
    // currently rolling back this transaction
    if (!inRollback)
    {
      if ((root_tdb && root_tdb->transactionReqd()) ||
          ((context_->getTransaction()->xnInProgress()) &&
          (context_->getTransaction()->exeStartedXn()) &&
          (context_->getTransaction()->autoCommit()) &&
          (autocommitXn())))
        {
          if (commitTransaction(diagsArea))
          {
            rc = ERROR;
            readyToReturn = TRUE;
          }
        }
    } // !inRollback
  } // !readyToReturn
  updateStatsAreaInContext();
  // Get rid of child query info if there is any
  if (childQueryId_ != NULL)
  {
    NADELETEBASIC(childQueryId_, &heap_);
    childQueryId_ = NULL;
    childQueryIdLen_ = 0;
  }
  if (childQueryCostInfo_ != NULL)
  {
    NADELETEBASIC(childQueryCostInfo_, &heap_);
    childQueryCostInfo_ = NULL;
  }
  if (childQueryCompStatsInfo_ != NULL)
  {
    NADELETEBASIC(childQueryCompStatsInfo_, &heap_);
    childQueryCompStatsInfo_ = NULL;
  }

  // clear transId from statement globals as it is no longer needed
  // this is to avoid reuse the transId when deleting the statement
  statementGlobals_->getTransid() = (Int64)-1;

  StmtDebug2("[END close] %p, result is %s", this,
             RetcodeToString(rc));
  return rc;
}

static inline void diagsTakeOver(ComDiagsArea &diagsArea,
				 CliGlobals *cliGlobals,
                                  short indexIntoCompilerArray)
{
  ComDiagsArea &exec_diags =
    *cliGlobals->getArkcmp(indexIntoCompilerArray)->getDiags();
  if (&diagsArea != &exec_diags)
    {
      if (diagsArea.getFunction() == ComDiagsArea::NULL_FUNCTION)
	diagsArea.setFunction(exec_diags.getFunction());
      diagsArea.mergeAfter(exec_diags);
      exec_diags.clear();
    }
}

NABoolean Statement::isDISPLAY()
{
  QueryText qt(source_str, charset_);
  return qt.isDISPLAY();
}

NABoolean Statement::isExeDebug(char *src, Lng32 charset)
{
  if (!src) {
    return FALSE;
  }
  else {
    if (charset == SQLCHARSETCODE_UCS2) {
          NAWchar* p = (NAWchar*)(src) + 7;
         
          return  p[0] == NAWchar('$') &&
                  p[1] == NAWchar('Z') &&
                  p[2] == NAWchar('Z') &&
                  p[3] == NAWchar('E') &&
                  p[4] == NAWchar('X') &&
                  p[5] == NAWchar('E') &&
                  p[6] == NAWchar('D') &&
                  p[7] == NAWchar('E') &&
                  p[8] == NAWchar('B') &&
                  p[9] == NAWchar('U') &&
                  p[10] == NAWchar('G') ;
    }
    else {
	  return str_cmp(src+7, "$ZZEXEDEBUG", str_len("$ZZEXEDEBUG")) == 0;
    }
  }
}

Int32 Statement::octetLen(char *s, Lng32 charset)
{
#pragma nowarn(1506)   // warning elimination 
  return charset==SQLCHARSETCODE_UCS2 ?  
    na_wcslen((const NAWchar*)s) * 
    CharInfo::maxBytesPerChar((CharInfo::CharSet)charset) : str_len(s);
#pragma warn(1506)  // warning elimination
}

Int32 Statement::octetLenplus1(char *s, Lng32 charset)
{
#pragma nowarn(1506)   // warning elimination 
  return charset==SQLCHARSETCODE_UCS2 ? 
    (na_wcslen((const NAWchar*)s)+1)*
    CharInfo::maxBytesPerChar((CharInfo::CharSet)charset) : str_len(s)+1;
#pragma warn(1506)  // warning elimination 
}

Int32 Statement::sourceLenplus1()
{
  return (source_length+1)*CharInfo::maxBytesPerChar((CharInfo::CharSet)charset_);
}

RETCODE Statement::prepareReturn ( const RETCODE retcode)
{
  if (versionToUse_ != versionOnEntry_)
  {
    // We changed the current compiler, reset it
    short index;
    getContext()->setOrStartCompiler(versionOnEntry_, NULL, index);
  }

  // Unconditionally reset version on entry.
  versionOnEntry_ = COM_VERS_UNKNOWN;
  if (retcode != NOT_FINISHED)
  {
    // We're done with the prepare, reset the version we used
    versionToUse_ = COM_VERS_UNKNOWN;
  }

  return retcode;
}

/*
NABoolean Statement::isStandaloneQ()
{
  NABoolean standaloneQ = FALSE;

  // if query from mxcs and the statement name starts with "SQL_CUR_",
  // then it is a standalone query. This is standard and guaranteed
  // mxcs behavior.
  // or if query is from mxci and the statement name starts 
  // with "__SQLCI_", then it is a standalone query.
  if ((getContext()->getSessionDefaults()->getOdbcProcess()) &&
      (statement_id->identifier_len > 0) &&
      (strncmp(statement_id->identifier, "SQL_CUR_", strlen("SQL_CUR_")) == 0))
    {
    standaloneQ = TRUE;
    }
  else if ((getContext()->getSessionDefaults()->getMxciProcess()) &&
	   (statement_id->identifier_len > 0) &&
	   (strncmp(statement_id->identifier, "__SQLCI_DML_", strlen("__SQLCI_DML_")) == 0))
    {
      standaloneQ = TRUE;
    }
  
  return standaloneQ;
}
*/
RETCODE Statement::prepare(char *source, ComDiagsArea &diagsArea,
			   char *passed_gen_code, 
			   ULng32 passed_gen_code_len,
			   Lng32 charset,
			   NABoolean unpackTdbs,
			   ULng32 cliFlags)
{
  StmtDebug1("[BEGIN prepare] %p", this);
  StmtDebug1("  Source: %s",
             source ? source : (source_str ? source_str : "(NULL)"));

  state_ = INITIAL_STATE_;

  if (aqrReprepareNeeded())
    setAqrReprepareNeeded(FALSE);

  if (NOT ((! (cliFlags & PREPARE_AUTO_QUERY_RETRY)) &&
	   (cliFlags & PREPARE_STANDALONE_QUERY) &&
	   source &&
	   (stmt_type == DYNAMIC_STMT) &&
	   unpackTdbs &&
	   (context_->getNumOfCliCalls() == 1)))
    {
      // do not use query text cache for explicitely prepared queries.
      cliFlags |= PREPARE_NO_TEXT_CACHE;
    }
  
  if (context_->aqrInfo())
    context_->aqrInfo()->setXnStartedAtPrepare(FALSE);
  
  RETCODE rc = prepare2(source, diagsArea, 
			passed_gen_code, passed_gen_code_len,
			charset, unpackTdbs, cliFlags);

  StmtDebug2("[END prepare] %p, result is %s", this, RetcodeToString(rc));
  return rc;
}

RETCODE Statement::prepare2(char *source, ComDiagsArea &diagsArea,
                            char *passed_gen_code, 
			    ULng32 passed_gen_code_len,
			    Lng32 charset,
			    NABoolean unpackTdbs,
			    ULng32 cliFlags)
{
  ULng32 fetched_gen_code_len = 0L;
  char *fetched_gen_code = NULL;
  short retcode = SUCCESS;   
  short indexIntoCompilerArray = 0;
#ifdef NA_CMPDLL
     
  // if there is any error using embedded cmpiler and we will switch to regular compiler
  NABoolean canUseEmbeddedArkcmp = ((cliFlags & PREPARE_USE_EMBEDDED_ARKCMP) != 0) ; // This flag 
  // will be set only by the master. If a Prepare call is made from the 
  // compiler(including the embedded compiler), it will use the regular compiler.
#endif // NA_CMPDLL

  ExSqlComp::OperationStatus status;
  Dealloc dealloc; // DTOR calls NAHeap::deallocateMemory for an object

  //  NABoolean newOperation = TRUE;
  NABoolean newOperation = (NOT ((cliFlags & PREPARE_NOT_A_NEW_OPERATION) != 0));
  NABoolean reComp       = (cliFlags & PREPARE_RECOMP) != 0;
  NABoolean aqRetry      = (cliFlags & PREPARE_AUTO_QUERY_RETRY) != 0;
  NABoolean deCache      = (cliFlags & PREPARE_WITH_DECACHE) != 0;
  NABoolean noTextCache  = (cliFlags & PREPARE_NO_TEXT_CACHE) != 0;
  NABoolean standaloneQuery = (cliFlags & PREPARE_STANDALONE_QUERY) != 0;
  this->setStandaloneQ(standaloneQuery);

  NABoolean wmsMonitoringNeeded = (cliFlags & PREPARE_MONITOR_THIS_QUERY) !=0;

  this->setWMSMonitorQuery(wmsMonitoringNeeded);
  // Remove compileStatsArea, if it exists
  if (compileStatsArea_  != NULL)
  {
    NADELETE(compileStatsArea_, ExStatisticsArea, compileStatsArea_->getHeap());
    compileStatsArea_ = NULL;
  }
  // We should not do prepares on a cloned statement. Clones share a
  // TDB tree with some other statement and compiles/recompiles should
  // always be done by that other statement.
  ex_assert(!isCloned(),
            "Statement::prepare() should not be called on a clone");

  // We may be doing a prepare for two reasons: 1) as part of a
  // dynamic SQL PREPARE operation or 2) as part of automatic
  // recompilation. The first case includes such things as 
  // EXECUTE IMMEDIATE and internal calls to prepare statements.
  // 
  // The value returned by the noWaitOpPending() member in the Statement 
  // object must be interpreted very carefully here, because its 
  // meaning depends on which of these two cases
  // we are in. In the first case, where we are doing an explicit
  // prepare, noWaitOpPending() TRUE implies that we are trying
  // to start a new explicit operation on a statement that already
  // has a no-wait operation in progress. This is a user error,
  // and is raised as such in this method.
  //
  // In the second case, however, this method has been called
  // from another Statement method to do an automatic recompilation.
  // If noWaitOpPending() == TRUE in this case, it is because the
  // calling method is processing an outstanding no-wait operation.
  // So, for example, we might be attempting an automatic
  // recompilation while redriving a no-wait fetch. This is not
  // a user error; in fact we want the automatic recompilation
  // to succeed.
  //
  // The way to distinguish these two cases is to consider the
  // reComp parameter. If it is FALSE, we know it is the first
  // case. If it is TRUE, we know it is the second.
  //
  // For the moment, we make all automatic recompilations waited,
  // even if we are redriving a no-wait operation. The reason we
  // do this is the Statement object lacks the state, and the
  // calling methods lack the logic, to detect on a redrive that
  // a no-wait automatic recompilation is in effect. This is a 
  // refactoring opportunity for a clever developer in a future 
  // release ;-).
  //
  // Note that since we make automatic recompilations waited,
  // we treat the noWaitOpEnabled_ flag differently in this case
  // as well.
  //
  // In this method, then, instead of testing noWaitOpPending_
  // directly, we use the following flag which takes reComp
  // into account.


  Lng32 rsa = getRowsetAtomicity();
  if (context_->getSessionDefaults()->getRowsetAtomicity() != -1)
    rsa = context_->getSessionDefaults()->getRowsetAtomicity(); //NOT_ATOMIC_;
#ifdef NA_CMPDLL
  //  if (context_->getSessionDefaults()->callEmbeddedArkcmp() && canUseEmbeddedArkcmp && !aqRetry)
  //  {
      if (canUseEmbeddedArkcmp && !context_->isEmbeddedArkcmpInitialized())
        {
          Int32 embeddedArkcmpSetup;
       	  // embeddedArkcmpSetup = arkcmp_main_entry();
       	  embeddedArkcmpSetup = context_->switchToCmpContext((Int32)0);
          if (embeddedArkcmpSetup == 0)           
            {
	      context_->setEmbeddedArkcmpIsInitialized(TRUE);
              //    context_->setEmbeddedArkcmpContext(CmpCommon::context());
            }
          else if (embeddedArkcmpSetup == -2)
            {
              diagsArea << DgSqlCode(-2079);
              return ERROR;
            }
          else
            {
              context_->setEmbeddedArkcmpIsInitialized(FALSE);
	      context_->setEmbeddedArkcmpContext(NULL);
            }
        }
      // Set the Global CmpContext from the one saved in the CLI context
      // for proper operation
      if (context_->isEmbeddedArkcmpInitialized() &&
          context_->getEmbeddedArkcmpContext())
      {
          cmpCurrentContext = context_->getEmbeddedArkcmpContext();
      }
      //   }
#endif // NA_CMPDLL
    
  if (newOperation)
    assert ((aqRetry && source) ||
	    ((!reComp) || (reComp && (!source))));

  if ((reComp) && (stmt_type == STATIC_STMT))
    {
    }
#ifdef _DEBUG
  if (getenv("TEST_INFO_EVENT"))
    {

      SQLMXLoggingArea::logSQLMXEventForError(0000, "Dummy Error with Dummy SQCode and QID", "DummyQID", FALSE);

      SQLMXLoggingArea::logExecRtInfo("Statement.cpp",999,"Testing info event", 999);
      
      SQLMXLoggingArea::logSQLMXAbortEvent("Statement.cpp",888, "testing abort event");
      SQLMXLoggingArea::logSQLMXAssertionFailureEvent("Statement.cpp",777,"testing assertion failure");
      SQLMXLoggingArea::logSQLMXDebugEvent("debug event" ,69,__LINE__);
      
      SQLMXLoggingArea::logMVRefreshInfoEvent("mv refresh info");
      SQLMXLoggingArea::logMVRefreshErrorEvent("mv refresh error");

      SQLMXLoggingArea::logCliReclaimSpaceEvent(100,200,300,400);

      SQLMXLoggingArea::logCompNQCretryEvent("select * from t1 where a > 10");
      SQLMXLoggingArea::logSortDiskInfo("disk101", 25, 2080);

      const char msgT[] = "SQL compiler: Optimization failed at pass two or higher. " 
                          "Execution will use the plan generated at pass one instead.";

      SQLMXLoggingArea::logSQLMXPredefinedEvent(msgT, LL_WARN);
    }
 #endif
  
  if (passed_gen_code)
    {
      // it is legal for passed_gen_code to be passed in as NULL here!
      copyGenCode(passed_gen_code, passed_gen_code_len, FALSE);

      
    }
  else if ((source) ||               // source is passed in. Preparing a stmt.
	   ((!source) && (reComp)) || // recompiling a statement at runtime.
	    !newOperation)
    {
      if (isExeDebug(source, charset))
	{
	  NADebug();
	  diagsArea << DgSqlCode(- CLI_STMT_NOT_PREPARED);
          // OK to return directly, we haven't done anything to
          // the current compiler settings yet
	  return ERROR;
	}
      
      if (context_->checkAndSetCurrentDefineContext())
	{

	     // define context changed, kill arkcmps, if they are runing.
             for (short i = 0; 
		  i < getContext()->getNumArkcmps();
		  i++)
	       cliGlobals_->getArkcmp(i)->endConnection();

	}

      // Get the version of compiler to use initially. There are several possibilities.
      // a) No particular version compiler is required, we use whatever is the current version.
      // b) The compiler version was explicitly set from outside, using setOrStartCompiler.
      //    This may happen for automatic retry of plan version errors, and for certain DDL
      //    operations.
      // c) The compiler version was requested, using the versionToUse_ data member.
      //    This may happen if a non-retryable statement encountered a plan version error.
      // In all cases, save whatever version was the default for our caller since prepare
      // may automatically set the compiler version further down the road.
      // 
      versionOnEntry_ = context_->getVersionOfCompiler();
      if (newOperation && (versionToUse_ == COM_VERS_UNKNOWN))
      {
        // This is a new prepare, and a particular version was not requested.
        // Use the version from the context.
        indexIntoCompilerArray = context_->getIndexToCompilerArray();  
        versionToUse_ = versionOnEntry_;
      }
      else
      {
        // This is a redrive of a nowait prepare, or a particular version was requested.
        // Use whatever we used originally/whatever is requested.
        getContext()->setOrStartCompiler(versionToUse_, NULL, indexIntoCompilerArray);
      }

      // From this point on, do not return directly as that will mess up the current compiler version.
      // Instead, do 
      //    return prepareReturn (<retcode>);
      short retry = TRUE;
      char * data = NULL;
      ULng32 dataLen = 0;
      ExSqlComp::Operator op;
      char * rlnilBuf = NULL;
      ULng32 rlnilLen = 0;
      while (retry)
	{
	  if (newOperation)
	    {

	      // Build request and send to arkcmp. 
	      if ((reComp) || (aqRetry && deCache))
		{
		  if ((reComp) && (root_tdb))
		    {
		      if (root_tdb->getLateNameInfoList())
			if ((root_tdb->getPlanVersion() < COM_VERS_R2_3) ||
			    (versionToUse_ < COM_VERS_R2_3))
			  
			  {
			    rlnilLen= root_tdb->getLateNameInfoList()->
			      getRecompLateNameInfoListLenPre1800();
			    
			    rlnilBuf = new(&heap_) char[rlnilLen];
			    root_tdb->getLateNameInfoList()->
			      getRecompLateNameInfoListPre1800(rlnilBuf);
			  }
			else
			  {
			    rlnilLen = 
			      root_tdb->getLateNameInfoList()->getRecompLateNameInfoListLen();
			    
			    rlnilBuf = new(&heap_) char[rlnilLen];
			    root_tdb->getLateNameInfoList()->
			      getRecompLateNameInfoList(rlnilBuf);
			  }
		    }
		  
		  CmpCompileInfo c((reComp ? source_str : source), 
				   (reComp ? sourceLenplus1() : octetLenplus1(source, charset)),
				   (Lng32) (reComp ? charset_ : charset),
				   (RecompLateNameInfoList *)rlnilBuf,
				   (Lng32) rlnilLen,
				   schemaName_, schemaNameLength_+1, 
				   recompControlInfo_, recompControlInfoLen_,
				   getInputArrayMaxsize(), (short)rsa);

		  if (aqRetry)
		    c.setAqrPrepare(aqRetry);
		  else if (noTextCache)
		  c.setNoTextCache(noTextCache);
		  
		  if (standaloneQuery)
		    c.setStandaloneQuery(standaloneQuery);

		  // set the nametype that was specified when this stmt was
		  // statically compiled. mxcmp will resolve table names based on
		  // this nametype. This field is only valid for auto recomp of
		  // static stmts. It is not looked at for dynamic stmt.
		  c.setNametypeNsk(nametypeNsk());
		  
		  // if this statement was statically compiled with odbc process
		  // on, then set it here. This will be used at auto recomp time.
		  c.setOdbcProcess(odbcProcess());
		  c.setSystemModuleStmt(systemModuleStmt());   
                  c.setAnsiHoldable(isAnsiHoldable());
                  c.setPubsubHoldable(isPubsubHoldable());
              	  dataLen = c.getLength();
		  // Dealloc dtor will deallocate the memory allocated by next statement
		  data = (char *)dealloc.getAddr
		    (new(dealloc.setHeap(&heap_)) char[dataLen]);
		  c.pack(data);
		  if (rlnilBuf)
		    NADELETEBASIC(rlnilBuf, &heap_);
		  rlnilBuf = NULL;
		  
		  // Release the existing TDB tree if one exists
		  assignRootTdb(NULL);
		  
		  op = (getStatementType() == DYNAMIC_STMT) ?
		    EXSQLCOMP::SQLTEXT_RECOMPILE :
		    EXSQLCOMP::SQLTEXT_STATIC_RECOMPILE;
		  
		  
		  // The R1.8 compiler does not understand the above type
		  // EXSQLCOMP::SQLTEXT_STATIC_RECOMPILE. So if we are talking
		  // to an R1.8 compiler then we have to change the type to
		  // EXSQLCOMP::SQLTEXT_STATIC_COMPILE
		  
		  if (cliGlobals_->getArkcmp(indexIntoCompilerArray)->
		      getVersion() == COM_VERS_R1_8 )
		    {
		      op = (getStatementType() == DYNAMIC_STMT) ?
			EXSQLCOMP::SQLTEXT_RECOMPILE :
			EXSQLCOMP::SQLTEXT_STATIC_COMPILE;
		    }
		} // recompiling statement
	      else
		{
		  CmpCompileInfo c(source, octetLenplus1(source, charset), (Lng32) charset,
				   NULL, 0, NULL, 0, NULL, 0,
				   getInputArrayMaxsize(), (short)rsa);

		  if (aqRetry)
		    c.setAqrPrepare(aqRetry);
		  else if (noTextCache)
		  c.setNoTextCache(noTextCache);

		  if (standaloneQuery)
		    c.setStandaloneQuery(standaloneQuery);
        	  c.setAnsiHoldable(isAnsiHoldable());
                  c.setPubsubHoldable(isPubsubHoldable());
                  dataLen = c.getLength();
		  // Dealloc dtor will deallocate the memory allocated by next statement
		  data = (char *)dealloc.getAddr
		    (new(dealloc.setHeap(&heap_)) char[dataLen]);
		  c.pack(data);
		  
		  op = EXSQLCOMP::SQLTEXT_COMPILE;
		}
	      
                
	      // send request
	      // request is nowaited if noWaitOpEnabled and not recompile
	      NABoolean waited = TRUE;

              // Use the embedded compiler first
              if (context_->getSessionDefaults()->callEmbeddedArkcmp() && 
		  canUseEmbeddedArkcmp && 
		  context_->isEmbeddedArkcmpInitialized() &&
		  CmpCommon::context() && (CmpCommon::context()->getRecursionLevel() == 0))
		  //!aqRetry  && cliGlobals_->isEmbeddedArkcmpInitialized())
                {
                  Int32 compStatus;
                  ComDiagsArea *da = ComDiagsArea::allocate(&heap_);

                  // clean up diags area of regular arkcmp, it could contain
                  // old errors from last use
                  if (cliGlobals_->getArkcmp() &&
                      cliGlobals_->getArkcmp()->getDiags())
                     cliGlobals_->getArkcmp()->getDiags()->clear();

                  compStatus = CmpCommon::context()->compileDirect(
                                   (char *)data, dataLen,
                                   // use arkcmp heap to store the plan
                                   cliGlobals_->getArkcmp(indexIntoCompilerArray)->getHeap(),
                                   charset, op,
                                   fetched_gen_code, fetched_gen_code_len,
                                   context_->getSqlParserFlags(), 
                                   NULL, 0, da);

                  diagsArea.mergeAfter(*da);
                  da->decrRefCount();

                  if (compStatus == ExSqlComp::SUCCESS)
                    {
                      // break from the while (retry) loop
                      break;
                    }
                  else
		    {
		      diagsArea << DgSqlCode(- CLI_STMT_NOT_PREPARED);
		      if (diagsArea.getRollbackTransaction())
		     	rollbackTransaction(diagsArea);
		      return prepareReturn (ERROR);
		    }
                }

	      ExSqlComp::ReturnStatus sendStatus = 
		cliGlobals_->getArkcmp(indexIntoCompilerArray)->sendRequest(
		     op, data, dataLen,
		     waited, 
		     0, charset, TRUE);
	      
	      if ( sendStatus == ExSqlComp::ERROR || 
		   sendStatus == ExSqlComp::WARNING )
		{
		  diagsTakeOver(diagsArea, cliGlobals_,indexIntoCompilerArray);
		  if (sendStatus == ExSqlComp::ERROR)
		    {
		      setState(INITIAL_);
#ifndef _DEBUG
                      // For release, if the mxcmp could not reply
                      // to the request, use error -2005, to let the 
                      // user know that a dialout has been generated.
		      diagsArea << DgSqlCode(arkcmpErrorNoDiags);
		      diagsArea << DgString0(source);
#endif
                      diagsArea << DgSqlCode(- CLI_STMT_NOT_PREPARED);
                      if (diagsArea.getRollbackTransaction())
			rollbackTransaction(diagsArea);
		      return prepareReturn (ERROR);
		    }
		  else	//if (sendStatus == ExSqlComp::WARNING)
		    retcode = WARNING;
		}
	    } // if new operation
	  
	  // check for completion of request.
	  status = cliGlobals_->getArkcmp(indexIntoCompilerArray)->status();
	  
	  if ( status != ExSqlComp::FINISHED )
	      {
	      // waited request should complete. Return error.
	      diagsTakeOver(diagsArea, cliGlobals_,indexIntoCompilerArray);
	      diagsArea << DgSqlCode(- CLI_IO_REQUESTS_PENDING) 
			<< DgString0("SQLTEXT_COMPILE");
	      return prepareReturn (ERROR); 
	    }
	  
	  // initialize pointer to returned data(from reply) in private state.
	  ExSqlComp::ReturnStatus replyStatus = 
	    cliGlobals_->getArkcmp(indexIntoCompilerArray)->getReply(
		 fetched_gen_code, 
		 fetched_gen_code_len);
	  
          retry = FALSE;

          if (replyStatus != ExSqlComp::SUCCESS)
            {
              diagsTakeOver (diagsArea, cliGlobals_, indexIntoCompilerArray);
 
              if (replyStatus == ExSqlComp::ERROR)
                {
                  
                  if (retry == FALSE)
                  {
                    // An error other than 25304, or failure to start downrev compiler
                    setState(INITIAL_);
		    
		    if (ABS(diagsArea.mainSQLCODE()) != 4074
			||
			diagsArea.getNumber() != 1)
		      diagsArea << DgSqlCode(- CLI_STMT_NOT_PREPARED);
		    return prepareReturn (ERROR);
		  }
		}
	      else
                {
                  retcode = WARNING;
		}
	    }

	} // while retry
      context_->killIdleMxcmp();
      assignRootTdb((ex_root_tdb *)fetched_gen_code);
      root_tdb_size = (Lng32) fetched_gen_code_len;
    }
  
  if (root_tdb)
    {
      diagsArea.setCost(root_tdb->getCost());
    }
  if (unpackTdbs)
    retcode = (short)unpackAndInit(diagsArea, indexIntoCompilerArray);
  
  return (RETCODE)retcode;
} // Statement::prepare

Lng32 Statement::unpackAndInit(ComDiagsArea &diagsArea,
			      short indexIntoCompilerArray)
{
  Lng32 retcode = 0;

  // Do not unpack the root tdb if the statement is from showplan.
  // CmpDescribePlan will unpack it.
  ComTdbRoot *thisTdb = root_tdb;

  //#if defined (NA_WINNT)
  //  if (root_tdb)
  //#else
  if (root_tdb && !thisTdb->isFromShowplan())
  //#endif
    {
      // Here, we have just freshly (re)prepared the plan using the latest
      // version of the compiler. Unpacking should be uneventful (i.e. no
      // object version migration should happen). Therefore, it should not
      // be necessary to reallocate space.
      //
      ComTdb dummyTdb;
      ex_root_tdb *newRoot = (ex_root_tdb *)
	root_tdb->driveUnpack((void *) root_tdb, &dummyTdb, unpackSpace_);
      
      assignRootTdb(newRoot);
      
      if (root_tdb == NULL)  
	{
	  // ERROR during unpacking. Shouldn't occur here since we have just
	  // freshly prepared the statement using the latest version of the
	  // compiler. This is an unexpected error.
	  //
	  if ((indexIntoCompilerArray >= 0) &&
	      (cliGlobals_->getArkcmp(indexIntoCompilerArray)->getDiags()))
	    diagsArea.mergeAfter(*cliGlobals_->getArkcmp()->getDiags());
	  diagsArea << DgSqlCode(- CLI_STMT_NOT_PREPARED);
          return prepareReturn (ERROR); 
	}
    }


      if ( (versionToUse_ != COM_VERS_COMPILER_VERSION)                    && // Used a downrev compiler
           (returnRecompWarn())                                            && // Will return recomp warnings
           (root_tdb->getQueryType() >= ComTdbRoot::SQL_SELECT_UNIQUE)     && // Query is DML
           (root_tdb->getQueryType() <= ComTdbRoot::SQL_DELETE_NON_UNIQUE)
         )
      {
        // We compiled a DML query with a downrev compiler - save information so that we can 
        // issue warning 25304 if required. We do this rather than issue the warning directly,
        // because we want warning 8576: Query was recompiled, to precede warning 25304 if applicable.
	mxcmpErrorCode_ = VERSION_COMPILER_USED_TO_COMPILE_QUERY;
        mxcmpStartedVersion_ = (COM_VERSION) versionToUse_; 
      }

  // Reset state in this statement, then loop through all clones and
  // make corresponding state changes in each.
  if (root_tdb)
    {
      setComputeBulkMoveInfo(TRUE);
    }
  setFixupState(0);
  setState(CLOSE_);
  setFirstResolveDone(FALSE);
  lnil_ = NULL;
  
  clonedStatements->position();
  Statement * clone = (Statement*)clonedStatements->getNext();
  for (; clone != NULL; clone = (Statement*)clonedStatements->getNext())
    {
      if (clone->root_tdb)
	{
	  clone->setComputeBulkMoveInfo(TRUE);
	}
      clone->setFixupState(0);
      clone->setState(CLOSE_);
      clone->setFirstResolveDone(FALSE);
      clone->lnil_ = NULL;
    }
  
  if (indexIntoCompilerArray >= 0)
    diagsTakeOver(diagsArea, cliGlobals_,indexIntoCompilerArray);
  
  if (root_tdb)
    diagsArea.setCost(root_tdb->getCost());
  StatsGlobals *statsGlobals = cliGlobals_->getStatsGlobals();
  Lng32 fragOffset;
  Lng32 fragLen;
  Lng32 topNodeOffset;
  SessionDefaults *sessionDefaults =
       context_->getSessionDefaults();
  if (statsGlobals != NULL && stmtStats_ != NULL && root_tdb != NULL 
        && getUniqueStmtId() != NULL) 
  {
    ex_root_tdb *rootTdb = getRootTdb();
    //root_tdb is not unpacked for SHOWPLAN and 
    // explain fragment can't be obtained for such prepared queries
    if (!rootTdb->isPacked() && rootTdb->explainInRms() &&
        rootTdb->getFragDir()->getExplainFragDirEntry
                 (fragOffset, fragLen, topNodeOffset) == 0)
    {
      short savedPriority, savedStopMode;
      short error = statsGlobals->getStatsSemaphore(cliGlobals_->getSemId(),
            cliGlobals_->myPin(), savedPriority, savedStopMode, 
            FALSE /*shouldTimeout*/);
      ex_assert(error == 0, "getStatsSemaphore() returned an error");
      stmtStats_->setExplainFrag((void *)(((char *)root_tdb)+fragOffset), fragLen, topNodeOffset);
      statsGlobals->releaseStatsSemaphore(cliGlobals_->getSemId(),cliGlobals_->myPin(),
                          savedPriority, savedStopMode);
    }
  }
  return prepareReturn ((RETCODE)retcode);
}

RETCODE Statement::closeTables(ComDiagsArea &diagsArea)
{
  // cancel the down request to my child
  ComDiagsArea *diagsPtr = NULL;
  Int32 retcode = root_tcb->cancel(statementGlobals_,diagsPtr);
  StmtDebug1("  root_tcb->cancel() returned %s",
             RetcodeToString((RETCODE) retcode));
  if (diagsPtr)
    {
      diagsArea.mergeAfter(*diagsPtr);
      diagsPtr->decrRefCount();    
      diagsPtr = NULL;
    }

  if (retcode)
    return ERROR;
  
  retcode = root_tcb->closeTables(statementGlobals_,
                                  statementGlobals_->getRtFragTable());
  if (retcode)
    return ERROR;
  
  return SUCCESS;
}

RETCODE Statement::reOpenTables(ComDiagsArea &diagsArea)
{
  closeTables(diagsArea);

  Int32 retcode =
    root_tcb->reOpenTables(
	 statementGlobals_,
	 statementGlobals_->getRtFragTable());
  if (retcode)
    return ERROR;
  
  return SUCCESS;
}

/////////////////////////////////////////////////////////////////////
// Searches for the given cursorName in the statement list. If found,
// and the cursor is an updatable cursor, returns pointer to that
// statement. Else, returns NULL.
/////////////////////////////////////////////////////////////////////
Statement * Statement::getCurrentOfCursorStatement(char * cursorName)
{
  ComDiagsArea &diags = context_->diags();

  if (!cursorName)
     return NULL;

  char nameBuf[ComMAX_1_PART_EXTERNAL_UTF8_NAME_LEN_IN_BYTES + 1 + 16]; // a null terminator + a few extra bytes
  char *pName = nameBuf;
  Lng32 len = str_len(cursorName);

  if (len > sizeof(nameBuf) - 1)
    pName = (char *)heap_.allocateMemory(len + 1);

  str_cpy_all(pName, cursorName, len);
  pName[len] = '\0';
  str_strip_blanks(pName,len);
  // Convert to ansi id format
  if (str_to_ansi_id(cursorName,pName,len))
	{
          diags << DgSqlCode(-CLI_INVALID_SQL_ID)
       << DgString0(pName);
        return NULL;
	}
  HashQueue * cursorList =
    context_->getCursorList();

  Statement *pStmt = NULL;
  Statement * stmt;
  
  cursorList->position(pName, len);
  while (stmt = (Statement *)cursorList->getNext())
    { 
      //char * stmtCursorName = stmt->getCursorName();
      SQLSTMT_ID* stmtCursorName = stmt->getCursorName();

// Need to use length in comparison when the
// new length argument is added for "cursorName".
      if (stmtCursorName &&
          (strcmp(pName, stmtCursorName->identifier) == 0))
        {
          if (stmt->getRootTdb() && (stmt->getRootTdb()->updatableSelect() ))
	    {
	      pStmt = stmt;
	      break;
	    }
          else
            break;
	  
        }
    }

  if (pName != nameBuf)
    heap_.deallocateMemory(pName);
  return pStmt;

}

///////////////////////////////////////////////////////////////////////
// RETURN: doSimCheck: if true, do similarity check.
//         doFixup:    if true and doSimCheck is false, do fixup again.
//                     Note: fixup is always done after sim check so if
//                           doSimCheck is returned as true, then doFixup
//                           is ignored.
///////////////////////////////////////////////////////////////////////
RETCODE Statement::resolveNames(LateNameInfoList * lnil,
                                Descriptor * inputDesc, 
                                ComDiagsArea &diagsArea,
                                NABoolean &doSimCheck,
				NABoolean &doFixup)
{
  doSimCheck = FALSE;
  doFixup    = FALSE;
  Lng32 curAnsiNameLen = 0;
  char * curAnsiName = 0;
  NABoolean contextChanged = FALSE;
  AnsiOrNskName *curName = NULL;
  Int16 retCode;
  char * parts[4];
  Lng32 numParts;
  bool isNskName = FALSE;
  char * fullyQualifiedSchemaName = schemaName_;

  if (lnil->definePresent())
    {
      // if this is the first time names are being resolved, then
      // do it even if the define context has not changed.
      unsigned short defcon = context_->getCurrentDefineContext();
      if ((NOT firstResolveDone()) ||
	  (defcon != defineContext()))
	{
	  contextChanged = TRUE;
	}
      defineContext() = defcon;
    }
  
  for (Int32 l = 0; l < (Int32) (lnil->getNumEntries()); l++)
    {
      LateNameInfo * lni = &(lnil->getLateNameInfo(l));
      
      lni->setAnsiNameChange(0);
      
      
      if (lni->isVariable())
	{
	  
	  if (lni->isDefine())
	    {
	    }
	  else if (lni->isEnvVar())
	    {
	      // get name from env var.
	      char envName[ComMAX_3_PART_EXTERNAL_UTF8_NAME_LEN_IN_BYTES+1];
	      curAnsiName = cliGlobals_->getEnv(lni->variableName());
	      
	      if ((! curAnsiName)||
		  ((curAnsiNameLen = str_len(curAnsiName)) >
		   ComMAX_3_PART_EXTERNAL_UTF8_NAME_LEN_IN_BYTES))
		{
		  
		  diagsArea << DgSqlCode(-EXE_INVALID_DEFINE_OR_ENVVAR)
			    <<DgString0(lni->variableName());
		  return ERROR;
		}
	      str_cpy_all(envName,curAnsiName,str_len(curAnsiName));
	      envName[curAnsiNameLen] = '\0';
	      
	      curName = new (&heap_) AnsiOrNskName(envName);
	      if (curName->convertAnsiOrNskName())
		{
		  diagsArea << DgSqlCode(-CLI_INVALID_SQL_ID)<<DgString0(envName);
		  delete curName;
		  return ERROR;
		}
	    } //endif env var
	  
	  else if (lni->isCachedParam())
	    {
	      // cached params are only resolved on the first execute after
	      // prepare. These values are set from constants and 
	      // cannot change for multiple executions of the same stmt.
	      if (firstResolveDone())
                continue; // Go back to the for loop to continue with the next lni
	
	      curAnsiName = 
		&root_tdb->getParameterBuffer()
		[lni->getCachedParamOffset()];
	      curName = new (&heap_) AnsiOrNskName(curAnsiName);
	      if (curName->convertAnsiOrNskName())
		{
		  diagsArea << DgSqlCode(-CLI_INVALID_SQL_ID)<<DgString0(curAnsiName);
		  delete curName;
		  return ERROR;
		}

	    } //endif cached param
	  else // hvar or param
	    {
	      // Here we need to validate what the hvar contains
	      // We need to make sure it is a string hvar and we call
	      // convDoIt so that we only get the length of the
	      // string that we need.
	      
	      char *source= 0;
	      Lng32 sourceLen = 0;
	      Lng32 sourceType = 0;
              Lng32 sourceCharset = CharInfo::UnknownCharSet;
	      void *var_ptr = 0;

	      inputDesc->getDescItem(lni->getInputListIndex(), 
				     SQLDESC_VAR_PTR, &var_ptr, 
				     0, 0, 0, 0);
	      inputDesc->getDescItem(lni->getInputListIndex(),
				     SQLDESC_LENGTH, &sourceLen,
				     0,0,0,0);
	      
	      inputDesc->getDescItem(lni->getInputListIndex(),
				     SQLDESC_TYPE_FS, &sourceType,
				     0,0,0,0);
	      
	      // Check if input is a string type
	      
	      if ((sourceType>=REC_MIN_CHARACTER) &&
                  (sourceType <= REC_MAX_CHARACTER))
                {
                  inputDesc->getDescItem(lni->getInputListIndex(),
                                         SQLDESC_CHAR_SET, &sourceCharset,
                                         0,0,0,0);

                  if (sourceCharset == CharInfo::UnknownCharSet &&
                      (sourceType == REC_BYTE_F_ASCII ||
                       sourceType == REC_BYTE_V_ASCII ||
                       sourceType == REC_BYTE_V_ANSI))
                    {
                      // some clients aren't accustomed yet to setting the
                      // charset of the SQL statement, treat those as ISO88591
                      // for single-byte based data types
                      sourceCharset = CharInfo::ISO88591;
                    }

                  if (stmt_type == STATIC_STMT &&
                      sourceCharset == CharInfo::ISO88591)
                    {
                      // our convention is to pass UTF-8 or UCS2 for
                      // names in embedded programs. However, embedded
                      // SQL does not support UTF-8 at this time.
                      // Temporary fix: Set input charset to UTF-8
                      // here until UTF-8 host varables are supported
                      // in embedded programs (if that ever happens)
                      sourceCharset = CharInfo::UTF8;
                    }
                }
              else
		{
		  diagsArea << DgSqlCode(-CLI_INVALID_OBJECTNAME);
		  return ERROR; 
		}
	      source = (char *)var_ptr;
	      
	      if (DFS2REC::isSQLVarChar(sourceType)) 
		{
		  // the first 2 bytes of data are actually the variable 
		  // length indicator
		  short VCLen;
		  str_cpy_all((char *) &VCLen, source, sizeof(short));
		  sourceLen = (Lng32) VCLen;
		  source = &source[sizeof(short)];
		}
	      
	      ComDiagsArea *diagsPtr = NULL;
	      char targetName[ComMAX_3_PART_EXTERNAL_UTF8_NAME_LEN_IN_BYTES + 1];
	      short retcode = convDoIt(source,
				       sourceLen,
				       (short) sourceType,
				       0,
				       sourceCharset,   // passed in as scale
				       targetName,
				       sizeof(targetName) - 1,
				       REC_BYTE_V_ANSI, // short targetType
				       0,               // Lng32 targetPrecision
				       (Lng32) SQLCHARSETCODE_UTF8, // Lng32 targetScale - also used as targetCharSet for CharType
				       0,
				       0,
				       &heap_,
				       &diagsPtr);
	      if (diagsPtr)
		{
		  diagsArea.mergeAfter(*diagsPtr);
		  diagsPtr->decrRefCount();
                  diagsPtr = NULL;
		}
	      if (retcode != ex_expr::EXPR_OK)
		{
		  diagsArea << DgSqlCode(-EXE_CONVERT_STRING_ERROR);
		  return ERROR;  
		}

	      if (! fullyQualifiedSchemaName)
		fullyQualifiedSchemaName = lni->compileTimeAnsiName();

	      curName = new (&heap_) AnsiOrNskName(targetName);
	      if (curName->convertAnsiOrNskName())
		{
		  diagsArea << DgSqlCode(-CLI_INVALID_SQL_ID)
			    <<DgString0(targetName);
		  delete curName;
		  return ERROR;
		  
		}
	    } // end if hvar 

    	  if (NOT lni->isMPalias())
	    {
	      if (lni->isAvoidSimCheck()) // Host Variable in SET TABLE TIMEOUT command without
		// Prototype clause will have the NAME_ONLY and VARIABLE bit is set
		// So,we will need at least 3 parts
		// If nsk name, system name will be filled in
		{
		  if (curName->extractParts(numParts, parts))
		    {
		      diagsArea << DgSqlCode(-CLI_INVALID_SQL_ID)
				<< DgString0(curName->getExternalName());
		      delete curName;
		      return ERROR;
		    }
		  if (numParts < 3)
		    {
		      diagsArea << DgSqlCode(-CLI_INVALID_SQL_ID)
				<< DgString0(curName->getExternalName());
		      delete curName;
		      return ERROR;
		    }
		  isNskName = curName->isNskName(); // will be set to False
		}
	      else
		isNskName = TRUE;
	      if (isNskName)
		{
		  curAnsiName = curName->getInternalName();
		  curAnsiNameLen = str_len(curAnsiName);
		  if (curAnsiName[0] != '\\')
		    {
		      
		    }
		}
	    }

	  if (lni->isMPalias() &&  NOT (lni->isAnsiPhySame())) {
	    // if MPAlias flag is set,  then we compiled for an MX table, or an MP table with 
	    // a MPAlias defined on it See comment in GenRelMisc.cpp PartitionAccess::codeGen 
	    // method where the mpalias flag is set. If that flag is set only for an MPAlias
	    // and not for MX tables then this else statement condition will have to be modified.
	    // The code below should be executed for MX tables and for MP tables access through
	    // their MPAlias. The code below is also not needed for accessing resource forks whose
	    // ansi name is same as their physical name.
	    
	    if (curName->extractParts(numParts, parts))
	      {
		diagsArea << DgSqlCode(-CLI_INVALID_SQL_ID)
			  << DgString0(curName->getExternalName());
		delete curName;
		return ERROR;
	      }
	    if (numParts != 3) {
	      if (curName->fillInMissingParts(fullyQualifiedSchemaName) == -1)
		{
		  diagsArea << DgSqlCode(-CLI_INVALID_SQL_ID)
			    << DgString0(curName->getExternalName());
		  delete curName;
		  return ERROR;
		}
	    } // end if numParts != 3
	    
	  } // end isMPAlias && isAnsiPhySame
	  
	  // if current ansi name is different than the last ansi name, 
	  // resolve the current ansi name. Remember this in lni.
	  retCode = lni->getLastUsedName(&heap_)->equals(curName);
	  if (retCode == -1)
	    {
	      diagsArea << DgSqlCode(-CLI_INTERNAL_ERROR);
	      delete curName;
	      return ERROR;
	    }
	  else
	    if (retCode == 0)
	      {
		lni->setAnsiNameChange(1);
		lni->setLastUsedName(curName);
		// If similarity check is to be avoided: Map the physical name
		// right here (otherwise done during the similarity check.)
		if ( lni->isAvoidSimCheck() ) 
		  {
		    if (! isNskName)
		      {
			if (mapAnsiToGuaName(lni, diagsArea) == ERROR)
			  return ERROR;
		      }
		    else
		      strcpy(lni->resolvedPhyName(), curName->getInternalName());
		    doFixup = TRUE; // fixup needs to be done again to 
		    // be able to use the new name.
		  }
		else
		  if (NOT doSimCheck)
		    {
		      doSimCheck = TRUE;
		      
		      // if this is a view name that has changed, mark it
		      // in the latenameinfo struct. This will be used later
		      // when similarity check is done in doQuerySimilarityCheck.
		      if (lni->isView())
			{
			  lni->setViewNameChange(1);
			}
		    }
	      }
	    else
	      {
		if (curName)
		  {
		    delete curName;
		    curName = NULL;
		  }


	      }
	  
	} // variable
      
    } // for
  
  if (NOT firstResolveDone())
    {
      setFirstResolveDone(TRUE);
    }
  
  return SUCCESS;
}


////////////////////////////////////////////////////////////////////
// This method performs similarity check between the information
// generated at compile time (si) and the information retrieved at
// runtime for table specified via tableName.
// RETURNS: ERROR:   if an error occured.
//          SUCCESS, otherwise.
//                   if sim check fails, then this is indicated by
//                   the return param, simCheckFailed, set to TRUE.      
/////////////////////////////////////////////////////////////////////
RETCODE Statement::doSimilarityCheck(SimilarityInfo * si,
				     LateNameInfo * lni,
				     char * tableName,
				     NABoolean &simCheckFailed,
				     ComDiagsArea &diagsArea
				     )
{
  return SUCCESS;
}

RETCODE Statement::doIUDSimilarityCheck(SimilarityInfo * si,
			                LateNameInfo * lni,
					char * tableName,
					Queue * indexInfoList,
					NABoolean &simCheckFailed,  
					ComDiagsArea &diagsArea)
{
  return SUCCESS;
}

RETCODE Statement::getMatchingIndex(Queue * indexInfoList,
				    char * indexAnsiName,
				    char * indexPhyName,
				    ComDiagsArea &diagsArea)
{
  indexInfoList->position();
  for (Int32 i = 0; i < indexInfoList->numEntries(); i++)
    {
      IndexInfo * ii = (IndexInfo*)(indexInfoList->getNext());

      if (str_cmp(indexAnsiName, ii->indexAnsiName(),
		  str_len(indexAnsiName)) == 0)
	{
	  strcpy(indexPhyName, ii->indexPhyName());
	  return SUCCESS;
	}
    }

  return SUCCESS;
}
  
RETCODE Statement::mapAnsiToGuaName(LateNameInfo * lni,
				    ComDiagsArea &diagsArea)
{
  return ERROR;
}

// this method resolves all table names that are used in this query.
RETCODE Statement::forceMapAllNames(LateNameInfoList * lnil,
				    ComDiagsArea &diagsArea)
{
  for (Int32 i = 0; i < (Int32) (lnil->getNumEntries()); i++)
    {
      LateNameInfo * lni = &(lnil->getLateNameInfo(i));

      lni->setAnsiNameChange(1);

      char *lastUsedAnsiName = lni->lastUsedAnsiName();

      // NA_NSK_REL1 -  need to change for ansi names 
      NABoolean isGuardianName =
         (lastUsedAnsiName && lastUsedAnsiName[0] == '\\') ? TRUE : FALSE;

      if (lni->isAnsiPhySame() || isGuardianName)
        {

	  // If ansi name is really a phys name, copy it to resolvedPhyName.
          // For the first release on NSK, all internal table names, such as
          // histograms, histints, etc, will have resolved physical names as
          // their ANSI name.
	  str_cpy(lni->resolvedPhyName(), lni->lastUsedAnsiName(),
		  str_len(lni->lastUsedAnsiName()) + 1, '\0');
	}
      else 
	{
          // VO, Metadata indexes
          // If all of the following is true:
          // - the lni represents an index
          // - the query is from a system module,
          // THEN the generator has set the last used ansi name to the 
          // compile time name of the base table. We will use that to find
          // the index runtime ANSI name.
          LateNameInfo * baseTableLni = NULL;
          if ( (lni->getNameSpace() == COM_INDEX_NAME)      &&
               (systemModuleStmt())
             )
          {
            if (lni->isVariable())
            {
              // resolve names has put the runtime name of the table in this lni
              baseTableLni = lni;
            }
            else
            {
              // iterate over the lnil to find the entry for the index' base table 
              for (Int32 ix = 0; ix < (Int32) (lnil->getNumEntries()); ix++)
              {
                LateNameInfo * lni2 = &(lnil->getLateNameInfo(ix));
                if (!strcmp (lni2->compileTimeAnsiName(), lni->lastUsedAnsiName()))
                {              
                    baseTableLni = lni2;
                    break;
                }
              }
            }

            if (baseTableLni == NULL)
            {
              // didn't find the base table in the lnil - quit!
              diagsArea << DgSqlCode(-CLI_INTERNAL_ERROR);
              return ERROR;
            }

            // Construct the runtime index name from 
            // - the runtime catalog and schema name parts of the base table
            // - the compile time object name part of the index
            char * indexParts[4];
            char * tableParts[4];
            Lng32 numIndexParts = -1, numTableParts = -1;
            AnsiOrNskName * indexCompileTimeAnsiName = new (&heap_) AnsiOrNskName(lni->compileTimeAnsiName());
            baseTableLni->getLastUsedName(&heap_)->extractParts (numTableParts, tableParts);
            indexCompileTimeAnsiName->extractParts (numIndexParts, indexParts);

            if ( (numIndexParts != 3) || (numTableParts != 3))
            {
              // Something rotten here ...
              delete indexCompileTimeAnsiName;
              diagsArea << DgSqlCode(-CLI_INTERNAL_ERROR);
              return ERROR;
            }

            char  indexExtName[ComMAX_3_PART_EXTERNAL_UTF8_NAME_LEN_IN_BYTES + 1]; 
            ComBuildANSIName (tableParts[0], tableParts[1], indexParts[2], indexExtName);
            delete indexCompileTimeAnsiName;

            AnsiOrNskName * indexName = new (&heap_) AnsiOrNskName(indexExtName);
            lni->setLastUsedName (indexName);
          }

	  RETCODE retcode = mapAnsiToGuaName(lni, diagsArea);
          if (baseTableLni != NULL && !lni->isVariable())
            // need to reset the last used ANSI name for a metadata index to that of the
            // compile time base table. Otherwise, the next name mapping will fail.
            lni->setLastUsedName (new (&heap_) AnsiOrNskName (baseTableLni->compileTimeAnsiName()));

          if (retcode != SUCCESS)
            return ERROR;
	  
	}
    }

  return SUCCESS;
}

/////////////////////////////////////////////////////////////////////////
// This method does similarity checks on all tables for which 
// the flag, doSimCheck(), is set.
// RETURNS: ERROR:   if an error occured.
//          SUCCESS, otherwise.
//                   if sim check fails, then this is indicated by
//                   the return param, simCheckFailed, set to TRUE.      
/////////////////////////////////////////////////////////////////////////     
RETCODE Statement::doQuerySimilarityCheck(QuerySimilarityInfo * qsi,
					  LateNameInfoList   * lnil,
					  NABoolean &simCheckFailed,
					  ComDiagsArea &diagsArea
					  )
{
  RETCODE retcode;

  simCheckFailed = FALSE;

  if (! qsi)
    return ERROR;

  NABoolean aqr = root_tdb->aqrEnabled();
  if (aqr)
    {
      diagsArea << DgSqlCode(-EXE_SIM_CHECK_FAILED)
		<< DgString0("Similarity check should not be reached with aqr enabled.");
      
      return ERROR;
    }

  // if similarity check is being done due to a view name change that
  // was passed thru an identifier, then recompile.
  if (lnil->viewPresent())
    {
      CollIndex i = 0;
      while (i < (Int32) lnil->getNumEntries())
	{
#pragma nowarn(1506)   // warning elimination 
	  LateNameInfo * lni = &(lnil->getLateNameInfo(i));
#pragma warn(1506)  // warning elimination 

	  if (lni->isViewNameChange())
	    {
	      lni->setViewNameChange(0);

	      simCheckFailed = TRUE;
	      return SUCCESS;
	      
	    }
	  i++;
	}
    }

  switch (qsi->getSimilarityCheckOption())
    {
    case QuerySimilarityInfo::INTERNAL_SIM_CHECK:
      {
	// accessing internal tables(catalog). Just resolve names. Similarity
	// check always passes for these tables.
	retcode = forceMapAllNames(lnil, diagsArea);
	if (retcode == ERROR)
	  return ERROR;

	for (Int32 i = 0; i < (Int32) (lnil->getNumEntries()); i++)
	  {
	    // ignore TS mismatch on the next open since similarity
	    // check has succeeded.
	    lnil->getLateNameInfo(i).setIgnoreTS(1);
	  }

	return SUCCESS;
      }
    break;

    case QuerySimilarityInfo::RECOMP_ON_TS_MISMATCH:
      {
	if (aqr)
	  {
	    diagsArea << DgSqlCode(-EXE_SIM_CHECK_FAILED)
		      << DgString0("Similarity check should not be reached.");
	    
	    return ERROR;
	  }

	simCheckFailed = TRUE;
	return SUCCESS;
      }
    break;

    case QuerySimilarityInfo::ERROR_ON_TS_MISMATCH:
      {
	diagsArea << DgSqlCode(-EXE_SIM_CHECK_FAILED)
		  << DgString0("Similarity check disabled.");
	      
	return ERROR;
      }
    break;
 
    case QuerySimilarityInfo::SIM_CHECK_AND_RECOMP_ON_FAILURE:
    case QuerySimilarityInfo::SIM_CHECK_AND_ERROR_ON_FAILURE:
      {
	if (aqr)
	  {
	    diagsArea << DgSqlCode(-EXE_SIM_CHECK_FAILED)
		      << DgString0("Similarity check should not be reached.");
	    
	    return ERROR;
	  }

	// do sim check in both these cases. If it passes, do
	// nothing. If it fails, then recompile or return error.
      }
    break;
    }

  qsi->siList()->position();
  SimilarityInfo * si;

  // index info list is set up for the target IUD'd table in an
  // IUD(Insert/Update/Delete) query. There may not be any indices
  // on the IUD'd table at compile time. In that case, the method 
  // doIUDSimilarityCheck validates that there are no indices on the
  // runtime IUD's table as well.
#pragma warning( disable : 4018 )
  if (qsi->indexInfoList() &&
      (qsi->namePosition() < lnil->getNumEntries()))
#pragma warning( default: 4018 )
    {
      si = (SimilarityInfo *)(qsi->siList()->get(qsi->namePosition()));
      LateNameInfo * lni = &lnil->getLateNameInfo(qsi->namePosition());
      
      retcode = mapAnsiToGuaName(lni, diagsArea);
      if (retcode == ERROR)
	return ERROR;
      
      simCheckFailed = FALSE;
      if (NOT si->simCheckDisable())
	{
	  if (doIUDSimilarityCheck(si,
				   lni,
				   lni->resolvedPhyName(),
				   qsi->indexInfoList(),
				   simCheckFailed, diagsArea) == ERROR)
	    return ERROR;
	}

      if (simCheckFailed)
	{
	  if (qsi->getSimilarityCheckOption() == 
	      QuerySimilarityInfo::SIM_CHECK_AND_ERROR_ON_FAILURE)
	    {
	      diagsArea << DgSqlCode(-EXE_SIM_CHECK_FAILED)
			<< DgString0("Automatic recompilation disabled.");
	      
	      return ERROR;
	    }
	  else
	    return SUCCESS;
	}

      // at this point we have validated that the runtime table and the
      // compile time table have matching indices which are in the same
      // order.
      lni->setIgnoreTS(1);
    }

  Int32 i = 0;
  qsi->siList()->position();
#pragma warning( disable: 4018 )
  while (((si = (SimilarityInfo *)(qsi->siList()->getNext())) != NULL) &&
         (i < lnil->getNumEntries()))
#pragma warning( default: 4018 )
    {
      LateNameInfo * lni = &lnil->getLateNameInfo(i);

      if (si->internalSimCheck())
	{
	  // do nothing. An internal system table is being accessed(a metadata
	  // table) and the timestamp info on those tables is not maintained.
	  // Consider the similarity check to pass in this case.
	  lni->setIgnoreTS(1);
	}
      else if (si->simCheckDisable())
	{
	  lni->setIgnoreTS(0);
	  simCheckFailed = TRUE;
	}
      else if (si->getMatchingIndex())
	{
	  if (getMatchingIndex(qsi->indexInfoList(), 
			       lni->compileTimeAnsiName(),
			       lni->resolvedPhyName(), diagsArea) == ERROR)
	    return ERROR;

	  // ignore TS mismatch on the next open since similarity
	  // check has succeeded.
	  lni->setIgnoreTS(1);
	}
      else if ((qsi->indexInfoList()) &&
	       (i == qsi->namePosition()))
	{
	  // This is the target IUD'd table.
	  // Nothing needs to be done here, this check has already
	  // been done before.
	  lni->setIgnoreTS(1);
	}
      else
	{
	  retcode = mapAnsiToGuaName(lni, diagsArea);
	  if (retcode == ERROR)
	    return ERROR;
	      
	  retcode = doSimilarityCheck(si, lni, lni->resolvedPhyName(),
				      simCheckFailed, diagsArea); 
#ifdef _DEBUG
          {
            char * envPtr = getenv ("SQLMX_DISPLAY_CATMAP");
            if (envPtr && *envPtr == '1')
            {
              diagsArea << DgSqlCode (DISTRIBUTION_DEBUG_WARNING)
                        << DgString0 (lni->lastUsedAnsiName())
                        << DgString1 ("maps to")
                        << DgString2 (lni->resolvedPhyName());
            }
          }

#endif
	  if (retcode  == ERROR)
	    return ERROR;
	  
	  if (simCheckFailed)
	    {
	      if (qsi->getSimilarityCheckOption() == 
		  QuerySimilarityInfo::SIM_CHECK_AND_ERROR_ON_FAILURE)
		{
		  diagsArea << DgSqlCode(-EXE_SIM_CHECK_FAILED)
			    << DgString0("Automatic recompilation disabled.");
		  
		  return ERROR;
		}
	      else
		return SUCCESS;
	    }

	  // ignore TS mismatch on the next open since similarity
	  // check has succeeded.
          lni->setIgnoreTS(1);
	}

	// Fix for 10-010614-3437: When we get here, we have found and
	// restored similar index information for the IUD stmt, so
	// don't compare the timestamps.
	//if (qsi->indexInfoList() && lni->isIndex())
	//  lni->setIgnoreTS(1);

      i++;
    }
  
  return SUCCESS;
}

RETCODE Statement::fixup(CliGlobals * cliGlobals, Descriptor * input_desc,
			 ComDiagsArea &diagsArea, NABoolean &doSimCheck,
                         NABoolean &partitionUnavailable, const NABoolean donePrepare)
{
  Int32 retcode;
  ExMasterStats *masterStats;
 
  if ((stmtStats_) && ((masterStats = stmtStats_->getMasterStats()) != NULL))
     masterStats->setStmtState(STMT_FIXUP_);

  // Initialize this method's output parameters  
  doSimCheck = FALSE;
  partitionUnavailable = FALSE;

  if (fixupState() != 0)
    return ERROR;

  if (!donePrepare)
  {
    // Don't check visibility if the statement has just been prepared
    switch (doVisibilityCheck ( root_tdb->getLateNameInfoList(), diagsArea))
    {
    case WARNING:
      doSimCheck = TRUE;
      return SUCCESS;
    case ERROR:
      return ERROR;
    default:
      break;
    }
  }

  /* fixup the generated code */
  //  statementGlobals_->resolvedNameList() = 
  //    (lnil_ ? lnil_ : root_tdb->getLateNameInfoList());
  statementGlobals_->setStartAddr((void *)root_tdb);
  statementGlobals_->setCliGlobals(cliGlobals_);

  // Keep timeout data locally for this statement
  //  (The "root build" builds the messages to the ESPs by copying the 
  //   relevant timeout data from the master globals.)
  statementGlobals_->setLocalTimeoutData(root_tdb);

  // if this is part of an auto query retry and esp need to be cleaned up,
  // set that indication in root tcb.
  if ((context_->aqrInfo()) &&
      (context_->aqrInfo()->espCleanup()))
    {
      // set flag for verify ESPs - make sure esp in cache is alive before
      // reuse it.
      statementGlobals_->setVerifyESP();
    }

  root_tcb = (ex_root_tcb *)(root_tdb->build(cliGlobals, statementGlobals_));

  if ((context_->aqrInfo()) &&
      (context_->aqrInfo()->espCleanup()))
    {
      // reset flag for verify ESPs
      statementGlobals_->resetVerifyESP();
    }

  statementGlobals_->takeGlobalDiagsArea(diagsArea);

  if ((diagsArea.mainSQLCODE() < 0) || (!root_tcb))
    {
      if ((diagsArea.contains(-EXE_TIMESTAMP_MISMATCH) &&
           (NOT tsMismatched()))
          // if table not found, primary partition may have moved.
          // so, try a similarity check to verify it.
          || diagsArea.contains(-EXE_TABLE_NOT_FOUND))
	{
	  setTsMismatched(TRUE);
	  doSimCheck = TRUE;
	  return SUCCESS;
	}

      if (diagsArea.contains(-EXE_PARTITION_UNAVAILABLE))
          // if partition availability error, use the catalog manager
          // to attempt to find another partition.
	{
          partitionUnavailable = TRUE;
	  return SUCCESS;
	}

      setTsMismatched(FALSE);
      rollbackTransaction(diagsArea);
      return ERROR;
    }

  if (inputData_)
    {
      root_tcb->setInputData(inputData_);
    }
  
  // QStuff ^^
  if (isPubsubHoldable() || isAnsiHoldable())
    {
      root_tcb->propagateHoldable(TRUE);
    }
  // QStuff __

  retcode = root_tcb->fixup();

  // fixup is done. restore esp priority to its execute priority if master
  // is not changing esp's priority by sending msgs.
  short rc = statementGlobals_->getRtFragTable()->restoreEspPriority();
  if (rc)
    {
    }

  if (retcode)
    {
      statementGlobals_->takeGlobalDiagsArea(diagsArea);

      // do similarity check if timestamp mismatch is returned at
      // fixup time.
      if (((diagsArea.contains(-EXE_TIMESTAMP_MISMATCH)) &&
	   (NOT tsMismatched()))
          || ((diagsArea.contains(-EXE_TABLE_NOT_FOUND)) &&
              (root_tdb->querySimilarityInfo()->getSimilarityCheckOption() !=
                        QuerySimilarityInfo::INTERNAL_SIM_CHECK)))
	  
	{
	  setTsMismatched(TRUE);
	  doSimCheck = TRUE;
	  return SUCCESS;
	}
      
      if (diagsArea.contains(-EXE_PARTITION_UNAVAILABLE))
          // if partition availability error, use the catalog manager
          // to attempt to find another partition.
	{
          partitionUnavailable = TRUE;
	  return SUCCESS;
	}

      setTsMismatched(FALSE);
      rollbackTransaction(diagsArea);
      return ERROR;
    }
  
  setTsMismatched(FALSE);

  // if this is an 'update where current of' query, and
  // the cursor statement was specified as a literal,
  // then find the cursor statement and hook it up here.
  if (root_tdb->updateCurrentOfQuery() &&
      root_tdb->fetchedCursorName())
    {
      currentOfCursorStatement_ =
	getCurrentOfCursorStatement(root_tdb->fetchedCursorName());
      
      if (currentOfCursorStatement_ == NULL)
	{
	  diagsArea << DgSqlCode(- CLI_NON_UPDATABLE_SELECT_CURSOR)
		    << DgString0(root_tdb->fetchedCursorName());
	  return ERROR;
	}
    }
  
  // clear all runtime flags in statementGlobals_->latenameinfolist()->
  // getLateNameInfo(i)
  if (root_tdb->getLateNameInfoList())
    {
      //      statementGlobals_->resolvedNameList()->resetFlags();
      root_tdb->getLateNameInfoList()->resetRuntimeFlags();
    }

  setFixupState(-1);

  return SUCCESS;
}

static
NABoolean compareTransModes(ex_root_tdb *root_tdb,
			    ExTransaction *currTransaction,
			    ComDiagsArea *diags = NULL,
                            NABoolean isSysModuleStmt = FALSE)
{
  TransMode
    &tmCompile = *root_tdb->getTransMode(),
    &tmRuntime = *currTransaction->getTransMode();

#ifdef _DEBUG
    static NABoolean dbg = !!getenv("TRANSMODE_DEBUG");
    if (dbg)
      cerr << "##tm: exe= " << tmRuntime.display()
           <<      " cmp= " << tmCompile.display()
           <<           " " << tmCompile.stmtLevelAccessOptions()
	   <<           " " << root_tdb->readonlyTransactionOK()
	   << endl;
#endif

  NABoolean recompileDueToRollbackMode = 
	( 
	  ((tmCompile.getRollbackMode() == TransMode::NO_ROLLBACK_IN_IUD_STATEMENT_) &&
	    (!currTransaction->autoCommit()))
	  ||
	  (((tmCompile.getRollbackMode() != TransMode::NO_ROLLBACK_IN_IUD_STATEMENT_) &&
	      (tmCompile.getRollbackMode() != TransMode::NO_ROLLBACK_)) &&
	    (tmRuntime.getRollbackMode() == TransMode::NO_ROLLBACK_))
	 ) ;

  NABoolean recompileDueToMultiCommitMode = !(tmCompile.multiCommitCompatible(tmRuntime));

  if (tmCompile.accessModeCompatible(tmRuntime) ||
      root_tdb->readonlyTransactionOK())
  {
    if (tmCompile.isolationLevelCompatible(tmRuntime) ||
        tmCompile.stmtLevelAccessOptions())
    {
      if( !recompileDueToRollbackMode && !recompileDueToMultiCommitMode)
	 return FALSE;
    }
  }

  // The run-time transaction mode ($0~int0) differs the compile-time ($1~int1).
  if (diags && !isSysModuleStmt)
    *diags << DgSqlCode(- CLI_TRANS_MODE_MISMATCH)
      << DgInt0(tmRuntime.display())
      << DgInt1(tmCompile.display())
      ;
  return TRUE;
}

inline static
void recompileReasonIsTransMode(ex_root_tdb *root_tdb,
				ExTransaction *currTransaction,
			 Lng32 recompileReason[])
{
  recompileReason[0] = CLI_TRANS_MODE_MISMATCH;
  recompileReason[1] = currTransaction->getTransMode()->display();
  recompileReason[2] = root_tdb->getTransMode()->display();
}

RETCODE Statement::error(ComDiagsArea &diagsArea)
{
  // Reset the autocommit flag to the user's view.
  resetAutoCommit();

  // abort the transaction, if auto commit is on or
  // rollbackTransaction flag is set in the diags area or
  // this is a query that would have dirtied the disk(like,
  // insert/update/delete). 
  rollbackTransaction(diagsArea);
  
  // if no other diags, as a last resort emit this rather 
  // cryptic message
  if (diagsArea.getNumber(DgSqlCode::ERROR_) == 0)
    diagsArea << DgSqlCode(- CLI_TCB_EXECUTE_ERROR);
  
  dealloc();
  space_.freeBlocks();
  statementGlobals_->reAllocate(1);
  
  setState(CLOSE_);
  
  setFixupState(0);
  
  return ERROR;
}

RETCODE Statement::execute(CliGlobals * cliGlobals, Descriptor * input_desc,
			   ComDiagsArea &diagsArea, ExecState  execute_state,
			   NABoolean fixupOnly, ULng32 cliflags)
{
  StmtDebug2("[BEGIN execute] %p, stmt_state %s", this, stmtState(getState()));

  RETCODE retcode = SUCCESS;
  NABoolean schemaFileLabelTSChecked = 0;

  NABoolean recompWarn;
  NABoolean partitionUnavailable = FALSE;
  NABoolean partitionAvailabilityChecked = FALSE;

  // This boolean indicates whether ANSI to Guardian name mappings
  // have failed following a "partition not available" error. The
  // first time we encounter such a failure we attempt an automatic
  // recompile and set this variable to TRUE. If the same failure is
  // encountered again after the recompile then we return an error to
  // the user.
  NABoolean partitionNameLookupsFailed = FALSE;

  // This boolean indicates whether a prepare has been done as part 
  // of this execution. If that is the case, visibility checks can
  // be skipped because the prepare will have done that already.
  NABoolean donePrepare = FALSE;

  Lng32 recompileReason[3];
  recompileReason[0] = recompileReason[1] = recompileReason[2] = 0;
  Int64 reCompileTime = (Int64)0;
  NABoolean reExecute=FALSE;
  ExMasterStats *masterStats = NULL;

  if (state_ != FIXUP_DONE_)
    state_ = execute_state;
  
  // To ensure correct handling of the implicit transactions (and
  // autocommit clearing and restoring) which happen when the CLI
  // makes recursive calls via CatMapAnsiNameToGuardianName,
  // CatMapGetCatalogVisibility, RTMD fetches, etc, please be sure to
  // call Statement::commitImplicitTransAndResetTmodes before
  // leaving this function.  So it is best not to code a "return" from
  // inside this while loop, but instead, set the retcode local
  // variable, and set the readyToReturnVariable to TRUE, then break
  // from the switch statement.

  NABoolean readyToReturn = FALSE;
  if (stmtStats_ != NULL) 
     masterStats = stmtStats_->getMasterStats();
  while (readyToReturn == FALSE)  
    {
#ifdef _DEBUG
      if ((getenv("SHOW_STATE")) &&
	  ((! root_tdb) ||
	   ((root_tdb) &&
	    (root_tdb->querySimilarityInfo()->getSimilarityCheckOption() !=
	     QuerySimilarityInfo::INTERNAL_SIM_CHECK))))
	{
	  char buf[40];

	  switch (state_)
	    {
	    case INITIAL_STATE_: strcpy(buf, "INITIAL_STATE_"); break;
	    case RESOLVE_NAMES_: strcpy(buf, "RESOLVE_NAMES_"); break;
	    case DO_SIM_CHECK_: strcpy(buf, "DO_SIM_CHECK_"); break;
	    case RECOMPILE_: strcpy(buf, "RECOMPILE_"); break;
	    case COMPILE_: strcpy(buf, "COMPILE_"); break;
	    case CHECK_DYNAMIC_SETTINGS_:
              strcpy(buf, "CHECK_DYNAMIC_SETTINGS_");
              break;
	    case FIXUP_: strcpy(buf, "FIXUP_"); break;
	    case FIXUP_DONE_: strcpy(buf, "FIXUP_DONE_"); break;
	    case EXECUTE_: strcpy(buf, "EXECUTE_"); break;
	    case RE_EXECUTE_: strcpy(buf, "RE_EXECUTE_"); break;
	    case RE_EXECUTE_AFTER_RECOMPILE_: strcpy(buf, "RE_EXECUTE_AFTER_RECOMPILE_");
	    case ERROR_: strcpy(buf, "ERROR_"); break;
	    case ERROR_RETURN_: strcpy(buf, "ERROR_RETURN_"); break;
	    default: strcpy(buf, "Unknown state!"); break;
	    }
	  cout << "State " << buf << endl;
	}
#endif

      switch (state_)
	{
	case INITIAL_STATE_:
	  {
            // Reclaim Statements if it is available only when the 
            // parent statements are executed
            if (context_->getNumOfCliCalls() == 1)
            {
              // Reclaim Statements if it is available
              context_->reclaimStatements();
            }
            if (masterStats != NULL)
            {
              Int64 jts = NA_JulianTimestamp();
	      if (NOT masterStats->isPrepAndExec() && (!fixupOnly))
	      {
	        masterStats->setElapsedStartTime(jts);
	      }
              if (! stmtStats_->aqrInProgress())
                aqrInitialExeStartTime_ = -1;
              if (! fixupOnly)
                 masterStats->setExeStartTime(aqrInitialExeStartTime_ == -1 ? 
                    jts : aqrInitialExeStartTime_);
	      masterStats->initBeforeExecute(jts);
              if (! stmtStats_->aqrInProgress())
                masterStats->resetAqrInfo();
	      }

	    if (stmt_state != CLOSE_)
	      {
		// Report an error because we are trying to execute a
		// statement which is already in an open state, or one
		// that was never prepared. One exception is a stored
		// procedure result set in the INITIAL_ state. It can
		// be described and executed without the application
		// first having done a prepare.
                if (!(parentCall_ && stmt_state == INITIAL_))
                {
		//ADebug();
		diagsArea << DgSqlCode(- CLI_STMT_NOT_CLOSE);
		state_ = ERROR_;
		statementGlobals_->setCancelState(CLI_CANCEL_TCB_READY);
		break;
	      }
              }

	    if (aqrReprepareNeeded())
	      {
		diagsArea << DgSqlCode(-EXE_USER_PREPARE_NEEDED);
		state_ = ERROR_;
		break;
	      }

	    if (!root_tdb &&
		!allocated() &&
		(statement_id->name_mode == cursor_name) &&
		(statement_id->identifier) &&
		(!isEqualByName((SQLSTMT_ID *)statement_id, cursor_name_))
		)
	      {
		SQLSTMT_ID tmpStmtId = *(SQLSTMT_ID *)statement_id;
		tmpStmtId.name_mode = stmt_name;
		Statement * bindToStmt =
		  context_->getStatement(&tmpStmtId);
		if (!bindToStmt)
		  {
		    diagsArea << DgSqlCode(-CLI_STMT_NOT_EXISTS);
		    state_ = ERROR_;
		    break;
		  }
		bindTo(bindToStmt);
	      }

            // Two cases to consider for CALL statements
            // a) This is a CALL statement. We need to reset the state
            //    of all child result sets before doing this execute. 
            //    The state should have already been reset when the
            //    CALL was closed but we do it again to be safe.
            // b) This is a stored procedure result set. We may need to
            //    to trigger an internal prepare before doing this
            //    execute. We also need to prevent a result set from
            //    being opened multiple times following a single 
            //    execution of the CALL.
            ExRsInfo *rsInfo = getResultSetInfo();
            if (rsInfo)
            {
              // Case a)
              rsInfo->reset();
            }
            if (parentCall_)
            {
              // Case b)
              ExRsInfo *parentRsInfo = parentCall_->getResultSetInfo();
              ex_assert(parentRsInfo, "No parent RS info available");

              ULng32 myIndex = parentRsInfo->getIndex(this);
              NABoolean openWasAttempted =
                parentRsInfo->openAttempted(myIndex);
              
              if (!openWasAttempted)
              {
                parentRsInfo->setOpenAttempted(myIndex);
              }
              else
              {
                diagsArea << DgSqlCode(-EXE_UDR_RS_REOPEN_NOT_ALLOWED)
                          << DgInt0((Lng32) myIndex);
                state_ = ERROR_;
                break;
              }
              
              RETCODE proxyRetcode = rsProxyPrepare(*parentRsInfo, myIndex,
                                                    diagsArea);
              if (proxyRetcode == ERROR)
              {
                state_ = ERROR_;
                break;
              }
            }
  
	    // Recompile if this stmt did not get compiled at 
	    // compilation time,
	    // or if the current transaction mode is different than the 
	    // mode specified at compile time.
	    if (! root_tdb)
	      {
		// A special case:
		// if DISPLAY query and no root_tdb, return. In this
		// case user does not want to execute the query.
		if (isDISPLAY()) 
		  {
			// change state so fetch can 'succeed' with an EOF.
			stmt_state = EOF_;
                        retcode = SUCCESS;
                        readyToReturn = TRUE;
                        break;
		  }

		// AQR has been enabled.
		if ((allocated()) &&
		    (context_->getSessionDefaults()->getAqrType() != 0))
		  {
		    // return error. AQR will handle recompile and retry.
		    diagsArea << DgSqlCode(-8583);
		    state_ = ERROR_;
		    break;
		  }

		state_ = COMPILE_;
		recompileReason[0] = SQL_EOF;	// eof here means EMPTY

		//diagsArea << DgSqlCode(EXE_RECOMPILE)	// a warning only
		//  << DgInt0(recompileReason[0]);
		  
		break;
	      }
	    else if ((root_tdb->transactionReqd() || root_tdb->isLRUOperation())
		     &&
		     compareTransModes(root_tdb, context_->getTransaction(),
				       (root_tdb->aqrEnabled() ? &diagsArea : NULL))
		     &&
              !systemModuleStmt() )
	      {
		if (root_tdb->aqrEnabled())
		  {
		    // return error. AQR will handle recompile and retry.
		    state_ = ERROR_;
		  }
		else
		  {
                    if (diagsArea.contains(-CLI_TRANS_MODE_MISMATCH))
                      diagsArea.clear();

		    state_ = COMPILE_;
		    recompileReasonIsTransMode(
			 root_tdb,
			 context_->getTransaction(),
			 recompileReason);
		    diagsArea << DgSqlCode(recompileReason[0])	// a warning only
			      << DgInt0(recompileReason[1]) 
			      << DgInt1(recompileReason[2]);
		  }
		break;
	      }


              if (root_tdb->inMemoryObjectDefn())
	      {
		// trying to executed a query which refers to an inMemory
		// object definition.
		// Return error.
                diagsArea << DgSqlCode(-CLI_CANNOT_EXECUTE_IN_MEM_DEFN);
                state_ = ERROR_;
                break;
	      }


            // if statistics were previously returned for this statement
            // (could happen for multiple executions of the same prepared
            //  or an embedded static statement), then re-initizalize the stat
            // area.	    
            ExStatisticsArea *statsArea = getStatsArea();
            if (statsArea != NULL &&
                statsArea->getCollectStatsType() != ComTdb::MEASURE_STATS)
            {
              StatsGlobals *statsGlobals = cliGlobals->getStatsGlobals();
              if (statsGlobals != NULL)
              {
                short savedPriority, savedStopMode;
                short error = statsGlobals->getStatsSemaphore(cliGlobals->getSemId(),
						      cliGlobals->myPin(), savedPriority, savedStopMode, 
                                                      FALSE /*shouldTimeout*/);
                ex_assert(error == 0, "getStatsSemaphore() returned an error");
                statsArea->initEntries();
                statsArea->restoreDop();
                statsGlobals->releaseStatsSemaphore(cliGlobals->getSemId(),cliGlobals->myPin(),
                          savedPriority, savedStopMode);
              }
              else
              {
                statsArea->initEntries();
                statsArea->restoreDop();
              }
            }
            if (stmtStats_ != NULL)
              stmtStats_->setAqrInProgress(FALSE);
            // LRU cannot run in a user transaction
            if (root_tdb && root_tdb->isLRUOperation() && context_->getTransaction()->xnInProgress())
	      {
                diagsArea << DgSqlCode(-EXE_CANT_BEGIN_USER_TRANS_WITH_LRU);
		retcode = ERROR;
	        state_ = ERROR_RETURN_;
                break;
	      }
	    
            // Start a transaction, if needed and one not already running.
	    //			if(!context_->getSuppressAutoXactStartFlag())
	    if ((NOT fixupOnly) ||
		(cliflags & PREPARE_STANDALONE_QUERY))
	      {
		if (beginTransaction(diagsArea))
		  {
		    retcode = ERROR;
		    state_ = ERROR_RETURN_;
		    //                readyToReturn = TRUE;
		    break;
		  }
	      }

	    setTsMismatched(FALSE);
	    state_ = RESOLVE_NAMES_;
	  }
	break;

	case RESOLVE_NAMES_:
	  {
	    NABoolean doSimCheck = FALSE;
	    NABoolean doFixup    = FALSE;

	    retcode = resolveNames(root_tdb->getLateNameInfoList(),
				   input_desc, diagsArea,
				   doSimCheck, doFixup);
	    if (retcode == ERROR)
	      {
		statementGlobals_->takeGlobalDiagsArea(diagsArea);
		state_ = ERROR_;
		break;
	      }
	    
	    if (doSimCheck) // do sim check due to name change
            {
	      state_ = DO_SIM_CHECK_;
            }
	    else
            {
              if (doFixup)
              {
                setFixupState(0);
              }
	      state_ = CHECK_DYNAMIC_SETTINGS_;
            }
	  }
	break;
	
	case DO_SIM_CHECK_:
	  {
            // This DO_SIM_CHECK_ state handles two distinct
            // tasks. One task is metadata lookups to discover
            // available partition names following a "partition not
            // available" error. The other task is the similarity
            // check. Right now the code does only one of these tasks
            // but never both. Might be best to break these two tasks
            // out into separate states.

            if (partitionUnavailable)
            {
              // We are getting ready to call catman code, and that code 
              // will recur into this CLI code.  The recursion doesn't work 
              // if any errors are in the context Diags Area - i.e, formal 
              // parameter diagsArea.  So we will clear the context 
              // diagsArea, but before clearing, we save off the conditions 
              // for two reasons: 
              // 1. If error is not fixed by catman, we want to return the 
              // original conditions (and any new conditions raise by catman) 
              // in the proper chronological order.
              // 2. Also, in case a warning was raised before the availability
              // error (especially, EXE_RECOMPILE), we need to report that, 
              // even if catman is able to find an available partition.
              //
              ComDiagsArea *saveContextDiagsArea = diagsArea.copy();
              diagsArea.clear();

              // Make a new diags area for catman to accumulate new conditions
              // into.
              ComDiagsArea *catmanDiagsArea = 
                                    ComDiagsArea::allocate(context_->exHeap());
              retcode = forceMapAllNames( lnil_ ? 
                            lnil_ : 
                            root_tdb->getLateNameInfoList(), *catmanDiagsArea);

              // Clear any new conditions have been added to the context diagsArea
              // They will have copies in the catmanDiagsArea.
              diagsArea.clear();

              // Now, construct a final diagsArea, with the pre-catman 
              // Conditions first, followed by the Conditions raised by the
              // catman. But if there is no error from the catman, clear the
              // pre-catman errors, because they are no longer relevant.

              if (retcode != ERROR)
              {
                Lng32 numErrors = saveContextDiagsArea->getNumber(DgSqlCode::ERROR_);
                while (numErrors--)
                {
                  saveContextDiagsArea->deleteError(numErrors);
                }
              }

              diagsArea.mergeAfter(*saveContextDiagsArea);
              saveContextDiagsArea->deAllocate();
              diagsArea.mergeAfter(*catmanDiagsArea);
              catmanDiagsArea->deAllocate();

              if (retcode == ERROR)
              {
                partitionAvailabilityChecked = TRUE;

                // If this is the first time the name lookups failed,
                // continue with a recompile. Otherwise stop working
                // and report the error.
                NABoolean reportTheError = FALSE;
                if (partitionNameLookupsFailed)
                  reportTheError = TRUE;

#ifdef NA_DEBUG_C_RUNTIME
                // In the debug build an environment setting can force
                // us to report the error here
                if (getenv("NO_RECOMP_WHEN_PART_UNAVAIL"))
                  reportTheError = TRUE;
#endif

                partitionNameLookupsFailed = TRUE;
                if (reportTheError)
                {
                  state_ = ERROR_;
                }
                else
                {
                  // Clear earlier errors from diags area, but leave warnings.
                  Lng32 numErrors = diagsArea.getNumber(DgSqlCode::ERROR_);
                  while (numErrors--)
                  {
                    diagsArea.deleteError(numErrors);
                  }
                  state_ = RECOMPILE_;
                }

                // This breaks us out of the DO_SIM_CHECK_ state
                break;
              }
              else
              {
                // At this point, all names are resolved to available
                // partitions, if at all possible.  If some names
                // still have no available partitions, we must
                // remember this fact so that the error (to be
                // discovered in the FIXUP_ state) will be returned to
                // the user.
                partitionAvailabilityChecked = TRUE;
                partitionUnavailable = FALSE;
                state_ = CHECK_DYNAMIC_SETTINGS_;

              } // if (retcode == ERROR) else ...
            } // if (partitionUnavailable)

            else
            {
	      NABoolean simCheckFailed = FALSE;

              if (root_tdb->querySimilarityInfo()->getSimilarityCheckOption() != 
                  QuerySimilarityInfo::ERROR_ON_TS_MISMATCH)
              {
                // Clear earlier errors from diags area, but leave warnings.
                Lng32 numErrors = diagsArea.getNumber(DgSqlCode::ERROR_);
                while (numErrors--)
                {
                  diagsArea.deleteError(numErrors);
                }
              }

              ComDiagsArea * diagsCopy = NULL;
              // If the diagsArea is populated, and this is not a recursive call into CLI,
              // then save a copy and re-instate after doQuerySimilarityCheck.
              // Clear the original diags area to avoid duplicate errors/warnings.
              if ((diagsArea.mainSQLCODE())    && 
                  (context_->getNumOfCliCalls() == 1)
                 )
              {
                diagsCopy = diagsArea.copy();
                diagsArea.clear();
              }

	      retcode =
	        doQuerySimilarityCheck(root_tdb->querySimilarityInfo(),
				       (lnil_ ? lnil_ : root_tdb->
				        getLateNameInfoList()),
				       simCheckFailed, diagsArea);

              if (diagsCopy)
              {
                // We saved something ...
                if (diagsArea.mainSQLCODE())
                {
                  // ... and doQuerySimilarityCheck also produced something, add to diagsCopy
                  diagsCopy->mergeAfter (diagsArea); 
                  diagsArea.clear();
                }
                // Put things back where they belong and get rid of the copy
                diagsArea.mergeAfter (*diagsCopy); 
                diagsCopy->deAllocate();
              }

	      if (retcode == ERROR)
	        {
		  state_ = ERROR_;
		  break;
	        }

	      setFixupState(0);
	      
	      if (simCheckFailed)
	        {
		  state_ = RECOMPILE_;
		  recompileReason[0] = EXE_SIM_CHECK_FAILED;
	        }
	      else
	        {
	          recompWarn = returnRecompWarn();
		  if (recompWarn &&
		      ((root_tdb->querySimilarityInfo()->getSimilarityCheckOption()
		       == QuerySimilarityInfo::SIM_CHECK_AND_RECOMP_ON_FAILURE) ||
		      (root_tdb->querySimilarityInfo()->getSimilarityCheckOption()
		       == QuerySimilarityInfo::SIM_CHECK_AND_ERROR_ON_FAILURE)))
		      
		    {
		      // similarity check passed. Return a warning indicating
		      // this. This is a temporary warning for testing.
		      diagsArea << DgSqlCode(EXE_SIM_CHECK_PASSED);
		    }
		  state_ = CHECK_DYNAMIC_SETTINGS_;
	        }
            }
	  }
	break;
	
	case COMPILE_:
	case RECOMPILE_:
	  {
	    // We want to ignore any errors that occur as part of dealloc 
	    // when called from here.
            // So, we mark the DiagsArea before making the call to dealloc(),
	    // and then rewind
            // back to there afterwards.
            Lng32 oldDiagsAreaMark = diagsArea.mark();
            Lng32 oldGlobalDiagsAreaMark = 0;
            if (statementGlobals_->getDiagsArea())
	      {
		oldGlobalDiagsAreaMark = statementGlobals_->getDiagsArea()->mark();
	      }
            
	    if (dealloc())
	      {
                //Leave the diagsArea as it is in case of error during the dealloc().
		state_ = ERROR_;
		break;
	      }
	    
            // Rewind to ignore all errors that occurred during a successful dealloc()
            if (statementGlobals_->getDiagsArea())
	      {
		statementGlobals_->getDiagsArea()->rewind(oldGlobalDiagsAreaMark, TRUE);
	      }
            diagsArea.rewind(oldDiagsAreaMark, TRUE);
	    
	    Int64 startTime = 0;
	    Int64 time = 0;

            Int32 transactionReqdPriorToRecompile = 0;
            NABoolean rootTdbExistsPriorToRecompile = TRUE;

            if (root_tdb)
               transactionReqdPriorToRecompile = root_tdb->transactionReqd();
            else
               rootTdbExistsPriorToRecompile = FALSE;

	    if (root_tdb &&
		(root_tdb->getCollectStatsType() == ComTdb::MEASURE_STATS))
	      startTime = NA_JulianTimestamp();

	    // similarity check not to be done or failed. Recompile.
	    // recompWarn = (root_tdb ? returnRecompWarn() : 0);
	    ULng32 flags = PREPARE_RECOMP;
            if (isCloned())
            {
              ex_assert(clonedFrom_, "Invalid clonedFrom_ pointer");
              retcode = clonedFrom_->prepare(NULL, diagsArea, NULL, 0, 
					     SQLCHARSETCODE_ISO88591 /* this setting does not matter because source - the 1st param - is set to NULL */, TRUE,
					     flags);
            }
            else
            {
              retcode = prepare(NULL, diagsArea, NULL, 0, 
				SQLCHARSETCODE_ISO88591 /* this setting does not matter because source - the 1st param - is set to NULL */, TRUE,
				flags);
            }

	    if ((retcode == ERROR) || (! root_tdb))
	      {
		if (! diagsArea.contains(-CLI_STMT_NOT_PREPARED))
		   diagsArea << DgSqlCode(- CLI_STMT_NOT_PREPARED);

		state_ = ERROR_;
		break;
	      }

            // After a successful compile or recompile, we need to be
            // able to react to a subsequent availability error on the
            // new plan by calling runtime metadata lookups that are
            // guaranteed to return the name of an available partition
            // if one can be found. By resetting these local variables
            // we become able to do the lookups again if necessary. If
            // we do not reset these variables, then after a recompile
            // if we encounter an unavailable partition we might
            // return an error to the application immediately which is
            // not the right thing to do. Instead we may need to do the
            // lookups again and try to use an available partition.
            partitionUnavailable = FALSE;
            partitionAvailabilityChecked = FALSE;

	    // The following stmt does not work since root_tdb changed after
            // prepare and the collectStatsType not setup correctly.
	    if ((root_tdb->getCollectStatsType() == ComTdb::MEASURE_STATS) &&
		(startTime != 0))
	      {
		time = NA_JulianTimestamp();
		reCompileTime = time - startTime;
		
		// update Measure sql process recompile counters.
		// Statement counters cannot be updated here since
		// stats area not allocated until fixup time.
		if (cliGlobals->getMeasProcCntrs() != NULL)
		  {
                    cliGlobals->getMeasProcCntrs()->incSqlStmtRecompiles(1);
		    cliGlobals->getMeasProcCntrs()->incSqlStmtRecompileTime(reCompileTime);
		  }
	      };
		
	    // if (!recompWarn)
	    recompWarn = returnRecompWarn();
	    if (recompWarn)
	      {
		diagsArea << DgSqlCode(EXE_RECOMPILE)	// a warning only
		  ;

	      }

            issuePlanVersioningWarnings (diagsArea);
            // For a cloned statement, the recomp was done on the original
            // statement, and warnings may be saved there too.
            if (isCloned())
              clonedFrom_->issuePlanVersioningWarnings (diagsArea);
   
            if (!transactionReqdPriorToRecompile && 
                rootTdbExistsPriorToRecompile && 
                root_tdb->transactionReqd())
               // If the statement is being recompiled, and did not need
               // a transaction before, but needs one now, start one,
               // after committing any implicit transaction started earlier
               // for visibility checking etc. This can only happen if the
               // table being accessed went from non-audited to audited.
               commitImplicitTransAndResetTmodes();

	    // Start a transaction, if needed and one not already running.
	    if (beginTransaction(diagsArea))
	      {
		state_ = ERROR_;
		break;
	      }

            // Indicate to subsequent states that we have prepared the query.
            donePrepare = TRUE;

	    if (state_ == COMPILE_ )
	      state_ = RESOLVE_NAMES_;
	    else
	      state_ = CHECK_DYNAMIC_SETTINGS_;
	  }
	break;

        case CHECK_DYNAMIC_SETTINGS_:
        {
          if (fixupState())
          {
            // If this fixed up statement was affected by SET TIMEOUT
            // or by a change in UDR runtime options then we want to
            // make sure it gets fixed up again
            if (statementGlobals_->timeoutSettingChanged() ||
                statementGlobals_->udrRuntimeOptionsChanged())
            {
              setFixupState(0);
            }
          }

          if (!fixupState())
            state_ = FIXUP_;
          else
            state_ = EXECUTE_;

        }
        break;
	
	case FIXUP_:
	  {
	    // We want to ignore any errors that occur as part of dealloc 
	    // when called from here.
            // So, we mark the DiagsArea before making the call to dealloc(),
	    // and then rewind
            // back to there afterwards.
            Lng32 oldDiagsAreaMark = diagsArea.mark();
            Lng32 oldGlobalDiagsAreaMark = 0;
            if (statementGlobals_->getDiagsArea())
	      {
		oldGlobalDiagsAreaMark = statementGlobals_->getDiagsArea()->mark();
	      }
            
            if (dealloc())
	      {
                //Leave the diagsArea as it is in case of error during the dealloc().
		state_ = ERROR_;
		break;
	      }
	    
            // Rewind to ignore all errors that occurred during a successful dealloc()
            if (statementGlobals_->getDiagsArea())
	      {
		statementGlobals_->getDiagsArea()->rewind(oldGlobalDiagsAreaMark, TRUE);
	      }
            diagsArea.rewind(oldDiagsAreaMark, TRUE);
	    space_.freeBlocks();
	    
	    statementGlobals_->reAllocate(1);
	    
	    setState(CLOSE_);
	    
	    setFixupState(0);

	    // move resolved names from LateNameInfoList to
	    // ResolvedNameList which will be shipped to PA's
	    if (root_tdb->getLateNameInfoList())
	      {
		ResolvedNameList *&rnl =
		  statementGlobals_->resolvedNameList();
		if (rnl && (rnl->numEntries() < root_tdb->getLateNameInfoList()->getNumEntries()))
		  {
		    // deallocate the previously allocated rnl
		    heap_.deallocateMemory(rnl);
		    rnl = NULL;
		  }

		if (! rnl)
		  rnl = 
		    (ResolvedNameList *)
		    (new(&heap_) 
		     char[sizeof(ResolvedNameList) +
			 ((root_tdb->getLateNameInfoList()->
			   getNumEntries() > 0 ) ?
			  ((root_tdb->getLateNameInfoList()->
			    getNumEntries() - 1) * sizeof(ResolvedName)):
			  0)]);

		rnl->numEntries() =
		   root_tdb->getLateNameInfoList()->getNumEntries();
		rnl->resetFlags();

		for (Int32 i = 0; 
		     i < (Int32) (root_tdb->getLateNameInfoList()->
				getNumEntries());
		     i++)
		  {
		    strcpy(rnl->getResolvedName(i).resolvedGuardianName(),
			   root_tdb->getLateNameInfoList()->
			   getLateNameInfo(i).resolvedPhyName());

                    short ignore = (short) root_tdb->getLateNameInfoList()->
                      getLateNameInfo(i).ignoreTS();
		    rnl->getResolvedName(i).setIgnoreTS(ignore);

                    rnl->getResolvedName(i).setResolvedAnsiName(
                           root_tdb->getLateNameInfoList()->
                           getLateNameInfo(i).getLastUsedName(&heap_)->getExternalName());
		  }

		// if this is an IUD query,
		// move the number of indices defined on the target
		// table to the latenameinfo entry for that table.
		// At open time, if this is an sql/mp table and no timestamp
		// mismatch is detected, the number of indices will be
		// validate. See call to doArkOpen in file ex_sql_table.cpp,
		// method SqlTable::SqlTable.
		QuerySimilarityInfo * qsi = root_tdb->querySimilarityInfo();
		if ((qsi->getSimilarityCheckOption() != QuerySimilarityInfo::INTERNAL_SIM_CHECK) &&
		    (qsi->indexInfoList()))
		  {
		    rnl->getResolvedName(qsi->namePosition()).setValidateNumIndexes(TRUE);
		    rnl->getResolvedName(
			 qsi->namePosition()).setNumIndexes(
			      (short)qsi->indexInfoList()->numEntries());
		  }
	      } // lateNameInfoList present

            StmtDebug1("[BEGIN fixup] %p", this);

	    NABoolean doSimCheck = FALSE;
	    retcode =
	      fixup(cliGlobals, input_desc, diagsArea, doSimCheck,
                      partitionUnavailable, donePrepare);


            StmtDebug2("[END fixup] %p, result is %s", this,
                       RetcodeToString(retcode));

	    if (((fixupOnly) ||
		 (root_tdb->aqrEnabled())) &&
		((retcode == ERROR) ||
		 (diagsArea.mainSQLCODE() < 0) ||
		 (doSimCheck)))
	      {
		state_ = ERROR_;
		break;
	      }

	    if ((retcode == ERROR) || 
                (partitionUnavailable && partitionAvailabilityChecked))
	      {
                // VO, Genesis solution 10-051125-2802:
                // We may have gotten a plan version error from ESP assignment
                if ( diagsArea.contains (-VERSION_COMPILER_VERSION_LOWER_THAN_OLDEST_SUPPORTED) ||
                     diagsArea.contains (-VERSION_COMPILER_USED_TO_COMPILE_QUERY)
                   )
                {
                  // Get rid of these errors - recompile will re-issue if we have an
                  // incurable incompatibility
		  diagsArea.clear();
		  state_ = RECOMPILE_;
                }
                else
                  state_ = ERROR_;
		break;
	      }

	    // update Measure stmt counters for recompilation.
	    // stats area is allocated in fixup (ex_root_tdb::build).

            ExStatisticsArea *stats = getStatsArea();
	    if ( reCompileTime > 0 &&
		 /*root_tdb->getCollectStats() == ComTdb::MEASURE_STATS &&*/
		 stats != NULL )
            {
              if (stats->getStmtCntrs() != NULL)
              {
                stats->getStmtCntrs()->incRecompiles(1);
                stats->getStmtCntrs()->incElapsedCompileTime(reCompileTime);
                reCompileTime = (Int64) 0;
              }
            }

	    if (doSimCheck || partitionUnavailable)
            {
	      state_ = DO_SIM_CHECK_;
            }
	    else
            {
              state_ = EXECUTE_;

              if (fixupOnly)
		{		   		  
		  if  (NOT(cliflags & PREPARE_STANDALONE_QUERY))
		    {
		      // if an explicitly prepared query, commit any
		      // transaction that was started during fixup
		      // stage. We don't want to hold onto this Xn
		      // between this stmt's prepare and its execute.
		      // Later, when this query is executed, a
		      // transaction would be started.

                      // Wait for UDR transactional replies before
                      // attempting to commit
                      NABoolean allRequests = FALSE;
                      completeUdrRequests(allRequests);

		      // The following call will only reset autoCommit
		      // which is needed for the commitTransaction()
		      // to actually commit.
		      resetAutoCommit(); 

		      // now call commitTransaction since autoCommit has been 
		      // reset
		      if (commitTransaction(diagsArea))
			{
			  state_ = ERROR_;
			  retcode = ERROR;
			  readyToReturn = TRUE;
			  break;
			}
		      retcode = SUCCESS;
		      readyToReturn = TRUE;
		      state_ = FIXUP_DONE_;
		    
		    }
		  else
		    {
		      retcode = SUCCESS;
		      readyToReturn = TRUE;
		      state_ = INITIAL_STATE_;
		    }
                  
		} // if (fixupOnly && (state_ != ERROR_))
            } // if (doSimCheck || partitionUnavailable) else ...
            
            // Transition to the ERROR_ state if errors were recorded
            // in statement globals. Also set readyToReturn to FALSE
            // so we don't return out of this method before processing
            // the state transition.
            if (state_ != ERROR_)
            {
              ComDiagsArea *stmtGlobDiags = statementGlobals_->getDiagsArea();
              if (stmtGlobDiags && stmtGlobDiags->mainSQLCODE() < 0)
              {
                statementGlobals_->takeGlobalDiagsArea(diagsArea);
                state_ = ERROR_;
                readyToReturn = FALSE;
              }
            }
            
	  } // case FIXUP_
	break;
	
	case FIXUP_DONE_:
	  {
	    // Begin a transaction before going to EXECUTE_ state since
	    // the transaction may have been committed
	    if (beginTransaction(diagsArea))
	      {
		retcode = ERROR;
		state_ = ERROR_RETURN_;
		break;
	      }
	    if (masterStats != NULL)
	      {
	       Int64 jts = NA_JulianTimestamp();
                if (NOT masterStats->isPrepAndExec())
	        {
                  masterStats->setElapsedStartTime(jts);
                }
                masterStats->setExeStartTime(aqrInitialExeStartTime_ == -1
                     ? jts : aqrInitialExeStartTime_);
              }
	    state_ = EXECUTE_;
	  }
	  break;
	case EXECUTE_:
	  {
	    if (masterStats != NULL)
	      {
		masterStats->
		  setFixupEndTime(NA_JulianTimestamp());
                if (!masterStats->getValidDDL())
                  {
                    diagsArea << DgSqlCode(-CLI_DDL_REDEFINED);
                    state_ = ERROR_;
                    break;
                  }
                if (!masterStats->getValidPrivs())
                  {
                    diagsArea << DgSqlCode(-CLI_INVALID_QUERY_PRIVS);
                    state_ = ERROR_;
                    break;
                  }
              }

	    /* execute it */
            if( root_tdb )
            {            
                // check if we have triggers
                if (root_tdb->getTriggersCount() > 0)
                {
                  retcode =
                    getTriggersStatus(root_tdb->stoiStoiList(), diagsArea);
                  if (retcode == ERROR)
                  {
                    state_ = ERROR_;
                    break;                
                  }
                }

                // check for statements with uninitialized mvs          
                char * pMvName;
                if( doesUninitializedMvExist( &pMvName, diagsArea ) )
                {                                
                    diagsArea << DgSqlCode(- CLI_MV_EXECUTE_UNINITIALIZED)
                              << DgTableName( (const char *)pMvName);
                    state_ = ERROR_;
                    break;                
                }
            } 
          

	    // BertBert VV
            // in case this is a holdable cursor propagate flag to master executor
            // leaf nodes
            if (isPubsubHoldable() &&
		!root_tdb->isEmbeddedUpdateOrDelete() &&
		!root_tdb->isStreamScan())
	      {
                // Holdable cursors are only supported for streaming cursors
		// and destructive cursors because there are some strange
		// side-effects (locks disappear after commit) that we don't
		// want to inflict on non-Publich/Subscribe functionality at
		// this time. There are no source-code changes needed to allow
		// holdable cursors in these other cases though.
                diagsArea << DgSqlCode(-CLI_CURSOR_CANNOT_BE_HOLDABLE);
                state_ = ERROR_;
                break;
              }
            // BertBert ^^
           
	    ComDiagsArea* diagsPtr = NULL;
	    
	    // if this is an 'update where current of' query, and
	    // the cursor statement name was specified via a hvar,
	    // then find the cursor statement and hook it up here.
	    // In this case, fetched statement has to be searched
	    // before each execute because the hvar value may 
	    // change between calls to Exec.
	    // Also validate that the tablename specified in the upd/del
	    // stmt is the same as the one in the declare cursor stmt.
	    if (root_tdb->updateCurrentOfQuery())
	      {
		if (root_tdb->fetchedCursorName() == NULL) // spec via hvar
		  {
		    // find the hvar that contains the cursor name in the 
		    // input desc list
		    Lng32 cursor_name = 0;
		    input_desc->getDescItem(root_tdb->fetchedCursorHvar(),
					    SQLDESC_VAR_PTR, &cursor_name, 
					    0, 0, 0, 0);
                    char * cursor_name_copy = NULL;
		    if (cursor_name == 0)
		      {
			diagsArea << DgSqlCode(-CLI_TCB_EXECUTE_ERROR);
			state_ = ERROR_;
			break;
		      }
		    else
		      {
                        Lng32 string_length = 0;
                        input_desc->getDescItem(root_tdb->fetchedCursorHvar(),
						SQLDESC_LENGTH, &string_length,
						0, 0, 0, 0);
                        cursor_name_copy = 
                        Descriptor::getCharDataFromCharHostVar
                          (diagsArea,
			   heap_,
                           (char *)cursor_name, 
                           string_length,
			   "CURSOR NAME", 
                           input_desc,
                           root_tdb->fetchedCursorHvar() - 1,  // Pass a zero-based index.
                           REC_BYTE_V_ANSI);
		      }
		    
		    currentOfCursorStatement_ =
		      getCurrentOfCursorStatement((char *)cursor_name_copy);
		    if (cursor_name_copy) heap_.deallocateMemory(cursor_name_copy);

		    if (currentOfCursorStatement_ == NULL)
		      {
			diagsArea << DgSqlCode(- CLI_NON_UPDATABLE_SELECT_CURSOR)
				  << DgString0((char *)cursor_name);
			state_ = ERROR_;
			break;
		      }
		  }

		// make sure that the table name in the update/del stmt is the
		// same as the tablename specified in the cursor.
		ex_root_tdb *cursorTdb = currentOfCursorStatement_->getRootTdb();
#pragma nowarn(1506)   // warning elimination 
		Int16 cursorTableNameLen = 
		  str_len( cursorTdb->getLateNameInfoList()->
						    getLateNameInfo(cursorTdb->baseTablenamePosition()).
						    lastUsedAnsiName());
		
		Int16 updelTableNameLen = 
		  str_len( root_tdb->getLateNameInfoList()->
			   getLateNameInfo(root_tdb->baseTablenamePosition()).
			   lastUsedAnsiName());
		if ( (cursorTableNameLen != updelTableNameLen ) || 

		     (str_cmp(root_tdb->getLateNameInfoList()->
			   getLateNameInfo(root_tdb->baseTablenamePosition()).
			   lastUsedAnsiName(), 
			   cursorTdb->getLateNameInfoList()->
			   getLateNameInfo(cursorTdb->baseTablenamePosition()).
                           lastUsedAnsiName(), 
			   updelTableNameLen
			   ) != 0) 
		    )
		  {
		    diagsArea << DgSqlCode(- CLI_NON_CURSOR_UPDEL_TABLE)
			      << DgString0(root_tdb->fetchedCursorName());
		    retcode = ERROR;
		    state_ = ERROR_RETURN_;
		    //                    readyToReturn = TRUE;
                    break;
		  }
	      }	   
 
	    // Get the row of primary key values from the referenced cursor and
	    // move it to my root tcb and ensure the update columns are valid.
	    if (root_tdb->updateCurrentOfQuery())
	      {
		if (currentOfCursorStatement_ == NULL)
		  {
		    diagsArea << DgSqlCode(- CLI_NON_UPDATABLE_SELECT_CURSOR);
		    state_ = ERROR_;
		    break;
		  }
		
		if (currentOfCursorStatement_->getState() != FETCH_)
		  {
		    // Must have fetched a row to do an update...current of.
		    // Add a better error message here. TBD.
		    diagsArea << DgSqlCode(- EXE_CURSOR_NOT_FETCHED);
		    state_ = ERROR_;
		    break;
		  }

		if (currentOfCursorStatement_->isDeletedCursor())
		  {
		    // Must have fetched a row to do an update...current of.
		    // Cannot update or delete a row that was previously
		    // deleted using this cursor.
		    diagsArea << DgSqlCode(- EXE_CURSOR_NOT_FETCHED);
		    state_ = ERROR_;
		    break;
		  }

		char * pkeyRow = 
		  currentOfCursorStatement_->getRootTcb()->getPkeyRow();
		if (pkeyRow == NULL)
		  {
		    // Add a better error message here. TBD.
		    diagsArea << DgSqlCode(- CLI_TCB_EXECUTE_ERROR);
		    state_ = ERROR_;
		    break;
		  }
		
		root_tcb->inputPkeyRow(pkeyRow);
		
		if (!currentOfCursorStatement_->root_tdb->isUpdateCol(root_tdb))
		  {
		    diagsArea << DgSqlCode(- CLI_INVALID_UPDATE_COLUMN);
		    state_ = ERROR_;
		    break;
		  }
	      }

	     // NOT_ATOMIC_FAILURE_LIMIT was specified through the statement attribute
	     // override any value we get from the CQD
	     if ((getNotAtomicFailureLimit() != 0) && 
	         (root_tdb->isNonFatalErrorTolerated())) {
	      root_tdb->setNotAtomicFailureLimit(getNotAtomicFailureLimit());
	     }
	    
	    // nothing happened yet.
            statementGlobals_->setGlobDiagsArea(0);
	    statementGlobals_->setRowsAffected(0);
	    diagsArea.setRowCount(0);
	    
            // Now that the statement is completely name-resolved, 
            // catalog-visiblity-checked, fixed up, compiled, recompiled, 
            // etc, etc, see if we started an implicit transaction to
            // perform any of these tasks and if so, commit it so that 
            // the statement can run without a trans (since if *we*
            // started the trans then this must be a READ UNCOMMITTED
            // statement.  Also, reset the autocommit setting if we 
            // had to temporarily turn it off.
            commitImplicitTransAndResetTmodes();


	    // before executing the statement, change master priority to
	    // be the same as ESP priority.
            SessionDefaults *sessionDefaults =
              statementGlobals_->getContext()->getSessionDefaults();
	    if (sessionDefaults->getAltpriMaster() ||
		sessionDefaults->getAltpriMasterSeqExe())
	      {
		// if session default altpri_master is set, then:
		//   -- always altpr parallel queries
		//   -- altpri sequential queries if ALTPRI_MASTER is set in 
		//      root tdb
		ExRtFragTable *fragTable = statementGlobals_->getRtFragTable();
                if (sessionDefaults->getAltpriMasterSeqExe() ||
		    (fragTable &&
                     fragTable->getState() != ExRtFragTable::NO_ESPS_USED))
		  {
		    IpcPriority myPriority = statementGlobals_->getMyProcessPriority();
		    IpcPriority espPriority;
		    if (sessionDefaults->getEspPriority() > 0)
		      espPriority = sessionDefaults->getEspPriority();
		    else if (sessionDefaults->getEspPriorityDelta() != 0)
		      espPriority = myPriority +
                        sessionDefaults->getEspPriorityDelta();
		    else
		      espPriority = myPriority;
		    
		    if ((espPriority > 200) ||
			(espPriority < 1))
		      espPriority = myPriority;
		    
		    // change master priority to be the same as ESP.
		    // Do this only for root cli level
		    if ((context_->getNumOfCliCalls() == 1) &&
			(myPriority != espPriority))
		      {
			ComRtSetProcessPriority(espPriority, FALSE);
			statementGlobals_->getCliGlobals()->setPriorityChanged(TRUE);
		      }
		  }
              }
	    NABoolean parentIsCanceled = updateChildQid();
	    if (parentIsCanceled)
	    {
	      diagsArea << DgSqlCode(-EXE_CANCELED);
	      state_ = ERROR_;
	      break;
	    }
	    //decide if this query needs to be monitored by WMS
	    NABoolean monitorThisQuery = FALSE;
	    // If there is no parent qid then filter out certain query types before monitoring
	    if (!getParentQid())
	    {
	    	if ((root_tdb->getWmsMonitorQuery()) &&
	    			(root_tdb->getQueryType() != SQL_CONTROL) &&
	    			(root_tdb->getQueryType() != SQL_SET_TRANSACTION) &&
	    			(root_tdb->getQueryType() != SQL_SET_CATALOG) &&
	    			(root_tdb->getQueryType() != SQL_SET_SCHEMA) &&
	    			(root_tdb->getSubqueryType() != SQL_DESCRIBE_QUERY) &&
	    			(root_tdb->getQueryType() != SQL_SELECT_UNIQUE) &&
	    			(root_tdb->getQueryType() != SQL_INSERT_UNIQUE) &&
	    			(root_tdb->getQueryType() != SQL_UPDATE_UNIQUE) &&
	    			(root_tdb->getQueryType() != SQL_DELETE_UNIQUE) &&
	    			(root_tdb->getQueryType() != SQL_OTHER) &&
		                (stmt_type != STATIC_STMT) &&
		                (getUniqueStmtId())
	    	)
	    	{
	    		monitorThisQuery = TRUE;
			if (stmtStats_)
			  stmtStats_->setWMSMonitoredCliQuery(TRUE);
	    	}
	    }
	    else
	    {
	    	//There is a parent qid associated with this query

	    	// If the query is a call statement don't monitor. mxosrvr
	    	//will monitor all call statements as well as DML statements
	    	// issued by SPJ body.
	    	if ((root_tdb->getQueryType() == SQL_CALL_NO_RESULT_SETS) ||
	    			(root_tdb->getQueryType() == SQL_CALL_WITH_RESULT_SETS) ||
	    			(root_tdb->getQueryType() == SQL_SP_RESULT_SET))
	    	{
	    		monitorThisQuery = FALSE;
	    	}
	    	// If the CQD WMS_CHILD_MONITOR_QUERY is TRUE

	    	// For ExeUtil queries ,also check if the prepare flag is set
	    	// and only then monitor it.
	    	else if (root_tdb->getQueryType() == SQL_EXE_UTIL  )
	    	{
	    		if (root_tdb->getWmsChildMonitorQuery() && wmsMonitorQuery())
			  {
	    			monitorThisQuery = TRUE;
				if (stmtStats_)
				  stmtStats_->setWMSMonitoredCliQuery(TRUE);
			  }
	    	}
	    	else
	    		// These are queries issued by internal callers.
	    		//The prepare flag is not set for these so simply
	    		// filter out simple queries and monitor it.
	    		if ( root_tdb->getWmsChildMonitorQuery() &&
	    				(root_tdb->getQueryType() != SQL_CONTROL) &&
	    				(root_tdb->getQueryType() != SQL_SET_TRANSACTION) &&
	    				(root_tdb->getQueryType() != SQL_SET_CATALOG) &&
	    				(root_tdb->getQueryType() != SQL_SET_SCHEMA) &&
	    				(root_tdb->getSubqueryType() != SQL_DESCRIBE_QUERY) &&
	    				(root_tdb->getQueryType() != SQL_SELECT_UNIQUE) &&
	    				(root_tdb->getQueryType() != SQL_INSERT_UNIQUE) &&
	    				(root_tdb->getQueryType() != SQL_UPDATE_UNIQUE) &&
	    				(root_tdb->getQueryType() != SQL_DELETE_UNIQUE) &&
	    				(root_tdb->getQueryType() != SQL_OTHER) &&
			                (stmt_type != STATIC_STMT) &&
			                (getUniqueStmtId())
			     )
			  {
			    monitorThisQuery = TRUE;
			    if (stmtStats_)
			      stmtStats_->setWMSMonitoredCliQuery(TRUE);
			  }
	    }
	      
	    if (monitorThisQuery)
	      {
		SQL_QUERY_COST_INFO query_cost_info;
		SQL_QUERY_COMPILER_STATS_INFO query_comp_stats_info;
		query_cost_info.cpuTime   = 0;
		query_cost_info.ioTime    = 0;
		query_cost_info.msgTime   = 0;
		query_cost_info.idleTime  = 0;
		query_cost_info.totalTime = 0;
		query_cost_info.cardinality = 0;
		query_cost_info.estimatedTotalMem  = 0;
		query_cost_info.resourceUsage = 0;
                query_cost_info.maxCpuUsage = 0;
		if (getRootTdb())
		  {
		    if (getRootTdb()->getQueryCostInfo())
		      {
                        getRootTdb()->getQueryCostInfo()->translateToExternalFormat(&query_cost_info);
		      }
		
		  }
		else
		  query_cost_info.totalTime = getRootTdb()->getCost();

	      
		if (getRootTdb())
		  {
		    CompilerStatsInfo *cmpStatsInfo = 
		      getRootTdb()->getCompilerStatsInfo();

		    if (cmpStatsInfo)
		      {
			short xnNeeded = (transactionReqd() ? 1 : 0);
			cmpStatsInfo->translateToExternalFormat(&query_comp_stats_info,xnNeeded);
			// CompilationStatsData. 
			CompilationStatsData *cmpData = 
			  getRootTdb()->getCompilationStatsData();


			SQL_COMPILATION_STATS_DATA *query_cmp_data = 
			  &query_comp_stats_info.compilationStats;
  
			if( cmpData )
			  {
                           Int64 cmpStartTime = -1;
                           Int64 cmpEndTime = NA_JulianTimestamp();
                           if (masterStats != NULL)
                              cmpStartTime = masterStats->getCompStartTime();
			    cmpData->translateToExternalFormat(query_cmp_data,
                                        cmpStartTime, cmpEndTime);
                            setCompileEndTime(cmpEndTime);
			  }   
		      }

		  }
	      


	      }	
      // done deciding if this query needs to be monitored and 
      // registered with WMS.
      // now execute it.
      if (masterStats != NULL)
	{
	  masterStats->setIsBlocking();
	  masterStats->setStmtState(STMT_EXECUTE_);
	}

      Int32 rc = root_tcb->execute(cliGlobals, statementGlobals_,
				   input_desc, diagsPtr, reExecute);

      if (masterStats != NULL)
	masterStats->setNotBlocking();
      if (rc < 0)
	retcode = ERROR;
      // "diagsPtr" is modified by the foregoing call.
      // If "diagsPtr" is NULL, there are no diags to merge
      // into "diagsArea".  Otherwise, "diagsPtr" is not NULL and does
      // point to a diags area from which we: 1) avoid the SQL function
      // 2) copy the ComCondition objects over.  Then we decrement
      // the reference count to indicate we're done with that
      // ComDiagsArea.
	    
      if (diagsPtr)
	{
	  diagsArea.mergeAfter(*diagsPtr);
	  diagsPtr->decrRefCount();    
	  diagsPtr = NULL;
	}
	    
      if (retcode == ERROR)
	{
	  root_tcb->cancel(statementGlobals_,diagsPtr);
	  state_ = ERROR_;
	  break;
	}
      else
	{
	  if (retcode == 0 && diagsArea.mainSQLCODE() > 0)
	    // It's a warning. So return 1. 
	    retcode = (RETCODE)1;
	  setState(OPEN_);
	  readyToReturn = TRUE;
	  break;
	}
    }
  break;
	
	case RE_EXECUTE_:                 // on error 60
	case RE_EXECUTE_AFTER_RECOMPILE_: // on plan version error
	  {
	    // save lnil & stuff
	    // if input descriptor was passed in at execute time, recreate 
	    // the input data
	    // Setting the boolean reExecute to true, will cause the
	    // inputData from the previous execution to be used since we
	    // have no input_desc anymore at this stage. 
	    if (inputData_)
	      heap_.deallocateMemory (inputData_) ;
	    inputData_ = NULL;
	    char * inputData;
	    root_tcb->getInputData(inputData, inputDatalen_);
	    if (inputData)
	      {
		inputData_ = (char*) heap_.allocateMemory (inputDatalen_) ;
		str_cpy_all(inputData_, inputData, (Lng32) inputDatalen_);
	      }
	    
	    setFixupState(0);
	    reExecute=TRUE;
            if (state_ == RE_EXECUTE_)
              state_ = CHECK_DYNAMIC_SETTINGS_;
            else
              state_ = RECOMPILE_;
	  }
	break;

	case ERROR_:
	  {
	    retcode = error(diagsArea);
	    state_ = ERROR_RETURN_;
	  }
	break;
	
	case ERROR_RETURN_:
	  {
            readyToReturn = TRUE;
	  }
	break;
	
	default:
	  state_ = ERROR_;
	  break;

	} // switch
    } // while return 

  commitImplicitTransAndResetTmodes();

  StmtDebug2("[END execute] %p, result is %s", this,
             RetcodeToString(retcode));
  return retcode;

} // Statement::execute diags

RETCODE Statement::fetch(CliGlobals * cliGlobals, Descriptor * output_desc,
			 ComDiagsArea &diagsArea,
                         NABoolean newOperation)
{
  StmtDebug2("[BEGIN fetch] %p, stmt state %s", this, stmtState(getState()));

  Int32 timeout = 0;
  Int32 retcode = SUCCESS;
  if (stmt_state == CLOSE_)
    {
      // trying to fetch from a statement which is in CLOSE state
      diagsArea << DgSqlCode(- CLI_STMT_CLOSE);
      StmtDebug3("[END fetch] %p, result is %s, stmt state %s", this,
                 RetcodeToString(ERROR), stmtState(getState()));
      return ERROR;
    }

  if (stmt_state == EOF_) // already returned EOF once.
  {
    if (output_desc && output_desc->rowwiseRowsetEnabled())
      output_desc->setDescItem(0, SQLDESC_ROWSET_NUM_PROCESSED,
				       0, NULL);
    StmtDebug3("[END fetch] %p, result is %s, stmt state %s", this,
               RetcodeToString(SQL_EOF), stmtState(getState()));
    return SQL_EOF;
  }

  if (!root_tcb)
    {
    // trying to fetch from a statement with a null root_tcb;
    // probably, a bug elsewhere. For example, sqlc translates
    //   exec sql prepare S1 from :buf;
    // into
    //   if ((SQLCODE = SQL_EXEC_ClearDiagnostics(&__SQL_id0))  < 0
    //   ||(SQLCODE = SQL_EXEC_SetDescPointers
    //       (&__SQL_id1,1,1,&(buf[0]),NULL)) < 0
    //   ||(SQLCODE = SQL_EXEC_AllocStmt(&__SQL_id0,NULL)) < 0
    //   ||(SQLCODE = SQL_EXEC_Prepare(&__SQL_id0,&__SQL_id1)) < 0);
    // Note that Prepare() will be short-circuited if any of the preceding
    // CLI calls fail silently and the result can be a null root_tcb which
    // will crash arkcmp unless we bulletproof against FETCH S1!
    diagsArea << DgSqlCode(- CLI_INTERR_NULL_TCB);
    StmtDebug3("[END fetch] %p, result is %s, stmt state %s", this,
               RetcodeToString(ERROR), stmtState(getState()));
    return ERROR;
  }
 
  if (newOperation)
  {
    if ((isAnsiHoldable() || isPubsubHoldable()) && transactionReqd())
    {
      if (! context_->getTransaction()->xnInProgress())
      {
        if (beginTransaction(diagsArea))
          return ERROR;
      }
    }
  }
  else
  {
    if ((isAnsiHoldable() || isPubsubHoldable()) && transactionReqd())
    {
      if (! context_->getTransaction()->xnInProgress())
      {
        ex_assert(0, "Transaction is Not Valid");
      }
    }
  }
  timeout = -1 ;

#ifdef NA_DEBUG_C_RUNTIME
  if (output_desc)
  {
    Lng32 outputRowsetSize  = 0;
    output_desc->getDescItem(0, SQLDESC_ROWSET_SIZE, &outputRowsetSize,
                             0, 0, 0, 0);
    if (outputRowsetSize > 1)
      StmtDebug1("  Output rowset size: %d", outputRowsetSize);
  }
#endif
  
  // Check for suspended query.  The other check called in the 
  // Scheduler::work.  We do it here simply because some users
  // expect if the query is suspended while the client is not 
  // blocked in SQL, the next fetch should not return any row.
  // Without this check, a row could be returned if it was ready,
  // since it would not be needed to call the Scheduler::work(). 
  statementGlobals_->getScheduler()->checkSuspendAndLimit();

  /*fetch row*/
  ComDiagsArea* diagsPtr = NULL;
  NABoolean closeCursorOnError = TRUE;
  ExMasterStats *masterStats =
    (stmtStats_ ? stmtStats_->getMasterStats() : NULL);
  if (masterStats)
    masterStats->setIsBlocking();
  if (output_desc && output_desc->rowwiseRowsetEnabled())
    {
      NABoolean eodSeen=FALSE;
      retcode = root_tcb->fetchMultiple(cliGlobals, statementGlobals_, 
					output_desc,
					diagsPtr, timeout, newOperation,
					closeCursorOnError,eodSeen);
      if ((retcode >0) && (eodSeen))
	{
	  // If a warning is returned along with EOD,we have to return the 
	  // warning retcode to MXCS otherwise they will not retrieve the diags
	  // But remember that eod was returned so we don't go through fetch 
	  // again when we are redriven
	  setState(EOF_);
	}
 StmtDebug1("  root_tcb->fetchMultiple() returned %s",
            RetcodeToString((RETCODE) retcode));

    }
  else
    {
      retcode = root_tcb->fetch(cliGlobals, statementGlobals_, output_desc,
				diagsPtr, timeout, newOperation,
				closeCursorOnError);
      if (output_desc && output_desc->rowwiseRowset())
	{
	  if ((retcode >= 0) &&
	      (retcode != 100))
	    {
	      output_desc->setDescItem(0, SQLDESC_ROWSET_NUM_PROCESSED,
				       1, NULL);
	    }
	  else
	    {
	      output_desc->setDescItem(0, SQLDESC_ROWSET_NUM_PROCESSED,
				       0, NULL);
	    }
	}

StmtDebug1("  root_tcb->fetch() returned %s",
           RetcodeToString((RETCODE) retcode));

    }

  if (masterStats)
    masterStats->setNotBlocking();

  Statement::ExecState execute_state;
  while ((retcode < 0)      &&
	 (diagsPtr != NULL) &&
	 (  // Handle lost open by trying to close/reopen the table
            (diagsPtr->contains(-EXE_LOST_OPEN))                        ||
	    (diagsPtr->contains(-EXE_PARTITION_UNAVAILABLE))            ||
	    // Handle plan versioning errors by trying to recompile the query
	    (diagsPtr->contains(-VERSION_PLAN_VERSION_HIGHER_THAN_MXV)) ||
	    (diagsPtr->contains(-VERSION_PLAN_VERSION_OLDER_THAN_OLDEST_SUPPORTED))
         )
	)
    {
#ifdef NA_DEBUG_C_RUNTIME
      StmtDebug1("  stmt state %s", stmtState(getState()));
      if (diagsPtr)
       {
        if (diagsPtr->contains(-EXE_LOST_OPEN))
            StmtDebug0("  diags contains -EXE_LOST_OPEN");
        if (diagsPtr->contains(-EXE_PARTITION_UNAVAILABLE))
            StmtDebug0("  diags contains -EXE_PARTITION_UNAVAILABLE");
       }
      StmtDebug1("  this %s a retryable stmt",
                (root_tdb->retryableStmt() ? "IS" : "IS NOT"));
#endif

      if (root_tdb->retryableStmt() && (getState() != FETCH_))
	{
          // A retryable statement in a retryable state
          short currentCompilerVersion = COM_VERS_UNKNOWN;
          short index;
	  if ((diagsPtr->contains(-EXE_LOST_OPEN)) ||
	      (diagsPtr->contains(-EXE_PARTITION_UNAVAILABLE)))
	    execute_state = RE_EXECUTE_;
	  else
	    {
	      // Plan version error. Set the state to RE_EXECUTE_AFTER_RECOMPILE_ and figure out what
              // version compiler to use, depending upon the actual error.
              // Save the current default compiler version, so we can reset it after preparing the query.
              currentCompilerVersion = getContext()->getVersionOfCompiler();
              if (diagsPtr->contains(-VERSION_PLAN_VERSION_HIGHER_THAN_MXV))
              {
                // plan version is too high, recompile with required downrev compiler
                retcode = getContext()->setOrStartCompiler((short)(*diagsPtr)[1].getOptionalInteger(1), NULL, index);
              }
              else
              {
                // plan version is too low, recompile with the current version compiler
                retcode = getContext()->setOrStartCompiler(COM_VERS_COMPILER_VERSION, NULL, index);
              }
	      
	      execute_state = RE_EXECUTE_AFTER_RECOMPILE_;
	      if (retcode == ERROR)
		{
                  // OK no to reset the compiler version, because we didnt actually set it 
		  setState(CLOSE_);
		  diagsPtr->decrRefCount();
		  return ERROR;
		}

              // Save the error information so that we can report it later as a warning
              fetchErrorCode_ = (VersionErrorCode) ABS(diagsPtr->mainSQLCODE());          // turn into warning
              fetchPlanVersion_ = (COM_VERSION) (*diagsPtr)[1].getOptionalInteger(0);
              fetchSupportedVersion_ = (COM_VERSION) (*diagsPtr)[1].getOptionalInteger(1);
              fetchNode_ = (*diagsPtr)[1].getOptionalString(0);
	    }

	  diagsArea.clear();

	  retcode = root_tcb->cancel(statementGlobals_,diagsPtr);

	  setState(CLOSE_);
	  
	  retcode = execute(cliGlobals, NULL, diagsArea, execute_state);
          StmtDebug1("  root_tcb->execute() returned %s",
                 RetcodeToString((RETCODE) retcode));

	  if (retcode == ERROR)
	    {
              if (currentCompilerVersion != COM_VERS_UNKNOWN)
                // Error path must also reset the current compiler version
                retcode = getContext()->setOrStartCompiler(currentCompilerVersion,NULL,index);

	      setState(CLOSE_);
	      diagsPtr->decrRefCount();
	      return ERROR;
	    }

          if (currentCompilerVersion != COM_VERS_UNKNOWN)
          {
            // Reset the current compiler version if we requested a downrev compiler
            retcode = getContext()->setOrStartCompiler(currentCompilerVersion,NULL,index);
            if (retcode == ERROR)
            {
              setState(CLOSE_);
              diagsPtr->decrRefCount();
              return ERROR;
            }
          }

	  diagsPtr->decrRefCount();
	  diagsPtr = NULL;

	  // if bulk move info needs to be recomputed, set that flag
	  // in the output descriptor.
	  // This could happen if the previous execute call caused an
	  // auto recomp and some output information got changed.
	  if ((output_desc) && (computeOutputDescBulkMoveInfo()))
	    {
	      output_desc->reComputeBulkMoveInfo();
	      setComputeOutputDescBulkMoveInfo(FALSE);
	    }

	  if (masterStats)
            masterStats->setIsBlocking();

          // $$$ in no-waited case, might want to consider reducing
	  // timeout by time spent (down to a minimum of 0 of course)
	  closeCursorOnError = TRUE;

	  retcode = root_tcb->fetch(cliGlobals, statementGlobals_,
				    output_desc, diagsPtr,
				    timeout, TRUE,
				    closeCursorOnError);
          StmtDebug1("  root_tcb->fetch() returned %s",
                   RetcodeToString((RETCODE) retcode));
          if (masterStats)
             masterStats->setNotBlocking();
	    
	} // if (retryable and state == FETCH)
      else
	{
          // Non-retryable statement/statement that already has fetched something.
          if ( diagsPtr->contains(-EXE_LOST_OPEN) ||
	       diagsPtr->contains(-EXE_PARTITION_UNAVAILABLE)
             )
          {
	    // An open was lost. Set the fixup state to 0 which will cause 
	    // the next execution to do fixup again; this will re-open the table.
	    setFixupState(0);
          }
          else
          {
            // A plan version error. Set the root_tdb to NULL so that 
            // the next execution will unconditionally recompile the query.
            assignRootTdb (NULL);

          }
          break;

	} // if (retryable and state == FETCH) else ...
    } 
  
  
  // "diagsPtr" is modified by the foregoing call.
  // If "diagsPtr" is NULL, there are no diags to merge
  // into "diagsArea".  Otherwise, "diagsPtr" is not NULL and does
  // point to a diags area from which we: 1) avoid the SQL function
  // 2) copy the ComCondition objects over.  Then we decrement
  // the reference count to indicate we're done with that ComDiagsArea.

  if (diagsPtr)
    {
      /*      if (diagsPtr->getNumber(DgSqlCode::WARNING_) > 0 &&
          diagsPtr->getNumber(DgSqlCode::ERROR_) == 0 &&
          retcode == ERROR &&
          diagsPtr->mainSQLCODE() >= 20000 &&
          diagsPtr->mainSQLCODE() <= 20999)
      {
        // Don't know why root_tcb->fetch returns retcode -1 (ERROR)
        // when the SQL/MX Utility internal stored procedure issues
        // warning messages but executes successfully otherwise
        // (i.e., error messages was issued).  Need to set retcode
        // to SQL_EOF so this routine does not issue the unwanted 
        // CLI_TCB_FETCH_ERROR message.  Cannot set retcode to either
        // SUCCESS or WARNING because mxci will issue the following
        // rows right after the warning messages if retcode is set
        // to SUCCESS or WARNING:
        //
        // RECOVERSTATUS
        // -------------
        //
        //     134936872
        //
        // If retcode is set to SQL_EOF, only the warning messages
        // will be printed by mxci.  Note that error/warning numbers
        // range between 20000 and 20999 are used by the MODIFY utility
        // and several other SQL/MX utilities (e.g., DUP, PURGEDATA).
        //
        retcode = SQL_EOF;
	}*/
      diagsArea.mergeAfter(*diagsPtr);
      diagsPtr->decrRefCount();    
      diagsPtr = NULL;
    }
  
  if (retcode < 0)
    {
      if (stmtStats_ != NULL && stmtStats_->getMasterStats() != NULL)
      {
        stmtStats_->getMasterStats()->setRowsAffected(statementGlobals_->getRowsAffected());
      }
      updateStatsAreaInContext();

      // Error case.
      
      // cancel the down request to my child.
      // Do it only if closeCursorOnError is set to TRUE, the cursor
      // remains open otherwise.

      if (closeCursorOnError)
	{
	  // We must do this to clean up the messages from the queues
	  // (Else there are messages left over and these are incorrectly
	  // read if the statement is re-executed.)
	  diagsPtr = NULL;
          if (root_tcb)
            // We could have deallocated the root tcb earlier
            retcode = root_tcb->cancel(statementGlobals_,diagsPtr);
            StmtDebug1("  root_tcb->cancel() returned %s",
                       RetcodeToString((RETCODE) retcode));

	  if (diagsPtr)
	    {
	      diagsArea.mergeAfter(*diagsPtr);
	      diagsPtr->decrRefCount();    
              diagsPtr = NULL;
	    }

          setState(CLOSE_);
	}

      // rollback savepoints, if they are being done.
      NABoolean doXnRollback = FALSE;
      rollbackSavepoint(diagsArea, doXnRollback);
      
      // abort the transaction, if auto commit is on or
      // rollbackTransaction flag is set in the diags area or
      // this is a query that would have dirtied the disk(like,
      // insert/update/delete). 
      if (rollbackTransaction(diagsArea, doXnRollback))
      {
        StmtDebug3("[END fetch] %p, result is %s, stmt state %s", this,
                   RetcodeToString(ERROR), stmtState(getState()));
        return ERROR;
      }

      // If fatal error, we need to start over again
      if (root_tcb && root_tcb->fatalErrorOccurred())
      {
        dealloc();
        space_.freeBlocks();
        statementGlobals_->reAllocate(1);
        setFixupState(0);
      }
      
      if (diagsArea.getNumber(DgSqlCode::ERROR_) == 0)
	{
	  // add an error indicating no error in diags. 
	  // We will aqr retry on this error.
	  diagsArea << DgSqlCode(-CLI_NO_ERROR_IN_DIAGS);
	}

      StmtDebug3("[END fetch] %p, result is %s, stmt state %s", this,
                 RetcodeToString(ERROR), stmtState(getState()));
      return ERROR;
    }

  if ( !newOperation 
       )
    {
      if (handleUpdDelCurrentOf(diagsArea) == SQL_EOF)
	  retcode = SQL_EOF;
    }

  if ((retcode != NOT_FINISHED) && (retcode != SQL_EOF) && 
      (getRootTdb()->isEmbeddedIUDWithLast1()))
      {
      	// Add the affected row count that was directly placed into
	// the master globals to those that are already in the diags
	// area.
	diagsArea.setRowCount(statementGlobals_->getRowsAffected());
      }

  if (retcode == WARNING)
    {
    StmtDebug3("[END fetch] %p, result is %s, stmt state %s", this,
		 RetcodeToString(WARNING), stmtState(getState()));
    return WARNING;
  }
  else if (retcode == SQL_EOF)
  {
    StmtDebug1("  [EOF] Fetched SQL_EOF for statement %p", this);
    
    if (!(getRootTdb()->isEmbeddedIUDWithLast1()))
      {
	// Add the affected row count that was directly placed into
	// the master globals to those that are already in the diags
	// area. Make both row counts (diags and statementGlobals_) the same.
	diagsArea.addRowCount(statementGlobals_->getRowsAffected());
	statementGlobals_->setRowsAffected(diagsArea.getRowCount());
      }
    if (stmtStats_ != NULL && stmtStats_->getMasterStats() != NULL)
    {
      stmtStats_->getMasterStats()->setRowsAffected(statementGlobals_->getRowsAffected());
    }
    updateStatsAreaInContext();
    
    setState(FETCH_);
    
    // If this is a stored procedure result set, do bookkeeping for
    // this EOF and if this is EOF for the final result set, then put
    // the parent CALL in an EOF state (which has the side effect of
    // ending an AUTOCOMMIT transaction that may be associated with
    // the CALL).
    if (parentCall_)
    {
      StmtDebug1("  [EOF] Parent CALL %p", parentCall_);

      ExRsInfo *parentRsInfo = parentCall_->getResultSetInfo();
      ex_assert(parentRsInfo, "No parent RS info available");
      
      ULng32 rsIndex = parentRsInfo->getIndex(this);
      parentRsInfo->setCloseAttempted(rsIndex);
      StmtDebug2("  [EOF] RS index %u, Num closed since CALL %u",
                 rsIndex, parentRsInfo->getNumClosedSinceLastCall());

      if (parentRsInfo->allResultsAreClosed())
      {
        RETCODE closeResult = parentCall_->close(diagsArea);
        StmtDebug1("  [EOF] parentCall_->close() returned %s",
                   RetcodeToString(closeResult));
        if (closeResult != ERROR)
        {
          parentCall_->setState(EOF_);
        }
        else
        {
          StmtDebug3("[END fetch] %p, result is %s, stmt state %s", this,
			     RetcodeToString(ERROR), stmtState(getState()));
          return ERROR;
        }
      }
    }
    
    StmtDebug0("  [EOF] About to call commitTransaction()...");
    
    // end the transaction, if auto commit is on.
    if (commitTransaction(diagsArea))
    {
      StmtDebug3("[END fetch] %p, result is %s, stmt state %s", this,
		     RetcodeToString(ERROR), stmtState(getState()));
      return ERROR;
    }

    StmtDebug0("  [EOF] Done. commitTransaction() was successful");

    setState(EOF_);
    
    if (output_desc)
    {
      // move EOF condition to diags area.
      diagsArea << DgSqlCode(SQL_EOF);
    }
    
    StmtDebug3("[END fetch] %p, result is %s, stmt state %s", this,
		 RetcodeToString(SQL_EOF), stmtState(getState()));
    return SQL_EOF;
  }

 
  else
    {
      // change priority back to fixup state, if asked for.
      if ((context_->getSessionDefaults()->getAltpriFirstFetch()) &&
	  (context_->getNumOfCliCalls() == 1) &&
	  (cliGlobals->priorityChanged()))
	{
	  ComRtSetProcessPriority(cliGlobals->myPriority(), FALSE);
	  cliGlobals->setPriorityChanged(FALSE);
	}

      setState(FETCH_);

      if (getRootTdb()->updatableSelect())
	resetDeletedCursor();

    StmtDebug3("[END fetch] %p, result is %s, stmt state %s", this,
		 RetcodeToString(SUCCESS), stmtState(getState()));
    return SUCCESS;
  }

} // Statement::fetch()

short Statement::handleUpdDelCurrentOf(ComDiagsArea &diags)
{
  short retcode = SUCCESS;

  // if this is an update, delete, or insert query and no rows were
  // affected and there are no warnings, return SQL_EOF. 
  // If there is a warning, return the warning.
  // This is an ANSI requirement.
  if (noRowsAffected(diags))
    {
      // if this is an "update/delete where current of" operator
      // and no rows were returned,
      // raise a warning. This is done since an absence of this
      // row at this point indicates that someone deleted this
      // row between the time it was fetched (using the
      // FETCH <cursor> INTO...  statement) and now.
      if ((isDeleteCurrentOf()) || (isUpdateCurrentOf()))
	{
	  diags << DgSqlCode(EXE_CURSOR_UPDATE_CONFLICT);
	}
	  
      retcode = ((diags.getNumber(DgSqlCode::WARNING_) > 0) ? 0 : SQL_EOF);
      // move EOF warning to diags area.
      if (retcode == SQL_EOF)
	diags << DgSqlCode(SQL_EOF);

    }
  else
    {
      // if delete where current of, mark the cursor that this fetched
      // row was deleted. This is to prevent another cursor delete/update
      // (ANSI positioned delete/update) on this deleted row.
      if (isDeleteCurrentOf())
	{
	  currentOfCursorStatement()->setDeletedCursor();
	}
    }
  return retcode;
}
  
void Statement::updateTModeValues()
{
  // Get the current transmode and update the values
  // for transaction typing.
  TransMode * cmpTransMode = root_tdb->getTransMode();
  TransMode * runTransMode = context_->getTransaction()->getTransMode();

  // In the unlikely event that we don't have a runtime transMode
  // just use the compiletimeTransMode.
  if (!runTransMode)
    runTransMode = cmpTransMode ;

  short roval = runTransMode->getAccessMode();
  short rbval = runTransMode->getRollbackMode();
  Lng32  aival = runTransMode->getAutoAbortIntervalInSeconds();

  // if AccessMode is not set at runtime then the the compile time 
  // setting is applied. Note that roval has an effect on the
  // transaction only if its value is READ_ONLY or READ_ONLY_SPECIFIED_BY_USER
  if ((roval != TransMode::READ_ONLY_) &&
      (roval != TransMode::READ_ONLY_SPECIFIED_BY_USER_))
	roval = cmpTransMode->getAccessMode();

  //if No rollback is specified through an IUD statement then it gets precedence
  // in compareTransMode we check that autocommit is on at runtime for this setting
  if (cmpTransMode->getRollbackMode() == TransMode::NO_ROLLBACK_IN_IUD_STATEMENT_)
    rbval = TransMode::NO_ROLLBACK_ ;

  // if AutoAbortInterval is not set at runtime then the the compile time 
  // setting is applied.
  if (aival == -1)
    aival = cmpTransMode->getAutoAbortIntervalInSeconds();
        
  context_->getTransaction()->updateROVal(roval);
  context_->getTransaction()->updateRBVal(rbval);
  context_->getTransaction()->updateAIVal(aival);

}


RETCODE Statement::doOltExecute(CliGlobals *cliGlobals,
				Descriptor * input_desc, 
				Descriptor * output_desc,
				ComDiagsArea &diagsArea,
				NABoolean &doNormalExecute,
				NABoolean &reExecute)
{
  Int32 retcode;

  NABoolean processDp2Xns = FALSE;
  if ((! context_->getTransaction()->xnInProgress()) &&
      (context_->getTransaction()->autoCommit()) &&
      (root_tdb->getDp2XnsEnabled()))
    {
      processDp2Xns = TRUE;
    }

  if (!root_tdb)
    {
      diagsArea << DgSqlCode(-CLI_STMT_NOT_EXISTS);
      return error(diagsArea);
    }

  if (stmt_state != CLOSE_)
    {
		// trying to execute a statement which is already in open
		// state
		diagsArea << DgSqlCode(- CLI_STMT_NOT_CLOSE);
		return ERROR;
    }
  
  ExMasterStats * masterStats = NULL;
  if (root_tdb && getStmtStats() && 
      (NULL != (masterStats = getStmtStats()->getMasterStats())))
    {
      if (!masterStats->getValidDDL())
        {
          diagsArea << DgSqlCode(-CLI_DDL_REDEFINED);
          return ERROR;
        }
      if (!masterStats->getValidPrivs())
        {
          diagsArea << DgSqlCode(-CLI_INVALID_QUERY_PRIVS);
          return ERROR;
        }
      if (root_tdb->qCacheInfoIsClass() && root_tdb->qcInfo())
        masterStats->setCompilerCacheHit(
                            root_tdb->qcInfo()->cacheWasHit());
     Int64 jts = NA_JulianTimestamp();
     if (NOT masterStats->isPrepAndExec())
	 masterStats-> setElapsedStartTime(jts);
     masterStats->setFixupStartTime(-1);
     masterStats->setFreeupStartTime(-1);
    masterStats->setExeStartTime(aqrInitialExeStartTime_ == -1 ? jts :
                               aqrInitialExeStartTime_);
     masterStats->setSqlErrorCode(0); 
     masterStats->setStmtState(STMT_EXECUTE_);
   }

  // Get the current transmode and update the values
  // for transaction typing.  Code is here so values
  // will be updated for BEGIN WORK statements.
  updateTModeValues();

  // Start a transaction, if needed and one not already running.
  if (root_tdb->transactionReqd())
    {
      if (processDp2Xns)
      {
        // if this query could be evaluated using dp2/tse transactions,
        // then let the query proceed
      }

      // A user started transaction must be present for olt execution.
      // if no user started transaction, then return and do normal
      // execution.
      else if ((! context_->getTransaction()->xnInProgress()) ||
	  ((context_->getTransaction()->exeStartedXn()) &&
	   (context_->getTransaction()->implicitXn())))
	{
	  doNormalExecute = TRUE;
	  reExecute = FALSE;
	  return SUCCESS;
	}
      else
	{
          if (compareTransModes(root_tdb, context_->getTransaction(),
				(root_tdb->aqrEnabled() ? &diagsArea : NULL))
		  && !systemModuleStmt() )
	  {
	    if (root_tdb->aqrEnabled())
	      {
		// return error. AQR will handle recompile and retry.
		  return(ERROR);
	      }
	    else
	      {
		doNormalExecute = TRUE;
                reExecute = FALSE;
                return SUCCESS;
	      }
	  }
      	  
          // move the transid from executor globals to statement globals,
	  // if a transaction is running.
	  statementGlobals_->getTransid() =
	    context_->getTransaction()->getExeXnId();

	  if (root_tdb->getUpdSavepointOnError())
	    {
	      // get a savepoint id which will be sent to DP2.
	      context_->getTransaction()->generateSavepointId();
	      
	      statementGlobals_->getSavepointId() =
		context_->getTransaction()->getSavepointId();
	    }
	}
    }

    ExStatisticsArea *statsArea = getStatsArea();
    if (statsArea != NULL &&
	statsArea->getCollectStatsType() != ComTdb::MEASURE_STATS)
    {
      StatsGlobals *statsGlobals = cliGlobals->getStatsGlobals();
      if (statsGlobals != NULL)
      {
        short savedPriority, savedStopMode;
        short error = statsGlobals->getStatsSemaphore(cliGlobals->getSemId(),
					      cliGlobals->myPin(), savedPriority, savedStopMode,
					      FALSE /*shouldTimeout*/);
        ex_assert(error == 0, "getStatsSemaphore() returned an error");
        statsArea->initEntries();
        statsArea->restoreDop();
        statsGlobals->releaseStatsSemaphore(cliGlobals->getSemId(),cliGlobals->myPin(),
	  savedPriority, savedStopMode);
      }
      else
      {
        statsArea->initEntries();
        statsArea->restoreDop();
      }
   }
 

  ComDiagsArea* diagsPtr = NULL;
  if (! fixupState()) // first time
    {
     if ((stmtStats_) && (stmtStats_->getMasterStats()))
      {
	stmtStats_->getMasterStats()->
	  setFixupStartTime(NA_JulianTimestamp());
      }
      if (dealloc())
        goto retError;
      
      space_.freeBlocks();
      
      statementGlobals_->reAllocate(1);
      
      setState(CLOSE_);
      
      setFixupState(0);

      // move resolved names from LateNameInfoList to
      // ResolvedNameList which will be shipped to PA's
      if (root_tdb->getLateNameInfoList())
	{
	  ResolvedNameList *&rnl =
	    statementGlobals_->resolvedNameList();
	  if (rnl && (rnl->numEntries() < root_tdb->getLateNameInfoList()->getNumEntries()))
	    {
	      // deallocate the previously allocated rnl
	      heap_.deallocateMemory(rnl);
	      rnl = NULL;
	    }
	  
	  if (! rnl)
	    rnl = 
	      (ResolvedNameList *)
	      (new(&heap_) 
	       char[sizeof(ResolvedNameList) +
		   ((root_tdb->getLateNameInfoList()->
		     getNumEntries() > 0 ) ?
		    ((root_tdb->getLateNameInfoList()->
		      getNumEntries() - 1) * sizeof(ResolvedName)):
		    0)]);
	  
	  rnl->numEntries() =
	    root_tdb->getLateNameInfoList()->getNumEntries();
	  rnl->resetFlags();
	  
	  for (UInt32 i = 0; 
	       i < root_tdb->getLateNameInfoList()->getNumEntries();
	       i++)
	    {
	      strcpy(rnl->getResolvedName((Int32) i).resolvedGuardianName(),
		     root_tdb->getLateNameInfoList()->
		     getLateNameInfo((Int32) i).resolvedPhyName());

              short ignore = (short) root_tdb->getLateNameInfoList()->
                getLateNameInfo((Int32) i).ignoreTS();

	      rnl->getResolvedName((Int32) i).setIgnoreTS(ignore);

#pragma nowarn(1506)   // warning elimination 
               rnl->getResolvedName(i).setResolvedAnsiName(
                   root_tdb->getLateNameInfoList()->
                   getLateNameInfo(i).getLastUsedName(&heap_)->getExternalName());
#pragma warn(1506)  // warning elimination 
	    }
	}

      if (processDp2Xns)
	{
	  implicitTransNeeded();

	  short taRetcode =
	    context_->getTransaction()->beginTransaction();
	  
	  if (taRetcode != 0)
	    {
	      diagsArea << DgSqlCode(- CLI_BEGIN_TRANSACTION_ERROR);
	      //	      cliGlobals_->setJmpBufPtr(oldJmpBufPtr);
	      return ERROR;
	    }
	}
        
      NABoolean doSimCheck = FALSE;
      NABoolean partitionUnavailable = FALSE;
      retcode = fixup(cliGlobals, input_desc, diagsArea, doSimCheck, partitionUnavailable, FALSE);
      if (doSimCheck || partitionUnavailable)
	{
	  commitImplicitTransAndResetTmodes();
 
          // Redrive the execution if fixup said so.
          // It is OK to clear the diags area, because
          // normal execution will perform the visibility check again.
          diagsArea.clear();

	  setTsMismatched(FALSE);

	  doNormalExecute = TRUE;
	  reExecute = FALSE;
	  return SUCCESS;
	}
      if ((stmtStats_) && (stmtStats_->getMasterStats()))
      {
	stmtStats_->getMasterStats()->
	  setFixupEndTime(NA_JulianTimestamp());
      }

      commitImplicitTransAndResetTmodes();
      if (retcode == ERROR)
        goto retError;
     
    }

  /* execute it */

  // nothing happened yet.
  statementGlobals_->setGlobDiagsArea(0);
  statementGlobals_->setRowsAffected(0);
  setState(OPEN_);
  updateChildQid();
  if (masterStats)
     masterStats->setIsBlocking();
  retcode = root_tcb->oltExecute(statementGlobals_, input_desc, 
				 output_desc, diagsPtr);
  StmtDebug1("  root_tcb->oltExecute() returned %s",
             RetcodeToString((RETCODE) retcode));

  if (masterStats)
     masterStats->setNotBlocking(); 
  if (diagsPtr)
    {      
      NABoolean lostOpen = diagsPtr->contains(-EXE_LOST_OPEN);

      if (lostOpen)
        {
          NABoolean retryableStatement = root_tdb->retryableStmt();
          
          if (retryableStatement)
            {
	      retcode = root_tcb->cancel(statementGlobals_,diagsPtr);
	      StmtDebug1("  root_tcb->cancel() returned %s",
			 RetcodeToString((RETCODE) retcode));
	      
              setState(CLOSE_);
	      doNormalExecute = TRUE;
	      reExecute = TRUE;
	      return SUCCESS;
            }
          else
            {
              // lost the open on a non-retryable statement;
              // force a fresh fix-up on next execution.
              setFixupState(0);
            }
	}
      
      diagsArea.mergeAfter(*diagsPtr);
      diagsPtr->decrRefCount();    
      diagsPtr = NULL;
    }

  if (retcode >= 0 && root_tcb->anyCbMessages())
  {
    Int32 cancelRetcode = root_tcb->cancel(statementGlobals_,diagsPtr);
    StmtDebug1("  root_tcb->cancel() returned %s",
             RetcodeToString((RETCODE) cancelRetcode));

    setState(CLOSE_);
    releaseTransaction(TRUE);
  }

  updateStatsAreaInContext();
  if (retcode < 0)
    {
      // rollback savepoints, if they are being done.
      NABoolean doXnRollback = FALSE;
      rollbackSavepoint(diagsArea, doXnRollback);

      retcode = root_tcb->cancel(statementGlobals_,diagsPtr);
      StmtDebug1("  root_tcb->cancel() returned %s",
                 RetcodeToString((RETCODE) retcode));

      setState(CLOSE_);

      // abort the transaction, if auto commit is on or
      // rollbackTransaction flag is set in the diags area or
      // this is a query that would have dirtied the disk(like,
      // insert/update/delete). 
      if (rollbackTransaction(diagsArea, doXnRollback))
	return ERROR;
 
      // if no other diags, as a last resort emit this rather 
      // cryptic message
      if (diagsArea.getNumber(DgSqlCode::ERROR_) == 0)
	diagsArea << DgSqlCode(- CLI_TCB_EXECUTE_ERROR);
      
      return ERROR;
      //      return error(diagsArea);
    }
  else if (retcode == SUCCESS)
    return SUCCESS;
  else if (retcode == WARNING)
    return WARNING; 
  else
    {
      diagsArea.setRowCount(statementGlobals_->getRowsAffected());
      if (getStmtStats() && (getStmtStats()->getMasterStats()))
          stmtStats_->getMasterStats()->setRowsAffected(statementGlobals_->getRowsAffected());
      if ((statementGlobals_->getRowsAffected() > 0) ||
	  (root_tdb->thereIsACompoundStatement()))
	return SUCCESS;
      else 
	{
	  if ((output_desc) ||
	      (root_tdb && (root_tdb->updDelInsertQuery())))
	    {
	      diagsArea << DgSqlCode(SQL_EOF);
	      return SQL_EOF;
	    }
	  else
	    return SUCCESS;
	}
    }
retError:
    return error(diagsArea);
}

Lng32 Statement::cancel()
{  
  StmtDebug2("[BEGIN cancel] %p, stmt state %s", this, stmtState(getState()));

  CancelState s = statementGlobals_->getCancelState();
  Lng32 retcode = 0;

  switch (s)
  {
  case CLI_CANCEL_TCB_INVALID:
    // 
    statementGlobals_->setCancelState(CLI_CANCEL_REQUESTED);
    break;

  case CLI_CANCEL_TCB_READY:
    // request to cancel down the tcb tree. 
    root_tcb->requestCancel();
    break;
  
  case CLI_CANCEL_DISABLE:
    retcode = -CLI_CANCEL_REJECTED;
    break;

  default:
    // CLI_CANCEL_REQUESTED
    // ignore since an outstanding cancel request exists.
    break;
  }

  StmtDebug3("[END cancel] %p, result is %s, stmt state %s",
             this, RetcodeToString((RETCODE) retcode), stmtState(getState()));
  return retcode;
}

void Statement::releaseStats()
{
  ExStatisticsArea *myStats = getStatsArea();
  ExStatisticsArea *myOrigStatsArea = getOrigStatsArea();
  ExStatisticsArea *ctxStats = context_->getStats();
  ExStatisticsArea *newStats;
  StatsGlobals *statsGlobals = cliGlobals_->getStatsGlobals();
  if (ctxStats && (ctxStats == myStats) && 
        ((Int32)myStats->getCollectStatsType() != SQLCLI_NO_STATS))
  {
    if (statsGlobals != NULL && stmtStats_ != NULL &&
        (Int32)myStats->getCollectStatsType() != SQLCLI_ALL_STATS) 
    {
      short savedPriority, savedStopMode;
      short error = statsGlobals->getStatsSemaphore(cliGlobals_->getSemId(),
                            cliGlobals_->myPin(), 
                            savedPriority, savedStopMode, FALSE );
      ex_assert(error == 0, "getStatsSemaphore() returned an error");
      // Make sure the ex_globals doesn't delete this stats area
      // in case of dynamic statements, since stmtStats is also
      // pointing to the same area
      getGlobals()->setStatsArea(NULL);
      // Context is pointing to it. Remove query shouldn't
      // deallocate it
      stmtStats_->setStmtStatsUsed(TRUE);
      context_->setStatsArea(myStats, FALSE, TRUE, FALSE);
      // Set the StmtStats that can be used to reset the used flag
      context_->setPrevStmtStats(stmtStats_);
      statsGlobals->releaseStatsSemaphore(cliGlobals_->getSemId(),
                                cliGlobals_->myPin(), 
                                savedPriority, savedStopMode);
    }
    else
    {
      // Resources for this statement are being deallocated. If the
      // context is pointing to my stats area, make a new copy of the
      // stats area and attach it to context.
      newStats = new (context_->exHeap())
      ExStatisticsArea(context_->exHeap(), 0,
                       myStats->getCollectStatsType());
      newStats->setStatsEnabled(myStats->statsEnabled());
      newStats->merge(myStats);
      if (newStats->getMasterStats() == NULL && stmtStats_ != NULL 
                   && stmtStats_->getMasterStats() != NULL)
      {
        ExMasterStats * ems = new(context_->exHeap())
              ExMasterStats(context_->exHeap());
        ems->copyContents(stmtStats_->getMasterStats());
        newStats->setMasterStats(ems);
      }
      if (stmtStats_ != NULL)
         stmtStats_->setStatsArea(NULL);
      // Attach the new stats area to the context
      context_->setStatsArea(newStats, TRUE, FALSE, TRUE);
    }
  }
  else
  if (myOrigStatsArea != NULL)
  {
    // Make sure the ex_globals doesn't delete this stats area
    // in case of dynamic statements, since stmtStats is also
    // pointing to the same area
    if (stmtStats_ != NULL && myOrigStatsArea != NULL &&
          (Int32)myOrigStatsArea->getCollectStatsType() != SQLCLI_ALL_STATS) 
       getGlobals()->setStatsArea(NULL);
  }
}

RETCODE Statement::releaseTcbs(NABoolean closeAllOpens)
{

  if (root_tcb)
  {
  releaseStats();
    // The root tcb takes care of deleting itself and of deleting
    // the statement globals.
    if (statementGlobals_)
    {
      ExRtFragTable *ft = statementGlobals_->getRtFragTable();
      
      // finish any transactional messages outstanding
      // for this statement, since the statement won't
      // be found anymore on the context's statement list
      // Should do this before releaseEsps, so that they 
      // will not be sending work or continue messages to 
      // each other after the deallocation of fragment 
      // instances has begun (see Soln 10-060504-6268).
      releaseTransaction(TRUE);

      // release all esps next
      releaseEsps(closeAllOpens);

      // Deallocate TCB trees for all stored procedure result set
      // children. The UDR leaf nodes in the result set TCB tree are
      // not valid once the UDR leaf node in this CALL statement
      // goes away, so those result set TCBs must be deallocated first.
      ExRsInfo *rsInfo = getResultSetInfo();
      if (rsInfo)
      {
        StmtDebug0("  About to call ExRsInfo::reset()");
        rsInfo->reset();
        
        ULng32 numChildren = rsInfo->getNumEntries();
        StmtDebug1("  Num RS children: %d", (Lng32) numChildren);
        
        for (ULng32 i = 1; i <= numChildren; i++)
        {
          Statement *rsChild = NULL;
          const char *proxySyntax = NULL;
          NABoolean open = FALSE;
          NABoolean closed = FALSE;
          NABoolean prepared = FALSE;
          
          NABoolean found = rsInfo->getRsInfo(i, rsChild, proxySyntax,
                                              open, closed, prepared); 
          
          if (found && rsChild)
          {
            StmtDebug1("  About to call dealloc() on RS %p", rsChild);
            rsChild->dealloc();
          }
          
        } // for each RS child
      } // if (rsInfo)

      // This call to deallocAndDelete() will trigger destructor calls
      // for all TCBs
      Int32 retcode = root_tcb->deallocAndDelete(statementGlobals_,ft);

      if (retcode < 0)
      {
        context_->diags() << DgSqlCode(- EXE_INTERNAL_ERROR);
        return ERROR;
      }
      
      root_tcb = NULL;
      
      //
      // Deallocating the TCB tree may have caused more messages
      // to be sent. To be safe, we once again wait for completion
      // of transactional messages.
      //
      releaseTransaction(TRUE);
      
    } // if (statementGlobals_)
    
  } // if (root_tcb)
  
  root_tcb = NULL;
  return SUCCESS;
}

RETCODE Statement::dealloc(NABoolean closeAllOpens)
{
  StmtDebug2("[BEGIN dealloc] %p, stmt state %s", this, stmtState(getState()));

  RETCODE result = SUCCESS;

  // stop the transaction, if once was started
  if ((context_->aqrInfo()->xnStartedAtPrepare()) &&
      (context_->getTransaction()->xnInProgress()) &&
      (context_->getTransaction()->exeStartedXn()) &&
      (context_->getTransaction()->autoCommit()) &&
      (autocommitXn()))
    {
      context_->aqrInfo()->setXnStartedAtPrepare(FALSE);
      
      if (commitTransaction(context_->diags()))
	{
	  // ignore error and proceed to deallocate
	}
    }
  
  context_->removeFromStatementWithEspsList(this);
  
  result = releaseTcbs(closeAllOpens);
  
  if (result == SUCCESS)
  {
    setState(CLOSE_);
    setFixupState(0);
    setComputeBulkMoveInfo(TRUE);
    
    // deallocate all cloned statements
    clonedStatements->position();
    Statement * clone = (Statement*)clonedStatements->getNext();
    for (; clone != NULL; clone = (Statement*)clonedStatements->getNext())
    {
      StmtDebug1("  About to call dealloc on clone %p", clone);
      clone->dealloc();
    }
    
    context_->removeFromCloseStatementList(this, FALSE);

    if (extractConsumerQueryTemplate_)
    {
      heap_.deallocateMemory(extractConsumerQueryTemplate_);
      extractConsumerQueryTemplate_ = NULL;
    }
  } // if (result == SUCCESS)

  StmtDebug2("[END dealloc] %p, stmt state %s", this, stmtState(getState()));
  return result;
}

static Lng32 getMaxParamIdx(ex_root_tdb *rootTdb){
  Lng32 maxParamIdx = 0;
  if(rootTdb->inputExpr()){
    maxParamIdx = rootTdb->inputExpr()->getMaxParamIdx();
  }
  
  if(rootTdb->outputExpr()){
    Lng32 outputParamIdx = rootTdb->outputExpr()->getMaxParamIdx();
    if(outputParamIdx > maxParamIdx)
      maxParamIdx = outputParamIdx;
  }
  return maxParamIdx;
}

RETCODE Statement::describe(Descriptor * desc, Lng32 what_desc,
			    ComDiagsArea &diagsArea)
{
  // One special case is for stored procedure result set proxy
  // statements. CLI callers do not prepare them. We do internal
  // prepares whenever the CLI caller describes or executes them.
  if (parentCall_)
  {
    ExRsInfo *rsInfo = parentCall_->getResultSetInfo();
    if (rsInfo)
    {
      ULng32 rsIndex = rsInfo->getIndex(this);
      RETCODE proxyRetcode = rsProxyPrepare(*rsInfo, rsIndex, diagsArea);
      if (proxyRetcode == ERROR)
        return ERROR;
    }
  }

  if (!root_tdb)
    return SUCCESS;

  InputOutputExpr *expr;
  enum ex_expr::exp_return_type expRType;

  Int32 retcode = 0; // be optimistic

  // A special case for DESCRIBE is when the SQL statement is a CALL
  // statement and the CLI caller wants to use a "wide" descriptor for
  // the CALL.
  if (root_tdb->hasCallStmtExpressions() && desc->isDescTypeWide())
  {
    // First populate the caller's descriptor with information from
    // the INPUT expression, the overlay information from the OUTPUT
    // expression into the same descriptor.

    Lng32 eNumEntries = getMaxParamIdx(root_tdb);
    if (desc->getMaxEntryCount() < eNumEntries){
      diagsArea << DgSqlCode(CLI_TDB_DESCRIBE_ERROR);
      return ERROR;
    }
    else if (desc->getUsedEntryCount() < eNumEntries) {
      desc->dealloc();
      desc->alloc(eNumEntries);
    }

    // The code in expr->describe sets the entry count in case of a Call stmt
    // only if the new count is greater than the old count. This
    // causes the old count to be returned during describe, if the 
    // same descriptor was reused and the number of entries in the new
    // query is less than the old count. 
    // Setting the entry count to 0 before calling describe.
    desc->setUsedEntryCount(0);

    if (expr = root_tdb->inputExpr())
    {
      UInt32 flags = 0;
      expr->setIsODBC(flags, root_tdb->odbcQuery());
      expr->setInternalFormatIO(flags, 
				context_->getSessionDefaults()->
				getInternalFormatIO());
      expr->setIsRWRS(flags, (root_tdb->getRWRSInfo() != NULL));
      expr->setIsDBTR(flags,
		      context_->getSessionDefaults()->getDbtrProcess());

      expRType = expr->describeInput(desc, NULL, flags);
      if(expRType != ex_expr::EXPR_OK)
	retcode = -1;
    }
    
    if ((retcode == 0) && (expr = root_tdb->outputExpr()))
    {
      UInt32 flags = 0;
      expr->setIsODBC(flags, root_tdb->odbcQuery());
      expr->setInternalFormatIO(flags, 
				context_->getSessionDefaults()->
				getInternalFormatIO());
      expr->setIsDBTR(flags,
		      context_->getSessionDefaults()->getDbtrProcess());
      expRType = expr->describeOutput(desc, flags);
      if(expRType != ex_expr::EXPR_OK)
	retcode = -1;
    }
  }
  else{
    if (what_desc == SQLWHAT_INPUT_DESC)
      {
      /* describe input */
      // retcode = root_tdb->describe(desc, 0);
      expr = root_tdb->inputExpr();
      if (expr == NULL)
	{
	  // set the entry count to zero. Otherwise desc will contain the
	  // entry count of the last describe.
	  desc->setUsedEntryCount(0);
	  return SUCCESS;
	}

      if (desc->getMaxEntryCount() < expr->getNumEntries())
	{
	  desc->setMaxEntryCount(expr->getNumEntries());
	}

      if (desc->getUsedEntryCount() < expr->getNumEntries())
	{
	  desc->dealloc();
	  desc->alloc(expr->getNumEntries());
	}
      
      UInt32 flags = 0;
      expr->setIsODBC(flags, root_tdb->odbcQuery());
      expr->setInternalFormatIO(flags, 
				context_->getSessionDefaults()->
				getInternalFormatIO());
      expr->setIsRWRS(flags, (root_tdb->getRWRSInfo() != NULL));
      expr->setIsDBTR(flags,
		      context_->getSessionDefaults()->getDbtrProcess());
      if (expr->describeInput(desc, root_tdb->getRWRSInfo(), flags) 
	  != ex_expr::EXPR_OK)
	retcode = -1;
      }
    else
      {
	/* describe output */
	// retcode = root_tdb->describe(desc, -1);
	expr = root_tdb->outputExpr();
	if (expr == NULL)
	  {
	    // set the entry count to zero. Otherwise desc will contain the
	    // entry count of the last describe.
	    desc->setUsedEntryCount(0);
	    return SUCCESS;
	  }
	
	if (desc->getMaxEntryCount() < expr->getNumEntries())
	  {
	    desc->setMaxEntryCount(expr->getNumEntries());
	  }

	if (desc->getUsedEntryCount() < expr->getNumEntries())
	  {
	    desc->dealloc();
	    desc->alloc(expr->getNumEntries());
	  }
	
	UInt32 flags = 0;
	expr->setIsODBC(flags, root_tdb->odbcQuery());
	expr->setInternalFormatIO(flags, 
				  context_->getSessionDefaults()->
				  getInternalFormatIO());
	expr->setIsDBTR(flags,
			context_->getSessionDefaults()->getDbtrProcess());
	if (expr->describeOutput(desc, flags) != ex_expr::EXPR_OK)
	  retcode = -1;
      }
  }
  if (retcode)
  {
    diagsArea << DgSqlCode(- CLI_TDB_DESCRIBE_ERROR);
    return ERROR;
  }

  return SUCCESS;
}

void Statement::copyGenCode(char * gen_code, ULng32 gen_code_len,
			    NABoolean unpackTDBs)
{
  StmtDebug3("[BEGIN copyGenCode] this %p, gen_code %p, len %u",
             this, gen_code, gen_code_len);

  ex_assert(!isCloned(),
            "copyGenCode() should not be called on a cloned statement");

  // Release the TDB tree if one exists
  assignRootTdb(NULL);

  // do some basic sanity checking
  if ((gen_code == 0) || (gen_code_len <= 0))
  {
    //    gen_code = 0;
    //    gen_code_len = 0;
    return;
  }
  
  CollHeap * h = cliGlobals_->getArkcmp()->getHeap();
  char *newTdbTree = (char *) (new (h) char[gen_code_len]);
  str_cpy_all(newTdbTree, gen_code, (Lng32) gen_code_len);
  
  assignRootTdb((ex_root_tdb *) newTdbTree);
  root_tdb_size = (Lng32) gen_code_len;
  
  if (unpackTDBs)
  {
  // Set up the reallocator for use when object version migration occurs.
  //
  ComTdb dummyTdb;
  ex_root_tdb *newRoot = (ex_root_tdb *)
    root_tdb->driveUnpack((void *)root_tdb,&dummyTdb, unpackSpace_);

  assignRootTdb(newRoot);
  
  if (root_tdb == NULL)
  {
    // ERROR during unpacking. Most likely case is verison-unsupported.
    // How do I report an error here ???
    //
    // diagsArea << DgSqlCode(- CLI_STMT_NOT_PREPARED);
    // return ERROR;
    //
    // Alternative: add code to drive a recompilation. Invalidate the plan.
    //
  }

  if ((stmt_type == STATIC_STMT) && (root_tdb))
#pragma nowarn(1506)   // warning elimination 
    setRecompWarn(root_tdb->recompWarn());
#pragma warn(1506)  // warning elimination 
    
  } // if (unpackTDBs)
  
  StmtDebug1("[END copyGenCode] this %p", this);
}

void Statement::copyInSourceStr(char * in_source_str_, Lng32 src_len_in_octets,
			 Lng32 charset)
{
  charset_ = charset;
  NAHeap * heap = context_->exHeap();
  if (source_str)
    NADELETEBASIC(source_str, heap);

  // do some basic sanity checking
  if ((in_source_str_ == 0) || (src_len_in_octets <= 0))
  {
     source_str = 0;
     source_length = 0;
     return;
  }

  Int32 maxBytesPerChar = CharInfo::maxBytesPerChar((CharInfo::CharSet)charset);
  source_str = new (heap) char[src_len_in_octets+maxBytesPerChar];
  str_cpy_all(source_str, in_source_str_, src_len_in_octets);
  if (charset == SQLCHARSETCODE_UCS2)
    ((NAWchar*)source_str)[src_len_in_octets/maxBytesPerChar] = 0;
  else
    source_str[src_len_in_octets] = '\0';
  source_length = src_len_in_octets;
}

void Statement::copyOutSourceStr(char * out_source_str, 
				 Lng32 &out_src_len_in_octets) // INOUT
{
  // do some basic sanity checking
  if ((out_source_str == NULL) || (out_src_len_in_octets <= 0) ||
      (out_src_len_in_octets < source_length))
    {
      out_src_len_in_octets = 0;
      return;
    }

  Int32 maxBytesPerChar = CharInfo::maxBytesPerChar((CharInfo::CharSet)charset_);
  str_cpy_all(out_source_str, source_str, source_length);
  if (charset_ == SQLCHARSETCODE_UCS2)
    ((NAWchar*)out_source_str)[source_length/maxBytesPerChar] = 0;
  else
    out_source_str[source_length] = '\0';

  out_src_len_in_octets = source_length;
}

void Statement::copySchemaName(char * schemaName, Lng32 schemaNameLength)
{
  if (schemaName_)
    NADELETEBASIC(schemaName_, (&heap_));

  // do some basic sanity checking
  if ((schemaName == 0) || (schemaNameLength <= 0))
  {
     schemaName_ = 0;
     schemaNameLength_ = 0;
     return;
  }

  schemaName_ = new (&heap_) char[schemaNameLength + 1];
  str_cpy_all(schemaName_, schemaName, schemaNameLength);
  schemaName_[schemaNameLength] = '\0';
  schemaNameLength_ = schemaNameLength;
}

void Statement::copyRecompControlInfo(char * basePtr,
				      char * recompControlInfo, 
				      Lng32 recompControlInfoLength)
{
  if (recompControlInfo_)
    NADELETEBASIC(recompControlInfo_, (&heap_));

  // do some basic sanity checking
  if ((recompControlInfo == 0) || (recompControlInfoLength <= 0))
  {
     recompControlInfo_ = 0;
     recompControlInfoLen_ = 0;
     return;
  }

  RtduRecompControlInfo inRCI;
  str_cpy_all((char*)&inRCI, recompControlInfo, sizeof(RtduRecompControlInfo));
  recompControlInfo_ = new (&heap_) char[inRCI.packedLength()];
  RtduRecompControlInfo * stmtRCI = 
    (RtduRecompControlInfo *)recompControlInfo_;

  inRCI.unpackIt(basePtr);

  char * cqdInfo = (char *)stmtRCI + sizeof(RtduRecompControlInfo);
  char * ctoInfo = (char *)cqdInfo + inRCI.cqdInfoLength();
  char * cqsInfo = (char *)ctoInfo + inRCI.ctoInfoLength();

  stmtRCI->initialize(inRCI.numCqdInfoEntries(),
		      cqdInfo, inRCI.cqdInfoLength(),
		      ctoInfo, inRCI.ctoInfoLength(),
		      cqsInfo, inRCI.cqsInfoLength());

  if (stmtRCI->cqdInfoLength() > 0)
    {
      str_cpy_all(stmtRCI->cqdInfo(), inRCI.cqdInfo(), 
		  inRCI.cqdInfoLength());
    }

  if (stmtRCI->ctoInfoLength() > 0)
    {
      str_cpy_all(stmtRCI->ctoInfo(), inRCI.ctoInfo(), 
		  inRCI.ctoInfoLength());
    }

  if (stmtRCI->cqsInfoLength() > 0)
    {
      str_cpy_all(stmtRCI->cqsInfo(), inRCI.cqsInfo(), 
		  inRCI.cqsInfoLength());
    }

  stmtRCI->packIt((char*)stmtRCI);

  recompControlInfoLen_ = inRCI.packedLength();
}


void Statement::setCursorName(const char * cn)
{
  // as a side effect of this method the statement is added
  // to the cursorList of the current context. If the cursorName
  // changes, the statement is removed from the cursorList and
  // then re-inserted with the new name. This is neccessary,
  // because the name is used for hashing into the cursorList.

  StmtDebug2("  Setting cursor name for statement %p to \"%s\"",
             this, (cn ? cn : "(NULL)"));

 ComDiagsArea &diags = context_->diags();

  Lng32 nameLength = 0;
  char *copy_of_cn;
 

  if (cursor_name_) {

// Need to use length in comparison when 
// the length argument is added for "cn".

    // if we are changing it to the same name, save some work...
    if (cn && !strcmp(cn, cursor_name_->identifier))
       return;
    context_->removeCursor(cursor_name_, statement_id->module);
    heap_.deallocateMemory(cursor_name_);
  }

  if (cn) {
    nameLength = str_len(cn);
    copy_of_cn = new (&heap_) char [nameLength+1];
    str_cpy_all(copy_of_cn,cn,nameLength);
    copy_of_cn[nameLength] = '\0';

    cursor_name_ =  (SQLSTMT_ID *)(heap_.allocateMemory(sizeof(SQLSTMT_ID)));
    init_SQLCLI_OBJ_ID(cursor_name_, SQLCLI_CURRENT_VERSION,
             cursor_name, 0, copy_of_cn, 0,
           SQLCHARSETSTRING_ISO88591, str_len(cn));

    StmtDebug1("  Adding statement %p to the cursor list", this);
    context_->addToCursorList(*this);
  }
  else
     cursor_name_ = 0;
}

short Statement::transactionReqd()
{
  return ((short) (root_tdb && root_tdb->transactionReqd()));
}

Int64 Statement::getRowsAffected()
{
  return statementGlobals_->getRowsAffected();
}

//////////////////////
// PRIVATE methods
//////////////////////


// starts a transaction, if one has not already been started
// and if needed.
short Statement::beginTransaction(ComDiagsArea &diagsArea)
{

  // Get the current transmode and update the values
  // for transaction typing.  Code is here so values
  // will be updated for BEGIN WORK statements.
  updateTModeValues();

  // implicit xns for ddl stmts will be started and committed/aborted
  // in arkcmp if auto commit is on. Otherwise, it will be started here.
  if ((root_tdb->transactionReqd()) &&
      ((NOT root_tdb->ddlQuery()) ||
       (NOT context_->getTransaction()->autoCommit())))
    {
      // the trans mode at compile time of this query must be the
      // same as the transaction mode at execution time.
      if (!systemModuleStmt() && 
            compareTransModes(
	    root_tdb,
	    context_->getTransaction(),
	    &diagsArea, systemModuleStmt()))
	return ERROR;
      if (context_->getTransaction()->userEndedExeXn())
      {
        if (!diagsArea.contains(-CLI_USER_ENDED_EXE_XN))
            diagsArea << DgSqlCode(- CLI_USER_ENDED_EXE_XN);
        return ERROR;
      }
      if (! context_->getTransaction()->xnInProgress())
        {
	  // if no auto begin, then do not start the transaction.
	  if (context_->getTransaction()->getTransMode()->getAutoBeginOff())
	    {
	      // return error. A transaction is needed, one is not
	      // running and autobegin has been disabled.
	      diagsArea << DgSqlCode(- CLI_AUTO_BEGIN_TRANSACTION_ERROR);
              return ERROR;
	    }

          StmtDebug1("  About to BEGIN TX for statement %p...", this);
	  
          // start a transaction since one is not already running.
          short taRetcode =
            context_->getTransaction()->beginTransaction();

          StmtDebug1("  Return code is %d", (Lng32) taRetcode);

          if (taRetcode != 0)
            {
	      diagsArea.mergeAfter(*context_->getTransaction()->getDiagsArea());
	      //          diagsArea << DgSqlCode(- CLI_BEGIN_TRANSACTION_ERROR);
              return ERROR;
            }

          context_->getTransaction()->implicitXn() = TRUE;

	  // this statement started a transaction in autocommit mode.
	  // It means that this xn will only be committed when this
	  // statement ends execution.
	  if (context_->getTransaction()->autoCommit())
          {
	    setAutocommitXn(TRUE);
            StmtDebug0("  AUTOCOMMIT transaction successfully started");
          }
	  else
          {
	    setAutocommitXn(FALSE);
            StmtDebug0("  Transaction successfully started");
          }

        } // if (! context_->getTransaction()->xnInProgress())

      // move the transid from executor globals to statement globals,
      // if a transaction is running.
      statementGlobals_->getTransid() =
        context_->getTransaction()->getExeXnId();
      
      StmtDebug2("  Statement %p now has trans ID %s", this,
                 TransIdToText(statementGlobals_->getTransid()));
	        
      // We might have suspended work on this or a previous transaction
      // during the last CLOSE operation.  Indicate to the root TCB that
      // we are willing to work on a transaction again and that it is
      // ok to send out transactional requests (to DP2 and to ESPs)
      if (statementGlobals_ && statementGlobals_->getRtFragTable())
        {
          statementGlobals_->getRtFragTable()->continueWithTransaction();
        }

      if (root_tdb->getUpdSavepointOnError())
	{
	  // get a savepoint id which will be sent to DP2.
	  context_->getTransaction()->generateSavepointId();

	  statementGlobals_->getSavepointId() =
	    context_->getTransaction()->getSavepointId();
	}
    } // if (root_tdb->transactionReqd())

    else
    {
      // Browse access cursors or the load phase of index will
      // have the transaction passed (to ESPs?) if one exists
      // in its statement globals
      if (context_->getTransaction()->xnInProgress())
        {
          statementGlobals_->getTransid() =
            context_->getTransaction()->getExeXnId();
        }
    }
    if (stmtStats_ && stmtStats_->getMasterStats() != NULL)
        stmtStats_->getMasterStats()->setTransId(statementGlobals_->getTransid());
  return 0;
}
  
// ends(commits) transaction, if one is running and auto commit is on.
short Statement::commitTransaction(ComDiagsArea &diagsArea)
{
  if (context_->getTransaction()->userEndedExeXn())
    {
      if (!diagsArea.contains(-CLI_USER_ENDED_EXE_XN))
         diagsArea << DgSqlCode(- CLI_USER_ENDED_EXE_XN);
      return ERROR;
    }

  if ((context_->getTransaction()->xnInProgress()) &&
      (context_->getTransaction()->exeStartedXn()) &&
      (context_->getTransaction()->autoCommit()) &&
      (autocommitXn()))
    {
      if (context_->aqrInfo())
	context_->aqrInfo()->setXnStartedAtPrepare(FALSE);

      // get current context and close all statements
      // started under the current transaction
      context_->closeAllCursors(ContextCli::CLOSE_ALL, ContextCli::CLOSE_CURR_XN);

      // if transaction is still active(it may have been committed at
      // close cursor time if auto commit is on), commit it.
      if (context_->getTransaction()->xnInProgress())
	{
	  StmtDebug2("  About to COMMIT, stmt %p, tx %s...", this,
		     TransIdToText(statementGlobals_->getTransid()));
	  // do waited commit for DDL queries
	  NABoolean waited = FALSE;
	  //if (root_tdb->ddlQuery())
	  //	    waited = TRUE;
	  short taRetcode = context_->commitTransaction(waited);
	  
          StmtDebug1("  Return code is %d", (Lng32) taRetcode);
      
	  setAutocommitXn(FALSE);

	  if (taRetcode != 0)
	    {
              // If there are diagnostics in the statement globals then add
              // them to the caller's diags area first. They may contain
              // information about something that went wrong before the
              // COMMIT was attempted. Then add information about the COMMIT
              // failure that just occurred.
              statementGlobals_->takeGlobalDiagsArea(diagsArea);
              diagsArea.mergeAfter(*context_->getTransaction()->getDiagsArea());
              return ERROR;
            }
          StmtDebug0("  COMMIT was successful");
        }
    }
  else
    {
      StmtDebug0("  No AUTOCOMMIT transaction for this stmt");
    }
  
  return 0;
}

short Statement::rollbackSavepoint(ComDiagsArea & diagsArea,
				   NABoolean &rollbackXn)
{
  rollbackXn = FALSE;
  
  NABoolean rollbackSP = FALSE;

  if (context_->getTransaction()->xnInProgress())
    {
      if ((context_->getTransaction()->exeStartedXn()) &&
	  (context_->getTransaction()->autoCommit()))
	{
	  rollbackSP = FALSE;
	}
      else if (diagsArea.getRollbackTransaction())
	rollbackSP = FALSE;
      else if (root_tdb && 
	       (root_tdb->transactionReqd() != 0))
	{
	  if (root_tdb->getUpdAbortOnError())
	    rollbackSP = FALSE;
	  else if (root_tdb->getUpdPartialOnError())
	    rollbackSP = FALSE;
	  else if (root_tdb->getUpdSavepointOnError())
	    rollbackSP = TRUE;
	  else if ((NOT root_tdb->getUpdErrorOnError()) &&
		   (NOT diagsArea.getNoRollbackTransaction()))
	    rollbackSP = FALSE;
	}
    }

  if (rollbackSP)
    {
#pragma nowarn(1506)   // warning elimination 
      short retcode = root_tcb->rollbackSavepoint();
#pragma warn(1506)  // warning elimination 
      if (retcode)
	{
	  diagsArea.mergeAfter(*statementGlobals_->getDiagsArea());
	  diagsArea << DgSqlCode(-CLI_SAVEPOINT_ROLLBACK_FAILED);
	  rollbackXn = TRUE;
	}
      else
	{
	  // do not abort this transaction.
	  rollbackXn = FALSE;
	  diagsArea << DgSqlCode(CLI_SAVEPOINT_ROLLBACK_DONE);
	  // clr count of affected rows, CLI_SAVEPOINT_ROLLBACK_DONE.
	  statementGlobals_->setRowsAffected(0);
	  diagsArea.setRowCount(0);
	}
    }

  return 0;
}

// abort (rollback) transaction, if one is running
short Statement::rollbackTransaction(ComDiagsArea & diagsArea,
				     NABoolean doXnRollback)
{
  ContextCli::CloseCursorType closeCursorType;

  if (context_->getTransaction()->userEndedExeXn())
    {
      if (!diagsArea.contains(-CLI_USER_ENDED_EXE_XN))
         diagsArea << DgSqlCode(- CLI_USER_ENDED_EXE_XN);
      return ERROR;
    }

  if (context_->getTransaction()->xnInProgress())
    {
      if (context_->aqrInfo())
	context_->aqrInfo()->setXnStartedAtPrepare(FALSE);

      NABoolean rollbackXn = FALSE;
      NABoolean autoCommitRollback = FALSE;
      if ((context_->getTransaction()->exeStartedXn()) &&
	  (context_->getTransaction()->autoCommit()))
	{
	  rollbackXn = TRUE;
	  autoCommitRollback = TRUE;
	}
      else if (diagsArea.getRollbackTransaction())
	rollbackXn = TRUE;
      else if (root_tdb && 
	       (root_tdb->transactionReqd() != 0))
	{
	  if (root_tdb->getUpdAbortOnError())
	    rollbackXn = TRUE;
	  else if (root_tdb->getUpdPartialOnError())
	    rollbackXn = FALSE;
	  else if ((NOT root_tdb->getUpdSavepointOnError()) &&
		   ((NOT root_tdb->getUpdErrorOnError()) &&
		    (NOT diagsArea.getNoRollbackTransaction())))
	    rollbackXn = TRUE;
	  else if (doXnRollback)
	    rollbackXn = TRUE;

	  // If aqr has been enabled and this query returned a 
	  // special error due to a concurrent ddl operation,
	  // then do not abort the transaction. This query will be retried
	  // and if this error persists, then the Xn will be aborted.
	  if (root_tdb->aqrEnabled() &&
	      ((diagsArea.mainSQLCODE() == -EXE_TIMESTAMP_MISMATCH)  ||
               (diagsArea.mainSQLCODE() == -CLI_INVALID_QUERY_PRIVS) ||
               (diagsArea.mainSQLCODE() == -CLI_DDL_REDEFINED)       ||
               (diagsArea.mainSQLCODE() == -EXE_SCHEMA_SECURITY_CHANGED)))
	    {
	      rollbackXn = FALSE;
	    }

          // If aqr has been enabled and this query returned a lost open
          // error due to a concurrent ddl operation, allow transaction
          // rollback if IUD.  IUD operations may have updated a subset of 
          // partitions before the lost open error was raised.  For example,
          // an earlier execution updated partitions 2, 3, and 4.  A ddl
          // operation now blows away these opens.  The re-exec updates 
          // partition #1, and the lost open error is raised for 2, 3, 
          // and 4.  The result can be data corruption unless we roll 
          // back the transaction.  See solution 10-100604-0887.
          //
          // But if not IUD, This query will be retried and if this error
          // persists, then the Xn will be aborted.
	  if (root_tdb->aqrEnabled() &&
	      (diagsArea.mainSQLCODE() == -EXE_LOST_OPEN) &&
	      (NOT root_tdb->updDelInsertQuery()))
	    {
	      rollbackXn = FALSE;
	    }
	}
      if (root_tdb && root_tdb->getPsholdCloseOnRollback())
        closeCursorType = ContextCli::CLOSE_ALL_INCLUDING_ANSI_PUBSUB_HOLDABLE;
      else
        closeCursorType = ContextCli::CLOSE_ALL_INCLUDING_ANSI_HOLDABLE;
      if (rollbackXn)
	{
	  short taRetcode;

          // clr count of affected rows.
          // ALM CR 6903 -- although some rows may have been affected
          // if an IUD used NO ROLLBACK, we don' currently have an accurate
          // way to count these, due to the way EXE cancels sessions
          // during error handling and the way the TSE does not dispatch
          // exe-in-dp2 sessions when raising errors such as lock timeouts.
          // So the fix for 6903 is to consistently return 0 rows affected.
          // In the future, we might enhance this.
	  statementGlobals_->setRowsAffected(0);
	  diagsArea.setRowCount(0);

	  NABoolean implicitTran = 
	    context_->getTransaction()->implicitXn();
          // get current context and close all statements
          // started under the current transaction
          context_->closeAllCursors(closeCursorType, ContextCli::CLOSE_CURR_XN,0,TRUE);

	  if (! context_->getTransaction()->xnInProgress())
	    return 0;

	  if (NOT autoCommitRollback)
	    {
	      //////////////////////////////////////////////////////////////
	      // An error occurred while doing an upd/ins/del stmt.
	      // We really need to roll back stmt, but until stmt atomicity
	      // support is not in, we must abort Xn.
	      // RollbackStatement ALWAYS rollbacks Xn. RollbackTransaction
	      // only rollbacks if executor started the Xn.
	      //////////////////////////////////////////////////////////////
	      if (context_->getTransaction()->exeStartedXn())
            {
              StmtDebug1("  About to rollback statement %p...", this);
		taRetcode = context_->getTransaction()
		  ->rollbackStatement();
            }
	      else
		{
		  // doom the transaction
              StmtDebug1("  About to DOOM TX for statement %p...", this);
		  taRetcode = context_->getTransaction()
		    ->doomTransaction();
		}
	    }
	  else
	    {
            StmtDebug1("  About to ROLLBACK TX for statement %p...", this);
	      taRetcode = context_->getTransaction()
		->rollbackTransactionWaited();
	    }

          StmtDebug1("  Return code is %d", (Lng32) taRetcode);

	  // release all outstanding I/Os with transactions, just like
	  // we do when we commit the transaction
	  context_->releaseAllTransactionalRequests();

          // fix 10-040526-4462. We need to force the transid in the context_
          // and the statement global to be in sync. Otherwise, the obsolete transid
          // in the statement global will be passed to the ESP during releaseESPs() 
          // calls. For any remote ESP, the bad transid will be rejected by the TMF
          // (inside the body of FS2_transid_to_buffer()) and the releasing operation 
          // on that ESP will fail, including the termination of the remote ESP. 
          // In some cases, the master will hung.
          //
          // After setting the transid in the statement global to -1 here, we just
          // bypass the call to FS2_transid_to_buffer(). Since remote ESPs caches
          // the transid, the cleanup operation will still use the "good" transid.
          // Note here the transid is obsolete from TMF point of view, but still  
          // valid (good) in terms of SQL/MX data structures (e.g., transid as the key
          // for table lookup).
          //
          // Note the transid in statement global should be to -1 after calling 
          // context::releaseAllTransactionalREquests() because that method calls 
          // statement::releaseTransaction() which uses the transid.
          statementGlobals_->getTransid() = (Int64)-1;

	  if (taRetcode != 0)
	    {
	      diagsArea.mergeAfter(*context_->
				   getTransaction()->getDiagsArea());
	      return ERROR;
	    }
	  else
	    {
              // Fix for solution 10-090908-4444 requires an extra
              // diags condition, error 8839.  To avoid changing lots
              // of expected files, don't do this in the regression
              // test environment.
	      if (! implicitTran)
		{
                  diagsArea << DgSqlCode(- CLI_VALIDATE_TRANSACTION_ERROR);
                  return ERROR;
                }
              else 
                {
                  if (context_->aqrInfo())
                    context_->aqrInfo()->setAbortedTransWasImplicit();
                }
            }
        }
      else if ((root_tdb) &&
	       (root_tdb->getUpdPartialOnError()))
	{
	  diagsArea << DgSqlCode(CLI_PARTIAL_UPDATED_DATA);

	  // Add the affected row count that was directly placed into
	  // the master globals to those that are already in the diags
	  // area. Make both row counts (diags and statementGlobals_)the same.
	  diagsArea.addRowCount(statementGlobals_->getRowsAffected());
	  statementGlobals_->setRowsAffected(diagsArea.getRowCount());
	}
    }

  return 0;
}


RETCODE Statement::doVisibilityCheck (LateNameInfoList * lnil,
                                      ComDiagsArea &diagsArea)
{
  RETCODE retcode = SUCCESS;

  // Visibility Checks disabled for  (10-081016-6563)
  //
  const NABoolean disableVisCheck = TRUE;

  if(disableVisCheck)
    return retcode;

  for (Int32 l = 0; l < (Int32) (lnil->getNumEntries()); l++)
    {
      LateNameInfo * lni = &(lnil->getLateNameInfo(l));
      if (   !lni->isAnsiPhySame()     // the name is not a physical name
          && !lni->isAnsiNameChange()  // has not been resolved via catman call
          && !lni->isView() )          // vis checks for views done elsewhere
      { 
        retcode = checkObjectVisibility(lni->getLastUsedName(&heap_), 
                                        lni->getNameSpace(),
                                        lni->resolvedPhyName(), 
                                        diagsArea);
        if (retcode != SUCCESS )
          break;
      } 
    }

  if (retcode == WARNING)
  {
    // Catalog is visible on local node, but either not visible or 
    // unrelated on remote node. Force name mapping. 
    retcode = forceMapAllNames (lnil, diagsArea);
    // Return WARNING so that the caller can force similarity check
    if (retcode != ERROR)
	retcode  = WARNING;
  }
  return retcode;
}

RETCODE Statement::checkObjectVisibility( AnsiOrNskName *ansiName,
					  const ComAnsiNameSpace nameSpace,
                                          char *guardianName,
                                          ComDiagsArea &diagsArea)
{
  return ERROR;
}

static
const NAWchar* get_name_mode(Lng32 name_mode)
{
  switch (name_mode)
  {
  case stmt_handle:
    return L"stmt_handle";
    break;

  case stmt_name:
    return L"stmt_name";
    break;

  case cursor_name:
    return L"cursor_name";
    break;

  case stmt_via_desc:
    return L"stmt_via_desc";

  case curs_via_desc:
    return L"curs_via_desc";
    break;

  default:
    return L"unknown";
    break;
  }
}

void Statement::dump(ostream * outstream)
{
  *outstream << "Statement:      " << this << '\n';

  *outstream << "Module:         ";
  if ((statement_id->module) && (statement_id->module->module_name))
//    *outstream << getModNameInLocale(statement_id->module);
    *outstream << (char *)(statement_id->module->module_name);  
  *outstream << '\n';

  *outstream << "Statement Name: "; 
  if (statement_id->identifier)
//    *outstream << getIdInLocale((SQLCLI_OBJ_ID*)statement_id);
    *outstream << (char *)(statement_id->identifier);
  *outstream << '\n';
  
  *outstream << "Cursor Name:    ";
  if (cursor_name_)
//    *outstream << getIdInLocale((SQLCLI_OBJ_ID*)cursor_name_);
    *outstream << (char *)(cursor_name_);
  *outstream << '\n';

  *outstream << "Name Mode:      " << get_name_mode(statement_id->name_mode) << '\n';

  *outstream << "Type:           " << (allocated() ? "DYNAMIC" : "STATIC") << '\n';

  *outstream << "Heap (total):   " << heap_.getTotalSize() << '\n';
  *outstream << "Heap (alloc):   " << heap_.getAllocSize() << '\n';
  *outstream << "Space (total):  " << space_.getAllocatedSpaceSize() << '\n';

  if (source_str)
    *outstream << source_str << '\n';

  *outstream << "----------------------------------------------------\n";
}

void Statement::setState(State newState) {
  // change the state of the statement. As a side effect the statement
  // might be removed or added from/to the openStatementList()
  switch (stmt_state) {
  case OPEN_:
  case EOF_:
  case FETCH_: //gps Add FETCH_ to "transition from" cases. (4/21/99)
  case RELEASE_TRANS_:
    // remove from list if newState is CLOSE_ or DEALLOCATED_
    if ((newState == CLOSE_) || (newState == DEALLOCATED_))
      {
        State originalState = stmt_state;

	// In certain cases, this statement is not added to the open
	// statement list. This is a performance optimization for
	// unique OLT queries. These queries are non-cursor queries
	// that are completed within one CLI call (ClearExecFetchClose).
	// See PerformTasks method in Cli.cpp for details.
	// Do not add them to open stmt list, 
	stmt_state = newState;
	if (NOT oltOpt())
	  context_->removeFromOpenStatementList(statement_id);

        // If this is a stored procedure result set and it is
        // transitioning out of an open state, then we have some
        // bookkeeping to do
        if (parentCall_ && originalState != EOF_)
        {
          ExRsInfo *parentRsInfo = parentCall_->getResultSetInfo();
          if (parentRsInfo)
          {
            StmtDebug2("  setState() changing RS state to %s, this %p",
                       stmtState(getState()), this);
            ULng32 rsIndex = parentRsInfo->getIndex(this);
            parentRsInfo->setCloseAttempted(rsIndex);
            StmtDebug2("  RS index %u, Num closed since CALL %u",
                       rsIndex, parentRsInfo->getNumClosedSinceLastCall());
          }
        }
        
      }
    break;

  case PREPARE_:
    // remove from list if newState is CLOSE_ or DEALLOCATED_ or INITIAL_
    if ((newState == CLOSE_) || (newState == DEALLOCATED_) || (newState == INITIAL_))
      {
	context_->removeFromOpenStatementList(statement_id);
      }
    break;

  case INITIAL_:
  case CLOSE_:
    // add to openStatementList if new state is OPEN_ or PREPARE_
    if ((newState == OPEN_) || (newState == PREPARE_))
      {
	if (NOT oltOpt())
	  context_->addToOpenStatementList(statement_id, this);
	else
	  context_->removeFromCloseStatementList(this, FALSE);
      }
    break;
  }

  if (stmt_state != newState)
  {
    StmtDebug3("*** Statement %p state change: %s -> %s",
               this, stmtState(stmt_state), stmtState(newState));
  }

  stmt_state = newState;

  if (stmtStats_ != NULL) 
  {
    if (stmtStats_->getMasterStats() != NULL)
     stmtStats_->getMasterStats()->setStmtState(newState);
    stmtStats_->setMergeReqd(TRUE);
  }
}

NABoolean Statement::noRowsAffected(ComDiagsArea & diagsArea)
{
  // ANSI says that an EOF is to be returned if no rows were affected
  // by an update/delete/insert operation.
  if ((root_tdb) && 
      (root_tdb->updDelInsertQuery()) &&
      (diagsArea.getRowCount() == 0) &&
      getRowsAffected() == 0)
    return TRUE;
  else
    return FALSE;
}


NABoolean Statement::isSelectInto()
{
  return (getRootTdb() && getRootTdb()->selectIntoQuery());
}

NABoolean Statement::isDeleteCurrentOf()
{
  return (getRootTdb() && getRootTdb()->deleteCurrentOfQuery());
}

NABoolean Statement::isUpdateCurrentOf()
{
  return (getRootTdb() && getRootTdb()->updateCurrentOfQuery());
}
// BertBert VV
NABoolean Statement::isEmbeddedUpdateOrDelete()
{
  return (getRootTdb() && getRootTdb()->isEmbeddedUpdateOrDelete());
}
NABoolean Statement::isStreamScan()
{
  return (getRootTdb() && getRootTdb()->isStreamScan());
}
// BertBert ^^

RETCODE Statement::setHoldable(ComDiagsArea &diagsArea, NABoolean h)
{
  if (root_tdb == NULL)
    return setAnsiHoldable(diagsArea, h);
  else
    return setPubsubHoldable(diagsArea, h);
}

RETCODE Statement::setPubsubHoldable(ComDiagsArea &diagsArea, NABoolean h)
{
  // tbd -- error for open stmt??
  if (h &&
      root_tdb &&
      !root_tdb->isEmbeddedUpdateOrDelete() &&
      !root_tdb->isStreamScan())
    {
      // Holdable cursors are only supported for streaming cursors
      // and destructive cursors because there are some strange
      // side-effects (locks disappear after commit) that we don't
      // want to inflict on non-Publich/Subscribe functionality at
      // this time. There are no source-code changes needed to allow
      // holdable cursors in these other cases though.
      diagsArea << DgSqlCode(-CLI_CURSOR_CANNOT_BE_HOLDABLE);
      return ERROR;
    }
  if (stmt_state == OPEN_ || stmt_state == FETCH_ || stmt_state == RELEASE_TRANS_)
    {
      // Cannot change holdable attribute while cursor is open.
      diagsArea << DgSqlCode(-CLI_CURSOR_ATTR_CANNOT_BE_SET);
      return ERROR;
    }
  
  if (h)
    holdable_ = SQLCLIDEV_PUBSUB_HOLDABLE;
  else
    holdable_ = SQLCLIDEV_NONHOLDABLE;
  return SUCCESS;
}

RETCODE Statement::setAnsiHoldable(ComDiagsArea &diagsArea, NABoolean h)
{
  // SQL_Exec_SetStmtAttr for setting the holdable cursor can't be called 
  // after the statement is prepared
  if (root_tdb || stmt_state == OPEN_ || stmt_state == FETCH_ || stmt_state == RELEASE_TRANS_)
    {
      // Cannot change holdable attribute while cursor is open.
      diagsArea << DgSqlCode(-CLI_CURSOR_ATTR_CANNOT_BE_SET);
      return ERROR;
    }
  
  if (h)
    holdable_ = SQLCLIDEV_ANSI_HOLDABLE;
  else
    holdable_ = SQLCLIDEV_NONHOLDABLE;
  return SUCCESS;
}

RETCODE Statement::setInputArrayMaxsize(ComDiagsArea &diagsArea, const Lng32 inpArrSize)
{
  if (inpArrSize < 0) {
    diagsArea << DgSqlCode(-CLI_ARRAY_MAXSIZE_INVALID_ENTRY);
    return ERROR;
  }

  inputArrayMaxsize_ = inpArrSize ;
  return SUCCESS ;
}

RETCODE Statement::setRowsetAtomicity(ComDiagsArea &diagsArea, const AtomicityType atomicity)
{
  if ((atomicity != UNSPECIFIED_) && (atomicity != ATOMIC_) && (atomicity != NOT_ATOMIC_)) {
    diagsArea << DgSqlCode(-CLI_INVALID_ATTR_VALUE);
    return ERROR;
  }

  rowsetAtomicity_ = atomicity ;
  return SUCCESS ;
}
  
RETCODE Statement::setNotAtomicFailureLimit(ComDiagsArea &diagsArea, const Lng32 limit)
{
  if (limit < 30) {
    diagsArea << DgSqlCode(-CLI_INVALID_ATTR_VALUE);
    return ERROR;
  }

  notAtomicFailureLimit_ = limit ;
  return SUCCESS ;
}
  
  

void Statement::setOltOpt(NABoolean v)
{
  if (! getRootTdb())
    return;

  if (v && getRootTdb()->doOltQueryOpt())
    flags_ |= OLT_OPT;
  else
    flags_ &= ~OLT_OPT; 
}

// Must be in CLOSE_ state.
// Will cause fixup at open.
Lng32 Statement::releaseSpace()
{
  StmtDebug2("[BEGIN releaseSpace] %p, stmt state %s",
             this, stmtState(getState()));

  if (stmt_state == INITIAL_)
  {
    StmtDebug2("[END releaseSpace] %p, result is %s",
               this, RetcodeToString(SUCCESS));
    return SUCCESS;
  }

  // Bugzilla 1662
  // A statement being reclaimed might be in the EOF_ state. We will
  // not attempt to reclaim these statements. Here's one way an EOF_
  // statement can be encountered:
  // * The statement has an autocommit transaction
  // * End-of-data is fetched
  // * Inside the CLI fetch, we commit the transaction, put the
  //   statement in the CLOSED_ state, and place the statement on
  //   the closed statement list
  // * Then we change the statement state to EOF_ so that a subsequent
  //   SQL_EXEC_CloseStmt will succeed
  // * The statement is now on the closed statement list, is in the
  //   EOF_ state, but is not actually a valid candidate for reclaim
  //   until the CLI caller issues SQL_EXEC_CloseStmt
  if (stmt_state == EOF_)
  {
    StmtDebug2("[END releaseSpace] %p, result is %s",
               this, RetcodeToString(SUCCESS));
    return SUCCESS;
  }

  assert(stmt_state == CLOSE_);
  RETCODE result = releaseTcbs(FALSE);
  
  if (result == SUCCESS)
  {
    setState(CLOSE_); // The state may have changed by a call within releaseTcbs()
    space_.freeBlocks();
    setFixupState(0);  // will fixup at exec()
    // To recalculate the bulk move info when the tcb is re-generated
    setComputeBulkMoveInfo(TRUE);
    if (stmtStats_ != NULL && stmtStats_->getMasterStats() != NULL)
      stmtStats_->getMasterStats()->incReclaimSpaceCount();
  }

  StmtDebug2("[END releaseSpace] %p, result is %s",
             this, RetcodeToString(result));
  return (Lng32) result;
}

NABoolean Statement::isReclaimable()
{
  if (root_tdb != NULL && 
      (root_tdb->getQueryType() == ComTdbRoot::SQL_INSERT_RWRS ||
       root_tdb->cantReclaimQuery()))
    return FALSE;
  else
    return TRUE;
}

NABoolean Statement::returnRecompWarn()
{
  if (stmt_type == STATIC_STMT)
    return recompWarn();
  else if (root_tdb)
    return root_tdb->recompWarn();
  else
    return FALSE;
}

// Wait for completion of UDR requests associated with this
// statement. If allRequests is FALSE then only wait for transactional
// requests.
RETCODE Statement::completeUdrRequests(NABoolean allRequests) const
{

  RETCODE result = SUCCESS;
  while (statementGlobals_ &&
         ((allRequests && statementGlobals_->numUdrMsgsOut() > 0) ||
          (!allRequests && statementGlobals_->numUdrTxMsgsOut() > 0)))
  {
    // First attempt to complete requests on scalar udr server
    IpcConnection *conn = statementGlobals_->getUdrConnection();
    ExUdrServer *udrServ = statementGlobals_->getUdrServer();
    if(conn != NULL && udrServ != NULL)
    {
      StmtDebug1(
      "  About to call ExUdrServer::completeUdrRequests(%p, FALSE)...",
        conn);

      udrServ->completeUdrRequests(conn, FALSE);
    }

    // Next, attempt to complete requests on dedicated udr servers
    // if there are any.
    LIST(ExUdrServer *) udrServList = statementGlobals_->getUdrServersD();
    for (CollIndex i = 0; i < udrServList.entries(); i++)
    {
      ExUdrServer *udrServ = udrServList[i];
      IpcConnection *conn = udrServ->getUdrControlConnection();
      
      StmtDebug1(
        "  About to call ExUdrServer::completeUdrRequests(0x%08x, FALSE)...",
        conn);
      udrServ->completeUdrRequests(conn, FALSE);
    }
    StmtDebug0("  Done");
  }
  
  return result;
}


Int32 Statement::updateMeasStmtCntrs(Int64 startTime)
{
  // update Measure statement counters if enabled.

  ExStatisticsArea *myStats = getStatsArea();
  ExMeasStmtCntrs *stmtCntrs = getGlobals()->getMeasStmtCntrs();

  if (getGlobals()->measStmtEnabled() && stmtCntrs)
    {
      stmtCntrs->incElapseBusyTime(NA_JulianTimestamp() - startTime);
      if (getModule() != NULL)  // static sql
       {
	 // if OLT, call ExMeas::ExMeasStmtCntrsBump directly since the 
         // counters are updated by Arkfs.
	 // For non-OLT, call ExStatisticsArea::updateStmtCntrs to 
	 // merge ExDp2Stats entries before calling 
	 // ExMeas::ExMeasStmtCntrsBump

	 if (oltOpt())
	   return stmtCntrs->ExMeasStmtCntrsBump
				  (getModule()->getStatementCount(),
				   getModule()->getModuleName(),
				   getModule()->getModuleNameLen());
	 else
	   if (myStats)
	     return myStats->updateStmtCntrs
				  (stmtCntrs,
				   getModule()->getStatementCount(),
				   getModule()->getModuleName(),
				   getModule()->getModuleNameLen());
       }
      else
      {
	// Dynamic statement. 
	// Fabricate the module name: SQLMX^EXECUTE_<stmt-name>
	// The same code appears in Statement::allocDynamicStmtCntrs.
    	// Could save the fabricatd name in Statement if performance is a 
	// concern.
 Int32 nameLen = 0;
	char modName[MODULE_ID_SIZE + 1];
	modName[MODULE_ID_SIZE] = 0;

	char * stmtName = NULL;
 Int32 idPrefixLen = 0;

	str_pad (&modName[0], MODULE_ID_SIZE);
	if (getUniqueStmtId() == NULL)
	  {
	    str_cpy (&modName[0], DYNAMIC_STMT_NAME, DYNAMIC_STMT_NAME_SIZE);
	    stmtName = (char *)getIdentifier();
	    
	    idPrefixLen = DYNAMIC_STMT_NAME_SIZE;
	  }
	else
	  {
	    stmtName = getUniqueStmtId();
	  }
	
	if (stmtName) 
	  {
	    nameLen = str_len(stmtName);
	    if (nameLen > (MODULE_ID_SIZE - idPrefixLen))
	      nameLen = MODULE_ID_SIZE - idPrefixLen;
	    str_cpy (&modName[idPrefixLen], stmtName, nameLen);
	  }
	     
	if (oltOpt())
	  return stmtCntrs->ExMeasStmtCntrsBump(1, &modName[0], 
						nameLen + idPrefixLen);
	else
	  if (myStats)
	    return myStats->updateStmtCntrs(stmtCntrs, 1, &modName[0], 
                                            nameLen + idPrefixLen);
      }
    }
  return 0;
}

void Statement::setUniqueStmtId(char * id)
{
  if (uniqueStmtId_)
    {
      // get start & finished messages to cancel broker cleaned up
      // before switching qid.
      if (root_tcb && root_tcb->anyCbMessages())
        releaseTransaction(TRUE);

      NADELETEBASIC(uniqueStmtId_, &heap_);
      uniqueStmtId_ = NULL;
    }

  if (id)
    {
      uniqueStmtId_ = new(&heap_) char[strlen(id)+1];
      strcpy(uniqueStmtId_, id);
      uniqueStmtIdLen_ = strlen(uniqueStmtId_);
    }
  else
    {
      // generate a unique id and set it.
      uniqueStmtId_ = new(&heap_) char[ComSqlId::MAX_QUERY_ID_LEN+1];
      
      char tmpLong[ 20 ];
      if (statement_id->name_mode == stmt_handle)
#ifdef NA_64BIT
	str_ltoa((ULong)getStmtHandle(), tmpLong);
#else
	str_itoa((ULong)getStmtHandle(), tmpLong);
#endif
      ComSqlId::createSqlQueryId(uniqueStmtId_,
				 ComSqlId::MAX_QUERY_ID_LEN+1,
				 uniqueStmtIdLen_,
				 strlen(context_->getSessionId()),
				 context_->getSessionId(),
				 cliGlobals_->getNextUniqueNumber(),
				 ((statement_id->name_mode == stmt_handle)
				  ? strlen(tmpLong)
				  : strlen(getIdentifier())),
				 (char*)
				 ((statement_id->name_mode == stmt_handle)
				  ? tmpLong
				  : getIdentifier())
				 );
    }
}

void Statement::allocDynamicStmtCntrs()
{
  // Allocate a stmt counter and set the
  // module name to SQLMX^EXECUTE_<stmt-name>
  // or to the uniqueStmtId which was generated for this stmt.
  Int32 nameLen = 0;
  char modName[MODULE_ID_SIZE + 1];
  modName[MODULE_ID_SIZE] = 0;

  char * stmtName = NULL;
  Int32 idPrefixLen = 0;
  str_pad (&modName[0], MODULE_ID_SIZE);
  if (getUniqueStmtId() == NULL)
    {
      str_cpy (&modName[0], DYNAMIC_STMT_NAME, DYNAMIC_STMT_NAME_SIZE);
      stmtName = (char *)getIdentifier();

      idPrefixLen = DYNAMIC_STMT_NAME_SIZE;
      if (stmtName)
	nameLen = str_len(stmtName);
    }
  else
    {
      stmtName = getUniqueStmtId();
      nameLen = getUniqueStmtIdLen();
    }

  if (stmtName) 
    {
      if (nameLen > (MODULE_ID_SIZE - idPrefixLen))
	nameLen = MODULE_ID_SIZE - idPrefixLen;
      str_cpy (&modName[idPrefixLen], stmtName, nameLen);
    }
  
  ExMeasStmtCntrs *stmtCntrs = statementGlobals_->getStmtCntrs();
  if (stmtCntrs != NULL)
    NADELETE(stmtCntrs, ExMeasStmtCntrs, &heap_);
  stmtCntrs = new(&heap_)ExMeasStmtCntrs();
  stmtCntrs->ExMeasStmtCntrsBump(1, &modName[0], 
				  nameLen + idPrefixLen);

  statementGlobals_->setStmtCntrs(stmtCntrs);
}  

// This method should always be used to assign a new value to the
// root_tdb data member. The method will keep the root_tdb pointer for
// a given statement in sync with its clones.
//
// NOTE: we really should have this method keep the root_tdb_size data
// member in sync with root_tdb. But currently root_tdb_size is only
// used by SHOWPLAN code paths and on other paths is not maintained. A
// possible future improvement is to keep root_tdb and root_tdb_size
// in sync on all code paths.

ex_root_tdb * Statement::assignRootTdb(ex_root_tdb *new_root_tdb)
{
  if (root_tdb == new_root_tdb)
    return root_tdb;

  if (root_tdb)
  {
    // dealloc() will release the TCB tree for this statement and will
    // also call dealloc() for any cloned statements
    dealloc();
    
    if (!isCloned())
    {
      // solution 10-040803-8511: root_tdb is not unpacked for SHOWPLAN
      // the lateNameInfoList is still the offset, not valid pointer
      if (!root_tdb->isPacked() && root_tdb->getLateNameInfoList() != NULL)
        for (Int32 i = 0;
             i < (Int32) (root_tdb->getLateNameInfoList()->getNumEntries());
             i++)
          root_tdb->getLateNameInfoList()->
            getLateNameInfo(i).zeroLastUsedAnsiName();     
      CollHeap *h = cliGlobals_->getArkcmp()->getHeap();
      h->deallocateMemory((void *) root_tdb);
      StmtDebug2("  Stmt %p deallocated root TDB %p", this, root_tdb);
    }
  }

  root_tdb = new_root_tdb;
  StmtDebug2("  Stmt %p root TDB is now %p", this, root_tdb);

#ifdef NA_DEBUG_C_RUNTIME
  Lng32 rs = (Lng32) (root_tdb ? root_tdb->getMaxResultSets() : 0);
  if (rs > 0)
    StmtDebug1("  Max result sets: %d", rs);
#endif

  clonedStatements->position();
  Statement *clone = (Statement *) clonedStatements->getNext();
  for (; clone != NULL; clone = (Statement *) clonedStatements->getNext())
  {
    clone->root_tdb = new_root_tdb;
    StmtDebug2("  Clone %p root TDB is now %p", clone, new_root_tdb);
  }

  return root_tdb;
}

RETCODE Statement::addDescInfoIntoStaticDesc(Descriptor * desc,
					     Lng32 what_desc,
					     ComDiagsArea &diagsArea)
{
  if(!root_tdb){
    return SUCCESS;
  }

  InputOutputExpr *expr;
  enum ex_expr::exp_return_type expRType;

  Int32 retcode = 0; // be optimistic

  // A special case for DESCRIBE is when the SQL statement is a CALL
  // statement and the CLI caller wants to use a "wide" descriptor for
  // the CALL.
  if (root_tdb->hasCallStmtExpressions() && desc->isDescTypeWide())
  {
    // First populate the caller's descriptor with information from
    // the INPUT expression, the overlay information from the OUTPUT
    // expression into the same descriptor.

    if(expr = root_tdb->inputExpr())
    {
      expRType = expr->addDescInfoIntoStaticDesc(desc, TRUE /*input*/);
      if(expRType != ex_expr::EXPR_OK)
	retcode = -1;
    }
    
    if((retcode == 0) && (expr = root_tdb->outputExpr()))
    {
      expRType = expr->addDescInfoIntoStaticDesc(desc, FALSE /*output*/);
      if(expRType != ex_expr::EXPR_OK)
	retcode = -1;
    }
  }
  else{
    NABoolean isInput;
    if (what_desc == SQLWHAT_INPUT_DESC){
      expr = root_tdb->inputExpr();      // input expr -> desc
      isInput = TRUE;
    }
    else{
      expr = root_tdb->outputExpr();	// output expr -> desc
      isInput = FALSE;
    }
    if(expr)
    {
      expRType = expr->addDescInfoIntoStaticDesc(desc, isInput);
      if(expRType != ex_expr::EXPR_OK)
	retcode = -1;
    }
  }
  
  if (retcode)
  {
    diagsArea << DgSqlCode(- CLI_TDB_DESCRIBE_ERROR);
    return ERROR;
  }

  return SUCCESS;
}

NABoolean Statement::containsUdrInteractions() const
{
  return (root_tdb && root_tdb->containsUdrInteractions());
}

//-----------------------------------------------------------------------------
//
// Read the trigger status array for a given table from its resource fork.
// fsRTMD.fetch() is used for the reading.
//

RETCODE  
Statement::rforkReadTriggerStatus(TriggerStatusWA* triggerStatusWA, 
				  char* physFileName,
				  const char* ansiName,
				  ComDiagsArea &diagsArea)
{
  return SUCCESS;

}


//------------------------------------------------------------------------------
// 
// For each stoi that is marked as subject table, get trigger status array from 
// the corresponding rfork. This status array is used to update the status of the
// relevant triggers in the call to updateTriggerStatusPerTable()
//
RETCODE Statement::getTriggersStatus(SqlTableOpenInfoPtr* stoiList, ComDiagsArea &diagsArea)
{
  
  TriggerStatusWA triggerStatusWA(&heap_, root_tcb);
  SqlTableOpenInfo* stoi;
  RETCODE rc = SUCCESS;
  
  for (Int32 i=0; i< root_tcb->getTableCount(); i++)
    {
	stoi=stoiList[i];
    if (stoi->subjectTable())
		{

		  // save the current diags before entering CLI again
		  ComDiagsArea* copyOfDiagsArea = diagsArea.copy(); 
  		  rc = rforkReadTriggerStatus(&triggerStatusWA, 
									  stoi->fileName(), 
									  stoi->ansiName(),
									  diagsArea);
		  // remove warning 100 from diags.
		  diagsArea.removeFinalCondition100();

		  // merge diags
		  diagsArea.mergeAfter(*copyOfDiagsArea);
		  copyOfDiagsArea->decrRefCount();
                  copyOfDiagsArea = NULL;

		  // select the status of the triggers relevant to this statement
		  // and update them in the root_tcb->triggerStatusVector_
		  triggerStatusWA.updateTriggerStatusPerTable();
		  triggerStatusWA.deallocateStatusArray();
		}
    }

#ifdef _DEBUG
  if (getenv("SHOW_ENABLE"))
  {
	  char int64Str[128];
	  cout << "Trigger Ids in TDB:" << endl;
	  cout << "-------------------" << endl;
	  for (Int32 i=0; i<triggerStatusWA.getTotalTriggersCount(); i++) 
	  {
		  convertInt64ToAscii(root_tdb->getTriggersList()[i], int64Str);
		  cout << i << " : " << int64Str << endl;
	  }
	  cout << endl;

  }
#endif //_DEBUG

  // we cannot check that status was received for all triggers, since
  // triggers may be dropped/added before similarity check is done...
  // if (triggerStatusWA.getTotalTriggersCount() == root_tdb->getTriggersCount())
  return rc;
  
}

// ++ MV -
// isIudTargetTable returns TRUE if the table is the target of an
// insert/update/delete operation, or if the table does not appear in stoi.
NABoolean Statement::isIudTargetTable(char                *tableName, 
				      SqlTableOpenInfoPtr *stoiList)
{
  NABoolean found = FALSE;
  for (Int32 i=0; root_tcb && i < root_tcb->getTableCount(); i++)
    {
      SqlTableOpenInfo *stoi=stoiList[i];

      if (! strcmp(stoi->ansiName(), tableName))
      {
	found = TRUE;
	if (stoi->getInsertAccess() || 
	    stoi->getUpdateAccess() || 
	    stoi->getDeleteAccess())
	return TRUE;
      }
    }

  if (found)
    return FALSE;
  else
    return TRUE;
}

RETCODE Statement::mvSimilarityCheck(char         *table, 
				     ULng32 siMvBitmap, 
				     ULng32 rcbMvBitmap,
				     NABoolean    &simCheckFailed,
				     ComDiagsArea &diagsArea)
{ 
  ComMvAttributeBitmap	siBitmap;
  ComMvAttributeBitmap	rcbBitmap;
  NABoolean iud = isIudTargetTable(table, root_tdb->stoiStoiList());

  siBitmap.initBitmap((ComSInt32)siMvBitmap);
  rcbBitmap.initBitmap((ComSInt32)rcbMvBitmap);

  // if it is INSERT/UPDATE/DELETE statement and table/MV has initialized 
  // ON STATEMENT MV on it - recompile
  if (iud &&
      rcbBitmap.getInitOnStmtMvOnMe())
  {
    if (returnRecompWarn())
      diagsArea << DgSqlCode(EXE_SIM_CHECK_FAILED)
		<< DgString0("Table has on statement MVs on it."); 
    simCheckFailed = TRUE;
    return SUCCESS;
  }

  // if it is INSERT/UPDATE/DELETE statement and table/MV had initialized 
  // ON STATEMENT MV on it - recompile
  if (iud &&
      siBitmap.getInitOnStmtMvOnMe() != rcbBitmap.getInitOnStmtMvOnMe())
  {
    if (returnRecompWarn())
      diagsArea << DgSqlCode(EXE_SIM_CHECK_FAILED)
		<< DgString0("On statement MVs have been removed."); 
    simCheckFailed = TRUE;
    return SUCCESS;
  }

  // if it is INSERT/UPDATE/DELETE statement and table/MV logging required 
  // bit was changed - recompile
  if (iud && siBitmap.getLoggingRequired() != rcbBitmap.getLoggingRequired())
  {
    if (rcbBitmap.getLoggingRequired())
    {
      if (returnRecompWarn())
	diagsArea << DgSqlCode(EXE_SIM_CHECK_FAILED)
	<< DgString0("Logging is required.");
    }
    else
    {
      if (returnRecompWarn())
	diagsArea << DgSqlCode(EXE_SIM_CHECK_FAILED)
		  << DgString0("Logging is not required any more.");
    }

    simCheckFailed = TRUE;
    return SUCCESS;
  }
  
  // if MV enable rewrite bit was change to disable rewrite - recompile
  if (siBitmap.getIsEnableRewrite()  && !rcbBitmap.getIsEnableRewrite())
  {
    if (returnRecompWarn())
      diagsArea << DgSqlCode(EXE_SIM_CHECK_FAILED)
		<< DgString0("MV rewrite was disabled.");
    simCheckFailed = TRUE;
    return SUCCESS;
  }

  // if MV audit bits were changed, but not between the values 
  // AUDIT <--> AUDITONREFRESH - recompile
  ComMvAuditType siMvAuditType = siBitmap.getMvAuditType();
  ComMvAuditType rcbMvAuditType = rcbBitmap.getMvAuditType();
  if (siMvAuditType != rcbMvAuditType &&
      !((siMvAuditType  == COM_MV_NO_AUDIT_ON_REFRESH && 
         rcbMvAuditType == COM_MV_AUDIT)                ||
        (rcbMvAuditType == COM_MV_NO_AUDIT_ON_REFRESH && 
         siMvAuditType  == COM_MV_AUDIT)))
  {
    if (returnRecompWarn())
      diagsArea << DgSqlCode(EXE_SIM_CHECK_FAILED)
		<< DgString0("MV audit status was changed.");
    simCheckFailed = TRUE;
    return SUCCESS;
  }


  // if table insertlog bit was changed - recompile
  if (iud && siBitmap.getIsInsertLog() != rcbBitmap.getIsInsertLog())
  {
    if (returnRecompWarn())
      diagsArea << DgSqlCode(EXE_SIM_CHECK_FAILED)
		<< DgString0("Table INSERTLOG attribute was changed.");
    simCheckFailed = TRUE;
    return SUCCESS;
  }

  // if statement is INSERT/UPDATE/DELETE on table and logging is required 
  // and range log bits was changed, but not between the values 
  // NO RANGELOG <--> MIX RANGELOG - recompile
  ComRangeLogType siRangeLogType = siBitmap.getRangeLogType();
  ComRangeLogType rcbRangeLogType = rcbBitmap.getRangeLogType();
  if (iud                                            && 
      siBitmap.getLoggingRequired()                  &&
      siRangeLogType != rcbRangeLogType              &&
      !((siRangeLogType  == COM_NO_RANGELOG     && 
         rcbRangeLogType == COM_MIXED_RANGELOG)    ||
	(rcbRangeLogType == COM_NO_RANGELOG     && 
	 siRangeLogType  == COM_MIXED_RANGELOG))
      )
  {
    if (returnRecompWarn())    
      diagsArea << DgSqlCode(EXE_SIM_CHECK_FAILED)
		<< DgString0("Table RANGELOG attribute was changed.");
    simCheckFailed = TRUE;
    return SUCCESS;
  }

  // MV is unavailable 
  if (rcbBitmap.getMvStatus() == COM_MVSTATUS_UNAVAILABLE)
  {
    if (returnRecompWarn())
      diagsArea << DgSqlCode(EXE_SIM_CHECK_FAILED)
		<< DgString0("Materialized view is not available.");
      simCheckFailed = TRUE;
      return SUCCESS;
  }

  simCheckFailed = FALSE;
  return SUCCESS;
}

// Discover whether there is already a transaction active
// so that we can avoid starting one when we call CatMapGetCatalogVisibilty,
// CatMapAnsiNameToGuardianName, or other recursive CLI calls.
NABoolean Statement::implicitTransNeeded(void)
{
  const NABoolean noTransInProgress = 
      (context_->getTransaction()->xnInProgress() == FALSE);
  if (noTransInProgress)
    anyTransWasStartedByMe_ = TRUE;
  return noTransInProgress;
}

// If autocommit is on, disable it, prior to making recursive CLI calls.
// Remember if we disabled autoCommit so we can enable before returning 
// from this method.
void Statement::turnOffAutoCommit(void)
{
  if (context_->getTransaction()->autoCommit())
    {
      autoCommitCleared_ = TRUE;
      context_->getTransaction()->disableAutoCommit();
    }
}


// Turn back on autoCommit if we had turned it off.  Maintain the 
// state variable so the statement can be reexecuted.
void Statement::resetAutoCommit(void)
{
  if (autoCommitCleared_)
  {
    autoCommitCleared_ = FALSE;
    context_->getTransaction()->enableAutoCommit();
  }
}
void Statement::saveTmodeValues(void)
{
  ExTransaction  *runTrans = context_->getTransaction();

  if (runTrans)
    {
      savedRoVal_ = runTrans->getROVal();
      savedRbVal_ = runTrans->getRBVal();
      savedAiVal_ = runTrans->getAIVal();
    }
}

void Statement::resetTmodeValues(void)
{
  ExTransaction * runTrans = context_->getTransaction();

  if (runTrans)
    {
      
      runTrans->updateROVal(savedRoVal_);
      runTrans->updateRBVal(savedRbVal_);
      runTrans->updateAIVal(savedAiVal_);
    }
}

// Commit any transaction that we started.  Turn back on autoCommit if we 
// had turned it off.  Maintain the state variables so the statement can be
// reexecuted.
void Statement::commitImplicitTransAndResetTmodes(void)
{
  if (anyTransWasStartedByMe_)
  {
    anyTransWasStartedByMe_ = FALSE;
    if (context_->getTransaction()->xnInProgress())
    {
      // Don't care about any error -- this was a readonly transaction.
      context_->getTransaction()->commitTransaction();
    }
  }
  resetAutoCommit();
  resetTmodeValues();
}


ExStatisticsArea *Statement::getStatsArea()
{
  if (getGlobals())
    return getGlobals()->getStatsArea();
  return NULL;
}

ExStatisticsArea *Statement::getOrigStatsArea()
{
  if (getGlobals())
    return getGlobals()->getOrigStatsArea();
  return NULL;
}

ExStatisticsArea *Statement::getCompileStatsArea()
{
  ExStatisticsArea *stats;
  if ((stats = getStatsArea()) != NULL)
    return stats;
  if (compileStatsArea_ != NULL)
    return compileStatsArea_;
  if (stmtStats_ == NULL || stmtStats_->getMasterStats() == NULL)
    return NULL;
  compileStatsArea_ = new (&heap_) 
    ExStatisticsArea(&heap_, 0, getRootTdb()->getCollectStatsType(),
      getRootTdb()->getCollectStatsType());
  ExMasterStats *masterStats = new(&heap_) ExMasterStats(&heap_);
  masterStats->copyContents(stmtStats_->getMasterStats());
  masterStats->setCollectStatsType(getRootTdb()->getCollectStatsType());
  compileStatsArea_->setMasterStats(masterStats);
  return compileStatsArea_;
}

void Statement::setStmtStats(NABoolean autoRetry)
{
  StatsGlobals *statsGlobals = NULL;
  short error;
  NABoolean stmtStatsRetained = FALSE;
  short savedPriority, savedStopMode;
  StmtStats *stmtStats = NULL;
  if (stmtStats_ != NULL)
  {
    if (getRootTdb())
      assignRootTdb (NULL);
  }
  statsGlobals = cliGlobals_->getStatsGlobals();
  if (statsGlobals != NULL)
  {
    error = statsGlobals->getStatsSemaphore(cliGlobals_->getSemId(),
                  cliGlobals_->myPin(), savedPriority, savedStopMode,
                  FALSE /*shouldTimeout*/);
    ex_assert(error == 0, "getStatsSemaphore() returned an error");
    if (autoRetry)
    {
      if (getUniqueStmtId() != NULL)
      {
        stmtStats = statsGlobals->getMasterStmtStats(getUniqueStmtId(), getUniqueStmtIdLen(), 
              RtsQueryId::ANY_QUERY_);
        ex_assert(stmtStats, "AQR but missing stmtStats.");
        stmtStatsRetained = TRUE;
      }
    }
    else
    {
      // If the same statement handle is used to prepare the query again
      // stmtStats_ would have been set, remove the query in that case
      if (stmtStats_ != NULL)
      {
        if (stmtStats_->getMasterStats() != NULL)
        {
          stmtStats_->getMasterStats()->setStmtState(Statement::DEALLOCATED_);
	  stmtStats_->getMasterStats()->setEndTimes(! stmtStats_->aqrInProgress());
        }
        // Make a copy of stmtStats_ pointer so that in case it is retained we could use 
        // the same stmtStats-
        stmtStats = stmtStats_;
        stmtStatsRetained = statsGlobals->removeQuery(cliGlobals_->myPin(), stmtStats_);
      }
    }
    if (getUniqueStmtId() != NULL)
    {
      if (! stmtStatsRetained)
      {
        stmtStats_ = statsGlobals->addQuery(cliGlobals_->myPin(), 
              getUniqueStmtId(),
              getUniqueStmtIdLen(), (void *)this, (Lng32)-1,
              source_str, source_length, TRUE);
        ex_assert(stmtStats_, "StmtStats_ is null after addQuery");
      }
      else
      {
        ExStatisticsArea *myStats = stmtStats->getStatsArea();
        stmtStats->reuse((void *)this);
        getGlobals()->setStatsArea(NULL);
        if (myStats != NULL && context_->getStats() == myStats)
          context_->setStatsArea(NULL, FALSE, FALSE, FALSE);
        stmtStats_ = stmtStats;
      }
      // update the parentQid
      char *parentQid = getParentQid();
      char *parentQidSystem = getParentQidSystem();
      ULng32 parentQidSystemLen; 
      if (parentQidSystem != NULL)
         parentQidSystemLen = str_len(parentQidSystem);
      else
         parentQidSystemLen = 0; 
      if (parentQid != NULL)
        stmtStats_->setParentQid(parentQid, str_len(parentQid), parentQidSystem, 
                  parentQidSystemLen, cliGlobals_->myCpu(), (short)cliGlobals_->myNodeNumber());
      else
        stmtStats_->setParentQid(NULL, 0, NULL, 0, cliGlobals_->myCpu(), (short)cliGlobals_->myNodeNumber());
    }
    else
      stmtStats_ = NULL;
    statsGlobals->releaseStatsSemaphore(cliGlobals_->getSemId(), cliGlobals_->myPin(),
       savedPriority, savedStopMode);
  }
  else
  {
    if (stmtStats_ != NULL)
    {
      NADELETE(stmtStats_, StmtStats, stmtStats_->getHeap());
      stmtStats_ = NULL;
    }   
    // runtime stats not supported on NT platform or runtime stats
    // subsystem not up and running.
    // Allocate ExMasterStats without going thru StatsGlobals.
    stmtStats_ = StatsGlobals::addStmtStats(stmtHeap(),
					cliGlobals_->myPin(), 
					getUniqueStmtId(),
					getUniqueStmtIdLen(),
                                        source_str, source_length);
  }
}

// VO, Plan Versioning Support.
void Statement::issuePlanVersioningWarnings (ComDiagsArea & diagsArea)
{
  if (returnRecompWarn())
  {
    if (fetchErrorCode_ != VERSION_NO_ERROR)
    {
      // A plan versioning error was detected at fetch time
      diagsArea << DgSqlCode (fetchErrorCode_)
                << DgInt0 (fetchPlanVersion_)
                << DgString0 (fetchNode_)
                << DgInt1 (fetchSupportedVersion_);
    }

    if (mxcmpErrorCode_ != VERSION_NO_ERROR)
    {
      // A plan versioning error was detected at prepare time
      diagsArea << DgSqlCode (mxcmpErrorCode_)
                << DgInt0 (mxcmpStartedVersion_)
                << DgInt1 (COM_VERS_COMPILER_VERSION);
    }
  }

  // Unconditionally clear the saved warning codes, even though we
  // may not have reported them - we don't want them hanging around
  // if we recompile for some other reason.
  fetchErrorCode_ = VERSION_NO_ERROR;
  mxcmpErrorCode_ = VERSION_NO_ERROR;
}
const char *Statement::stmtState(State state) 
{
  switch (state)
  {
    case INITIAL_:       return "INITIAL";
    case OPEN_:          return "OPEN";
    case EOF_:           return "EOF";
    case CLOSE_:         return "CLOSE";
    case DEALLOCATED_:   return "DEALLOCATED";
    case FETCH_:         return "FETCH";
    case CLOSE_TABLES_:  return "CLOSE_TABLES";
    case PREPARE_:       return "PREPARE";
    case PROCESS_ENDED_: return "PROCESS_ENDED";
    case RELEASE_TRANS_: return "RELEASE_TRANS";
    case SUSPENDED_:     return "SUSPENDED";
    case STMT_EXECUTE_:  return "EXECUTE";
    case STMT_FIXUP_:    return "FIXUP";
    default:             return ComRtGetUnknownString((Int32) state);
  }
}

ExRsInfo *Statement::getResultSetInfo() const
{
  if (statementGlobals_)
    return statementGlobals_->getResultSetInfo();
  return NULL;
}

ExRsInfo *Statement::getOrCreateResultSetInfo()
{
  ex_assert(statementGlobals_, "No statement globals available");
  return statementGlobals_->getResultSetInfo(TRUE);
}

// For stored procedure result set proxy statements, return TRUE if
// the current statement source matches the newSource input string.
NABoolean Statement::rsProxyCompare(const char *newSource) const
{
  NABoolean result = FALSE;

  if (newSource != NULL && source_str != NULL &&
      charset_ == SQLCHARSETCODE_ISO88591 &&
      str_cmp_ne(source_str, newSource) == 0)
  {
    result = TRUE;
  }

  return result;
}

// For stored procedure result set proxy statements, see if a
// prepare of proxy syntax is required and if so, do the internal 
// prepare
RETCODE Statement::rsProxyPrepare(ExRsInfo &rsInfo,          // IN
                                  ULng32 rsIndex,     // IN
                                  ComDiagsArea &diagsArea)   // INOUT
{
  StmtDebug3("[BEGIN rsProxyPrepare] %p, rsIndex %u, stmt state %s",
             this, rsIndex, stmtState(getState()));

  RETCODE result = SUCCESS;

  // These variables will be populated below by the call to
  // getRsInfo()
  NABoolean preparedFlag = FALSE;
  Statement *proxyStmt = NULL;
  NABoolean openFlag = FALSE;
  NABoolean closedFlag = FALSE;

  // We have the ability to acquire proxy strings from the
  // environment. The mechanism is currently disabled. See comments in
  // the getProxySyntaxFromEnvironment() function (in this file) for
  // more info.
  const char *proxySyntax = NULL;

  if (proxySyntax)
  {
    StmtDebug0("  *** WILL USE PROXY SYNTAX FROM AN ENV VAR");
  }
  else
  {
    NABoolean found = rsInfo.getRsInfo(rsIndex, proxyStmt, proxySyntax,
                                       openFlag, closedFlag, preparedFlag);
  }

  StmtDebug2("  rsIndex %u, prepared flag %d", rsIndex, (Int32) preparedFlag);
  StmtDebug1("  proxySyntax [%s]", (proxySyntax ? proxySyntax : "(NULL)"));
  
  if (proxySyntax == NULL)
  {
    diagsArea << DgSqlCode(-EXE_UDR_RS_NOT_AVAILABLE)
              << DgInt0((Int32) rsIndex);
    result = ERROR;
  }
  
  if (result != ERROR)
  {
    if (!preparedFlag)
    {
      NABoolean okToReusePlan = FALSE;
      if (stmt_state != INITIAL_ && root_tdb != NULL)
      {
        // This means we currently have a plan. Next step is to decide
        // if it suitable for reuse.
        if (rsProxyCompare(proxySyntax))
          okToReusePlan = TRUE;
      }

      if (!okToReusePlan)
      {
        // $$$$ PROXY RECOMPILE: We can consider returning a new
        // warning condition when a proxy is prepared. This may help
        // CLI callers avoid doing describes on a proxy after every
        // CALL execution.
        result = prepare((char *) proxySyntax, diagsArea, NULL, 0L);
      }

      if (result != ERROR)
      {
        rsInfo.setPrepared(rsIndex);
      }
      else
      {
        // Add a condition to the diags area indicating it was an
        // internal operation that failed unexpectedly
        diagsArea << DgSqlCode(-EXE_UDR_RS_ALLOC_INTERNAL_ERROR);
      }
    }
  }
  
  StmtDebug3("[END rsProxyPrepare] %p, stmt state %s, retcode %s",
             this, stmtState(getState()), RetcodeToString(result));
  
  return result;
}

// Helper function to convert a char string to quoted char string.
// Also, single quote chars will be replaced with two single quote chars.
static
char* toQuotedString(char *src, Lng32 srcLen, NAHeap *heap)
{
  // Allocate a buffer to fix the resultant string.
  char *target = new (heap) char[2 * srcLen + 3];
  char *targetPtr = target;

  *targetPtr++ = '\'';  // beginning quote

  for (Lng32 pos = 0; pos < srcLen; pos++)
  {
    *targetPtr++ = src[pos];

    if (src[pos] == '\'')
      *targetPtr++ = '\'';
  }
  *targetPtr++ = '\'';  // ending quote
  *targetPtr = '\0';  // NULL terminator

  return target;
}

// getProxySyntax generates the text of a SELECT statement that we
// call "proxy syntax". The two uses of these SELECTs are stored
// procedure result sets and parallel extract consumer queries.
//
// The result set proxy syntax is of the form:
// 
//     SELECT * FROM TABLE ( SP_RESULT_SET ( <col-type-spec>,
//                                           <col-type-spec>, ... ) )
//
// where <col-type-spec> is in the format
//  <cat>.<sch>.<table>.<colname> datatype [HEADING '<heading>'] [NOT NULL]
//
// The extract consumer syntax is of the form:
// 
//     SELECT * FROM TABLE ( EXTRACT_SOURCE ( 'ESP', 'esp-process-handle',
//                                            'security-key', 
//                                            <col-type-spec>,
//                                            <col-type-spec>, ... ) )
//
// The getProxySyntax function takes a prefix and suffix as input and
// generates the string:
//
//    <prefix> <col-type-spec>, ... <suffix>
//
//  In addition to generating proxy syntax, this method also computes
//  the size of the proxy syntax string.
//
//  This method first assumes that 'proxy' with 'maxlength' size
//  is sufficient for holding proxy syntax. If it realizes that
//  'proxy' does not have enough space then the copying stops but the
//  function proceeds to compute the required size
//
//  The size of proxy syntax will be returned in spaceRequired.
//
RETCODE Statement::getProxySyntax(char *proxy, Lng32 maxlength,
                                  Lng32 *spaceRequired,
                                  const char *prefix, const char *suffix)
{
  // In the code below, once we set hasEnoughSpace to FALSE,
  // it will never be changed to TRUE again.
  NABoolean hasEnoughSpace = TRUE;

  // If proxy is NULL, we only compute the size of proxy syntax
  // if spaceRequired is provided.
  if (!proxy) hasEnoughSpace = FALSE;

  if (!proxy && ! spaceRequired)
    return SUCCESS;

  InputOutputExpr *expr = getRootTdb()->outputExpr();
  if (expr == NULL)
  {
    if (spaceRequired) *spaceRequired = 0;
    return SUCCESS;
  }

  SQLMODULE_ID mod_id;
  SQLDESC_ID desc_id;

  mod_id.module_name = 0;
  desc_id.name_mode = desc_handle;
  desc_id.identifier = 0;
  desc_id.handle = 0;
  desc_id.module = &mod_id;

  Descriptor *outdesc = new (&heap_) Descriptor(&desc_id,
                                                expr->getNumEntries(),
                                                context_);
  outdesc->dealloc();
  outdesc->alloc(expr->getNumEntries());

  // Describe the OUTPUT expression
  UInt32 flags = 0;
  expr->setIsODBC(flags, root_tdb->odbcQuery());
  expr->setInternalFormatIO(flags, 
			    context_->getSessionDefaults()->
			    getInternalFormatIO());
  expr->setIsDBTR(flags,
		  context_->getSessionDefaults()->getDbtrProcess());
  expr->describeOutput(outdesc, flags);

  // Now generate proxy syntax string
  char *proxyPtr = proxy;
  Lng32 spaceLeft = maxlength;
  Lng32 spaceNeeded = 0;

  if (prefix == NULL)
    prefix = "";
  if (suffix == NULL)
    suffix = "";

  Lng32 prefixLen = str_len(prefix);
  Lng32 suffixLen = str_len(suffix);

  if (spaceLeft < prefixLen) hasEnoughSpace = FALSE;
  spaceNeeded += prefixLen;
  if (hasEnoughSpace)
  {
    str_cpy_all(proxyPtr, prefix, prefixLen);
    proxyPtr += prefixLen;
    spaceLeft -= prefixLen;
  }

  for (Int32 entry = 1; entry <= expr->getNumEntries(); entry++)
  {
    char *name = NULL;
    Lng32 nameLen;

    // get CATALOG attribute
    outdesc->getDescItemPtr(entry, SQLDESC_CATALOG_NAME, &name, &nameLen);
    if (name != NULL)
    {
      char *catName = ToAnsiIdentifier2(name, nameLen, &heap_);
      Lng32 catLen = str_len(catName);

      // Write CATALOG attribute
      if (spaceLeft < catLen + 1) hasEnoughSpace = FALSE;
      spaceNeeded += (catLen + 1);
      if (hasEnoughSpace)
      {
        str_cpy_all(proxyPtr, catName, catLen);
        str_cpy_all(proxyPtr+catLen, ".", 1);
        proxyPtr += (catLen + 1);
        spaceLeft -= (catLen + 1);
      }
      heap_.deallocateMemory(catName);
    }

    // get SCHEMA attribute
    outdesc->getDescItemPtr(entry, SQLDESC_SCHEMA_NAME, &name, &nameLen);
    if (name != NULL)
    {
      char *schName = ToAnsiIdentifier2(name, nameLen, &heap_);
      Lng32 schLen = str_len(schName);

      // Write SCHEMA attribute
      if (spaceLeft < schLen + 1) hasEnoughSpace = FALSE;
      spaceNeeded += (schLen + 1);
      if (hasEnoughSpace)
      {
        str_cpy_all(proxyPtr, schName, schLen);
        str_cpy_all(proxyPtr+schLen, ".", 1);
        proxyPtr += (schLen + 1);
        spaceLeft -= (schLen + 1);
      }
      heap_.deallocateMemory(schName);
    }

    // get TABLE attribute
    outdesc->getDescItemPtr(entry, SQLDESC_TABLE_NAME, &name, &nameLen);
    if (name != NULL)
    {
      char *tabName = ToAnsiIdentifier2(name, nameLen, &heap_);
      Lng32 tabLen = str_len(tabName);

      // Write TABLE attribute
      if (spaceLeft < tabLen + 1) hasEnoughSpace = FALSE;
      spaceNeeded += (tabLen + 1);
      if (hasEnoughSpace)
      {
        str_cpy_all(proxyPtr, tabName, tabLen);
        str_cpy_all(proxyPtr+tabLen, ".", 1);
        proxyPtr += (tabLen + 1);
        spaceLeft -= (tabLen + 1);
      }

      heap_.deallocateMemory(tabName);
    }

    // get COLUMN Name attribute
    outdesc->getDescItemPtr(entry, SQLDESC_NAME, &name, &nameLen);
    if (name != NULL)
    {
      char *colName = ToAnsiIdentifier2(name, nameLen, &heap_);
      Lng32 colLen = str_len(colName);

      // Write COLUMN attribute
      if (spaceLeft < colLen + 1) hasEnoughSpace = FALSE;
      spaceNeeded += (colLen + 1);
      if (hasEnoughSpace)
      {
        str_cpy_all(proxyPtr, colName, colLen);
        str_cpy_all(proxyPtr+colLen, " ", 1);
        proxyPtr += (colLen + 1);
        spaceLeft -= (colLen + 1);
      }

      heap_.deallocateMemory(colName);
    }

    // get Dataype TEXT FORMAT attribute
    outdesc->getDescItemPtr(entry, SQLDESC_TEXT_FORMAT, &name, &nameLen);
    if (name != NULL)
    {
      // Write Datatype attribute
      if (spaceLeft < nameLen + 1) hasEnoughSpace = FALSE;
      spaceNeeded += nameLen + 1;
      if (hasEnoughSpace)
      {
        str_cpy_all(proxyPtr, name, nameLen);
        str_cpy_all(proxyPtr + nameLen, " ", 1);
        proxyPtr += (nameLen + 1);
        spaceLeft -= (nameLen + 1);
      }
    }

    // get HEADING attribute
    outdesc->getDescItemPtr(entry, SQLDESC_HEADING, &name, &nameLen);
    if ((name != NULL) && (str_len(name) != 0))
    {
      // quotedHeading will be quoted string format i.e., the string will be
      // in single quotes and also any quotes in the string are doubled
      char *quotedHeading = toQuotedString(name, nameLen, &heap_);
      Lng32 quotedHeadLen = str_len(quotedHeading);

      // Write HEADING attribute
      if (spaceLeft < quotedHeadLen + 18) hasEnoughSpace = FALSE;
      spaceNeeded += (quotedHeadLen + 18);
      if (hasEnoughSpace)
      {
        str_cpy_all(proxyPtr, "HEADING _ISO88591", 17);
        str_cpy_all(proxyPtr+17, quotedHeading, quotedHeadLen);
        str_cpy_all(proxyPtr+17+quotedHeadLen, " ", 1);
        proxyPtr += (quotedHeadLen + 18);
        spaceLeft -= (quotedHeadLen + 18);
      }

      heap_.deallocateMemory(quotedHeading);
    }

    // Write "NOT NULL" attribute
    Lng32 nullable;
    outdesc->getDescItem(entry, SQLDESC_NULLABLE, &nullable, NULL, 0, NULL, 0);
    if (nullable == 0)
    {
      if (spaceLeft < 8) hasEnoughSpace = FALSE;
      spaceNeeded += 8;
      if (hasEnoughSpace)
      {
        str_cpy_all(proxyPtr, "NOT NULL", 8);
	proxyPtr += 8;
	spaceLeft -= 8;
      }
    }

    if (entry == expr->getNumEntries())
    {
      // This is last entry, so append the suffix
      if (spaceLeft < suffixLen)
        hasEnoughSpace = FALSE;
      spaceNeeded += suffixLen;
      if (hasEnoughSpace)
      {
        str_cpy_all(proxyPtr, suffix, suffixLen);
	proxyPtr += suffixLen;
	spaceLeft -= suffixLen;
      }
    }
    else
    {
      // Add ','
      if (spaceLeft < 2) hasEnoughSpace = FALSE;
      spaceNeeded += 2;
      if (hasEnoughSpace)
      {
        str_cpy_all(proxyPtr, ", ", 2);
        proxyPtr += 2;
        spaceLeft -= 2;
      }
    }
  }

  // Set the required space size if asked.
  if (spaceRequired) *spaceRequired = spaceNeeded;

  // Clean up
  outdesc->dealloc();
  NADELETE(outdesc, Descriptor, &heap_);

  return SUCCESS;
}

RETCODE Statement::getRSProxySyntax(char *proxy, Lng32 maxlength,
                                    Lng32 *spaceRequired)
{
  return getProxySyntax(proxy, maxlength, spaceRequired,
                        "SELECT * FROM TABLE ( SP_RESULT_SET ( ", " ) )");
}

RETCODE Statement::getExtractConsumerSyntax(char *proxy, Lng32 maxlength,
                                            Lng32 *spaceRequired)
{
  const char *prefix =
    "SELECT * FROM TABLE(EXTRACT_SOURCE('ESP', '%s', '%s', ";
  const char *suffix = ") )";
  return getProxySyntax(proxy, maxlength, spaceRequired, prefix, suffix);
}

#ifdef NA_DEBUG_C_RUNTIME
void Statement::StmtPrintf(const char *formatString, ...) const
{
  if (!stmtDebug_)
    return;

  FILE *f = stdout;
  va_list args;
  va_start(args, formatString);
  fprintf(f, "[STMT] ");
  vfprintf(f, formatString, args);
  fprintf(f, "\n");
  fflush(f);
}
#endif
/******************************************************************************
    Method: Statement::doesUninitializedMvExist

    Description:       
        Any time the statement is executed, check the list to see if
        any mvs are still uninitialized.  If they are initialized, remove
        them from the list.

        If one uninitialized mv is found, return immediately with error
        since this statement cannot be executed.

    Parameters:
        char **pMvName (OUTPUT)
            - this parameter will be set to the name of the uninitialized
              mv if it is found.

        ComDiagsArea &diagsArea                   
            - diags area for error messages              

    Return:
        - return TRUE if an uninitialized mv is found          
                         
******************************************************************************/
NABoolean 
Statement::doesUninitializedMvExist( char **pMvName,
                                     ComDiagsArea &diagsArea )
{  
   NABoolean bUninitializedMvExists = FALSE; // assume none exist   
  
   UninitializedMvName *uninitializedMvList = NULL;
   const short uninitializedMvCount = root_tdb->uninitializedMvCount();

   uninitializedMvList = root_tdb->uninitializedMvList();

   // if the list is NULL, the return value will show that none exist.
   if( uninitializedMvList )
   {
       // for each name in the uninitializedMvList
       for( short i = 0; i < uninitializedMvCount; i++ )
       {           
           UninitializedMvName currentMv = uninitializedMvList[ i ];

           if( isUninitializedMv( currentMv.getPhysicalName(),
                                  currentMv.getAnsiName(), 
                                  diagsArea ) )
           {           
               // point output to name in root_tdb
               (*pMvName) = uninitializedMvList[ i ].getAnsiName(); 
               bUninitializedMvExists = TRUE;
               break; // exit loop since at least one is found
           } 
           
       }    
   }   
   return bUninitializedMvExists;
}
/******************************************************************************
    Method: Statement::isUninitializedMv

    Description:
        Determine whether a table in the statement is an uninitialized mv.  
        This information is gathered from the ExRcb object.

    Parameters:
        char * physicalName
            - table location.  used to get rfork info
            
        const char *ansiName             
            - table ansi name.  used for error reporting

        ComDiagsArea &diagsArea                   
            - diags area for error messages
              
    Return:
        - return TRUE if this mv exists but is uninitialized.             
                                
******************************************************************************/
NABoolean 
Statement::isUninitializedMv( const char * physicalName,
                              const char * ansiName,
                              ComDiagsArea &diagsArea )
{
    return FALSE;
}

void Statement::buildConsumerQueryTemplate()
{
  if (extractConsumerQueryTemplate_ == NULL)
  {
    Lng32 len = 1000;
    NABoolean done = FALSE;
    Lng32 spaceRequired = 0;
    while (!done)
    {


      // add one for NULL terminator
      extractConsumerQueryTemplate_ = (char *)heap_.allocateMemory(len + 1);

      // Now we call a function to generate the consumer syntax string.
      // The function returns a string WITHOUT a null terminator. The
      // number of bytes required for the full string (not including
      // the null terminator) is returned in the output parameter 
      // spaceRequired.
      RETCODE rc = getExtractConsumerSyntax(extractConsumerQueryTemplate_,
                                            len,
                                            &spaceRequired);
      ex_assert(rc == SUCCESS,
                "Unexpected error from getExtractConsumerSyntax");

      if (spaceRequired > len)
      {
        len = spaceRequired;
        heap_.deallocateMemory(extractConsumerQueryTemplate_);
        extractConsumerQueryTemplate_ = NULL;
      }
      else
      {
        extractConsumerQueryTemplate_[spaceRequired] = 0;
        done = TRUE;
      }
    }
  }
}

Lng32 Statement::getConsumerQueryLen(ULng32 index)
{
  // First build the consumer query template
  buildConsumerQueryTemplate();
  
  // Minimum length will include a null terminator so initialize the
  // result to 1
  Lng32 result = 1;

  const char *tmpl = extractConsumerQueryTemplate_;
  const char *phandle = statementGlobals_->getExtractEspPhandleText(index);
  const char *key = statementGlobals_->getExtractSecurityKey();

  if (phandle == NULL)
    phandle = "";
  if (key == NULL)
    key = "";

  Lng32 reqdLen = str_len(tmpl)
    + str_len(phandle)
    + str_len(key)
    - 4  // to account for the "%s" format specifiers
    + 1; // to account for the null terminator
  result = reqdLen;

  return result;
}

void Statement::getConsumerQuery(ULng32 index, char *buf, Lng32 buflen)
{
  if (buflen < 1)
    return;

  // First build the consumer query template
  buildConsumerQueryTemplate();

  buf[0] = 0;

  const char *tmpl = extractConsumerQueryTemplate_;
  const char *phandle = statementGlobals_->getExtractEspPhandleText(index);
  const char *key = statementGlobals_->getExtractSecurityKey();

  if (phandle == NULL)
    phandle = "";
  if (key == NULL)
    key = "";

  Lng32 reqdLen = str_len(tmpl)
    + str_len(phandle)
    + str_len(key)
    - 4  // to account for the "%s" format specifiers
    + 1; // to account for the null terminator
  ex_assert(buflen >= reqdLen, "Consumer query buffer too small");
  str_sprintf(buf, tmpl, phandle, key);
}

Lng32 Statement::getConsumerCpu(ULng32 index)
{
  Lng32 result = -1;
  short cpu = statementGlobals_->getExtractEspCpu(index);
  Lng32 nodeNumber = statementGlobals_->getExtractEspNodeNumber(index);
  if (cpu >= 0 && nodeNumber >= 0)
  {
    result = (nodeNumber << 8);
    result += (cpu & 0x00ff);
  }
  return result;
}

         
Lng32 Statement::setParentQid(char *queryId)
{
  Lng32 len = 0;
  if (queryId != NULL)
  {
    len = str_len(queryId);
    if (len < ComSqlId::MIN_QUERY_ID_LEN)
      return -CLI_INVALID_ATTR_VALUE;
    if (len < 4 || (len > 4 && str_cmp((const char *)queryId, COM_SESSION_ID_PREFIX, 4) != 0))
      return -CLI_INVALID_ATTR_VALUE;
  }
  if (parentQid_)
    NADELETEBASIC(parentQid_, &heap_);
  if (queryId != NULL)
  {
    parentQid_ = new(&heap_) char[len+1];
    str_cpy_all(parentQid_, queryId, len);
    parentQid_[len] = '\0';
  }
  else
  {
    parentQid_ = NULL;
    len = 0;
  }
  if (stmtStats_ && stmtStats_->getMasterStats() != NULL)
    stmtStats_->getMasterStats()->setParentQid(parentQid_, len);
  return 0;
}

void Statement::setParentQidSystem(char *parentQidSystem)
{
  Lng32 len = 0;
  if (parentQidSystem != NULL)
  {
    len = str_len(parentQidSystem);
    str_cpy_all(parentQidSystem_, parentQidSystem, len);
    parentQidSystem_[len] = '\0';
  }
  else
    parentQidSystem_[0] = '\0'; 
  if (stmtStats_ && stmtStats_->getMasterStats() != NULL)
    stmtStats_->getMasterStats()->setParentQidSystem(parentQidSystem_, len);
}

char *Statement::getParentQid()
{
  char *parentQid;
  if (parentQid_ != NULL)
    parentQid = parentQid_;
  else
  {
    if (context_->getSessionDefaults())
      parentQid = context_->getSessionDefaults()->getParentQid();
    else
      parentQid = NULL;
  }
  return parentQid;
}

char *Statement::getParentQidSystem()
{
  char *parentQidSystem;
  if (parentQidSystem_[0] != '\0')
    parentQidSystem = parentQidSystem_;
  else
  {
    if (context_->getSessionDefaults())
      parentQidSystem = context_->getSessionDefaults()->getParentQidSystem();
    else
      parentQidSystem = NULL;
  }
  return parentQidSystem;
}

Int64 Statement::getExeStartTime()
{
  ExStatisticsArea *statsArea;
  ExMasterStats *masterStats;
  statsArea = getStatsArea();
  
  if (statsArea != NULL && (masterStats = statsArea->getMasterStats()) != NULL)
      return masterStats->getExeStartTime();
  else
      return -1;
}

void Statement::setExeStartTime(Int64 exeStartTime)
{
   if (exeStartTime != -1)
      aqrInitialExeStartTime_ = exeStartTime;
} 

Lng32 Statement::initStrTarget(SQLDESC_ID * sql_source,
                               ContextCli &currContext,
                               ComDiagsArea &diags,
                               StrTarget &strTarget)
{
  if (! sql_source)
    return 0;

  if (sql_source->name_mode == string_data)
    {
      CharInfo::CharSet externalCharset =
              CharInfo::getCharSetEnum(sql_source->charset);
      CharInfo::CharSet internalCharset = CharInfo::UTF8;
      ComDiagsArea *diagsPtr = &diags;


      strTarget.init((char*)sql_source->identifier, 
		     sql_source->identifier_len, 
                     CharInfo::getFSTypeFixedChar(externalCharset),
                     externalCharset,
                     internalCharset,
                     currContext.exCollHeap(),
                     diagsPtr);
    }
  else
    {
      Descriptor * desc = currContext.getDescriptor(sql_source);
      
      /* descriptor must exist */
      if (!desc)
	{
	  diags << DgSqlCode(-CLI_DESC_NOT_EXISTS);
	  return -CLI_DESC_NOT_EXISTS;
	}
      
      strTarget.init(desc, 1);
    }
  
  if (!strTarget.getStr())
    {
      diags << DgSqlCode(-CLI_STMT_NOT_PREPARED);
      return -CLI_STMT_NOT_PREPARED;
    }
  copyInSourceStr(strTarget.getStr(), (octetLen(strTarget.getStr(), strTarget.getIntCharSet())), strTarget.getIntCharSet());
  return 0;
}

NABoolean Statement::updateChildQid()
{
  NABoolean parentIsCanceled = FALSE;
  StatsGlobals *statsGlobals = cliGlobals_->getStatsGlobals();
  
  if (statsGlobals != NULL && uniqueStmtId_ != NULL && parentQid_ != NULL &&
      getStatsArea() != NULL && stmtStats_ != NULL && stmtStats_->updateChildQid())
  {
    short savedPriority, savedStopMode;
    short error = statsGlobals->getStatsSemaphore(cliGlobals_->getSemId(),
          cliGlobals_->myPin(), savedPriority, savedStopMode, 
          FALSE /*shouldTimeout*/);
    ex_assert(error == 0, "getStatsSemaphore() returned an error");
    StmtStats *ss = statsGlobals->getMasterStmtStats(parentQid_, str_len(parentQid_), RtsQueryId::ANY_QUERY_);
    if (ss != NULL)
    {
      ExMasterStats *parentMasterStats = ss->getMasterStats();
      if (parentMasterStats)
      {
        parentMasterStats->setChildQid(uniqueStmtId_, uniqueStmtIdLen_);
        if (parentMasterStats->getCanceledTime() != -1)
          parentIsCanceled = TRUE;
      }
    }
    statsGlobals->releaseStatsSemaphore(cliGlobals_->getSemId(),cliGlobals_->myPin(),
                    savedPriority, savedStopMode);
  }
  return parentIsCanceled;
}
/*
// make the context's stats point to this statement's stats. 
      // Context points to the most recent executed statement's
      // stat area so later a getStatistics CLI call without a
      // statement ID can return it.
*/
void Statement::updateStatsAreaInContext()
{
  ExStatisticsArea *statsArea;
  ComTdb::CollectStatsType statsType;
  ExMasterStats *masterStats;
  statsArea = getStatsArea();
  if (stmtStats_ != NULL && 
      statsArea && 
      ((statsType = statsArea->getCollectStatsType()) != (Int32)SQLCLIDEV_NO_STATS) && 
      stmt_type == Statement::DYNAMIC_STMT)
  {
    if (statsType == (Int32)SQLCLIDEV_ALL_STATS)
    {
      if ((masterStats = statsArea->getMasterStats()) != NULL)
      {
        NADELETE(masterStats, ExMasterStats, masterStats->getHeap());
        statsArea->setMasterStats(NULL);
      }
    }
    if (statsArea->getMasterStats() == NULL)
	{
	  ExMasterStats * ems = new(context_->exHeap())
	    ExMasterStats(context_->exHeap());
	  if (stmtStats_->getMasterStats())
	    ems->copyContents(stmtStats_->getMasterStats());
          ems->setCollectStatsType(getRootTdb()->getCollectStatsType());
	  statsArea->setMasterStats(ems);
	}
    context_->setStatsArea(getStatsArea(), FALSE, (cliGlobals_->getStatsGlobals() != NULL));
  }
}

Lng32 Statement::setChildQueryInfo(ComDiagsArea *diagsArea, char * uniqueQueryId,
        Lng32 uniqueQueryIdLen,
        SQL_QUERY_COST_INFO *query_cost_info,
        SQL_QUERY_COMPILER_STATS_INFO *comp_stats_info)
{
  NAHeap *heap = stmtHeap();
  
  if (uniqueQueryId == NULL || query_cost_info == NULL || comp_stats_info == NULL)
  {
    if (diagsArea != NULL)
     *diagsArea << DgSqlCode(-CLI_INVALID_ATTR_VALUE);
    return ERROR;
  }
  if (childQueryId_ != NULL)
  {
    NADELETEBASIC(childQueryId_, heap);
  }
  childQueryId_ = new (heap) char[uniqueQueryIdLen+1];
  str_cpy_all(childQueryId_, uniqueQueryId, uniqueQueryIdLen);
  childQueryId_[uniqueQueryIdLen] = '\0';
  childQueryIdLen_ = uniqueQueryIdLen;
  if (childQueryCostInfo_ != NULL)
  {
    NADELETEBASIC(childQueryCostInfo_, heap);
  }
  childQueryCostInfo_ = new (heap) SQL_QUERY_COST_INFO;
  str_cpy_all((char *)childQueryCostInfo_, (const char *)query_cost_info, sizeof(SQL_QUERY_COST_INFO));
  if (childQueryCompStatsInfo_ != NULL)
  {
    NADELETEBASIC(childQueryCompStatsInfo_, heap);
  }
  childQueryCompStatsInfo_ = new (heap) SQL_QUERY_COMPILER_STATS_INFO;
  str_cpy_all((char *)childQueryCompStatsInfo_, (const char *)comp_stats_info, sizeof(SQL_QUERY_COMPILER_STATS_INFO));
  return SUCCESS;
}

Lng32 Statement::getChildQueryInfo(ComDiagsArea &diagsArea, char * uniqueQueryId,
     Lng32 uniqueQueryIdMaxLen,
     Lng32 * uniqueQueryIdLen,
     SQL_QUERY_COST_INFO *query_cost_info,
     SQL_QUERY_COMPILER_STATS_INFO *comp_stats_info)
{
  if (childQueryId_ == NULL)
  {
     diagsArea << DgSqlCode(-EXE_RTS_QID_NOT_FOUND);
     return ERROR;
  }
  if (childQueryIdLen_ > uniqueQueryIdMaxLen || uniqueQueryId == NULL ||
      uniqueQueryIdLen == NULL)
  {
     diagsArea << DgSqlCode(-CLI_BUFFER_TOO_SMALL);
     return ERROR;
  }
  str_cpy_all(uniqueQueryId, (const char *)childQueryId_, childQueryIdLen_);
  *uniqueQueryIdLen = childQueryIdLen_;
  if (childQueryCostInfo_ != NULL && query_cost_info != NULL)
    str_cpy_all((char *)query_cost_info, (const char *)childQueryCostInfo_, 
          sizeof(SQL_QUERY_COST_INFO));
  if (childQueryCompStatsInfo_ != NULL && comp_stats_info != NULL)
    str_cpy_all((char *)childQueryCompStatsInfo_, (const char *)comp_stats_info,
            sizeof(SQL_QUERY_COMPILER_STATS_INFO));
  return SUCCESS;
}


Need to allow room for a trailing null. You'll have to declare one more byte here than you pass as the second parameter to stringToHex. Alternatively, change the stringToHex function to allow for room (for example, change the statement "outLen = (outLen / 2)" to "outLen = (outLen / 2) - 1"