/*!
  @file           IFR_ResultSet.h
  @author         ThomasS
  @ingroup        IFR_Fetch
  @brief          Implements class for result set processing
  @see            

\if EMIT_LICENCE

    ========== licence begin  GPL
    Copyright (c) 2001-2005 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



\endif
*/
#ifndef IFR_RESULTSET_H
#define IFR_RESULTSET_H

#include <stdlib.h>
#include "SAPDB/Interfaces/Runtime/IFR_ErrorHndl.h"
#include "SAPDB/Interfaces/Runtime/IFR_ParseInfo.h"
#include "SAPDB/Interfaces/Runtime/IFR_Connection.h"
#include "SAPDB/Interfaces/Runtime/IFR_FetchInfo.h"
#include "SAPDB/Interfaces/Runtime/IFR_FetchChunk.h"

class IFR_RowSet;
class IFR_UpdatableRowSet;

/**
   @brief A class for representing a database result set
   @ingroup IFR_Common
   A database result set is usually generated by executing a statement that queries 
   the database.

   Select statements, catalog functions, and some procedures create result sets.
   For example, the following SQL statement creates a result set containing all
   the rows and columns in the DUAL table:

     <code>SELECT * FROM DUAL</code>

   A result set can be empty, which is different from no result set at all. For
   example, the following SQL statement creates an empty result set:

     <code>SELECT * FROM DUAL WHERE 1 = 2</code>
 
   A IFR_ResultSet object maintains a cursor pointing to its current row of data.
   Initially the cursor is positioned before the first row. The <code>next</code>
   method moves the cursor to the next row, and because it returns 
   <code>IFR_NO_DATA_FOUND</code> when there are no more rows in the IFR_ResultSet
   object, it can be used in a while loop to iterate through the result set.

   Example for creating a <code>IFR_ResultSet</code> object:
     
     <code>
     IFR_Statement *stmt = conn->createStatement (); <br>
     stmt->execute ("SELECT * FROM DUAL"); <br>
     IFR_ResultSet *rs = stmt->getResultSet (); <br>
     rs->next(); <br>
     </code>

   To speed up the time used by retrieving the data from the database, the
   IFR_ResultSet class supports so called block cursors, which can return more
   than one row at a time. The rows returned by a block cursor are called rowset.
   The result set is fixed, the rowset is not - it changes position and contents
   each time a new set of rows is retrieved from the database.

   To use block cursors, the method <code>setRowSetSize()</code> has to be used   
   with a parameter greater than 1.

   Navigation within the data the IFR_ResultSet object represents is done by the
   use of navigation methods like <code>first()</code>, <code>next()</code>,
   <code>previous()</code>, <code>relative()</code> etc.

   In case of block cursors, after applying the navigation methods, the cursor
   points to the actual rowset. Assuming for example a result set size of 50
   and a rowset size of 10. Then in the following sequence the block cursor points 
   to the indicated rows:

   - first()    : Rows  1 - 10 of the result set
   - next()     : Rows 11 - 20 of the result set
   - next()     : Rows 21 - 30 of the result set
   - previous() : Rows 11 - 20 of the result set
   - last()     : Rows 41 - 50 of the result set

   The rowset can be retrieved by the use of the moethod <code>getRowSet()</code>.   

   To perform operations that operate on a single row withihnthe rowset when multiple 
   rows have been fetched, the application must first indicate which row is the current 
   row. When a block cursor first returns a rowset, the current row is the first row of the
   rowset. To change the current row in the rowset, the application calls the rowset method
   <code>setPos()</code>.

   On the current row, the data of a certain column can be retrieved by calling the
   rowset method <code>getObject()</code>.

   Data fetched from the database is returned to the application in variables that
   the application has allocated for this purpose. Before this can be done, the 
   application must associate,mor bind, these variables to the columns of the result
   set. Applications can bind as many or as few columns of the result set as they
   choose, including binding no columns at all.

   Binding of columns is done by calls to the method <code>bindColumn()</code>.
   Depending of the rowset size, the column binding can be done for more than
   one row.

   After positioning the cursor by the use of the navigation methods, the data
   from the database is filled into the bounded column variables by a call to
   the rowset method <code>fetch()</code>. In case of block cursors, the number
   of rows actually filled can be determined by the use of the result set method 
   <code>getFetchedRows()</code>.

   For unbounded columns, data can filled into application variables with
   <code>getObject()</code>, or - in case of block cursors - by calling
   <code>setPos()</code> on the rowset and then calling <code>getObject()</code>.

 */
class IFR_ResultSet 
    : public IFRUtil_RuntimeItem, 
      public IFR_ConnectionItem 
{
     friend class IFR_RowSet;
     friend class IFR_UpdatableRowSet;

public:

    enum ResultSetConstants {
        IFR_DEFAULT_FETCHSIZE      = 32767,
        IFR_POSITION_BEFORE_FIRST  = 1,
        IFR_POSITION_INSIDE        = 2,
        IFR_POSITION_AFTER_LAST    = 3,
        IFR_POSITION_NOT_AVAILABLE = 4
    };

  /**
   * Creates a new result set object. The position will be <i>before the first row</i>,
   * and the preferred direction will be <code>IFR_ResultSet::IFR_FETCH_FORWARD</code>.
   * @param connection the current connection.
   * @param fetchInfo short info and column names.
   * @param statement the statement that produced this result set.
   * @param fetchSize the maximum number of rows to fetch at once, use <code>-1</code> 
   *        for default fetch size.
   * @param empty True if the result set is empty.
   * @param maxRows the last row to fetch, use <code>0</code> to disable.
   */
  IFR_ResultSet (IFR_Connection& connection,
                 IFR_FetchInfo& fetchInfo,
                 IFR_Statement& statement,
                 IFR_Int2 fetchSize,
                 int maxRows,
                 IFR_Int4 concurType,
                 IFR_Int4 type,
                 IFR_Bool empty,
                 IFR_FetchChunk *firstChunk,
                 IFR_Bool closeOnLast,
                 IFR_Bool& memory_ok);
    

  /**
   * Destructor for Resultset.
   */
  ~IFR_ResultSet();

  /**
   * Returns the connection object for this resultset. 
   */
  IFR_Connection *getConnection() const;

  /**
   * Binds a user supplied memory buffer to a host parameter.
   *
   * @param paramIndex parameter number, ordered sequentially in increasing
   *        parameter order, starting at 1.
   * @param paramType the type of the parameter.
   * @param paramAddr a pointer to a buffer for the parameter's data.
   * @param paramLengthIndicator pointer to parameter length or indicator
   * @param paramLen the length of the parameter buffer in bytes.
   * @param terminate Specifies that the output buffer should be finished
   *        with a C style zero terminator. The <code>terminated</code> flag 
   *        works only for the hostvar type character (ASCII, UCS2 or UTF8).
   *
   * @return <code>IFR_OK</code> if binding was successful; <code>IFR_NOT_OK</code>
   *         if wrong parameterIndex.
   * @todo: Indicator handling and truncation handling
   */
  IFR_Retcode bindColumn (const IFR_UInt4 paramIndex, 
                          const IFR_HostType paramType, 
                          void *paramAddr,
                          IFR_Length *paramLengthIndicator,
                          const IFR_Length paramLen = -1,
                          IFR_Bool terminate=IFR_TRUE);

  /**
   * Binds a user supplied memory buffer to a host parameter.
   *
   * @param paramIndex parameter number, ordered sequentially in increasing
   *        parameter order, starting at 1.
   * @param paramType the type of the parameter.
   * @param paramAddr a pointer to a buffer for the parameter's data.
   * @param paramLengthIndicator pointer to parameter length or indicator
   * @param paramPosIndicator pointer to start position of non-integral data to read
   * @param paramLen the length of the parameter buffer in bytes.
   * @param terminate Specifies that the output buffer should be finished
   *        with a C style zero terminator. The <code>terminated</code> flag 
   *        works only for the hostvar type character (ASCII, UCS2 or UTF8).
   *
   * @return <code>IFR_OK</code> if binding was successful; <code>IFR_NOT_OK</code>
   *         if wrong parameterIndex.
   * @todo: Indicator handling and truncation handling
   */
  IFR_Retcode bindColumn (const IFR_UInt4 paramIndex, 
                          const IFR_HostType paramType, 
                          void *paramAddr,
                          IFR_Length *paramLengthIndicator,
                          IFR_Length *paramPosIndicator,
                          const IFR_Length paramLen = -1,
                          IFR_Bool terminate=IFR_TRUE);

    /**
     * Clears the information about the columns that have been bound.
     * @return IFR_OK always.
     */ 
    IFR_Retcode clearColumns();

  /**
   * Sets the size of the row array of bounded parameters.
   * @param rowsetsize the number of rows.
   * @return <code>IFR_OK</code> if success
   *         <code>IFR_NOT_OK</code> otherwise
   */
  IFR_Retcode setRowSetSize (IFR_UInt4 rowsetsize);

  /**
   * Gets the size of the row array.
   * @return the size of the array of bounded parameters.
   */
  IFR_UInt getRowSetSize ();

  /**
   * @brief Gets the row status array.
   * @return A pointer to the first element of the row status array.
   */
  const IFR_Retcode *getRowStatus() const;

  /**
   * Gets number of rows in the current result set
   * @return number of rows in result set
   **/
  IFR_Int4 getResultCount ();

  /**
   * @brief Retrieves the rowset returned by block cursor operations.
   *
   * @return <code>*rowset</code> if the resultset object has a rowset
             <code>NULL</code> otherwise.
   */
  IFR_RowSet *getRowSet ();

  /**
   * @brief Retrieves the updatable rowset returned by block cursor operations.
   *
   * @return <code>*rowset</code> if the resultset object has a rowset
             <code>NULL</code> otherwise.
   */
  IFR_UpdatableRowSet *getUpdatableRowSet ();

  /**
   * Gets the number of rows actually fetched into bounded parameters.
   * @return number og rows fetched.
   */
  IFR_UInt getFetchedRows ();

  /**
   * Moves the cursor to the given row number in
   * this <code>IFR_ResultSet</code> object.
   *
   * <p>If the row number is positive, the cursor moves to 
   * the given row number with respect to the
   * beginning of the result set. The first row is row 1, the second
   * is row 2, and so on. 
   *
   * <p>If the given row number is negative, the cursor moves to
   * an absolute row position with respect to
   * the end of the result set.  For example, calling the method
   * <code>absolute(-1)</code> positions the 
   * cursor on the last row; calling the method <code>absolute(-2)</code>
   * moves the cursor to the next-to-last row, and so on.
   *
   * <p>An attempt to position the cursor beyond the first/last row in
   * the result set leaves the cursor before the first row or after 
   * the last row.
   *
   * @param row the number of the row to which the cursor should move.
   *        A positive number indicates the row number counting from the
   *        beginning of the result set; a negative number indicates the
   *        row number counting from the end of the result set
   * @return <code>IFR_OK</code> if the cursor is on the result set;
   * <code>IFR_NO_DATA_FOUND</code> otherwise;
   * <code>IFR_NOT_OK</code> if a database access error occurs.
   */
  IFR_Retcode absolute (int row);

  /**
   * Moves the cursor down one row from its current position.
   * A <code>IFR_ResultSet</code> cursor is initially positioned
   * before the first row; the first call to the method
   * <code>next</code> makes the first row the current row; the
   * second call makes the second row the current row, and so on. 
   *
   * <P>A <code>IFR_ResultSet</code> object's
   * warning chain is cleared when a new row is read.
   *
   * @return <code>IFR_OK</code> if the new current row is valid; 
   * <code>IFR_NO_DATA_FOUND</code> if there are no more rows;
   * <code>IFR_NOT_OK</code> if a database access error occurs
   */
  IFR_Retcode next ();

  /**
   * Moves the cursor a relative number of rows, either positive or negative.
   * Attempting to move beyond the first/last row in the
   * result set positions the cursor before/after the
   * the first/last row. Calling <code>relative(0)</code> is valid, but does
   * not change the cursor position.
   *
   * <p>Note: Calling the method <code>relative(1)</code>
   * is identical to calling the method <code>next()</code> and 
   * calling the method <code>relative(-1)</code> is identical
   * to calling the method <code>previous()</code>.
   *
   * @param relativePos an <code>int</code> specifying the number of rows to
   *        move from the current row; a positive number moves the cursor
   *        forward; a negative number moves the cursor backward
   * @return <code>IFR_OK</code> if the cursor is on a row;
   *         <code>IFR_NO_DATA_FOUND</code> otherwise;
   *         <code>IFR_NOT_OK</code> if a database access error occurs,
   *         there is no current row, or the result set type is 
   *         <code>IFR_TYPE_FORWARD_ONLY</code>
   */
  IFR_Retcode relative (int relativePos);

  /**
   * Moves the cursor to the previous row in this
   * <code>IFR_ResultSet</code> object.
   *
   * @return <code>IFR_OK</code> if the cursor is on a valid row; 
   * <code>IFR_NO_DATA_FOUND</code> if it is off the result set;
   * <code>IFR_NOT_OK</code> if a database access error
   * occurs or the result set type is <code>IFR_TYPE_FORWARD_ONLY</code>
   */
  IFR_Retcode previous ();

  /**
   * Moves the cursor to the first row in
   * this <code>IFR_ResultSet</code> object.
   *
   * @return <code>IFR_OK</code> if the cursor is on a valid row;
   * <code>IFR_NO_DATA_FOUND</code> if there are no rows in the result set;
   * <code>IFR_NOT_OK</code> if a database access error
   * occurs or the result set type is <code>IFR_TYPE_FORWARD_ONLY</code>
   * 
   */
  IFR_Retcode first ();

  /**
   * Moves the cursor to the last row in
   * this <code>IFR_ResultSet</code> object.
   *
   * @return <code>IFR_OK</code> if the cursor is on a valid row;
   * <code>IFR_NO_DATA_FOUND</code> if there are no rows in the result set
   * <code>IFR_NOT_OK</code> if a database access error
   * occurs or the result set type is <code>IFR_TYPE_FORWARD_ONLY</code>
   */
  IFR_Retcode last();

  /**
   * Moves the cursor to the end of this <code>IFR_ResultSet</code> object.
   * @return <code>IFR_OK</code> if success
   *         <code>IFR_NOT_OK</code> if a dabase access error occurs
   */ 
  IFR_Retcode afterLast ();

  /**
   * Moves the cursor in front of this <code>IFR_ResultSet</code> object.
   * @return <code>IFR_OK</code> if success
   *         <code>IFR_NOT_OK</code> if a dabase access error occurs
   */
  IFR_Retcode beforeFirst ();

  /**
   * Closes this result set. Further operations are not allowed.
   */
  void close ();

  /**
   * Returns the type of this result set.  The type is determined by
   * the statement that created the result set.
   *
   * @return <code>IFR_TYPE_FORWARD_ONLY</code>, <code>IFR_TYPE_SCROLL_INSENSITIVE</code>, or
   * <code>IFR_TYPE_SCROLL_SENSITIVE</code>
   */
    inline IFR_Int4 getType() const
    {
        return m_type;
    }

  /**
   * Returns the fetch size for this <code>IFR_ResultSet</code> object
   * @return the current fetch size for this <code>IFR_ResultSet</code> object.
   */
  IFR_Int2 getFetchSize ();

  /**
   * Gives a hint as to the number of rows that should be fetched from the database when
   * more rows are needed for this <code>IFR_ResultSet</code> object. If not called, a default
   * fetch size is used.
   * @param fetchSize the number of rows to fetch.
   * @return <code>IFR_OK</code> if success,
             <code>IFR_NOT_OK</code> otherwise
   */
  IFR_Retcode setFetchSize (IFR_Int2 fetchSize);

  /**
   * Retrieves whether the cursor is before the first row in this <code>IFR_ResultSet</code> object. 
   *
   * @return <code>true</code> if the cursor is before the first row; <code>false</code> if the 
   * cursor is at any other position or the result set contains no rows.
   */
  bool isBeforeFirst ();

  /**
   * Retrieves whether the cursor is after the last row in this <code>IFR_ResultSet</code> object.
   *
   * @return <code>true</code> if the cursor is before the first row; <code>false</code> if the 
   * cursor is at any other position or the result set contains no rows.
   */
  bool isAfterLast ();

  /**
   * Checks if columns are bound which have the position read indicator set.
   *
   * @return <code>true</code> if at least one column has been bound with position
   *         indicator set, <code>false</code> otherwise.
   */
  bool hasPositionedRead ();

  /**
   * Retrieves the current row number. The first row is number 1, the second number 2, and so on.
   *
   * @return the current row number; 0 if there is no current row.
   */
  int getRow ();

  /**
   * Returns the SQL statement that generated the result set
   *
   * @return pointer to the statement
   */
  const IFR_Statement* getStatement () const;

  /**
   * Returns true, if the result set is updatable
   *
   * @return true or false
   */
  const IFR_Bool isUpdatable () const;

  /**
   * Returns the parameter vector of result set
   *
   * @return pointer to the vector
   */
  const IFRUtil_Vector<IFR_Parameter>* getParamVector () const;

  /**
   * @brief Retrieves a <code>IFR_ResultSetMetaData</code> object.
   * Retrieves a <code>IFR_ResultSetMetaData</code> object that contains information 
   * about the columns of this <code> IFR_ResultSet</code> object. 
   *
   * @return A <code>IFR_ResultSetMetaData</code> object that describes the columns or
   * null if the meta data cannot retrieved. 
   */
  IFR_ResultSetMetaData* getResultSetMetaData();

  /**
   * Asserts that the result set is not closed.
   * @return <code>IFR_OK</code> if result set is not closed;
   * <code>IFR_NOT_OK</code> otherwise.
   */
  IFR_Retcode assertNotClosed ();

protected:
  /**
   * Initializes member variables of the <code>IFR_ResultSet</code> object.
   * @param empty True if there are no rows in this result set.
   */
  void initializeFields (IFR_Bool empty);

  /**
   * Gets the conversion object for the specified column
   * @param colIndex the index of the column (numbering starts at 1)
   * @return A <code>IFRConversion_Converter</code> object, if any
   *         A null pointer, if conversion object cannot be found or wrong index
   */
  IFRConversion_Converter *findColumnInfo (int colIndex);

    /**
     * Gets the conversion objects from the fetch info
     * @return The list of converters in the fetch information.
     */
    IFRConversion_ConverterList& getColInfo ()
    {
        return m_FetchInfo->getColInfo();
    }

  /**
   * Gets the current data part the cursor of the <code>IFR_ResultSet</code> object is
   * pointing to
   * @param part the data part that will be set to the actual data
   * @return <code>IFR_OK</code> if cursor points to a valid position within the result set
             <code>IFR_NOT_OK</code> if cursor points to an invalid position within the result set
             <code>IFR_NO_DATA_FOUND</code> if there is no current data chunk
   */
  IFR_Retcode getCurrentData (IFRPacket_DataPart& part);

private:

  /**
   * Asserts that the result set is not a <code>IFR_FORWARD_ONLY</code> result.
   *
   * @return <code>IFR_OK</code> if result set is not a <code>IFR_FORWARD_ONLY</code> result;
   * <code>IFR_NOT_OK</code> otherwise.
   */
  IFR_Retcode assertNotForwardOnly ();

  /**
   * Asserts that the row set of a result set does not match to the concurrency defined
   * in the statement (IFR_Statement::READ_ONLY or  <code>IFR_Statement::UPDATABLE</code>).
   *
   */
  void assertWrongConcurrency ();

  /**
   * Check whether to honor <code>m_MaxRows</code>.
   */
  bool maxRowIsSet ();

  /**
   * Check whether the number of rows is there.
   */
  bool rowsInResultSetKnown ();

  /**
   * Executes an absolute fetch, to the physical row given.
   * @param physicalRow the physical row. It is assumed that it is > 0, and 
   * less than maxrows/rowsInResultSet
   *
   * @param res <code>true</code> if the fetch did position at the row, <code>false</code>
   * otherwise.
   *
   * @return <code>IFR_OK</code> if fetch success; <code>false</code> if database access error
   * occurs.
   */
  IFR_Retcode fetchAbsoluteUp (int physicalRow, bool &res);

  /**
   * Executes an absolute fetch, to the physical row given.
   * @param physicalRow the physical row. It is assumed that it is < 0, and 
   * within the possibly set m_MaxRows limit.
   *
   * @param res <code>true</code> if the fetch did position at the row, <code>false</code>
   * otherwise.
   *
   * @return <code>IFR_OK</code> if fetch success; <code>false</code> if database access error
   * occurs.
   */
  IFR_Retcode fetchAbsoluteDown (int physicalRow, bool& res);

  /**
   * Returns absolute position in result set from negative position
   * @param row the row index to be inverted
   * @return the inverted row position
   */
  int invertPosition (int row);

  /**
   * Updates the current chunk. 
   * Also consistently:
   * <ul>
   *  <li>moves the position states to <code>IFR_POSITION_INSIDE</code></li>
   *  <li>updates the chunk size of necessary</li>
   *  <li>eventually updates the number of rows in this result set</li>
   * </ul>
   *
   * @param newChunk the new chunk to set.
   */
  IFR_Retcode  setCurrentChunk (IFR_FetchChunk* newChunk);

  /**
   * Sets the current fetch chunk to 0, hereby possibly
   * deleting the old one.
   */
  void clearCurrentChunk();
  
  /**
   * Updates statistical information like number of rows in result set etc.
   **/
  void updateRowStatistics ();

  /**
   * Sets the number of rows currently contained in the <code>IFR_ResultSet</code> object
   * @param rows number of rows in result set
   **/
  void setRowsInResultSet (int rows);

  /**
   * Returns the logical position in the current data chunk
   * @return the logical position in the current data chunk
   **/
  int getInternalRow ();

  /**
   * Determines how many rows are in the result. This is done by
   * doing step-wise <code>FETCH ABSOLUTE</code> command to perform 
   * a binary search.
   * @return <code>IFR_OK</code> if the determining the result set size succeeds, 
   *   <code>IFR_NOT_OK</code> if a database error occurs while accessing the result 
   *   set.
   * @todo This function should be possible to get from the database kernel.
   */
  IFR_Retcode getRowsInResult ();
  
  /**
   * Fetch the next chunk, moving forward over the result set. 
   */
  IFR_Retcode fetchNextChunk ();

  /**
   * Executes a FETCH FIRST, and stores the result internally.
   * @return <code>IFR_OK</code> if the cursor is positioned correctly;
   * <code>IFR_NOT_OK</code> if a database access error occurs.
   */
  IFR_Retcode fetchFirst ();

  /**
   * Executes a FETCH LAST, and stores the result internally.
   * @return <code>IFR_OK</code> if the cursor is positioned correctly;
   * <code>IFR_NOT_OK</code> if a database access error occurs.
   */
  IFR_Retcode fetchLast ();

  /**
   * Fills the actual rowset with data
   * @return <code>IFR_OK</code> if success,
   *         <code>IFR_NOT_OK</code> if a database access error occurs
   **/
  IFR_Retcode fetch ();

    /**
     * Converts data into the bounded columns
     * @param startrow Index of first row in result set to convert data from
     *                 (numbering starts at 1)
     * @param count Number of rows to convert and fill.
     * @return <code>IFR_OK</code> if success
     *         <code>IFR_NOT_OK</code> otherwise
     */
    IFR_Retcode fillRowsWithData(IFR_Int4 startrow,
                                 IFR_Int4 count);

  /**
   * Positions the cursor to an absolute position within result set
   * @param row the position the cursor should point to
   * @return <code>IFR_OK</code> if success
             <code>IFR_NOT_OK</code> if a database access error occurs
             <code>IFR_NO_DATA_FOUND</code> if row positions outside result set
   **/
    IFR_Retcode mfAbsolute (int row);

  /**
   * Positions the cursor to the next position within result set
   * @return <code>IFR_OK</code> if success
             <code>IFR_NOT_OK</code> if a database access error occurs
             <code>IFR_NO_DATA_FOUND</code> if outside result set
   **/
  IFR_Retcode mfNext ();

  /**
   * Positions the cursor to the first row of result set
   * @return <code>IFR_OK</code> if success
             <code>IFR_NOT_OK</code> if a database access error occurs
             <code>IFR_NO_DATA_FOUND</code> if no data at all
   **/
  IFR_Retcode mfFirst ();

  /**
   * Positions the cursor relative to current position within result set
   * @param relativePos the relative cursor position
   * @return <code>IFR_OK</code> if success
             <code>IFR_NOT_OK</code> if a database access error occurs
             <code>IFR_NO_DATA_FOUND</code> if outside result set
   **/
  IFR_Retcode mfRelative (int relativePos);

  /**
   * Positions the cursor relative to the previous position within result set
   * @return <code>IFR_OK</code> if success
             <code>IFR_NOT_OK</code> if a database access error occurs
             <code>IFR_NO_DATA_FOUND</code> if outside result set
   **/
  IFR_Retcode mfPrevious ();

  /**
   * Positions the cursor to the last row of result set
   * @return <code>IFR_OK</code> if success
             <code>IFR_NOT_OK</code> if a database access error occurs
             <code>IFR_NO_DATA_FOUND</code> if no data at all
   **/
  IFR_Retcode mfLast ();

  void createRowSet (IFR_Bool& memory_ok);

  /**
   * Initializes a packet for a GETVAL operation.
   * @param requestpacket the actual request packet
   * @param segment the segment for sending the getval message
   * @param datapart the long data part to be added to the segment
   * @return <code>IFR_OK</code> on success
   *         <code>IFR_NOT_OK</code> otherwise
   */
  IFR_Retcode getvalInitPacket(IFRPacket_RequestPacket& requestpacket,
			       IFRPacket_RequestSegment& segment,
			       IFRPacket_LongDataPart &datapart);

  // will be used in IFR_UpdatableResultSet
protected:
  IFR_Connection *m_Connection; //!< the current connection
  IFR_Statement* m_Statement;  //!< the statement that created the <code>IFR_ResultSet</code> object

private:

  IFR_FetchInfo* m_FetchInfo;  //!< the <code>IFR_FetchInfo</code> object
  IFRUtil_Vector<IFR_Parameter> *m_ParamVector;  //!< the parameters that are bound are set here.
  int m_rowsetsize; //!< the rowset size

  /**
   * The <code>m_MaxRows</code> value. This is set to -1 if no max rows
   * are set.
   */
  int m_MaxRows;
  bool m_IsClosed; //!< flag for closed result set

  /**
   * The fetch size that is set.
   */
  IFR_Int2 m_FetchSize;

  /**
   * The status of the position, i.e. one of the <code>IFR_POSITION_XXX</code> constants.
   */
  int m_PositionState;

  /**
   * The status of the current chunk.
   */
  int m_PositionStateOfChunk;

  IFR_Int4 m_concurType;              //!< updatable or read only
  IFR_Int4 m_type;                    //!< forward-only ?   

  bool m_Empty;                       //!< is this result set totally empty
  int m_SafeFetchSize;                //!< The fetch size that is known to be good.
                                      //!< This one is used when going backwards in the result set.
  int m_LargestKnownAbsPos;           //!< largest known absolute position to be inside.
  int m_MaxRowsOutSideResult;         //!< flag: -1 -> maxrows is inside the result
                                      //!<        0 -> unknown
                                      //!<        1 -> maxrows is outside the result
  int m_RowsInResultSet;              //!< the number of rows in this result set, or -1 if not known
  int m_FetchedRows;                  //!< the number of rows fetched into the rowset
  bool m_hasposread;                  //!< True, if result set has columns bound with position indicator set
    IFR_Bool m_close_on_last;         //!< Whether to signal the statement that the last row had 
                                      //!< been fetched.
    /**
     * The current rowset.
     */
    IFR_RowSet *m_rowset;
    IFR_UpdatableRowSet *m_upd_rowset;
    
    IFR_UInt4 m_rowsetstartrow;         //!< the start row of the current row set
    
    IFRUtil_Vector<IFR_Retcode> m_rowstatusarray; //!< The row status array of the result set.
    
    /**
     * The data of the last fetch operation.
     */
    IFR_FetchChunk* m_CurrentChunk;
    
public:
    /**
     * tracing
     */
    friend IFR_TraceStream& operator << (IFR_TraceStream& s, const IFR_ResultSet& resultset);
};

/**
   Traces the result set object. 
   Currently are traced:
    - The position state 
    - The chunk state
 */
IFR_TraceStream& operator << (IFR_TraceStream& s, const IFR_ResultSet& resultset);

#endif // IFR_RESULTSET_H
