/*


    ========== licence begin GPL
    Copyright (C) 2002-2003 SAP AG

    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License
    as published by the Free Software Foundation; either version 2
    of the License, or (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
    ========== licence end


*/
package com.sap.dbtech.jdbc;

import java.sql.SQLException;
import java.sql.Array;
import java.sql.Blob;
import java.sql.Clob;
import java.sql.Ref;
import java.sql.ResultSetMetaData;
import java.sql.Types;
import java.sql.ResultSet;
import java.util.*;
import java.math.BigDecimal;
import java.net.URL;
import java.io.InputStream;
import java.io.Reader;

import com.sap.dbtech.jdbc.exceptions.*;
import com.sap.dbtech.jdbc.packet.*;
import com.sap.dbtech.jdbc.translators.*;
import com.sap.dbtech.jdbc.translators.AbstractProcedurePutval;
import com.sap.dbtech.util.*;
import com.sap.dbtech.vsp00.*;
import com.sap.dbtech.vsp001.*;

/**
 *
 */
public class CallableStatementSapDB
    extends StatementSapDB
    implements java.sql.CallableStatement, SQLParamController
{
        private Vector inputOMSStreams;
        private Vector outputOMSStreams;
        private Vector inputProcedureLongs;
        
        final static int maxParseAgainCnt = 10;
    Parseinfo                   parseinfo;
    boolean                     lastWasNull;
    StructuredMem               replyMem;
    protected Object []         inputArgs;
    Vector                      inputLongs;
    java.util.Vector            batchRows;
    short []                    outPutTypes;
    byte []                     outPutScale;
    FetchInfo                   fetchInfo;
    java.util.AbstractMap       columnMap; /*points to colmapping of Parseinfo for faster access*/
    private final String initialParamValue = "initParam";

    /**
     *
     * @param connection com.sap.dbtech.jdbc.ConnectionSapDBTech
     * @param sql java.lang.String
     * @exception java.sql.SQLException The exception description.
     */
    CallableStatementSapDB(
        ConnectionSapDB connection,
        String sql)
    throws SQLException
    {
        super(connection,
             ResultSet.TYPE_FORWARD_ONLY,
             defaultConcurrency_C,
             connection.getHoldability());

        this.constructor(sql);
    }
    /**
     *
     * @param connection com.sap.dbtech.jdbc.ConnectionSapDBTech
     * @param sql java.lang.String
     * @exception java.sql.SQLException The exception description.
     */
    CallableStatementSapDB(
        ConnectionSapDB connection,
        String sql,
        int resultSetType,
        int resultSetConcurrency,
        int resultSetHoldability)
    throws SQLException
    {
        super (connection, resultSetType, resultSetConcurrency,resultSetHoldability);
        this.constructor(sql);
    }
    /**
     * JDBC 2.0
     *
     * Adds a set of parameters to the batch.
     *
     * @exception SQLException if a database access error occurs
     * @see Statement#addBatch
     */
    public void addBatch()
    throws SQLException
    {
        if (this.batchItems == null) {
            this.batchItems = new java.util.Vector ();
        }
        this.batchItems.addElement(this.inputArgs);
        Object [] nextRow = new Object [this.parseinfo.paramInfos.length];
        DBTechTranslator paraminfos[] = this.parseinfo.paramInfos;
        int paraminfos_length = paraminfos.length;
        for (int i = 0; i < paraminfos_length; ++i) {
            nextRow [i] = paraminfos[i].cloneObjectForBatch(this.inputArgs[i]);
        }
        this.inputArgs = nextRow;
    }
    /**
     * JDBC 2.0
     *
     * Adds a SQL command to the current batch of commmands for the statement.
     * This method is optional.
     *
     * @throws SQLException always (not allowed for PreparedStatement).
     *
     */
    public void addBatch(String sql)
                                throws SQLException
    {
        throw new JDBCDriverException (MessageTranslator.translate
                                                                                                                                                         (MessageKey.ERROR_PREPAREDSTATEMENT_ADDBATCH),
                                                                                                                                                         this);
                }

    /**
     *
     * @return int
     */
    private int calculateInputRecord ()
    {
        int result = 0;
        DBTechTranslator currentInfo;
        int currentFieldLen;

        for (int i = 0; i < this.parseinfo.paramInfos.length; ++i) {
            currentInfo = this.parseinfo.paramInfos[i];
            if (currentInfo.isInput()) {
                currentFieldLen = currentInfo.getPhysicalLength();
                if (this.parseinfo.varDataInput) {
                    if (currentFieldLen < 250) {
                        result += 1;
                    } else {
                        result += 3; 
                    }
                } else {
                    result += 1;
                }
                result += currentFieldLen;
            }
        }
        return result;
    }

    /**
     *
     */
    public void clearParameters ()
    throws SQLException
    {
        for (int i = 0; i < this.inputArgs.length; ++i) {
            this.inputArgs [i] = initialParamValue;
        }
    }
    /**
     *
     * @param sql java.lang.String
     * @exception java.sql.SQLException The exception description.
     */
    private void constructor (
        String sql)
    throws SQLException
    {
        this.parseinfo = this.doParse (sql, false);
    }

    /**
     * Parses the SQL command, or looks the parsed command up in the
     * cache.
     * @param sql The SQL to parse.
     * @param parseAgain if <code>true</code>, the data of the
     *   existing <code>Parseinfo</code> structure shall be overwritten.
     * @return the <code>Parseinfo</code> produced.
     * @exception java.sql.SQLException The exception description.
     */
    private Parseinfo doParse (String sql,
                               boolean parseAgain)
        throws SQLException
    {
        if (sql == null) {
            throw new SQLExceptionSapDB(MessageTranslator.translate
                                        (MessageKey.ERROR_SQLSTATEMENT_NULL),
                                        "42000");
        }

        ReplyPacket replyPacket;
        PartEnumeration enume;
        Parseinfo result = null;
        ParseinfoCache cache = this.connection.parseCache;
        String[] columnNames = null;

        if (sql == null)
          throw new SQLExceptionSapDB("SQL statement is null","42000");
        this.fetchInfo = null;

        if (parseAgain) {
            result = this.parseinfo;
            result.setMassParseid(null);
        }
        else if (cache != null) {
            result = cache.findParseinfo (sql);
        }
        if ((result == null) || parseAgain) {
            /*
             * exceute SQL
             */
            // boolean backupWithInfo=setWithInfo;
            // !!! withinfo flag is not set as it may cause a crash !!!
            try {
                setWithInfo=true;
                replyPacket = this.sendSQL (sql, this.resultSetType, this.resultSetConcurrency, parseAgain);
            } catch(com.sap.dbtech.jdbc.exceptions.TimeoutException exc){
                if (this.statementType == Statement_UpdatableResultSet){
                    this.connection.close();
                    throw exc;
                }
                replyPacket = this.sendSQL (sql, this.resultSetType, this.resultSetConcurrency, parseAgain);
            }
            //             finally {
            //                 setWithInfo=backupWithInfo;
            //             }
            /*
             * parse result
             */
            if (!parseAgain) {
                result = new Parseinfo (this.connection, sql, replyPacket.functionCode ());
            }
          
            
            enume = replyPacket.partEnumeration ();
            DBTechTranslator shortInfos[] = null;
            while (enume.hasMoreElements ()) {
                enume.nextElement ();
                switch (enume.partKind ()) {
                case PartKind.Parsid_C:
                    int parseidPos = replyPacket.getPartDataPos ();
                    result.setParseIdAndSession(replyPacket.getBytes (parseidPos, 12),
                                                replyPacket.getInt4 (parseidPos));
                    break;
                case PartKind.Shortinfo_C:
                    shortInfos=replyPacket.parseShortFields(this.connection.isSpaceoptionSet,
                                                            result.isDBProc, 
                                                            result.procParamInfos, false);
                    break;
                case PartKind.Vardata_Shortinfo_C:
                    result.varDataInput = true;
                    shortInfos=replyPacket.parseShortFields(this.connection.isSpaceoptionSet,
                                                            result.isDBProc, 
                                                            result.procParamInfos, true);
                    break;
                case PartKind.Resulttablename_C:
                    result.setSelect(true);
                    int cursorLength = replyPacket.partLength ();
                    if (cursorLength > 0) {
                        this.cursorName = replyPacket.getString (replyPacket.getPartDataPos (), cursorLength);
                    }
                    break;
                case PartKind.Tablename_C:
                    result.setUpdateTableName(replyPacket.getString (replyPacket.getPartDataPos (), replyPacket.partLength ()));
                    break;
                case PartKind.Columnnames_C:
                    columnNames = replyPacket.parseColumnNames ();
                    break;
                default:
//                    this.addWarning(new SQLWarning
//                                    (MessageTranslator.translate
//                                     (MessageKey.WARNING_PART_NOTHANDLED,
//                                      PartKind.names[enume.partKind()]))
//                                    );
                    break;
                }
            }
            result.setShortInfosAndColumnNames(shortInfos, columnNames);
            if ((cache != null) && !parseAgain) {
                cache.addParseinfo (result);
            }
        }
        this.inputArgs = new Object [result.paramInfos.length];
        this.clearParameters();
        return result;
    }
    /**
     * execute method comment.
     */
    public boolean execute()
    throws java.sql.SQLException
    {
        this.assertOpen ();
        return this.execute (maxParseAgainCnt);
    }
    /**
     *
     */
    private void
    reparse ()
    throws java.sql.SQLException
    {
        Object [] tmpArgs = this.inputArgs;
        this.doParse (this.parseinfo.sqlCmd, true);
        this.inputArgs = tmpArgs;
    }
    /**
     *
     */
     protected String getUpdTablename(String sqlCmd) {
       return this.parseinfo.updTableName;
     }

    /**
     * execute method comment.
     */
    public boolean execute(int afterParseAgain)
        throws SQLException
    {
        if (this.connection == null) {
            throw new InternalJDBCError(MessageTranslator.translate(MessageKey.ERROR_INTERNAL_CONNECTIONNULL));
        }
        RequestPacket requestPacket;
        ReplyPacket replyPacket;
        boolean isQuery;
        DataPart dataPart;

        // if this is one of the statements that is executed
        // during parse instead of execution, execute it
        // by doing a reparse
        if(this.parseinfo.isAlreadyExecuted()) {
            this.replyMem = null;
            this.closeResultSet (true);
            if (this.connection == null) {
                throw new NullPointerException ();
            }
            this.reparse();
            this.rowsAffected=0;
            return false;
        }

        if (! this.parseinfo.isValid ()) {
            this.reparse ();
        }

        try {
            this.canceled = false;
            this.closeResultSet(true);
            // check if a reparse is needed.
            if (!this.parseinfo.isValid ()) {
                this.reparse ();
            }
            this.replyMem = null;
                        this.outputOMSStreams = null;

            requestPacket = this.connection.getRequestPacket (this.packetEncodingUnicode);
            requestPacket.initExecute (this.parseinfo.getParseId(),
                                       this.connection.autocommit,
                                       this.resultSetType);
            if (this.parseinfo.isSelect) {
                requestPacket.addCursorPart (this.cursorName);
            }
            // We must add a data part if we have input parameters or even if
            // we have output streams.
            if (this.parseinfo.inputCount > 0 || this.parseinfo.hasStreams) {
                dataPart = requestPacket.newDataPart(this.parseinfo.varDataInput);
                if (this.parseinfo.inputCount > 0) {
                    dataPart.addRow(this.parseinfo.inputCount);
                    for (int i = 0; i < this.parseinfo.paramInfos.length; ++i) {
                        if (this.parseinfo.paramInfos[i].isInput()
                                && initialParamValue == this.inputArgs[i]) {
                            if (this.parseinfo.paramInfos[i].isStreamKind()
                                    && this.outPutTypes != null
                                    && this.outPutTypes[i + 1] != 0) {
                                if (this.outputOMSStreams == null) {
                                    this.outputOMSStreams = new Vector();
                                }
                                ABAPStreamTranslator t = (ABAPStreamTranslator) this.parseinfo.paramInfos[i];
                                AbstractABAPStreamGetval getval = t
                                        .createGetval();
                                outputOMSStreams.add(getval);
                                t.put(dataPart, getval);
                            } else {
                                throw new SQLException(MessageTranslator
                                        .translate(
                                                MessageKey.ERROR_MISSINGINOUT,
                                                Integer.toString(i + 1)),
                                        "02000");
                            }
                        } else {
                            this.parseinfo.paramInfos[i].put(dataPart,
                                    this.inputArgs[i]);
                        }
                    }
                    this.inputProcedureLongs = null;
                    if (this.parseinfo.hasLongs) {
                        if (this.parseinfo.isDBProc) {
                            this.handleProcedureStreamsForExecute(dataPart,
                                    this.inputArgs);
                        } else {
                            this.handleStreamsForExecute(dataPart,
                                    this.inputArgs);
                        }
                    }
                    if (this.parseinfo.hasStreams) {
                        this.handleOMSStreamsForExecute(dataPart);
                    }
                } else {
                    // we have only streams
                    this.handleOMSStreamsForExecute(dataPart);
                }
                dataPart.close();
            }
            /*add a decribe order if command rturns a resultset*/
            if (  this.parseinfo.isSelect
                &&this.parseinfo.columnInfos == null
                &&this.parseinfo.functionCode != FunctionCode.DBProcWithResultSetExecute_FC ){
                  requestPacket.initDbsCommand("DESCRIBE ",false, false, ResultSet.TYPE_FORWARD_ONLY);
                  requestPacket.addParseidPart(this.parseinfo.getParseId());
            }
            try {
                replyPacket = this.connection.execute (requestPacket, this,                                              
                        (!this.parseinfo.hasStreams && this.inputProcedureLongs==null)?ConnectionSapDB.GC_ALLOWED:ConnectionSapDB.GC_NONE);
                // Recycling of parse infos and cursor names is not allowed
                // if streams are in the command. Even sending it just behind
                // as next packet is harmful. Same with INPUT LONG parameters of
                // DB Procedures.
            }
            catch (SQLException dbExc) {
                if ((dbExc.getErrorCode() == -8) && afterParseAgain > 0) {
                    this.resetPutvals (this.inputLongs);
                    this.reparse ();
                    this.connection.freeRequestPacket(requestPacket);
                    afterParseAgain--;
                    return this.execute (afterParseAgain);
                }
                else {
                    // The request packet has already been recycled in
                    // Connection.execute()
                    throw dbExc;
                }
            }

            // --- now it becomes difficult ...
            if (this.parseinfo.isSelect) {
                isQuery = this.parseResult(replyPacket, null, this.parseinfo
                        .getColumnInfos(), this.parseinfo.columnNames);
            } else {
                if(inputProcedureLongs != null) {
                    replyPacket = this.processProcedureStreams(replyPacket);
                } else if (this.parseinfo.hasStreams) {
                    replyPacket = this.processOMSStreams(replyPacket);
                }
                isQuery = this.parseResult(replyPacket, null, this.parseinfo
                        .getColumnInfos(), this.parseinfo.columnNames);
                int returnCode = replyPacket.returnCode();
                if (replyPacket.existsPart(PartKind.Data_C)) {
                    this.replyMem = replyPacket.getPointer(replyPacket
                            .getPartDataPos());
                }
                if ((this.parseinfo.hasLongs && !this.parseinfo.isDBProc) && (returnCode == 0)) {
                    this.handleStreamsForPutval(replyPacket);
                }
            }

            return isQuery;
        }
        catch (TimeoutException timeout) {
            if (this.connection.isInTransaction()
                || this.statementType == Statement_UpdatableResultSet    ) {
                throw timeout;
            } else {
                this.closeResultSet(true);
                this.resetPutvals (this.inputLongs);
                this.reparse ();
                return this.execute (maxParseAgainCnt);
            }
        } finally{
            this.canceled = false;
        }
        
    }


    /**
     * This method is inherited from <code>java.sql.Statement</code>. <b>This method
     * executes the current statement, which is in contrast to the standard. According to
     * the standard, it has
     * always to throw an <code>java.sql.SQLException</code> (JDBC, sec. 13.2.4).</b>
     * @param statement The statement (ignored).
     * @exception java.sql.SQLException if a database error occurs during execution
     *   of the parsed statement.
     */
    public boolean execute (
        String sql)
    throws SQLException
    {
        /*
         * special hack for requisit
         */
        return this.execute ();
/*         boolean result;                                                    */
/*         Statement stmt = this.connection.createStatement ();               */
/*                                                                            */
/*         result = stmt.execute (sql);                                       */
/*         if (result) {                                                      */
/*             this.currentResultSet = (ResultSetSapDB) stmt.getResultSet (); */
/*             this.rowsAffected = stmt.getUpdateCount ();                    */
/*         }                                                                  */
/*         return result;                                                     */
    }
    /**
     *
     */
    /**
     * JDBC 2.0
     *
     * Submits a batch of commands to the database for execution.
     * This method is optional.
     *
     * @return an array of update counts containing one element for each
     * command in the batch.  The array is ordered according
     * to the order in which commands were inserted into the batch.
     * @throws SQLException if a database access error occurs or the
     * driver does not support batch statements
     */
    public int[] executeBatch ()
    throws SQLException
    {
        this.assertOpen ();
        if (this.parseinfo != null
            && this.parseinfo.isSelect)
            throw new BatchUpdateExceptionSapDB
                (MessageTranslator.translate(MessageKey.ERROR_BATCHRESULTSET),
                 new int[0]);
        if (this.parseinfo != null
            && (this.parseinfo.functionCode == FunctionCode.DBProcExecute_FC
                || this.parseinfo.functionCode == FunctionCode.DBProcWithResultSetExecute_FC)){
              for (int i = 0; i < this.parseinfo.paramInfos.length; i++) {
                 if (this.parseinfo.paramInfos[i].isOutput())
                      throw new BatchUpdateExceptionSapDB
                          (MessageTranslator.translate(MessageKey.ERROR_BATCHPROCOUT),
                           new int[0]);
              }
        }

        if (this.batchItems == null) {
            return new int [0];
        }
        Vector streamVec = null;
        boolean inTrans = this.connection.isInTransaction ();
        java.util.Vector localBatchItems = this.batchItems;
        this.batchItems = null;
        try {
            this.canceled = false;
            int count = localBatchItems.size ();
            RequestPacket requestPacket;
            ReplyPacket replyPacket = null;
            int inputCursor = 0;
            boolean noError = true;
            int recordSize = 0;
            int insertCountPartSize = RequestPacket.resultCountPartSize ();
            int executeCount = -1;
            int [] result = new int[count];
            this.rowsAffected = -1;

            /*initialize update counts*/
            for (int i = 0; i < result.length; i++) {
              result[i]=StatementSapDB.BATCH_SUCCESS_NO_INFO_C;
            }

            if (this.parseinfo.getMassParseid() == null) {
                this.parseMassCmd(false);
            }

            if (this.parseinfo.paramInfos.length > 0) {
                recordSize = this.calculateInputRecord ();
            }
            while ((inputCursor < count) && noError) {
                streamVec  = null;
                int firstRecordNo = inputCursor;
                requestPacket = this.connection.getRequestPacket(this.packetEncodingUnicode);
                requestPacket.initExecute (this.parseinfo.getMassParseid(),
                                           this.connection.autocommit,
                                           this.resultSetType);
                if (executeCount == -1) {
                    requestPacket.addUndefResultCount ();
                }
                else {
                    requestPacket.addResultCount(executeCount);
                }
                requestPacket.addCursorPart (this.cursorName);
                DataPart dataPart;
                if (this.parseinfo.paramInfos.length > 0) {
                    dataPart = requestPacket.newDataPart (this.parseinfo.varDataInput);
                    if (executeCount == -1) {
                        dataPart.setFirstPart ();
                    }

                    do {
                        Object [] row = (Object []) localBatchItems.elementAt(inputCursor);
                        dataPart.addRow(this.parseinfo.inputCount);
                        for (int i = 0; i < this.parseinfo.paramInfos.length; ++i) {

                          /*check whether the parameter was set by application or throw an exception*/
                          if (this.parseinfo.paramInfos[i].isInput()
                              && initialParamValue == row [i])
                              throw new BatchUpdateExceptionSapDB (MessageTranslator.translate(MessageKey.ERROR_BATCHMISSINGIN,
                                                                   Integer.toString(inputCursor+1),
                                                                   Integer.toString(i+1)),
                                                                   "0200", makeBatchCountArray(result));

                          this.parseinfo.paramInfos [i].put (dataPart, row [i]);
                        }
                        if (this.parseinfo.hasLongs) {
                            this.handleStreamsForExecute (dataPart, row);
                            if (streamVec == null)
                              streamVec = new Vector(this.inputLongs.size());
                            streamVec.addAll(this.inputLongs);
                        }
                        dataPart.moveRecordBase ();
                        ++inputCursor;
                    } while ((inputCursor < count)
                           && dataPart.hasRoomFor (recordSize, insertCountPartSize)
                           && this.parseinfo.isMassCmd());

                    if (inputCursor == count) {
                        dataPart.setLastPart ();
                    }
                    dataPart.closeArrayPart (inputCursor - firstRecordNo);
                }
                else{
                  ++inputCursor; //commands without parameters
                }
                try {
                    replyPacket = this.connection.execute (requestPacket, this, ConnectionSapDB.GC_DELAYED);
                }
                catch (SQLException dbExc) {
                    if (dbExc.getErrorCode() == -8) {
                        this.resetPutvals (streamVec);
                        this.parseMassCmd(true);
                        inputCursor = firstRecordNo;
                        continue;   // redo this packet
                    }
                    else {
                        SQLExceptionSapDB specific = (SQLExceptionSapDB) dbExc;
                        // An autocommit session does roll back automatically all what was
                        // in this package. Thus, in case of an error we must not
                        // add the current count from the packet.
                        if(!this.connection.getAutoCommit()) {
                            if(this.rowsAffected >0) {
                                this.rowsAffected += specific.getErrorPos () - 1;
                            } else {
                                this.rowsAffected = specific.getErrorPos () - 1;
                            }
                        }
                        throw new BatchUpdateExceptionSapDB (dbExc,
                                                             new Integer(inputCursor + 1),
                                                             makeBatchCountArray(result));
                    }
                }
                executeCount = replyPacket.resultCount (false);
                if (this.parseinfo.hasLongs) {
                    this.handleStreamsForPutval (replyPacket);
                }
                if (! this.parseinfo.isMassCmd()
                    && executeCount != -1){
                  result[inputCursor-1] = executeCount;
                  if(this.rowsAffected >0) {
                    this.rowsAffected += executeCount;
                  } else {
                     this.rowsAffected = executeCount;
                  }
                }else {
                  this.rowsAffected = executeCount;
                }
            }
            return result;
        }
        catch (TimeoutException timeout) {
            if (inTrans
                    || this.statementType == Statement_UpdatableResultSet) {
                throw timeout;
            }
            else {
                this.batchItems = localBatchItems;
                this.resetPutvals (streamVec);
                return this.executeBatch ();
            }
        } finally{
          this.canceled = false;  
        }
    }

    private int[] makeBatchCountArray(int [] resultArr)
    {
      int [] erg;
      if (this.rowsAffected > 0) {
        erg = new int [this.rowsAffected];
        System.arraycopy(resultArr,0,erg,0,erg.length);
      }
      else {
        erg = new int [0];
      }
      return erg;
    }

    /**
     * executeQuery method comment.
     */
    public java.sql.ResultSet executeQuery()
    throws java.sql.SQLException
    {
        if (this.parseinfo != null
            && ! this.parseinfo.isSelect) {
            throw new SQLExceptionSapDB(MessageTranslator.translate(MessageKey.ERROR_SQLSTATEMENT_ROWCOUNT));
        } else {
            this.execute ();
            return this.currentResultSet;
        }
    }

    /**
     * This method is inherited from <code>java.sql.Statement</code>. It has
     * always to throw an <code>java.sql.SQLException</code> (JDBC, sec. 13.2.4).
     * @param statement The statement (ignored).
     * @exception java.sql.SQLException always
     */
    public java.sql.ResultSet executeQuery(String statement)
        throws java.sql.SQLException
    {
        throw new SQLExceptionSapDB(MessageTranslator.translate
                                    (MessageKey.ERROR_EXECUTEQUERY_PREPAREDSTATEMENT));
    }

    /**
     * executeQuery method comment.
     */
    public ResultSetSapDB executeQuerySap ()
    throws java.sql.SQLException
    {
        if (this.parseinfo != null
            && ! this.parseinfo.isSelect) {
            throw new SQLExceptionSapDB(MessageTranslator.translate(MessageKey.ERROR_SQLSTATEMENT_ROWCOUNT));
        }
        return(ResultSetSapDB) this.currentResultSet;
    }

    /**
     *
     */
    public int executeUpdate()
        throws java.sql.SQLException
    {
        if (this.parseinfo != null
            && this.parseinfo.isSelect) {
            throw new SQLExceptionSapDB(MessageTranslator.translate(MessageKey.ERROR_SQLSTATEMENT_RESULTSET));
        } else {
            this.execute ();
            if(this.hasRowCount) {
                return this.rowsAffected;
            } else {
                return 0;
            }
        }
    }

    /**
     * This method is inherited from <code>java.sql.Statement</code>. It has
     * always to throw an <code>java.sql.SQLException</code> (JDBC, sec. 13.2.4).
     * @param statement The statement (ignored).
     * @exception java.sql.SQLException always
     */
    public int executeUpdate(String statement)
        throws java.sql.SQLException
    {
        throw new SQLExceptionSapDB(MessageTranslator.translate
                                    (MessageKey.ERROR_EXECUTEUPDATE_PREPAREDSTATEMENT));

    }

    /**
     * findColumn method comment.
     */
    private DBTechTranslator findColInfo (
        int colIndex)
    throws SQLException
    {
        DBTechTranslator info;

        try {
            info = this.parseinfo.paramInfos [colIndex - 1];
        }
        catch (ArrayIndexOutOfBoundsException exc) {
            throw new JDBCDriverException
                (MessageTranslator.translate(MessageKey.ERROR_COLINDEX_NOTFOUND,
                                             Integer.toString(colIndex)),
                 this);
        }
        return info;
    }

    private DBTechTranslator findParamInfo (String paramName)
        throws SQLException
    {
        if (!this.parseinfo.isDBProc) {
            throw new SQLExceptionSapDB
                (MessageTranslator.translate(MessageKey.ERROR_SQLSTATEMENT_NOPROCEDURE));
        }
        if (this.columnMap == null) {
            this.columnMap = this.parseinfo.getColumnMap ();
        }
        DBTechTranslator info = (DBTechTranslator) this.columnMap.get (paramName);
        if (info == null) {
            info = (DBTechTranslator)
                this.columnMap.get (paramName.toUpperCase ());
            if (info != null) {
                // cache different case for faster lookup next time
                this.columnMap.put (paramName, info);
            }
        }
        if (info == null) {
        /*maybe the parameter couldn't retrieved because of kernel bug*/
        throw new InvalidColumnException (paramName, this);
        }
        return info;
    }
    /**
     * JDBC 2.0
     *
     * Gets the value of a JDBC <code>ARRAY</code> parameter as an
     * {@link Array} object in the Java programming language.
     * @param i the first parameter is 1, the second is 2, and
     * so on
     * @return the parameter value as an <code>Array</code> object in
     * the Java programming language.  If the value was SQL NULL, the
     * value <code>null</code> is returned.
     * @exception SQLException if a database access error occurs
     */
    public Array getArray (int i)
        throws SQLException
    {
        throwNotSupported(MessageTranslator.translate(MessageKey.ERROR_ARRAY_UNSUPPORTED));
        return null;
    }

    //--------------------------JDBC 2.0-----------------------------

    /**
     * JDBC 2.0
     *
     * Gets the value of a JDBC <code>NUMERIC</code> parameter as a
     * <code>java.math.BigDecimal</code> object with as many digits to the
     * right of the decimal point as the value contains.
     * @param parameterIndex the first parameter is 1, the second is 2,
     * and so on
     * @return the parameter value in full precision.  If the value is
     * SQL NULL, the result is <code>null</code>.
     * @exception SQLException if a database access error occurs
     */
    public java.math.BigDecimal getBigDecimal(
        int parameterIndex)
    throws SQLException
    {
        assertOpen();
        return this.findColInfo (parameterIndex).getBigDecimal (this, this.getReplyData());
    }
    /**
     * getBigDecimal method comment.
     */
    public java.math.BigDecimal getBigDecimal(
        int parameterIndex,
        int scale)
    throws java.sql.SQLException
    {
        assertOpen();
        return this.findColInfo (parameterIndex).getBigDecimal (scale, this, this.getReplyData());
    }
    /**
     * JDBC 2.0
     *
     * Gets the value of a JDBC <code>BLOB</code> parameter as a
     * {@link Blob} object in the Java programming language.
     * @param i the first parameter is 1, the second is 2, and so on
     * @return the parameter value as a <code>Blob</code> object in the
     * Java programming language.  If the value was SQL NULL, the value
     * <code>null</code> is returned.
     * @exception SQLException if a database access error occurs
     */
    public Blob getBlob (
        int i)
    throws SQLException
    {
        assertOpen();
        return this.findColInfo (i).getBlob (this, this.getReplyData(), this.getReplyData());
    }
    /**
     * getBoolean method comment.
     */
    public boolean getBoolean(
        int parameterIndex)
    throws java.sql.SQLException
    {
        assertOpen();
        return this.findColInfo (parameterIndex).getBoolean (this, this.getReplyData());
    }
    /**
     * getByte method comment.
     */
    public byte getByte(
        int parameterIndex)
    throws java.sql.SQLException
    {
        assertOpen();
        return this.findColInfo (parameterIndex).getByte (this, this.getReplyData());
    }
    /**
     * getBytes method comment.
     */
    public byte[] getBytes(int parameterIndex)
        throws java.sql.SQLException  {
        assertOpen();
        return this.findColInfo (parameterIndex).getBytes (this, this.getReplyData());
    }

    /**
     * JDBC 2.0
     *
     * Gets the value of a JDBC <code>CLOB</code> parameter as a
     * <code>Clob</code> object in the Java programming language.
     * @param i the first parameter is 1, the second is 2, and
     * so on
     * @return the parameter value as a <code>Clob</code> object in the
     * Java programming language.  If the value was SQL NULL, the
     * value <code>null</code> is returned.
     * @exception SQLException if a database access error occurs
     */
    public Clob getClob (
        int i)
    throws SQLException
    {
        assertOpen();
        return this.findColInfo (i).getClob (this, this.getReplyData(), this.getReplyData());
    }

    /**
     * getDate method comment.
     */
    public java.sql.Date getDate(
        int parameterIndex)
    throws java.sql.SQLException
    {
        assertOpen();
        return this.findColInfo (parameterIndex).getDate (this, this.getReplyData(),null);
    }
    /**
     * Gets the value of a JDBC <code>DATE</code> parameter as a
     * <code>java.sql.Date</code> object, using
     * the given <code>Calendar</code> object
     * to construct the date.
     * With a <code>Calendar</code> object, the driver
     * can calculate the date taking into account a custom timezone and locale.
     * If no <code>Calendar</code> object is specified, the driver uses the
     * default timezone and locale.
     *
     * @param parameterIndex the first parameter is 1, the second is 2,
     * and so on
     * @param cal the <code>Calendar</code> object the driver will use
     *            to construct the date
     * @return the parameter value.  If the value is SQL NULL, the result is
     * <code>null</code>.
     * @exception SQLException if a database access error occurs
     */
    public java.sql.Date getDate(int parameterIndex,
                                 Calendar cal)
        throws SQLException
    {
        assertOpen();
        return this.findColInfo (parameterIndex).getDate (this, this.getReplyData(),cal);
    }

    /**
     * getDouble method comment.
     */
    public double getDouble(
        int parameterIndex)
    throws java.sql.SQLException
    {
        assertOpen();
        return this.findColInfo (parameterIndex).getDouble (this, this.getReplyData());
    }
    /**
     * getFloat method comment.
     */
    public float getFloat(
        int parameterIndex)
    throws java.sql.SQLException
    {
        assertOpen();
        return this.findColInfo (parameterIndex).getFloat (this, this.getReplyData());
    }
    /**
     *
     * @return java.lang.Object
     * @param index int
     */
    Object getInputParameter (
        int parameterIndex)
    {
        return this.inputArgs [parameterIndex - 1];
    }
    /**
     * getInt method comment.
     */
    public int getInt(
        int parameterIndex)
    throws java.sql.SQLException
    {
        assertOpen();
        return this.findColInfo (parameterIndex).getInt (this, this.getReplyData());
    }
    /**
     * getLong method comment.
     */
    public long getLong(
        int parameterIndex)
    throws java.sql.SQLException
    {
        assertOpen();
        return this.findColInfo (parameterIndex).getLong (this, this.getReplyData());
    }

    /**
     * JDBC 2.0
     *
     * Gets the number, types and properties of a ResultSet's columns.
     *
     *
     * @return the description of a ResultSet's columns
     * @exception SQLException if a database access error occurs
     */
    public ResultSetMetaData getMetaData()
    throws SQLException
    {
        if(this.fetchInfo==null) {
            if(this.parseinfo==null) {
                return null;
            } else {
                if(   (! this.parseinfo.isSelect)
                   && (this.parseinfo.functionCode != FunctionCode.Select_FC)
                   && (this.parseinfo.functionCode != FunctionCode.DBProcWithResultSetExecute_FC)) {
                // leave as is if this is not a simple select
                    return null;
                }
                DBTechTranslator[] colinfos=this.parseinfo.getColumnInfos();
                if(colinfos!=null) {
                    return new ResultSetMetaDataSapDB(colinfos);
                } else {
                    // send describe parseid
                    try {
                      this.parseinfo.doDescribeParseId();
                    }
                    catch (Exception ex) {
                      return null;
                    }
                    return new ResultSetMetaDataSapDB (
                           this.getFetchInfo(this.cursorName,
                                             this.parseinfo.getColumnInfos(),
                                             this.parseinfo.columnNames).getColInfo());
                }
            }
        } else {
            return new ResultSetMetaDataSapDB (this.fetchInfo.getColInfo());
        }
    }

    /**
     * getObject method comment.
     */
    public Object getObject(
        int parameterIndex)
    throws java.sql.SQLException
    {
        assertOpen();
        Object result=null;
        int typeCode;
        int scale;
        DBTechTranslator translator = this.findColInfo (parameterIndex);
        StructuredMem replymem = this.getReplyData();

        if (this.outPutTypes == null) {
            typeCode = 0;
        }
        else {
            typeCode = this.outPutTypes [parameterIndex];
        }
        switch (typeCode) {
            case Types.BIT:
                if(!translator.isNull(this, replymem))
                   result = new Boolean (translator.getBoolean(this, replymem));
                break;
            case Types.TINYINT:
                if(!translator.isNull(this, replymem))
                    result = new Byte (translator.getByte (this, replymem));
                break;
            case Types.SMALLINT:
                if(!translator.isNull(this, replymem))
                    result = new Short (translator.getShort (this, replymem));
                break;
            case Types.INTEGER:
                if(!translator.isNull(this, replymem))
                    result = new Integer (translator.getInt (this, replymem));
                break;
            case Types.BIGINT:
                if(!translator.isNull(this, replymem))
                    result = new Long (translator.getLong (this, replymem));
                break;
            case Types.REAL:
                if(!translator.isNull(this, replymem))
                    result = new Float (translator.getFloat (this, replymem));
                break;
            case Types.FLOAT:
                if(!translator.isNull(this, replymem))
                    result = new Float (translator.getFloat (this, replymem));
                break;
            case Types.DOUBLE:
                if(!translator.isNull(this, replymem))
                    result = new Double (translator.getDouble (this, replymem));
                break;

            case Types.NUMERIC:
            case Types.DECIMAL:
                scale = this.outPutScale [parameterIndex];
                if (scale == -1) {
                    result = translator.getBigDecimal(this, replymem);
                }
                else {
                    result = translator.getBigDecimal(scale, this, replymem);
                }
                break;

            case Types.CHAR:
            case Types.VARCHAR:
            case Types.LONGVARCHAR:
                result = translator.getString (this, replymem);
                break;

            case Types.DATE:
                result = translator.getDate (this, replymem, null);
                break;
            case Types.TIME:
                result = translator.getTime (this, replymem, null);
                break;
            case Types.TIMESTAMP:
                result = translator.getTimestamp(this, replymem, null);
                break;

            case Types.BINARY:
            case Types.VARBINARY:
            case Types.LONGVARBINARY:
                result = translator.getBytes (this, replymem);
                break;

            case java.sql.Types.BLOB:
                result = translator.getBlob (this, replymem, replymem);
                break;
            case java.sql.Types.CLOB:
                result = translator.getClob (this, replymem, replymem);
                break;
            default:
                result = translator.getObject (this, replymem);
        }
        return result;
    }
    /**
     * JDBC 2.0
     *
     * Returns an object representing the value of OUT parameter
     * <code>i</code> and uses <code>map</code> for the custom
     * mapping of the parameter value.
     * <p>
     * This method returns a Java object whose type corresponds to the
     * JDBC type that was registered for this parameter using the method
     * <code>registerOutParameter</code>.  By registering the target
     * JDBC type as <code>java.sql.Types.OTHER</code>, this method can
     * be used to read database-specific abstract data types.
     * @param i the first parameter is 1, the second is 2, and so on
     * @param map the mapping from SQL type names to Java classes
     * @return a java.lang.Object holding the OUT parameter value.
     * @exception SQLException if a database access error occurs
     */
    public Object  getObject (int i,
                              Map map)
        throws SQLException
    {
        throw new NotImplemented (MessageTranslator.translate(MessageKey.ERROR_GETOBJECT_NOTIMPLEMENTED));
    }

    /**
     * JDBC 2.0
     *
     * Gets the value of a JDBC <code>REF(&lt;structured-type&gt;)</code>
     * parameter as a {@link Ref} object in the Java programming language.
     * @param i the first parameter is 1, the second is 2,
     * and so on
     * @return the parameter value as a <code>Ref</code> object in the
     * Java programming language.  If the value was SQL NULL, the value
     * <code>null</code> is returned.
     * @exception SQLException if a database access error occurs
     */
    public Ref getRef (int i)
        throws SQLException
    {
        throwNotSupported(MessageTranslator.translate(MessageKey.ERROR_REF_UNSUPPORTED));
        return null;
    }

     /**
      *
      * @return com.sap.dbtech.util.StructuredMem
      */
     public StructuredMem getReplyData ()
         throws SQLException
     {
         if(this.replyMem==null &&
            ((this.outputOMSStreams==null)
             ||(this.outputOMSStreams!=null && this.outputOMSStreams.size()==0))) {
            throw new SQLExceptionSapDB(MessageTranslator.translate
                                        (MessageKey.ERROR_NOOUTPARAMDATA));
         }
         return this.replyMem;
     }

    /**
     * getShort method comment.
     */
    public short getShort(
        int parameterIndex)
    throws java.sql.SQLException
    {
        return this.findColInfo (parameterIndex).getShort (this, this.getReplyData());
    }
    /**
     * getString method comment.
     */
    public String getString(
        int parameterIndex)
    throws java.sql.SQLException
    {
        return this.findColInfo (parameterIndex).getString (this, this.getReplyData());
    }
    /**
     * getTime method comment.
     */
    public java.sql.Time getTime(
        int parameterIndex)
    throws java.sql.SQLException
    {
        return this.findColInfo (parameterIndex).getTime (this, this.getReplyData(),null);
    }
    /**
     * Gets the value of a JDBC <code>TIME</code> parameter as a
     * <code>java.sql.Time</code> object, using
     * the given <code>Calendar</code> object
     * to construct the time.
     * With a <code>Calendar</code> object, the driver
     * can calculate the time taking into account a custom timezone and locale.
     * If no <code>Calendar</code> object is specified, the driver uses the
     * default timezone and locale.
     *
     * @param parameterIndex the first parameter is 1, the second is 2,
     * and so on
     * @param cal the <code>Calendar</code> object the driver will use
     *            to construct the time
     * @return the parameter value; if the value is SQL NULL, the result is
     * <code>null</code>.
     * @exception SQLException if a database access error occurs
     */
    public java.sql.Time getTime(
        int parameterIndex,
        Calendar cal)
    throws SQLException
    {
        return this.findColInfo (parameterIndex).getTime (this, this.getReplyData(),cal);
    }

    /**
     * getTimestamp method comment.
     */
    public java.sql.Timestamp getTimestamp(int parameterIndex) throws java.sql.SQLException {
        return this.findColInfo (parameterIndex).getTimestamp (this, this.getReplyData(),null);
    }
    /**
     * Gets the value of a JDBC <code>TIMESTAMP</code> parameter as a
     * <code>java.sql.Timestamp</code> object, using
     * the given <code>Calendar</code> object to construct
     * the <code>Timestamp</code> object.
     * With a <code>Calendar</code> object, the driver
     * can calculate the timestamp taking into account a custom timezone and locale.
     * If no <code>Calendar</code> object is specified, the driver uses the
     * default timezone and locale.
     *
     *
     * @param parameterIndex the first parameter is 1, the second is 2,
     * and so on
     * @param cal the <code>Calendar</code> object the driver will use
     *            to construct the timestamp
     * @return the parameter value.  If the value is SQL NULL, the result is
     * <code>null</code>.
     * @exception SQLException if a database access error occurs
     */
    public java.sql.Timestamp getTimestamp(int parameterIndex,
                                           Calendar cal)
        throws SQLException
    {
        return this.findColInfo (parameterIndex).getTimestamp (this, this.getReplyData(),cal);
    }


    private static class PutvalComparator implements Comparator
    {
        public int compare(Object o1, Object o2)
        {
            Putval p1 = (Putval) o1;
            Putval p2 = (Putval) o2;

            int p1_bufpos = p1.getBufpos();
            int p2_bufpos = p2.getBufpos();

            return p1_bufpos - p2_bufpos;
        }

        public boolean equals(Object o)
        {
            return o==this;
        }
    }

    private static final PutvalComparator putvalComparator = new PutvalComparator();

    /**
     *
     * @exception java.sql.SQLException The exception description.
     */
    private void handleStreamsForExecute (DataPart dataPart,
                                                                          Object [] arguments)
        throws SQLException
    {
        Putval putval;
        Enumeration putvals;
        int i;

        /*
         * get all putval objects
         */
        this.inputLongs = new Vector ();
        for (i = 0; i < this.parseinfo.paramInfos.length; ++i) {
            Object inarg = arguments [i];
            if (inarg == null) {
                continue;
            }
            try {
                putval = (Putval) inarg;
                this.inputLongs.addElement (putval);
            }
            catch (ClassCastException exc) {
                // not a long for input, ignore
            }
        }
        if(this.inputLongs.size()>1) {
            Collections.sort(this.inputLongs, putvalComparator);
        }
        /*
         * write data (and patch descriptor)
         */
        putvals = this.inputLongs.elements ();
        for (i = 0; putvals.hasMoreElements (); ++i) {
            putval = (Putval) putvals.nextElement ();
            if (putval.atEnd()){
              throw new SQLExceptionSapDB(MessageTranslator.translate(MessageKey.ERROR_STREAM_ISATEND));  
            }
                        putval.transferStream (dataPart, i);
        }
    }
    
    private void handleProcedureStreamsForExecute(DataPart dataPart, Object[] objects)throws SQLExceptionSapDB
    {
        this.inputProcedureLongs = new Vector();
        for(int i=0; i<this.parseinfo.paramInfos.length; ++i) {
            Object arg = this.inputArgs[i];
            if(arg == null) {
                continue;
            } else {
                try {
                    AbstractProcedurePutval pv = (AbstractProcedurePutval) arg;
                    inputProcedureLongs.addElement(pv);
                    pv.updateIndex(inputProcedureLongs.size() - 1);
                } catch(ClassCastException ignored) {
                    continue;
                }
            }
        }
    }
    

        /**
         * 
         * @param dataPart
         * @param objects
         */
    private void handleOMSStreamsForExecute(DataPart dataPart)
    {
        //
        this.inputOMSStreams = new Vector();
        for (int i = 0; i < this.parseinfo.paramInfos.length; ++i) {
            Object inarg = this.inputArgs[i];
            if (inarg == null) {
                continue;
            }
            try {
                this.inputOMSStreams
                        .addElement((AbstractABAPStreamPutval) inputArgs[i]);
            } catch (ClassCastException exc) {
                // not a stream
            }
        }
        int inputoms_size = inputOMSStreams.size();
        for (int k = 0; k < inputoms_size; ++k) {
            ABAPStreamDescriptor t = (ABAPStreamDescriptor) inputOMSStreams
                    .elementAt(k);
            t.updateIndex(k);
        }
        if (this.outputOMSStreams != null) {
            // update the index for the output streams
            for (int k = 0; k < outputOMSStreams.size(); ++k) {
                ABAPStreamDescriptor t = (ABAPStreamDescriptor) outputOMSStreams
                        .elementAt(k);
                t.updateIndex(k);
            }
        }
    }

    private ReplyPacket processProcedureStreams(ReplyPacket packet)
    	throws SQLException
    {
        ReplyPacket erg = null;
        do {
            try {
                if (packet.existsPart(PartKind.AbapIStream_C)) {
                    StreamInfo[] streaminfos = packet.parseStreamInfos();
                    StreamInfo info = streaminfos[0];
                    int tabid = info.getTabId();
                if (tabid < 0 || tabid > inputProcedureLongs.size()) {
                        throw new SQLExceptionSapDB(MessageTranslator
                                .translate(MessageKey.ERROR_UNKNOWN_PROCEDURELONG, Integer
                                        .toString(tabid)));
                 }
                 AbstractProcedurePutval pv = (AbstractProcedurePutval) inputProcedureLongs.elementAt(tabid);
                 RequestPacket requestPacket = connection.getRequestPacket(this.packetEncodingUnicode);
                 DataPart dataPart = requestPacket.initStreamCommand(connection.autocommit);
                 pv.transferStream(dataPart, info.getRowCount());
                 dataPart.close();
                 packet = connection.execute(requestPacket, this, ConnectionSapDB.GC_NONE);
                } else {
                    erg =  packet;
                    break;
                }
            } catch(SQLException sqlEx) {
                ReplyPacket tmppacket = connection.sendStreamErrorPacket(sqlEx);
                if(tmppacket == null) {
                    throw sqlEx;
                }
                erg =  tmppacket;
                break;
            }
        } while (true);
        for (int k = 0; k < inputProcedureLongs.size(); ++k) {
            AbstractProcedurePutval pv = (AbstractProcedurePutval) inputProcedureLongs.elementAt(k);
            pv.closeStream();
        }
        return erg;
    }

        
    private ReplyPacket processOMSStreams(ReplyPacket replyPacket)
            throws SQLException
    {

        do {
            if (replyPacket.existsPart(PartKind.AbapIStream_C)) {
                int tabid = replyPacket.parseABAPTabIDForInput();
                AbstractABAPStreamPutval pv = (AbstractABAPStreamPutval) this.inputOMSStreams
                        .elementAt(tabid);
                if (pv.atEnd()) {
                    throw new SQLExceptionSapDB(MessageTranslator.translate(
                            MessageKey.ERROR_STREAM_EOF, Integer
                                    .toString(tabid)));
                }
                RequestPacket requestPacket = this.connection
                        .getRequestPacket(this.packetEncodingUnicode);
                DataPart dataPart = requestPacket
                        .initStreamCommand(this.connection.autocommit);
                pv.transferStream(dataPart);
                dataPart.close();
                replyPacket = connection.execute(requestPacket, this,
                        ConnectionSapDB.GC_NONE);
            } else if (replyPacket.existsPart(PartKind.AbapOStream_C)) {
                int tabid = replyPacket.parseABAPTabIDForOutput();
                AbstractABAPStreamGetval gv = (AbstractABAPStreamGetval) this.outputOMSStreams
                        .elementAt(tabid);
                boolean eos = gv.addReplyData(replyPacket);
                RequestPacket requestPacket = this.connection
                        .getRequestPacket(this.packetEncodingUnicode);
                DataPart datapart = requestPacket
                        .initStreamCommand(this.connection.autocommit);
                if (eos) {
                    datapart.fillWithOMSReturnCode(100);
                } else {
                    datapart.fillWithOMSReturnCode(0);
                }
                datapart.close();
                replyPacket = connection.execute(requestPacket, this,
                        ConnectionSapDB.GC_NONE);
            } else {
                if (this.outputOMSStreams != null) {
                    for (int i = 0; i < this.outputOMSStreams.size(); ++i) {
                        AbstractABAPStreamGetval gv = (AbstractABAPStreamGetval) this.outputOMSStreams
                                .elementAt(i);
                        if (gv != null) {
                            gv.coalesceReply();
                        }
                    }
                }
                return replyPacket;
            }
        } while (true);
    }
    /**
     *  
     */
    private void getChangedPutvalDescriptors (
        ReplyPacket replyPacket)
    {
        byte [][] descriptorArray = replyPacket.parseLongDescriptors ();
        byte [] descriptor;
        com.sap.dbtech.util.StructuredBytes descriptorPointer;
        Putval putval;
        int valIndex;
        if (! replyPacket.existsPart (PartKind.Longdata_C)) {
                return;
        }
        for (int i = 0; i < descriptorArray.length; ++i) {
                descriptor = descriptorArray [i];
                descriptorPointer = new com.sap.dbtech.util.StructuredBytes (descriptor);
                valIndex = descriptorPointer.getInt2 (LongDesc.Valind_O);
                putval = (Putval) this.inputLongs.elementAt (valIndex);
                putval.setDescriptor (descriptor);
                }
    }
    /**
     *
     * @exception java.sql.SQLException The exception description.
     */
    private void handleStreamsForPutval(ReplyPacket replyPacket)
            throws SQLException {
        if (this.inputLongs.size() == 0) {
            return;
        }

        Putval lastStream = (Putval) this.inputLongs.lastElement();
        RequestPacket requestPacket;
        DataPart dataPart;
        int descriptorPos;
        Putval putval;
        int firstOpenStream = 0;
        int count = this.inputLongs.size();
        boolean requiresTrailingPacket = false;

        while (!lastStream.atEnd()) {
            this.getChangedPutvalDescriptors(replyPacket);
            requestPacket = this.connection.getRequestPacket(this.packetEncodingUnicode);
            dataPart = requestPacket.initPutval(this.connection.autocommit);
            /*
             * get all descriptors and putvals
             */
            for (int i = firstOpenStream; (i < count)
                    && dataPart.hasRoomFor(LongDesc.Size_C + 1); ++i) {

                putval = (Putval) this.inputLongs.elementAt(i);
                if (putval.atEnd()) {
                    ++firstOpenStream;
                } else {
                    descriptorPos = dataPart.getExtent();
                    putval.putDescriptor(dataPart, descriptorPos);
                    dataPart.addArg(descriptorPos, LongDesc.Size_C + 1);
                    if (this.canceled) {
                        putval.markErrorStream();
                        ++firstOpenStream;
                    } else {
                        putval.transferStream(dataPart, i);
                        if (putval.atEnd()) {
                            ++firstOpenStream;
                        }
                    }
                }
            }
            if (lastStream.atEnd() && !this.canceled) {
                try {
                    lastStream.markAsLast(dataPart);
                } catch (ArrayIndexOutOfBoundsException exc) {
                    // no place for end of LONGs marker
                    requiresTrailingPacket = true;
                }
            }
            // at end: patch last descriptor
            dataPart.close();
            /*
             * execute and get descriptors
             */
            replyPacket = this.connection.execute(requestPacket, this,
                    ConnectionSapDB.GC_DELAYED);
            /*
             * write trailing end of LONGs marker
             */
            if (requiresTrailingPacket && !this.canceled) {
                requestPacket = this.connection.getRequestPacket(false);
                dataPart = requestPacket.initPutval(this.connection.autocommit);
                lastStream.markAsLast(dataPart);
                dataPart.close();
                // temporary fix for problem with kernel and LONG values in
                // autocommit mode (again disabled).
                if(false) {            
	                try {
	                	this.connection.execute(requestPacket, this,
	                			ConnectionSapDB.GC_DELAYED);
	                } catch(SQLException sqlEx) {
	                	if(this.connection.getAutoCommit() && sqlEx.getErrorCode() == -7065) {
	                		// nothing
	                	} else {
	                		throw sqlEx;
	                	}
	                }
                } else {
                	this.connection.execute(requestPacket, this,
                			ConnectionSapDB.GC_DELAYED);
                }
            }
        }
        if (this.canceled) {
            throw new SQLExceptionSapDB(MessageTranslator
                    .translate(MessageKey.ERROR_STATEMENT_CANCELLED), "42000",
                    -102);

        }
    }


    
    /**
     * 
     * @exception java.sql.SQLException
     *                The exception description.
     */
    private void parseMassCmd (boolean parsegain)
    throws SQLException
    {
        RequestPacket requestPacket;
        ReplyPacket replyPacket;

        requestPacket = this.connection.getRequestPacket (false);
        try{
            requestPacket.initParseCommand (this.parseinfo.sqlCmd, true, parsegain);
            this.packetEncodingUnicode = false;
        } catch (ConversionExceptionSapDB e) {
            this.connection.freeRequestPacket(requestPacket);
            requestPacket = this.connection.getRequestPacket (true);
            this.packetEncodingUnicode = true;
            requestPacket.initParseCommand (this.parseinfo.sqlCmd, true, parsegain);
        }
        requestPacket.setMassCommand ();
        //requestPacket.addCursorPart (this.cursorName);
        replyPacket = this.connection.execute (requestPacket, this, ConnectionSapDB.GC_ALLOWED);
        
        if (replyPacket.existsPart (PartKind.Parsid_C)) {
            this.parseinfo.setMassParseid(replyPacket.getBytes (replyPacket.getPartDataPos (), 12));
        }
    }
    /**
     * registerOutParameter method comment.
     */
    public void registerOutParameter(
        int parameterIndex,
        int sqlType)
    throws java.sql.SQLException
    {
        this.registerOutParameter (parameterIndex, sqlType, -1);
    }
    /**
     * registerOutParameter method comment.
     */
    public void registerOutParameter(int parameterIndex, int sqlType, int scale) throws java.sql.SQLException {
        if (this.outPutTypes == null) {
            this.outPutTypes = new short [this.parseinfo.paramInfos.length + 1];
            this.outPutScale = new byte [this.parseinfo.paramInfos.length + 1];
        }
        this.outPutTypes [parameterIndex] = (short) sqlType;
        this.outPutScale [parameterIndex] = (byte) scale;
    }
    /**
     * JDBC 2.0
     *
     * Registers the designated output parameter.  This version of
     * the method <code>registerOutParameter</code>
     * should be used for a user-named or REF output parameter.  Examples
     * of user-named types include: STRUCT, DISTINCT, JAVA_OBJECT, and
     * named array types.
     *
     * Before executing a stored procedure call, you must explicitly
     * call <code>registerOutParameter</code> to register the type from
     * <code>java.sql.Types</code> for each
     * OUT parameter.  For a user-named parameter the fully-qualified SQL
     * type name of the parameter should also be given, while a REF
     * parameter requires that the fully-qualified type name of the
     * referenced type be given.  A JDBC driver that does not need the
     * type code and type name information may ignore it.   To be portable,
     * however, applications should always provide these values for
     * user-named and REF parameters.
     *
     * Although it is intended for user-named and REF parameters,
     * this method may be used to register a parameter of any JDBC type.
     * If the parameter does not have a user-named or REF type, the
     * typeName parameter is ignored.
     *
     * <P><B>Note:</B> When reading the value of an out parameter, you
     * must use the <code>getYYY</code> method whose Java type YYY corresponds to the
     * parameter's registered SQL type.
     *
     * @param parameterIndex the first parameter is 1, the second is 2,...
     * @param sqlType a value from java.sql.Types
     * @param typeName the fully-qualified name of an SQL structured type
     * @exception SQLException if a database-access error occurs
     */
    public void registerOutParameter (
        int paramIndex,
        int sqlType,
        String typeName)
    throws SQLException
    {
        this.registerOutParameter (paramIndex, sqlType, -1);
    }

    /**
     * Overwrites the inherited method. Instead of executing the command,
     * this does a parse only!
     * @param requestPacket the request packet.
     * @param sqlCmd the SQL command to parse.
     * @exception java.sql.SQLException if a database error occurs.
     */
    ReplyPacket sendCommand (
        RequestPacket requestPacket,
        String sqlCmd,
        int gcFlags,
        boolean parseAgain)
    throws SQLException
    {
        ReplyPacket replyPacket;

        requestPacket.initParseCommand (sqlCmd, true, parseAgain);
        if(setWithInfo)
            requestPacket.setWithInfo();
        replyPacket = this.connection.execute (requestPacket, false, true, this,
                                               gcFlags);
        return replyPacket;
    }

    /**
     * JDBC 2.0
     *
     * Sets an Array parameter.
     *
     * @param i the first parameter is 1, the second is 2, ...
     * @param x an object representing an SQL array
     * @exception SQLException if a database access error occurs
     */
    public void setArray (int i,
                          Array x)
        throws SQLException
    {
        throwNotSupported(MessageTranslator.translate(MessageKey.ERROR_ARRAY_UNSUPPORTED));
    }

    /**
     * setAsciiStream method comment.
     */
    public void setAsciiStream(
        int parameterIndex,
        java.io.InputStream x,
        int length)
    throws java.sql.SQLException
    {
        Object arg = this.findColInfo (parameterIndex).transAsciiStreamForInput (x,length);
        this.inputArgs [parameterIndex - 1] = arg;
    }
    /**
     * setBigDecimal method comment.
     */
    public void setBigDecimal(
        int parameterIndex,
        java.math.BigDecimal x)
    throws java.sql.SQLException
    {
        Object arg = this.findColInfo (parameterIndex).transBigDecimalForInput (x);
        this.inputArgs [parameterIndex - 1] = arg;
    }
    /**
     * setBinaryStream method comment.
     */
    public void setBinaryStream(
        int parameterIndex,
        java.io.InputStream x,
        int length)
    throws java.sql.SQLException
    {
        Object arg = this.findColInfo (parameterIndex).transBinaryStreamForInput (x,length);
        this.inputArgs [parameterIndex - 1] = arg;
    }
    /**
     * JDBC 2.0
     *
     * Sets a BLOB parameter.
     *
     * @param i the first parameter is 1, the second is 2, ...
     * @param x an object representing a BLOB
     * @exception SQLException if a database access error occurs
     */
    public void setBlob (
        int i,
        Blob x)
    throws SQLException
    {
        Object arg = this.findColInfo (i).transBlobForInput (x);
        this.inputArgs [i - 1] = arg;
    }
    /**
     * setBoolean method comment.
     */
    public void setBoolean(
        int parameterIndex,
        boolean x)
    throws java.sql.SQLException
    {
        Object arg = this.findColInfo (parameterIndex).transBooleanForInput (x);
        this.inputArgs [parameterIndex - 1] = arg;
    }
    /**
     * setByte method comment.
     */
    public void setByte(
        int parameterIndex,
        byte x)
    throws java.sql.SQLException
    {
        Object arg = this.findColInfo (parameterIndex).transByteForInput (x);
        this.inputArgs [parameterIndex - 1] = arg;
    }
    /**
     * setBytes method comment.
     */
    public void setBytes(
        int parameterIndex,
        byte[] x)
    throws java.sql.SQLException
    {
        Object arg = this.findColInfo (parameterIndex).transBytesForInput (x);
        this.inputArgs [parameterIndex - 1] = arg;
    }
    /**
     * JDBC 2.0
     *
     * Sets the designated parameter to the given <code>Reader</code>
     * object, which is the given number of characters long.
     * When a very large UNICODE value is input to a LONGVARCHAR
     * parameter, it may be more practical to send it via a
     * java.io.Reader. JDBC will read the data from the stream
     * as needed, until it reaches end-of-file.  The JDBC driver will
     * do any necessary conversion from UNICODE to the database char format.
     *
     * <P><B>Note:</B> This stream object can either be a standard
     * Java stream object or your own subclass that implements the
     * standard interface.
     *
     * @param parameterIndex the first parameter is 1, the second is 2, ...
     * @param x the java reader which contains the UNICODE data
     * @param length the number of characters in the stream
     * @exception SQLException if a database access error occurs
     */
    public void setCharacterStream(
        int parameterIndex,
        java.io.Reader reader,
        int length)
    throws SQLException
    {
        Object arg = this.findColInfo (parameterIndex).transCharacterStreamForInput (reader, length);
        this.inputArgs [parameterIndex - 1] = arg;
    }
    /**
     * JDBC 2.0
     *
     * Sets a CLOB parameter.
     *
     * @param i the first parameter is 1, the second is 2, ...
     * @param x an object representing a CLOB
     * @exception SQLException if a database access error occurs
     */
    public void setClob (
        int i,
        Clob x)
    throws SQLException
    {
        Object arg = this.findColInfo (i).transClobForInput (x);
        this.inputArgs [i - 1] = arg;
    }
    /**
     * setDate method comment.
     */
    public void setDate(
        int parameterIndex,
        java.sql.Date x)
    throws java.sql.SQLException
    {
        this.setDate(parameterIndex,x,null);
    }
    /**
     * JDBC 2.0
     *
     * Sets the designated parameter to a java.sql.Date value,
     * using the given <code>Calendar</code> object.  The driver uses
     * the <code>Calendar</code> object to construct an SQL DATE,
     * which the driver then sends to the database.  With a
     * a <code>Calendar</code> object, the driver can calculate the date
     * taking into account a custom timezone and locale.  If no
     * <code>Calendar</code> object is specified, the driver uses the default
     * timezone and locale.
     *
     * @param parameterIndex the first parameter is 1, the second is 2, ...
     * @param x the parameter value
     * @param cal the <code>Calendar</code> object the driver will use
     *            to construct the date
     * @exception SQLException if a database access error occurs
     */
    public void setDate(
        int parameterIndex,
        java.sql.Date x,
        Calendar cal)
    throws SQLException
    {
       if(cal==null) {
         cal=Calendar.getInstance();
       }
       Object arg = this.findColInfo (parameterIndex).transDateForInput (x,cal);
       this.inputArgs [parameterIndex - 1] = arg;
    }

    /**
     * setDouble method comment.
     */
    public void setDouble(
        int parameterIndex,
        double x)
    throws java.sql.SQLException
    {
        Object arg = this.findColInfo (parameterIndex).transDoubleForInput (x);
        this.inputArgs [parameterIndex - 1] = arg;
    }
    /**
     * setFloat method comment.
     */
    public void setFloat(
        int parameterIndex,
        float x)
    throws java.sql.SQLException
    {
        Object arg = this.findColInfo (parameterIndex).transFloatForInput (x);
        this.inputArgs [parameterIndex - 1] = arg;
    }
    /**
     * setInt method comment.
     */
    public void setInt(int parameterIndex,
        int x)
    throws java.sql.SQLException
    {
        Object arg = this.findColInfo (parameterIndex).transIntForInput (x);
        this.inputArgs [parameterIndex - 1] = arg;
    }
    /**
     *
     * @param wasNull boolean
     */
    public void setLastWasNull (
        boolean wasNull)
    {
        this.lastWasNull = wasNull;
    }
    /**
     * setLong method comment.
     */
    public void setLong(
        int parameterIndex,
        long x)
    throws java.sql.SQLException
    {
        Object arg = this.findColInfo (parameterIndex).transLongForInput (x);
        this.inputArgs [parameterIndex - 1] = arg;
    }
    /**
     * setNull method comment.
     */
    public void setNull(
        int parameterIndex,
        int sqlType)
    throws java.sql.SQLException
    {
        this.inputArgs [parameterIndex - 1] = null;
    }

    public void setDefault(
            int parameterIndex)
        throws java.sql.SQLException
        {
            this.inputArgs [parameterIndex - 1] = DBTechTranslator.DefaultValue;
        }
    /**
     * JDBC 2.0
     *
     * Sets the designated parameter to SQL NULL.  This version of setNull should
     * be used for user-named types and REF type parameters.  Examples
     * of user-named types include: STRUCT, DISTINCT, JAVA_OBJECT, and
     * named array types.
     *
     * <P><B>Note:</B> To be portable, applications must give the
     * SQL type code and the fully-qualified SQL type name when specifying
     * a NULL user-defined or REF parameter.  In the case of a user-named type
     * the name is the type name of the parameter itself.  For a REF
     * parameter the name is the type name of the referenced type.  If
     * a JDBC driver does not need the type code or type name information,
     * it may ignore it.
     *
     * Although it is intended for user-named and Ref parameters,
     * this method may be used to set a null parameter of any JDBC type.
     * If the parameter does not have a user-named or REF type, the given
     * typeName is ignored.
     *
     *
     * @param parameterIndex the first parameter is 1, the second is 2, ...
     * @param sqlType a value from java.sql.Types
     * @param typeName the fully-qualified name of an SQL user-named type,
     *  ignored if the parameter is not a user-named type or REF
     * @exception SQLException if a database access error occurs
     */
    public void setNull (
        int paramIndex,
        int sqlType,
        String typeName)
    throws java.sql.SQLException
    {
        this.setNull (paramIndex, sqlType);
    }
    /**
     * setObject method comment.
     */
    public void setObject(
        int parameterIndex,
        Object x)
    throws java.sql.SQLException
    {
        Object arg = this.findColInfo (parameterIndex).transObjectForInput (x);
        this.inputArgs [parameterIndex - 1] = arg;
    }
    /**
     * setObject method comment.
     */
    public void setObject(
        int parameterIndex,
        Object x,
        int targetSqlType)
    throws java.sql.SQLException
    {
        // specials for JDBC Compliance
        switch(targetSqlType) {
        case Types.INTEGER:
            if(x instanceof Number) {
                Number n=(Number)x;
                this.setInt(parameterIndex, n.intValue());
                return;
            }
        case Types.BIGINT:
            if(x instanceof Number) {
                Number n=(Number)x;
                this.setLong(parameterIndex, n.longValue());
                return;
            }
        }
        this.setObject (parameterIndex, x);
    }
    /**
     * setObject method comment.
     */
    public void setObject(
        int parameterIndex,
        Object x,
        int targetSqlType,
        int scale)
    throws java.sql.SQLException
    {
        // ignore targetSqlType
        this.setObject (parameterIndex, x, scale);
    }
    /**
     * JDBC 2.0
     *
     * Sets a REF(&lt;structured-type&gt;) parameter.
     *
     * @param i the first parameter is 1, the second is 2, ...
     * @param x an object representing data of an SQL REF Type
     * @exception SQLException if a database access error occurs
     */
    public void setRef (int i,
                        Ref x)
        throws SQLException
    {
        throwNotSupported(MessageTranslator.translate(MessageKey.ERROR_REF_UNSUPPORTED));
    }

    /**
     * setShort method comment.
     */
    public void setShort(
        int parameterIndex,
        short x)
    throws java.sql.SQLException
    {
        Object arg = this.findColInfo (parameterIndex).transShortForInput (x);
        this.inputArgs [parameterIndex - 1] = arg;
    }
    /**
     * setString method comment.
     */
    public void setString(
        int parameterIndex,
        String x)
    throws java.sql.SQLException
    {
        this.assertOpen();
        if ( x != null
             && this.connection.isSQLModeOracle
             && x.equalsIgnoreCase("") ) {
          /* in oracle mode a null values will be inserted
             if the string value is equal to "" */
          this.inputArgs [parameterIndex - 1] = null;
        }
        else {
          Object arg = this.findColInfo (parameterIndex).transStringForInput (x);
          this.inputArgs [parameterIndex - 1] = arg;
        }
    }
    /**
     * setTime method comment.
     */
    public void setTime(
        int parameterIndex,
        java.sql.Time x)
    throws java.sql.SQLException
    {
       this.setTime(parameterIndex,x, null);
    }
    /**
     * JDBC 2.0
     *
     * Sets the designated parameter to a java.sql.Time value,
     * using the given <code>Calendar</code> object.  The driver uses
     * the <code>Calendar</code> object to construct an SQL TIME,
     * which the driver then sends to the database.  With a
     * a <code>Calendar</code> object, the driver can calculate the time
     * taking into account a custom timezone and locale.  If no
     * <code>Calendar</code> object is specified, the driver uses the default
     * timezone and locale.
     *
     * @param parameterIndex the first parameter is 1, the second is 2, ...
     * @param x the parameter value
     * @param cal the <code>Calendar</code> object the driver will use
     *            to construct the time
     * @exception SQLException if a database access error occurs
     */
    public void setTime(int parameterIndex,
                        java.sql.Time x,
                        Calendar cal)
        throws SQLException
    {
       if(cal==null) {
          cal=Calendar.getInstance();
       }
       Object arg = this.findColInfo (parameterIndex).transTimeForInput (x, cal);
       this.inputArgs [parameterIndex - 1] = arg;
    }

    /**
     * setTimestamp method comment.
     */
    public void setTimestamp(
        int parameterIndex,
        java.sql.Timestamp x)
    throws java.sql.SQLException
    {
        this.setTimestamp(parameterIndex,x,null);
    }
    /**
     * JDBC 2.0
     *
     * Sets the designated parameter to a java.sql.Timestamp value,
     * using the given <code>Calendar</code> object.  The driver uses
     * the <code>Calendar</code> object to construct an SQL TIMESTAMP,
     * which the driver then sends to the database.  With a
     * a <code>Calendar</code> object, the driver can calculate the timestamp
     * taking into account a custom timezone and locale.  If no
     * <code>Calendar</code> object is specified, the driver uses the default
     * timezone and locale.
     *
     * @param parameterIndex the first parameter is 1, the second is 2, ...
     * @param x the parameter value
     * @param cal the <code>Calendar</code> object the driver will use
     *            to construct the timestamp
     * @exception SQLException if a database access error occurs
     */
    public void setTimestamp(int parameterIndex,
                             java.sql.Timestamp x,
                             Calendar cal)
        throws SQLException
    {
        if(cal==null) {
           cal=Calendar.getInstance();
        }
        Object arg = this.findColInfo (parameterIndex).transTimestampForInput (x, cal);
        this.inputArgs [parameterIndex - 1] = arg;
    }

    /**
     * setUnicodeStream method comment.
     */
    public void setUnicodeStream(
        int parameterIndex,
        java.io.InputStream x,
        int length)
    throws java.sql.SQLException
    {
        Object arg = this.findColInfo (parameterIndex).transUnicodeStreamForInput (x);
        this.inputArgs [parameterIndex - 1] = arg;
    }
    /**
     * wasNull method comment.
     */
    public boolean wasNull()
    throws java.sql.SQLException
    {
        return this.lastWasNull;
    }
    /**
     *
     */
    protected FetchInfo
    getFetchInfo (
        String cursorName,
        DBTechTranslator [] infos,
        String [] columnNames)
    throws SQLException
    {
        if (this.fetchInfo == null) {
            this.fetchInfo = new FetchInfo (this.connection,
                cursorName, infos, columnNames, this.packetEncodingUnicode);
        }
        else {
            if (!this.fetchInfo.getCursorName ().equals (cursorName)) {
                this.fetchInfo = new FetchInfo (this.connection,
                cursorName, infos, columnNames, this.packetEncodingUnicode);
            }
        }
        return this.fetchInfo;
    }

    protected void updateFetchInfo(DBTechTranslator [] infos,  String[] columnNames) throws SQLException  {
        this.parseinfo.setMetaData(infos, columnNames);
    }
    /**
     *
     */
    public void
    close ()
        throws SQLException
    {
        this.replyMem=null;
        if (this.connection != null
        	&& this.parseinfo != null	
            && !this.parseinfo.cached) {
            this.connection.dropParseid (this.parseinfo.getParseId());
            this.parseinfo.setParseIdAndSession(null, -1);
            this.connection.dropParseid (this.parseinfo.getMassParseid());
            this.parseinfo.setMassParseid(null);
        }
        super.close ();
    }
    /**
     *
     */
    protected void
    resetPutvals (Vector inpLongs)
    {
        if (inpLongs != null) {
            Enumeration putvals = inpLongs.elements ();
            while (putvals.hasMoreElements ()) {
                Putval putval = (Putval) putvals.nextElement ();
                putval.reset ();
            }
        }
    }
  public void registerOutParameter(String parameterName, int sqlType) throws SQLException {
    this.registerOutParameter (parameterName, sqlType, -1);
  }
  public void registerOutParameter(String parameterName, int sqlType, int scale) throws SQLException {
     this.registerOutParameter((this.findParamInfo(parameterName).getColIndex())+1, sqlType, scale);
  }
  public void registerOutParameter(String parameterName, int sqlType, String typeName) throws SQLException {
      this.registerOutParameter (parameterName, sqlType, -1);
  }
  public URL getURL(int parm1) throws java.sql.SQLException {
        this.throwNotSupported("Type URL");
        return  null;
  }
  public void setURL(String parm1, URL parm2) throws java.sql.SQLException {
        this.throwNotSupported("Type URL");
  }
  public void setNull(String parameterName, int sqlType) throws SQLException {
    this.setNull((this.findParamInfo(parameterName).getColIndex())+1,sqlType);
  }
  public void setDefault(String parameterName) throws SQLException {
      this.setDefault((this.findParamInfo(parameterName).getColIndex())+1);
    }
  public void setBoolean(String parameterName, boolean x) throws SQLException {
    this.setBoolean((this.findParamInfo(parameterName).getColIndex())+1,x);
  }
  public void setByte(String parameterName, byte x) throws SQLException {
    this.setByte((this.findParamInfo(parameterName).getColIndex())+1,x);
  }
  public void setShort(String parameterName, short x) throws SQLException {
    this.setShort((this.findParamInfo(parameterName).getColIndex())+1,x);
  }
  public void setInt(String parameterName, int x) throws SQLException {
    this.setInt((this.findParamInfo(parameterName).getColIndex())+1,x);
  }
  public void setLong(String parameterName, long x) throws SQLException {
    this.setLong((this.findParamInfo(parameterName).getColIndex())+1,x);
  }
  public void setFloat(String parameterName, float x) throws SQLException {
    this.setFloat((this.findParamInfo(parameterName).getColIndex())+1,x);
  }
  public void setDouble(String parameterName, double x) throws SQLException {
    this.setDouble((this.findParamInfo(parameterName).getColIndex())+1,x);
  }
  public void setBigDecimal(String parameterName, BigDecimal x) throws SQLException {
    this.setBigDecimal((this.findParamInfo(parameterName).getColIndex())+1,x);
  }
  public void setString(String parameterName, String x) throws SQLException {
    this.setString((this.findParamInfo(parameterName).getColIndex())+1,x);
  }
  public void setBytes(String parameterName, byte[] x) throws SQLException {
    this.setBytes((this.findParamInfo(parameterName).getColIndex())+1,x);
  }
  public void setDate(String parameterName, java.sql.Date x) throws SQLException {
    this.setDate((this.findParamInfo(parameterName).getColIndex())+1,x);
  }
  public void setTime(String parameterName, java.sql.Time x) throws SQLException {
    this.setTime((this.findParamInfo(parameterName).getColIndex())+1,x);
  }
  public void setTimestamp(String parameterName, java.sql.Timestamp x) throws SQLException {
    this.setTimestamp((this.findParamInfo(parameterName).getColIndex())+1,x);
  }
  public void setAsciiStream(String parameterName, InputStream x, int length) throws SQLException {
    this.setAsciiStream((this.findParamInfo(parameterName).getColIndex())+1,x,length);
  }
  public void setBinaryStream(String parameterName, InputStream x, int length) throws SQLException {
    this.setBinaryStream((this.findParamInfo(parameterName).getColIndex())+1,x,length);
  }
  public void setObject(String parameterName, Object x, int targetSqlType, int scale) throws SQLException {
    this.setObject((this.findParamInfo(parameterName).getColIndex())+1,x,targetSqlType,scale);
  }
  public void setObject(String parameterName, Object x, int targetSqlType) throws SQLException {
    this.setObject((this.findParamInfo(parameterName).getColIndex())+1,x,targetSqlType);
  }
  public void setObject(String parameterName, Object x) throws SQLException {
    this.setObject((this.findParamInfo(parameterName).getColIndex())+1,x);
  }
  public void setCharacterStream(String parameterName, Reader reader, int length) throws SQLException {
    this.setCharacterStream((this.findParamInfo(parameterName).getColIndex())+1,reader,length);
  }
  public void setDate(String parameterName, java.sql.Date x, Calendar cal) throws SQLException {
    this.setDate((this.findParamInfo(parameterName).getColIndex())+1,x,cal);
  }
  public void setTime(String parameterName, java.sql.Time x, Calendar cal) throws SQLException {
    this.setTime((this.findParamInfo(parameterName).getColIndex())+1,x,cal);
  }
  public void setTimestamp(String parameterName, java.sql.Timestamp x, Calendar cal) throws SQLException {
    this.setTimestamp((this.findParamInfo(parameterName).getColIndex())+1,x,cal);
  }
  public void setNull(String parameterName, int sqlType, String typeName) throws SQLException {
    this.setNull((this.findParamInfo(parameterName).getColIndex())+1,sqlType,typeName);
  }
  public String getString(String parameterName) throws SQLException {
      assertOpen();
      return this.findParamInfo (parameterName).getString (this, this.getReplyData());
  }
  public boolean getBoolean(String parameterName) throws SQLException {
      assertOpen();
      return this.findParamInfo (parameterName).getBoolean (this, this.getReplyData());
  }
  public byte getByte(String parameterName) throws SQLException {
      assertOpen();
      return this.findParamInfo (parameterName).getByte (this, this.getReplyData());
  }
  public short getShort(String parameterName) throws SQLException {
      assertOpen();
      return this.findParamInfo (parameterName).getShort (this, this.getReplyData());
  }
  public int getInt(String parameterName) throws SQLException {
      assertOpen();
      return this.findParamInfo (parameterName).getInt (this, this.getReplyData());
  }
  public long getLong(String parameterName) throws SQLException {
      assertOpen();
      return this.findParamInfo (parameterName).getLong (this, this.getReplyData());
  }
  public float getFloat(String parameterName) throws SQLException {
      assertOpen();
      return this.findParamInfo (parameterName).getFloat (this, this.getReplyData());
  }
  public double getDouble(String parameterName) throws SQLException {
      assertOpen();
      return this.findParamInfo (parameterName).getDouble (this, this.getReplyData());
  }
  public byte[] getBytes(String parameterName) throws SQLException {
      assertOpen();
      return this.findParamInfo (parameterName).getBytes (this, this.getReplyData());
  }
  public java.sql.Date getDate(String parameterName) throws SQLException {
      assertOpen();
      return this.findParamInfo (parameterName).getDate (this, this.getReplyData(),null);
  }
  public java.sql.Time getTime(String parameterName) throws SQLException {
      assertOpen();
      return this.findParamInfo (parameterName).getTime (this, this.getReplyData(),null);
  }
    public java.sql.Timestamp getTimestamp(String parameterName) throws SQLException {
        assertOpen();
        return this.findParamInfo (parameterName).getTimestamp (this, this.getReplyData(),null);
    }
    public Object getObject(String parameterName) throws SQLException {
      assertOpen();
      return this.findParamInfo (parameterName).getObject (this, this.getReplyData());
    }
    public BigDecimal getBigDecimal(String parameterName) throws SQLException {
        assertOpen();
        return this.findParamInfo (parameterName).getBigDecimal (this, this.getReplyData());
    }
  public Object getObject(String parameterName, Map map) throws SQLException {
        throw new NotImplemented ();
  }
  public Ref getRef(String parameterName) throws SQLException {
        throwNotSupported(MessageTranslator.translate(MessageKey.ERROR_REF_UNSUPPORTED));
        return  null;
  }
  public Blob getBlob(String parameterName) throws SQLException {
      assertOpen();
      return this.findParamInfo (parameterName).getBlob (this, this.getReplyData(), this.getReplyData());
  }
  public Clob getClob(String parameterName) throws SQLException {
      assertOpen();
      return this.findParamInfo (parameterName).getClob (this, this.getReplyData(), this.getReplyData());
  }
  public Array getArray(String parameterName) throws SQLException {
        throwNotSupported(MessageTranslator.translate(MessageKey.ERROR_ARRAY_UNSUPPORTED));
        return  null;
  }
  public java.sql.Date getDate(String parameterName, Calendar cal) throws SQLException {
      assertOpen();
      return this.findParamInfo (parameterName).getDate (this, this.getReplyData(),cal);
  }
  public java.sql.Time getTime(String parameterName, Calendar cal) throws SQLException {
      assertOpen();
      return this.findParamInfo (parameterName).getTime (this, this.getReplyData(),cal);
  }
  public java.sql.Timestamp getTimestamp(String parameterName, Calendar cal) throws SQLException {
        assertOpen();
        return this.findParamInfo (parameterName).getTimestamp (this, this.getReplyData(),cal);
  }
  public URL getURL(String parm1) throws java.sql.SQLException {
        throwNotSupported(MessageTranslator.translate(MessageKey.ERROR_URL_UNSUPPORTED));
        return  null;
  }
  public void setURL(int parm1, URL parm2) throws java.sql.SQLException {
      throwNotSupported(MessageTranslator.translate(MessageKey.ERROR_URL_UNSUPPORTED));
  }
  public java.sql.ParameterMetaData getParameterMetaData() throws java.sql.SQLException {
       return ParameterMetaDataSapDB.createParameterMetaDataSapDB(this.parseinfo.getParamInfo());
  }

        public AbstractABAPStreamGetval getOMSGetval(int index)
                throws SQLException {
                if(this.outputOMSStreams == null) {
                        return null;
                }
                for(int i=0; i<this.outputOMSStreams.size(); ++i) {
                        AbstractABAPStreamGetval t = (AbstractABAPStreamGetval) this.outputOMSStreams.elementAt(i);
                        if(t != null) {
                                if(index == t.getColIndex())  {
                                        return t;
                                }
                        }
                }
                throw new SQLExceptionSapDB(MessageTranslator.translate(MessageKey.ERROR_COLINDEX_NOTFOUND, Integer.toString(index)));
        }

  boolean isParameterSet(int parameterIndex){
    return ! (initialParamValue == this.inputArgs[parameterIndex-1]);  
  }

  void unsetParameter(int parameterIndex){
      this.inputArgs[parameterIndex-1] = initialParamValue;   
    }

  Object[] getInputArgs() {
    return inputArgs;
  }      
}
