/* ----------------------------------------------------------------------------
 *
 * Raima Database Manager
 *
 * Copyright (c) 2011 Raima Inc.,  All rights reserved.
 *
 * Use of this software, whether in source code format, or in executable,
 * binary object code form, is governed by the Birdstep LICENSE which
 * is fully described in the LICENSE.TXT file, included within this
 * distribution of files.
 *
 * ----------------------------------------------------------------------------
 */

#ifndef _CURSOR_H
#define _CURSOR_H

#include "DbTypes.h"

namespace RDM_CPP {

/*! \brief The Cursor base class
 * 
 * This Cursor class provides the base cursor implmentation.
 *
 * This is a class with very little overhead - a single pointer - that
 * is a 'smart pointer' (i.e. will automatically get destroyed when the last
 * reference is removed).
 *
 * To keep the overhead down this class should have no virtual functions.
*/
/*lint -esym(1790,RDM_CPP::Cursor) */
class PUBLIC_CLASS Cursor {
public:
    /* Handle more than one reference to the underlying cursor */
    /*! \brief Cursor Default Constructor

        The default constructor, copy constructor, assignment operator, and 
        destructor implement a smart pointer for the Cursor interface and it's
        generated subclasses.  The number of references to the underlying 
        implemention object will be maintained.  When the number of references 
        to an implementation object is down to zero the object will be released.

        The default constructor will ininitiaze the number of references to the 
        underlying implementation object to one.
    */
    Cursor (void) throw ();
    
    /*! \brief Cursor Copy Constructor

        The default constructor, copy constructor, assignment operator, and 
        destructor implement a smart pointer for the Cursor interface and it's
        generated subclasses.  The number of references to the underlying 
        implemention object will be maintained.  When the number of references 
        to an implementation object is down to zero the object will be released.

        The copy constructor will increment the number of references to the 
        underlying implementation object by one.
    */
    Cursor (const Cursor& cursor) throw ();
    
    /*! \brief Cursor assignment operator
     
        The default constructor, copy constructor, assignment operator, and 
        destructor implement a smart pointer for the Cursor interface and it's
        generated subclasses.  The number of references to the underlying implemention object will be
        maintained.  When the number of references to an implementation object is down to
        zero the object will be released.

        The assignment will increment the number of references to the underlying implementation
        object by one for the new reference.
    */
    Cursor& operator = (const Cursor& cursor) throw ();
    
    /*! \brief Cursor Destructor
        
      The default constructor, copy constructor, assignment operator, and 
      destructor implement a smart pointer for the Cursor interface and it's
      generated subclasses.  The number of references to the underlying 
      implemention object will be maintained.  When the number of references to
      an implementation object is down to zero the object will be released.

      The destructor will decrement the number of references to the underlying 
      implementation object by one.
    */
    ~Cursor ();

    /*! \brief Get the record type for the current cursor position
      
       \return The record type
    */
    recordType GetType (void) const throw (const rdm_exception&);

    /*! \brief Get a count of the number of records contained in a cursor collection
      
        \return The number of records contained in the cursor collection
  
        \par Locking Requirements in ReadOnly-Strict/Shared-Strict Modes
        A Snapshot transaction or a Read transaction with locks on the relevant 
        cursor record(s)

        \throws 
        rdm_exception (S_TRPRECOMMITTED, S_INVCURSOR_OP, S_NOTLOCKED)
      
        \par Library
        rdmcppapi-12
    */
    uint64_t GetCount (void) const throw (const rdm_exception&);

    /*! \brief Mark the end of an array of record types
      
        Use this when setting up an array of record types that is
        passed in to BeginRead or BeginUpdate.
      
        \par Locking Requirements
        None

        \return A record type end marker

        \par Library
        rdmcppapi-12
    */
    static recordType NoMoreTypes (void) throw () {
        return (recordType) 0;
    }

    /*! \brief Delete the record at the current cursor position
     
        This method removes the current record of cursor from the
        database.

        After the record has been removed the cursor will no longer have a 
        current record as it has been removed from the database.  However it will 
        maintain a virtual position which be the position between the 
        records neighboring the record that was deleted.  The neighboring
        records are dependent upon on the type of the source cursor.

        \return The Cursor you are using

        \par Locking Requirements in Shared/Shared-Strict Modes
        An Update transaction with locks on the relevant cursor record(s)

        \throws 
        rdm_exception (S_TRPRECOMMITTED, S_INVCURSOR_OP, S_SET_GONE, S_RECORD_GONE, S_NOCR, S_NOTRANS, S_NOTLOCKED)
      
        \par Library
        rdmcppapi-12
    */
    /*lint -esym(534,RDM_CPP::Cursor::Delete) (the return value does not need to be checked) */
    Cursor Delete (void) const throw (const rdm_exception&);
    
    /*! \brief Disconnect and Delete the record at the current cursor position
     
        This method disconnects the current record of cursor from all
        sets and removes it from the database.

        After the record has been removed the cursor will no longer have a 
        current record as it has been removed from the database.  However it will 
        maintain a virtual position which be the position between the 
        records neighboring the record that was deleted.  The neighboring
        records are dependent upon on the type of the source cursor.

        \return The Cursor you are using
        
        \par Locking Requirements in Shared/Shared-Strict Modes
        An Update transaction with locks on the relevant cursor record(s)

        \throws 
        rdm_exception (S_TRPRECOMMITTED, S_INVCURSOR_OP, S_SET_GONE, S_RECORD_GONE, S_NOCR, S_NOTRANS, S_NOTLOCKED)
      
        \par Library
        rdmcppapi-12
    */
    /*lint -esym(534,RDM_CPP::Cursor::DisconnectAndDelete) (the return value does not need to be checked) */
    Cursor DisconnectAndDelete (void) const throw (const rdm_exception&);

    /* Basic navigation for this cursor */
    /*! \brief Navigate to the first record in the Cursor collection

        This method will position a cursor to the first record in the
        collection.  If there are no records in the collection then the
        cursor will be positioned to AfterLast.

        There is a type specific version of this method in all generated subclasses.

        \return The Cursor you are using
        
        \par Locking Requirements in ReadOnly-Strict/Shared-Strict Modes
        A Snapshot transaction or a Read transaction with locks on the relevant 
        cursor record(s)

        \throws rdm_exception (S_TRPRECOMMITTED, S_INVCURSOR_OP, S_SET_GONE, S_RECORD_GONE, S_NOTLOCKED)
 
        \par Library
        rdmcppapi-12
    */
    /*lint -esym(534,RDM_CPP::Cursor::First) (the return value does not need to be checked) */
    const Cursor& First (void) const throw (const rdm_exception&) { return this->_First (); };
    
    /*! \brief Navigate to the next record in the Cursor collection
      
        This method will position a cursor to the next record in the
        collection.

        If the cursor was positioned to the last record in the collection then
        the cursor will be positioned to AfterLast.

        If cursor was positioned to AfterLast then the function will
        throw a rdm_exception with the S_INVALID_ITERATION error code.

        There is a type specific version of this method in all generated subclasses.
        
        \return The Cursor you are using
        
        \par Locking Requirements in ReadOnly-Strict/Shared-Strict Modes
        A Snapshot transaction or a Read transaction with locks on the relevant 
        cursor record(s)

        \throws rdm_exception (S_TRPRECOMMITTED, S_INVCURSOR_OP, S_SET_GONE, S_RECORD_GONE, S_NOTLOCKED)
 
        \par Library
        rdmcppapi-12
    */
    /*lint -esym(534,RDM_CPP::Cursor::Next) (the return value does not need to be checked) */
    const Cursor& Next (void) const throw (const rdm_exception&) { return this->_Next (); };
    
    /*! \brief Navigate to the previous record in the Cursor collection
    
        This method will position a cursor to the previous record in the
        collection.

        If the cursor was positioned to the first record in the collection
        then the cursor will be positioned to BeforeFirst.

        If the cursor was positioned to BeforeFirst then the function will
        throw rdm_exception with the S_INVALID_ITERATION error code.
        
        \return The Cursor you are using
        
        \par Locking Requirements in ReadOnly-Strict/Shared-Strict Modes
        A Snapshot transaction or a Read transaction with locks on the relevant 
        cursor record(s)

        \throws rdm_exception (S_TRPRECOMMITTED, S_INVCURSOR_OP, S_SET_GONE, S_RECORD_GONE, S_NOTLOCKED)
 
        \par Library
        rdmcppapi-12
    */
    /*lint -esym(534,RDM_CPP::Cursor::Prev) (the return value does not need to be checked) */
    const Cursor& Prev (void) const throw (const rdm_exception&) { return this->_Prev (); };
    
    /*! \brief Navigate to the last record in the Cursor collection
     
        This method will position a cursor to the last record in the
        collection.  If there are no records in the collection then the
        cursor will be positioned to BeforeFirst.

        There is a type specific version of this method in all generated subclasses.
        
        \return The Cursor you are using

        \par Locking Requirements in ReadOnly-Strict/Shared-Strict Modes
        A Snapshot transaction or a Read transaction with locks on the relevant 
        cursor record(s)

        \throws rdm_exception (S_TRPRECOMMITTED, S_INVCURSOR_OP, S_SET_GONE, S_RECORD_GONE, S_NOTLOCKED)
 
        \par Library
        rdmcppapi-12
    */
    /*lint -esym(534,RDM_CPP::Cursor::Last) (the return value does not need to be checked) */
    const Cursor& Last (void) const throw (const rdm_exception&) { return this->_Last (); };

    /* Operators instead of functions above */
    /*! \brief Prefix increment operator
     
        This method will position a cursor to the next record in the
        collection.

        If cursor was positioned to the last record in the collection then
        the cursor will be positioned to AfterLast.

        If cursor was positioned to AfterLast then the method will
        throw a rdm_exception with the error code S_INVALID_ITERATION.

        \return The Cursor you are using (positioned to the next record)

        \par Locking Requirements in ReadOnly-Strict/Shared-Strict Modes
        A Snapshot transaction or a Read transaction with locks on the relevant 
        cursor record(s)

        \throws rdm_exception (S_TRPRECOMMITTED, S_INVCURSOR_OP, S_SET_GONE, S_RECORD_GONE, S_NOTLOCKED, S_INVALID_ITERATION)
 
        \par Library
        rdmcppapi-12
    */
    const Cursor& operator ++ (void) const throw (const rdm_exception&) { return Next ();}
    
    /*! \brief Prefix decrement operator
     
        This method will position a cursor to the previous record in the
        collection.

        If cursor was positioned to the first record in the collection
        then the cursor will be positioned to BeforeFirst.

        If cursor was positioned to BeforeFirst then the method will
        throw a rdm_exception with the error code S_INVALID_ITERATION.

        \return The source Cursor you are using (positioned to the previous 
        record)

        \par Locking Requirements in ReadOnly-Strict/Shared-Strict Modes
        A Snapshot transaction or a Read transaction with locks on the relevant
        cursor record(s)

        \throws rdm_exception (S_TRPRECOMMITTED, S_INVCURSOR_OP, S_SET_GONE, S_RECORD_GONE, S_NOTLOCKED, S_INVALID_ITERATION)
 
        \par Library
        rdmcppapi-12
    */
    const Cursor& operator -- (void) const throw (const rdm_exception&) { return Prev ();}
    
    /*! \brief Obtain a Cursor for the current record type order by DBA
     
        Create a new recscan Cursor of records of the same type as the current 
        record of the source cursor.  Position the new cursor to the same record
        as the source cursor is positioned to. 
     
        \return A Cursor positioned to the same record the Cursor is 
                positioned to
        
        \par Locking Requirements
        None
      
        \throws rdm_exception (S_TRPRECOMMITTED, S_INVCURSOR_OP, S_NOMEMORY)

        \par Library
        rdmcppapi-12
    */
    Cursor GetRecordsAtRecord (void) const throw (const rdm_exception&);

    /*! \brief Obtain a Cursor for the current record type order by DBA
    
        Create a new recscan cursor doing of records of the same type as the 
        current record of the source cursor.  Position the new cursor at 
        BeforeFirst.

        \return A Cursor containing the same types of records as the records
                in source cursor, positioned at BeforeFirst, and ordered by DBA
        
        \par Locking Requirements
        None

        \throws 
        rdm_exception (S_TRPRECOMMITTED, S_INVCURSOR_OP, S_NOMEMORY)
      
        \par Library
        rdmcppapi-12
    */
    Cursor GetRecords (void) const throw (const rdm_exception&);
    
    /*! \brief Obtain a singleton Cursor for the source cursor's current record
       
        Create a new singleton cursor positioned to the same record as the 
        source cursor.

        If the source cursor is not at a valid record then a rdm_exception will
        be thrown.
     
        \return A singleton Cursor positioned at the record the source Cursor 
        is positioned to
        
        \par Locking Requirements
        None

        \throws 
        rdm_exception (S_TRPRECOMMITTED, S_INVCURSOR_OP, S_NOMEMORY, S_SET_GONE, S_RECORD_GONE, S_NOCR)
      
        \par Library
        rdmcppapi-12
    */
    Cursor GetSelf (void) const throw (const rdm_exception&) { return this->_GetSelf (); };
    
    /*! \brief Clone a cursor
    
        This method crates a cursor as a clone of the source cursor.  The
        resulting cursor will be of the same type, contain the same
        records, and will have the same position and current record as
        the source cursor.

        This is method will be intentionally hidden by the generated class
        derived for a specific database.
       
        \return A Cursor that is an exact clone of the source cursor

        \par Locking Requirements
        None

        \throws 
        rdm_exception (S_TRPRECOMMITTED, S_INVCURSOR_OP)
      
      
        \par Library
        rdmcppapi-12
    */
    Cursor Clone (void) const throw (const rdm_exception&) { return this->_Clone (); };

    /*! \brief Obtain the static BeforeFirst Cursor

        The 'BeforeFirst' cursor can be used in the comparison methods.
        The 'BeforeFirst' cursor is positioned at the 'BeforeFirst' position and 
        it's position can not be changed.

        \return A singleton Cursor at the BeforeFirst position
        
        \par Locking Requirements
        None

        \par Library
        rdmcppapi-12
    */
    static Cursor GetBeforeFirst (void) throw ();
    
    /*! \brief Obtain the static AfterLast Cursor

        The 'AfterLast' cursor can be used in the comparison methods.
        The 'AfterLast' cursor is positioned at the 'AfterLast' position and 
        it's position can not be changed.

        \return A singleton Cursor at the AfterLast position
        
        \par Locking Requirements
        None

        \par Library
        rdmcppapi-12
    */
    static Cursor GetAfterLast (void) throw ();
    
    /*! \brief Check to see if the Cursor in the the BeforeFirst position

        \retval true If the current cursor position is before the first record in the collection
        \retval false Otherwise
        
        \par Locking Requirements
        None
      
        \throws 
        rdm_exception (S_TRPRECOMMITTED, S_INVCURSOR_OP, S_SET_GONE, S_RECORD_GONE, S_LOST_POSITION)
      
        \par Library
        rdmcppapi-12
    */
    bool isBeforeFirst (void) const throw (const rdm_exception&);

    /*! \brief Position the cursor to BeforeFirst

        Position the cursor to the special BeforeFirst position.

        Navigating to the previous position from this special position will position
        the cursor to the last record in the cursor collection.  Navigationg forward will 
        throw a rdm_exception with the S_INVALID_ITERATION error code.
        
        \par Locking Requirements
        None
      
        \throws 
        rdm_exception (S_TRPRECOMMITTED, S_INVCURSOR_OP, S_SET_GONE, S_RECORD_GONE, S_LOST_POSITION)
      
        \par Library
        rdmcppapi-12
    */
    void BeforeFirst (void) const throw (const rdm_exception&);
    
    /*! \brief Check to see if the Cursor in the the AfterLast position

        \retval true If the current cursor position is after the last record in the collection
        \retval false Otherwise
        
        \par Locking Requirements
        None

        \throws 
        rdm_exception (S_TRPRECOMMITTED, S_INVCURSOR_OP, S_SET_GONE, S_RECORD_GONE, S_LOST_POSITION)
      
        \par Library
        rdmcppapi-12
    */
    bool isAfterLast (void) const throw (const rdm_exception&);

    /*! \brief Position the cursor to AfterLast

        Position the cursor to the special AfterLast position.

        Navigating to the previous position from this special position will position
        the cursor to the last record in the cursor collection.  Navigationg forward will 
        throw a rdm_exception with the S_INVALID_ITERATION error code.
        
        
        \par Locking Requirements
        None

        \throws 
        rdm_exception (S_TRPRECOMMITTED, S_INVCURSOR_OP, S_SET_GONE, S_RECORD_GONE, S_LOST_POSITION)
      
        \par Library
        rdmcppapi-12
    */
    void AfterLast (void) const throw (const rdm_exception&);

    /*! \brief Check to see where the cursor is positioned
       
        This function will return information about special conditions for a cursor's position.

        The enumeration values have the following meanings:

        - CURSOR_AT_RECORD         The cursor is positioned at a valid record
        - CURSOR_BETWEEN_RECORDS   The cursor is positioned between records
        - CURSOR_BETWEEN_KEYS      The cursor is positioned between key values
        - CURSOR_BEFORE_FIRST      The cursor is positioned before all records
        - CURSOR_AFTER_LAST        The cursor is positioned after all records
        - CURSOR_DELETED           The cursor whose current record has been deleted
        - CURSOR_KEY_CHANGED       The cursor whose key value has been changed
        - CURSOR_UNLINKED          The cursor whose curent record has been unlinked
        - CURSOR_RELINKED          The cursor whose curent record has been relinked
        - CURSOR_RECORD_GONE       The cursor had it's singleton record deleted
        - CURSOR_SET_GONE          The cursor had it's owner deleted
        - CURSOR_LOST_POSITION     The cursor had it's position lost

        As you navigate (using Next, Prev, First, Last, BeforeFirst, 
        AfterLast, or any of the Find* functions), use CreateRecord, 
        or create a cursor using any of the Db class Get methods the cursor will
        be in any of these states CURSOR_AT_RECORD, CURSOR_BETWEEN_RECORDS, 
        CURSOR_BETWEEN_KEYS, or CURSOR_BEFORE_FIRST.  Changes to the record 
        through this cursor or any other cursor may put the cursor in some 
        other state. For all these state changes except CURSOR_LOST_POSITION 
        a virtual position is maintained and you can navigate from this virtual
        position using Next and Prev. Other types of navigation based on this 
        cursor use the current record and not the virtual position.  Clone will
        make an exact copy with the exact same state, position, and current 
        record.

        \returns A RDM_CURSOR_POSITION value
       
        \par Locking Requirements
        None

        \throws 
        rdm_exception (S_TRPRECOMMITTED, S_INVCURSOR_OP, S_SET_GONE, S_RECORD_GONE, S_NOT_RELATED)
      
        \par Library
        rdmcppapi-12
    */
    RDM_CURSOR_POSITION CheckPosition (void) const throw (const rdm_exception&);
   
    /*! \brief Check to see if passed in cursor is positioned before the source
        cursor's current position

        This method compares the current position of source cursor relative 
        to secondary (passed in) cursor and will return TRUE if the position 
        for the primary cursor is before the position of the secondary cursor.

        If the cursor types are not the same the current record of the
        secondary cursor will be used and then converted to a position in the
        cursor type of source cursor. If the current record of the secondary 
        cursor is not a valid cursor position in the source a rdm_exception
        will be thrown.
    
        This more specifically means:

        - If the source cursor is a key cursor the comparison will be based on 
          key value.
        - If the source cursor is a record cursor the comparison will be based 
          on database address value
        - If the source cursor is a set member cursor the comparison will be 
          based on the order in the set chain
        - If the source cursor is a singleton cursor the comparison is only 
          valid if the secondary cursor and the source cursor are the same record
          (there is no order for a singleton)
        - If the record at the current position of the secondary cursor is not
          in the collection of the source cursor a rdm_exception will be thrown.
        - There are two distinct types of errors for the rdm_exception when the
          record in the secondary cursor is not found in the collection of
          the source cursor:
        - If records in cursor_secondary can never be in the collection
          of the source cursor based on the schema information (it is a
          different record type or from another database) then S_NOT_RELATED will
          be the error code in the rdm_exception.
        - If the record in the secondary cursor could be found in the
          collecion for the source cursor but is not (it has a different set
          owner) then S_NOT_IN_CURSOR will be the error code in the 
          rdm_exception.
        - In the case where the cursors are related but secondary cursor
          is in a special position (BeforeFirst/AfterLast) then the
          cursors must be of the same type to have a meaningful comparison
          (both key cursors based on the same key, both set cursors with
          the same owner, etc.).  If it is not a meaningful comparison
          S_NOT_IN_CURSOR is returned.

        \retval true If the secondary cursor's position is before the source
        cursor's current position
        \retval false Otherwise
        
        \par Locking Requirements
        None

        \throws 
        rdm_exception (S_TRPRECOMMITTED, S_INVCURSOR_OP, S_SET_GONE, S_RECORD_GONE, S_NOT_RELATED)
      
        \par Library
        rdmcppapi-12
    */
    bool isBefore (
        const Cursor& cursor /**< [in] The Cursor to compare against */
        ) const throw (const rdm_exception&);

    /*! \brief Check to see if passed in cursor is positioned before or at the
        source cursor's current position

        This method compares the current position of source cursor relative 
        to secondary (passed in) cursor and will return TRUE if the position 
        for the primary cursor is before or at the position of the secondary 
        cursor.

        If the cursor types are not the same the current record of the
        secondary cursor will be used and then converted to a position in the
        cursor type of source cursor. If the current record of the secondary 
        cursor is not a valid cursor position in the source a rdm_exception
        will be thrown.
    
        This more specifically means:

        - If the source cursor is a key cursor the comparison will be based on 
          key value.
        - If the source cursor is a record cursor the comparison will be based 
          on database address value
        - If the source cursor is a set member cursor the comparison will be 
          based on the order in the set chain
        - If the source cursor is a singleton cursor the comparison is only 
          valid if the secondary cursor and the source cursor are the same record
          (there is no order for a singleton)
        - If the record at the current position of the secondary cursor is not
          in the collection of the source cursor a rdm_exception will be thrown.
        - There are two distinct types of errors for the rdm_exception when the
          record in the secondary cursor is not found in the collection of
          the source cursor:
        - If records in cursor_secondary can never be in the collection
          of the source cursor based on the schema information (it is a
          different record type or from another database) then S_NOT_RELATED will
          be the error code in the rdm_exception.
        - If the record in the secondary cursor could be found in the
          collecion for the source cursor but is not (it has a different set
          owner) then S_NOT_IN_CURSOR will be the error code in the 
          rdm_exception.
        - In the case where the cursors are related but secondary cursor
          is in a special position (BeforeFirst/AfterLast) then the
          cursors must be of the same type to have a meaningful comparison
          (both key cursors based on the same key, both set cursors with
          the same owner, etc.).  If it is not a meaningful comparison
          S_NOT_IN_CURSOR is returned.

        \retval true If the secondary cursor's position is before or at the 
        source cursor's current position
        \retval false Otherwise
        
        \par Locking Requirements
        None

        \throws 
        rdm_exception (S_TRPRECOMMITTED, S_INVCURSOR_OP, S_SET_GONE, S_RECORD_GONE, S_NOT_RELATED)
      
        \par Library
        rdmcppapi-12
    */
    bool isBeforeAt (
        const Cursor& cursor /**< [in] The Cursor to compare against */
        ) const throw (const rdm_exception&);

    /*! \brief Check to see if passed in cursor is positioned at the same 
         record as the source cursor

        This method compares the current position of source cursor relative 
        to secondary (passed in) cursor and will return TRUE if the position 
        for the primary cursor is at the position of the secondary cursor.

        If the cursor types are not the same the current record of the
        secondary cursor will be used and then converted to a position in the
        cursor type of source cursor. If the current record of the secondary 
        cursor is not a valid cursor position in the source a rdm_exception
        will be thrown.
    
        This more specifically means:

        - If the source cursor is a key cursor the comparison will be based on 
          key value.
        - If the source cursor is a record cursor the comparison will be based 
          on database address value
        - If the source cursor is a set member cursor the comparison will be 
          based on the order in the set chain
        - If the source cursor is a singleton cursor the comparison is only 
          valid if the secondary cursor and the source cursor are the same record
          (there is no order for a singleton)
        - If the record at the current position of the secondary cursor is not
          in the collection of the source cursor a rdm_exception will be thrown.
        - There are two distinct types of errors for the rdm_exception when the
          record in the secondary cursor is not found in the collection of
          the source cursor:
        - If records in cursor_secondary can never be in the collection
          of the source cursor based on the schema information (it is a
          different record type or from another database) then S_NOT_RELATED will
          be the error code in the rdm_exception.
        - If the record in the secondary cursor could be found in the
          collecion for the source cursor but is not (it has a different set
          owner) then S_NOT_IN_CURSOR will be the error code in the 
          rdm_exception.
        - In the case where the cursors are related but secondary cursor
          is in a special position (BeforeFirst/AfterLast) then the
          cursors must be of the same type to have a meaningful comparison
          (both key cursors based on the same key, both set cursors with
          the same owner, etc.).  If it is not a meaningful comparison
          S_NOT_IN_CURSOR is returned.


        \retval true If the secondary cursor is positioned to the same record
        as the source cursor
        \retval false Otherwise
        
        \par Locking Requirements
        None

        \throws 
        rdm_exception (S_TRPRECOMMITTED, S_INVCURSOR_OP, S_SET_GONE, S_RECORD_GONE, S_NOT_RELATED)
      
        \par Library
        rdmcppapi-12
    */
    bool isAt (
        const Cursor& cursor /**< [in] The Cursor to compare against */
        ) const throw (const rdm_exception&);

    /*! \brief Check to see if passed in cursor is positioned after or at the
               source cursor's current position

        This method compares the current position of source cursor relative 
        to secondary (passed in) cursor and will return TRUE if the position 
        for the primary cursor is at or after the position of the secondary cursor.

        If the cursor types are not the same the current record of the
        secondary cursor will be used and then converted to a position in the
        cursor type of source cursor. If the current record of the secondary 
        cursor is not a valid cursor position in the source a rdm_exception
        will be thrown.
    
        This more specifically means:

        - If the source cursor is a key cursor the comparison will be based on 
          key value.
        - If the source cursor is a record cursor the comparison will be based 
          on database address value
        - If the source cursor is a set member cursor the comparison will be 
          based on the order in the set chain
        - If the source cursor is a singleton cursor the comparison is only 
          valid if the secondary cursor and the source cursor are the same record
          (there is no order for a singleton)
        - If the record at the current position of the secondary cursor is not
          in the collection of the source cursor a rdm_exception will be thrown.
        - There are two distinct types of errors for the rdm_exception when the
          record in the secondary cursor is not found in the collection of
          the source cursor:
        - If records in cursor_secondary can never be in the collection
          of the source cursor based on the schema information (it is a
          different record type or from another database) then S_NOT_RELATED will
          be the error code in the rdm_exception.
        - If the record in the secondary cursor could be found in the
          collecion for the source cursor but is not (it has a different set
          owner) then S_NOT_IN_CURSOR will be the error code in the 
          rdm_exception.
        - In the case where the cursors are related but secondary cursor
          is in a special position (BeforeFirst/AfterLast) then the
          cursors must be of the same type to have a meaningful comparison
          (both key cursors based on the same key, both set cursors with
          the same owner, etc.).  If it is not a meaningful comparison
          S_NOT_IN_CURSOR is returned.

        \retval true If the secondary cursor is positioned after or at the
        source cursor's current position
        \retval false Otherwise
        
        \par Locking Requirements
        None

        \throws 
        rdm_exception (S_TRPRECOMMITTED, S_INVCURSOR_OP, S_SET_GONE, S_RECORD_GONE, S_NOT_RELATED)
      
        \par Library
        rdmcppapi-12
    */
    bool isAfterAt (
        const Cursor& cursor /**< [in] The Cursor to compare against */
        ) const throw (const rdm_exception&);
    
    /*! \brief Check to see if passed in cursor is positioned after the source
               cursor's current position.

        This method compares the current position of source cursor relative 
        to secondary (passed in) cursor and will return TRUE if the position 
        for the primary cursor is after the position of the secondary cursor.

        If the cursor types are not the same the current record of the
        secondary cursor will be used and then converted to a position in the
        cursor type of source cursor. If the current record of the secondary 
        cursor is not a valid cursor position in the source a rdm_exception
        will be thrown.
    
        This more specifically means:

        - If the source cursor is a key cursor the comparison will be based on 
          key value.
        - If the source cursor is a record cursor the comparison will be based 
          on database address value
        - If the source cursor is a set member cursor the comparison will be 
          based on the order in the set chain
        - If the source cursor is a singleton cursor the comparison is only 
          valid if the secondary cursor and the source cursor are the same record
          (there is no order for a singleton)
        - If the record at the current position of the secondary cursor is not
          in the collection of the source cursor a rdm_exception will be thrown.
        - There are two distinct types of errors for the rdm_exception when the
          record in the secondary cursor is not found in the collection of
          the source cursor:
        - If records in cursor_secondary can never be in the collection
          of the source cursor based on the schema information (it is a
          different record type or from another database) then S_NOT_RELATED will
          be the error code in the rdm_exception.
        - If the record in the secondary cursor could be found in the
          collecion for the source cursor but is not (it has a different set
          owner) then S_NOT_IN_CURSOR will be the error code in the 
          rdm_exception.
        - In the case where the cursors are related but secondary cursor
          is in a special position (BeforeFirst/AfterLast) then the
          cursors must be of the same type to have a meaningful comparison
          (both key cursors based on the same key, both set cursors with
          the same owner, etc.).  If it is not a meaningful comparison
          S_NOT_IN_CURSOR is returned.

        \retval true If the secondar cursor is positioned after the source 
        cursor's current position
        \retval false Otherwise
        
        \par Locking Requirements
        None

        \throws 
        rdm_exception (S_TRPRECOMMITTED, S_INVCURSOR_OP, S_SET_GONE, S_RECORD_GONE, S_NOT_RELATED)
      
        \par Library
        rdmcppapi-12
    */
    bool isAfter (
        const Cursor& cursor /**< [in] The Cursor to compare against */
        ) const throw (const rdm_exception&);
    
    /*! \brief Check to see if passed in cursor is positioned to a different
               record than the source cursor.

        This method compares the current position of source cursor relative 
        to secondary (passed in) cursor and will return TRUE if the position 
        for the primary cursor is not at the position of the secondary cursor.

        If the cursor types are not the same the current record of the
        secondary cursor will be used and then converted to a position in the
        cursor type of source cursor. If the current record of the secondary 
        cursor is not a valid cursor position in the source a rdm_exception
        will be thrown.
    
        This more specifically means:

        - If the source cursor is a key cursor the comparison will be based on 
          key value.
        - If the source cursor is a record cursor the comparison will be based 
          on database address value
        - If the source cursor is a set member cursor the comparison will be 
          based on the order in the set chain
        - If the source cursor is a singleton cursor the comparison is only 
          valid if the secondary cursor and the source cursor are the same record
          (there is no order for a singleton)
        - If the record at the current position of the secondary cursor is not
          in the collection of the source cursor a rdm_exception will be thrown.
        - There are two distinct types of errors for the rdm_exception when the
          record in the secondary cursor is not found in the collection of
          the source cursor:
        - If records in cursor_secondary can never be in the collection
          of the source cursor based on the schema information (it is a
          different record type or from another database) then S_NOT_RELATED will
          be the error code in the rdm_exception.
        - If the record in the secondary cursor could be found in the
          collecion for the source cursor but is not (it has a different set
          owner) then S_NOT_IN_CURSOR will be the error code in the 
          rdm_exception.
        - In the case where the cursors are related but secondary cursor
          is in a special position (BeforeFirst/AfterLast) then the
          cursors must be of the same type to have a meaningful comparison
          (both key cursors based on the same key, both set cursors with
          the same owner, etc.).  If it is not a meaningful comparison
          S_NOT_IN_CURSOR is returned.

        \retval true If the secondary cursor is positioned to a different 
        record than the source cursor.
        \retval false Otherwise
        
        \par Locking Requirements
        None

        \throws 
        rdm_exception (S_TRPRECOMMITTED, S_INVCURSOR_OP, S_SET_GONE, S_RECORD_GONE, S_NOT_RELATED)
      
        \par Library
        rdmcppapi-12
    */
    bool isNotAt (
        const Cursor& cursor /**< [in] The Cursor to compare against */
        ) const throw (const rdm_exception&);

    /* Operators instead of functions above */
    /*! \brief Less than operator

        This operator compares the current position of primary (left-most)
        cursor relative to secondary (right-most) cursor and will return TRUE 
        if the position for the primary cursor is before the position of the 
        secondary cursor.

        If the cursor types are not the same the current record of the
        secondary cursor will be used and then converted to a position in the
        cursor type of source cursor. If the current record of the secondary 
        cursor is not a valid cursor position in the source a rdm_exception
        will be thrown.
    
        This more specifically means:

        - If the source cursor is a key cursor the comparison will be based on 
          key value.
        - If the source cursor is a record cursor the comparison will be based 
          on database address value
        - If the source cursor is a set member cursor the comparison will be 
          based on the order in the set chain
        - If the source cursor is a singleton cursor the comparison is only 
          valid if the secondary cursor and the source cursor are the same record
          (there is no order for a singleton)
        - If the record at the current position of the secondary cursor is not
          in the collection of the source cursor a rdm_exception will be thrown.
        - There are two distinct types of errors for the rdm_exception when the
          record in the secondary cursor is not found in the collection of
          the source cursor:
        - If records in cursor_secondary can never be in the collection
          of the source cursor based on the schema information (it is a
          different record type or from another database) then S_NOT_RELATED will
          be the error code in the rdm_exception.
        - If the record in the secondary cursor could be found in the
          collecion for the source cursor but is not (it has a different set
          owner) then S_NOT_IN_CURSOR will be the error code in the 
          rdm_exception.
        - In the case where the cursors are related but secondary cursor
          is in a special position (BeforeFirst/AfterLast) then the
          cursors must be of the same type to have a meaningful comparison
          (both key cursors based on the same key, both set cursors with
          the same owner, etc.).  If it is not a meaningful comparison
          S_NOT_IN_CURSOR is returned.

        \retval true If the secondary cursor's position is before the primary 
        cursor's current position
        \retval false Otherwise
        
        \par Locking Requirements
        None

        \throws 
        rdm_exception (S_TRPRECOMMITTED, S_INVCURSOR_OP, S_SET_GONE, S_RECORD_GONE, S_NOT_RELATED, S_NOT_IN_CURSOR)
      
        \par Library
        rdmcppapi-12
    */
    bool operator < (
        const Cursor& cursor /**< [in] The Cursor to compare against */
        ) const throw (const rdm_exception&) { return isBefore (cursor);}

    /*! \brief Less than or equal to operator

        This operator compares the current position of primary (left-most)
        cursor relative to secondary (right-most) cursor and will return TRUE 
        if the position for the primary cursor is before or at the position of the 
        secondary cursor.

        If the cursor types are not the same the current record of the
        secondary cursor will be used and then converted to a position in the
        cursor type of source cursor. If the current record of the secondary 
        cursor is not a valid cursor position in the source a rdm_exception
        will be thrown.
    
        This more specifically means:

        - If the source cursor is a key cursor the comparison will be based on 
          key value.
        - If the source cursor is a record cursor the comparison will be based 
          on database address value
        - If the source cursor is a set member cursor the comparison will be 
          based on the order in the set chain
        - If the source cursor is a singleton cursor the comparison is only 
          valid if the secondary cursor and the source cursor are the same record
          (there is no order for a singleton)
        - If the record at the current position of the secondary cursor is not
          in the collection of the source cursor a rdm_exception will be thrown.
        - There are two distinct types of errors for the rdm_exception when the
          record in the secondary cursor is not found in the collection of
          the source cursor:
        - If records in cursor_secondary can never be in the collection
          of the source cursor based on the schema information (it is a
          different record type or from another database) then S_NOT_RELATED will
          be the error code in the rdm_exception.
        - If the record in the secondary cursor could be found in the
          collecion for the source cursor but is not (it has a different set
          owner) then S_NOT_IN_CURSOR will be the error code in the 
          rdm_exception.
        - In the case where the cursors are related but secondary cursor
          is in a special position (BeforeFirst/AfterLast) then the
          cursors must be of the same type to have a meaningful comparison
          (both key cursors based on the same key, both set cursors with
          the same owner, etc.).  If it is not a meaningful comparison
          S_NOT_IN_CURSOR is returned.

        \retval true If the secondary cursor's position is before or at the
                     primary cursor's current position
        \retval false Otherwise
        
        \par Locking Requirements
        None

        \throws 
        rdm_exception (S_TRPRECOMMITTED, S_INVCURSOR_OP, S_SET_GONE, S_RECORD_GONE, S_NOT_RELATED)
      
        \par Library
        rdmcppapi-12
    */
    bool operator <= (
        const Cursor& cursor /**< [in] The Cursor to compare against */
        ) const throw (const rdm_exception&) { return isBeforeAt (cursor);}

    /*! \brief Equal to operator

        This operator compares the current position of primary (left-most)
        cursor relative to secondary (right-most) cursor and will return TRUE 
        if the position for the primary cursor is at the position of the 
        secondary cursor.

        If the cursor types are not the same the current record of the
        secondary cursor will be used and then converted to a position in the
        cursor type of source cursor. If the current record of the secondary 
        cursor is not a valid cursor position in the source a rdm_exception
        will be thrown.
    
        This more specifically means:

        - If the source cursor is a key cursor the comparison will be based on 
          key value.
        - If the source cursor is a record cursor the comparison will be based 
          on database address value
        - If the source cursor is a set member cursor the comparison will be 
          based on the order in the set chain
        - If the source cursor is a singleton cursor the comparison is only 
          valid if the secondary cursor and the source cursor are the same record
          (there is no order for a singleton)
        - If the record at the current position of the secondary cursor is not
          in the collection of the source cursor a rdm_exception will be thrown.
        - There are two distinct types of errors for the rdm_exception when the
          record in the secondary cursor is not found in the collection of
          the source cursor:
        - If records in cursor_secondary can never be in the collection
          of the source cursor based on the schema information (it is a
          different record type or from another database) then S_NOT_RELATED will
          be the error code in the rdm_exception.
        - If the record in the secondary cursor could be found in the
          collecion for the source cursor but is not (it has a different set
          owner) then S_NOT_IN_CURSOR will be the error code in the 
          rdm_exception.
        - In the case where the cursors are related but secondary cursor
          is in a special position (BeforeFirst/AfterLast) then the
          cursors must be of the same type to have a meaningful comparison
          (both key cursors based on the same key, both set cursors with
          the same owner, etc.).  If it is not a meaningful comparison
          S_NOT_IN_CURSOR is returned.

        \retval true If the secondary cursor's position is at the primary 
        cursor's current position
        \retval false Otherwise
        
        \par Locking Requirements
        None

        \throws 
        rdm_exception (S_TRPRECOMMITTED, S_INVCURSOR_OP, S_SET_GONE, S_RECORD_GONE, S_NOT_RELATED)
      
        \par Library
        rdmcppapi-12
    */
    bool operator == (
        const Cursor& cursor /**< [in] The Cursor to compare against */
        ) const throw (const rdm_exception&) { return isAt (cursor);}

    /*! \brief Greater than or equal to operator
      
        This operator compares the current position of primary (left-most)
        cursor relative to secondary (right-most) cursor and will return TRUE 
        if the position for the primary cursor is after or at the position of the 
        secondary cursor.

        If the cursor types are not the same the current record of the
        secondary cursor will be used and then converted to a position in the
        cursor type of source cursor. If the current record of the secondary 
        cursor is not a valid cursor position in the source a rdm_exception
        will be thrown.
    
        This more specifically means:

        - If the source cursor is a key cursor the comparison will be based on 
          key value.
        - If the source cursor is a record cursor the comparison will be based 
          on database address value
        - If the source cursor is a set member cursor the comparison will be 
          based on the order in the set chain
        - If the source cursor is a singleton cursor the comparison is only 
          valid if the secondary cursor and the source cursor are the same record
          (there is no order for a singleton)
        - If the record at the current position of the secondary cursor is not
          in the collection of the source cursor a rdm_exception will be thrown.
        - There are two distinct types of errors for the rdm_exception when the
          record in the secondary cursor is not found in the collection of
          the source cursor:
        - If records in cursor_secondary can never be in the collection
          of the source cursor based on the schema information (it is a
          different record type or from another database) then S_NOT_RELATED will
          be the error code in the rdm_exception.
        - If the record in the secondary cursor could be found in the
          collecion for the source cursor but is not (it has a different set
          owner) then S_NOT_IN_CURSOR will be the error code in the 
          rdm_exception.
        - In the case where the cursors are related but secondary cursor
          is in a special position (BeforeFirst/AfterLast) then the
          cursors must be of the same type to have a meaningful comparison
          (both key cursors based on the same key, both set cursors with
          the same owner, etc.).  If it is not a meaningful comparison
          S_NOT_IN_CURSOR is returned.

        \retval true If the secondary cursor's position is after or at the
                     primary cursor's current position
        \retval false Otherwise
        
        \par Locking Requirements
        None

        \throws 
        rdm_exception (S_TRPRECOMMITTED, S_INVCURSOR_OP, S_SET_GONE, S_RECORD_GONE, S_NOT_RELATED)
      
        \par Library
        rdmcppapi-12
    */
    bool operator >= (
        const Cursor& cursor /**< [in] The Cursor to compare against */
        ) const throw (const rdm_exception&) { return isAfterAt (cursor);}

    /*! \brief Greater than operator

        This operator compares the current position of primary (left-most)
        cursor relative to secondary (right-most) cursor and will return TRUE 
        if the position for the primary cursor is after the position of the 
        secondary cursor.

        If the cursor types are not the same the current record of the
        secondary cursor will be used and then converted to a position in the
        cursor type of source cursor. If the current record of the secondary 
        cursor is not a valid cursor position in the source a rdm_exception
        will be thrown.
    
        This more specifically means:

        - If the source cursor is a key cursor the comparison will be based on 
          key value.
        - If the source cursor is a record cursor the comparison will be based 
          on database address value
        - If the source cursor is a set member cursor the comparison will be 
          based on the order in the set chain
        - If the source cursor is a singleton cursor the comparison is only 
          valid if the secondary cursor and the source cursor are the same record
          (there is no order for a singleton)
        - If the record at the current position of the secondary cursor is not
          in the collection of the source cursor a rdm_exception will be thrown.
        - There are two distinct types of errors for the rdm_exception when the
          record in the secondary cursor is not found in the collection of
          the source cursor:
        - If records in cursor_secondary can never be in the collection
          of the source cursor based on the schema information (it is a
          different record type or from another database) then S_NOT_RELATED will
          be the error code in the rdm_exception.
        - If the record in the secondary cursor could be found in the
          collecion for the source cursor but is not (it has a different set
          owner) then S_NOT_IN_CURSOR will be the error code in the 
          rdm_exception.
        - In the case where the cursors are related but secondary cursor
          is in a special position (BeforeFirst/AfterLast) then the
          cursors must be of the same type to have a meaningful comparison
          (both key cursors based on the same key, both set cursors with
          the same owner, etc.).  If it is not a meaningful comparison
          S_NOT_IN_CURSOR is returned.

        \retval true If the secondary cursor's position is after the primary 
        cursor's current position
        \retval false Otherwise
        
        \par Locking Requirements
        None

        \throws 
        rdm_exception (S_TRPRECOMMITTED, S_INVCURSOR_OP, S_SET_GONE, S_RECORD_GONE, S_NOT_RELATED)
      
        \par Library
        rdmcppapi-12
    */
    bool operator > (
        const Cursor& cursor /**< [in] The Cursor to compare against */
        ) const throw (const rdm_exception&) { return isAfter (cursor);}

    /*! \brief Not equal to operator

        This operator compares the current position of primary (left-most)
        cursor relative to secondary (right-most) cursor and will return TRUE 
        if the position for the primary cursor is not at the position of the 
        secondary cursor.

        If the cursor types are not the same the current record of the
        secondary cursor will be used and then converted to a position in the
        cursor type of source cursor. If the current record of the secondary 
        cursor is not a valid cursor position in the source a rdm_exception
        will be thrown.
    
        This more specifically means:

        - If the source cursor is a key cursor the comparison will be based on 
          key value.
        - If the source cursor is a record cursor the comparison will be based 
          on database address value
        - If the source cursor is a set member cursor the comparison will be 
          based on the order in the set chain
        - If the source cursor is a singleton cursor the comparison is only 
          valid if the secondary cursor and the source cursor are the same record
          (there is no order for a singleton)
        - If the record at the current position of the secondary cursor is not
          in the collection of the source cursor a rdm_exception will be thrown.
        - There are two distinct types of errors for the rdm_exception when the
          record in the secondary cursor is not found in the collection of
          the source cursor:
        - If records in cursor_secondary can never be in the collection
          of the source cursor based on the schema information (it is a
          different record type or from another database) then S_NOT_RELATED will
          be the error code in the rdm_exception.
        - If the record in the secondary cursor could be found in the
          collecion for the source cursor but is not (it has a different set
          owner) then S_NOT_IN_CURSOR will be the error code in the 
          rdm_exception.
        - In the case where the cursors are related but secondary cursor
          is in a special position (BeforeFirst/AfterLast) then the
          cursors must be of the same type to have a meaningful comparison
          (both key cursors based on the same key, both set cursors with
          the same owner, etc.).  If it is not a meaningful comparison
          S_NOT_IN_CURSOR is returned.

        \retval true If the secondary cursor's position is not the same as the
                     primary cursor's current position
        \retval false Otherwise
        
        \par Locking Requirements
        None

        \throws 
        rdm_exception (S_TRPRECOMMITTED, S_INVCURSOR_OP, S_SET_GONE, S_RECORD_GONE, S_NOT_RELATED)
      
        \par Library
        rdmcppapi-12
    */
    bool operator != (
        const Cursor& cursor /**< [in] The Cursor to compare against */
        ) const throw (const rdm_exception&) { return isNotAt (cursor);}

    /*! \brief Get the Db object associated with the Cursor

        Each active cursor is associated with a Db object.  This method allows
        a user to get a reference to the Db oject associated with the source
        Cursor.

        \return The Db object associated with this Cursor
        
        \par Locking Requirements
        None

        \throws 
        rdm_exception (S_TRPRECOMMITTED, S_INVCURSOR_OP)
      
        \par Library
        rdmcppapi-12
    */
    Db GetDb (void) throw (const rdm_exception&);

    /*! \brief Get the database address Cursors's current record

        This method returns the database address of the current record for
        the Cursor.

        If the cursor is not at a valid record a rdm_exception will be thrown.
   
        \return The database address of the record
    
        \par Locking Requirements in ReadOnly-Strict/Shared-Strict Modes
        A Snapshot transaction or a Read transaction with locks on the relevant
        cursor record(s)
      
        \throws 
        rdm_exception (S_TRPRECOMMITTED, S_INVCURSOR_OP, S_SET_GONE, S_RECORD_GONE, S_NOCR, S_NOMEMORY, S_NOT_LOCKED)
      
        \par Library
        rdmcppapi-12
    */
    DB_ADDR GetDBA (
        ) const throw (const rdm_exception&);

    /*! \brief Position a cursor to a particular record by database address
       
        This method will position a cursor to the record at database
        address specified by dba.  The cursor can be any type of cursor and
        does not need to be a record scan cursor.

        If there is no exact match found then:

        - If the cursor is a record scan cursor and dba is in the file
          that record is stored in then the function will return
          S_NOTFOUND and the cursor will be placed in the
          CURSOR_BETWEEN_RECORDS position.  Navigating forward (next)
          from that position will position the cursor at the next DBA
          larger than the specified DBA.  Navigating backward (prev)
          from that position will position the cursor at the next DBA
          smaller than the specified DBA.

        - Otherwise the function will throw a rdm_exception with the 
          S_NOT_IN_CURSOR error code and the cursor position will be left 
          unchanged.

        \par Locking Requirements in ReadOnly-Strict/Shared-Strict Modes
        A Snapshot transaction or a Read transaction with locks on the relevant 
        cursor record(s)

        \throws 
        rdm_exception (S_TRPRECOMMITTED, S_INVCURSOR_OP, S_SET_GONE, S_RECORD_GONE, S_NOT_RELATED)
      
        \par Library
        rdmcppapi-12
    */
    void FindRecordsByDBA (
        const DB_ADDR& dba /**< [in] The database address of the record the Cursor is to be positioned to*/
        ) const throw (const rdm_exception&);
    
    /*! \brief Add a new member to a set cursor

        This method will add a new member record to a set cursor.  The passed 
        in cursor must be positioned to a record that is a valid member of
        the set the source cursor is based on.  The current record of the passed
        in cursor will be added as a member of the set the source cursor is
        based on and will be associated to the current owner record of the
        source cursor.

        An exception will be thrown if the source cursor is not a set cursor
        or if the member cursor is not positioned to a valid member record.
        
        \par Locking Requirements in Shared/Shared-Strict Modes
        An Update transaction with locks on the relevant cursor record(s)

        \throws 
        rdm_exception (S_TRPRECOMMITTED, S_INVCURSOR_OP, S_SET_GONE, S_RECORD_GONE, S_NOCR, S_NOTLOCKED, S_NOTRANS)
      
        \par Library
        rdmcppapi-12
    */
    void AddMember (
        const Cursor& member /**< A cursor positioned to a record that is a valid member for the set the source Cursor is based on */
        ) const throw (const rdm_exception&);
    
    /*! \brief Remove the current record from a set cursor

        This function disconnects the current record of the source cursor from 
        the set associated with the cursor.  The source cursor must be based on a set
        (obtained from a call to a GetMember* method).

        The source cursor will maintain the original current record and position 
        even though the current record is no longer in the set.  Calling 
        next/prev will position the cursor relative to the original position.
         
        \par Locking Requirements in Shared/Shared-Strict Modes
        An Update transaction with locks on the relevant cursor record(s)

        \throws 
        rdm_exception (S_TRPRECOMMITTED, S_INVCURSOR_OP, S_SET_GONE, S_RECORD_GONE, S_NOCR, S_NOTLOCKED, S_NOTRANS, S_NOTCON)
        
        \par Library
        rdmcppapi-12
    */
    void RemoveMember () const throw (const rdm_exception&);
    
    /*! \brief Release the cursor
        
        The default constructor, copy constructor, assignment operator, and 
        destructor implement a smart pointer for the Cursor interface and it's
        generated subclasses.  The number of references to the underlying 
        implemention object will be maintained.  When the number of references 
        to an implementation object is down to zero the object will be released.

        The constructor will initialize the number of references to the 
        underlying implementation object to one.
    */
    Cursor& Release (void) throw (const rdm_exception&);

protected:
    /** 
      \internal

      \brief Internal IDb pointer
    */
    ICursor *m_icursor;

    /* Protected members for internal use only */
    
    /** 
        \internal

        \brief Position the Cursor to the first record in it's collection
      
        \return The source cursor now positioned to the first record in it's
        collection
        
        \par Locking Requirements in Shared-Strict Mode
        A Read transaction with read lock on record type of the cursor's current record.
        If the cursor is based on a Set you will need a lock on all valid member record 
        types
      
        \par Library
        rdmcppapi-12
    */
    const Cursor& _First (void) const throw (const rdm_exception&);
   
    /** \internal
      
        \brief Position the Cursor to the next record in it's collection
       
        \return The source cursor now positioned to the next record in it's
                collection
        
        \par Locking Requirements in Shared-Strict Mode
        A Read transaction with read lock on record type of the cursor's current record.
        If the cursor is based on a Set you will need a lock on all valid member record 
        types
      
        \par Library
        rdmcppapi-12
    */
    const Cursor& _Next (void) const throw (const rdm_exception&);

    /** \internal
      
        \brief Position the Cursor to the last record in it's collection
       
        \return The source cursor now positioned to the last record in it's
                collection
        
        \par Locking Requirements in Shared-Strict Mode
        A Read transaction with read lock on record type of the cursor's current record.
        If the cursor is based on a Set you will need a lock on all valid member record 
        types
      
        \par Library
        rdmcppapi-12
    */
    const Cursor& _Last (void) const throw (const rdm_exception&);

    /** \internal
      
        \brief Position the Cursor to the previous record in it's collection
       
        \return The source cursor now positioned to the previous record in it's
                collection
        
        \par Locking Requirements in Shared-Strict Mode
        A Read transaction with read lock on record type of the cursor's current record.
        If the cursor is based on a Set you will need a lock on all valid member record 
        types
      
        \par Library
        rdmcppapi-12
    */
    const Cursor& _Prev (void) const throw (const rdm_exception&);

    /** \internal
      
        \brief Get a singleton containing the records the source cursor is
               positioned to.
       
        \return The new singleton Cursor
        
        \par Locking Requirements in Shared-Strict Mode
        None
      
        \par Library
        rdmcppapi-12
    */
    Cursor _GetSelf (void) const throw (const rdm_exception&);
    
    /** \internal
      
        \brief Get a clone of the source Cursor
       
        \return The new clone Cursor
        
        \par Locking Requirements in Shared-Strict Mode
        None
      
        \par Library
        rdmcppapi-12
    */
    Cursor _Clone (void) const throw (const rdm_exception&);

    /** \internal
      
        \brief Verify that the Cursor is based on the specified record

        \param record_type [in] The type to check if the the Cursor is based on
    */
    void VerifyType (
        recordType record_type
        ) const throw (const rdm_exception&);
    
    /** \internal 
      
        \brief Verify that the Cursor record type and assign the source Cursor
        to the passed in Cursor

        \param type [in] The record type to verify
        \param cursor [in] The cursor to assign
    */
    Cursor& _AssignAndVerifyType (
        recordType type,
        const Cursor& cursor
        ) throw (const rdm_exception&);

    
    /** 
      \internal
      
      \brief Constructor
     
      Applications should not directly create Cursor classes.  They should use
      the Db or other Cursor objects to get new Cursors
      
      \param icursor The ICursor interface to based this cursor on
    */
    Cursor (
        ICursor *icursor
        ) throw ();
    
    /**
      \internal
      
      \brief Constructor
    
      Applications should not directly create Cursor classes.  They should use
      the Db or other Cursor objects to get new Cursors
        
      \param cursor [in] A Cursor to based the new Cursor on
      \param record_type [in] The recordType of the new Cursor
    */
    Cursor (
        const Cursor& cursor,
        recordType record_type
        ) throw (const rdm_exception&);

    /*! \internal 
      
        \brief Get a singleton cursor positioned to the owner record of the 
        specified set.

        Applications should not directly call this method, a set type specific
        method will be generated for each set member record in the database.

        This method return a singleton cursor that is positioned to the owner
        record for the specified  set.  The source cursor must be positioned
        to a record that is a valid member of the specified set.
  
        \param type [in] The set identifier for the set to get the owner for

        \return A singleton Cursor object positioned to the owner
    
        \par Locking Requirements in Shared-Strict Mode
        A Read transaction with locks on record type of the cursor's current record
        and the owner record type of the specified set
      
        \par Library
        rdmcppapi-12
    */
    Cursor _GetOwner (
        setType type
        ) const throw (const rdm_exception&);
    
    /*! \internal 
      
        \brief Get the database address of the owner record for the 
        specified set.

        Applications should not directly call this method, a set type specific
        method will be generated for each set member record in the database.

        This method returns the database address of the owner record for the 
        specified set.  The set cursor must be positioned at a record that is
        a valid member of the specified set.
   
        \param type [in] The set identifier for the set to get the owner DBA for
        \return The database address of the set owner
    
        \par Locking Requirements in Shared-Strict Mode
        A Read transaction with locks on record type of the cursor's current record
        and the owner record type of the specified set
      
        \par Library
        rdmcppapi-12
    */
    DB_ADDR _GetOwnerDBA (
        setType type 
        ) const throw (const rdm_exception&);

    /*! \internal 
      
        \brief Check to see if a record has an owner for specified set.

        Applications should not directly call this method, a set type specific
        method will be generated for each set member record in the database.

        This method will return true if the Cursor's current record is actively
        related to an owner record for the specified set.
   
        \return A boolean value
        \retval true if the current record is related to an owner for the specified set
        \retval false Otherwise
    
        \par Locking Requirements in Shared-Strict Mode
        A Read transaction with locks on record type of the cursor's current record
        and the owner record type of the specified set
      
        \par Library
        rdmcppapi-12
    */
    bool _HasOwner (setType type) const throw (const rdm_exception&);

    /*! \internal 
      
        \brief Get a Cursor collection containing all of the member records 
        related to current record of the source Cursor by the specified set.

        Applications should not directly call this method, a set type specific
        method will be generated for each set member record in the database.

        This method will return a Cursor contain a collection of all the member
        records related to the source Cursor's current record by the specified
        set.  The current record of the source Cursor must be a valid owner of
        the specified set.  The cursor will initially be positioned to 
        'BeforeFirst'.
   
        \param type [in] The set identifer of the set to get the members for

        \return A Cursor containing the collection of member records
    
        \par Locking Requirements in Shared-Strict Mode
        None
      
        \par Library
        rdmcppapi-12
    */
    Cursor _GetMembers (
        setType type 
        ) const throw (const rdm_exception&);
    
    /*! \internal 
      
        \brief Get a Cursor collection containing all of the member records 
        related to current record of the source Cursor by the specified set.

        Applications should not directly call this method, a set type specific
        method will be generated for each set member record in the database.

        This method will return a Cursor contain a collection of all the member
        records related to the source Cursor's current record by the specified
        set.  The current record of the source Cursor must be a valid member of
        the specified set.  The new Cursor will initially be positioned to the
        same record as the source Cursor.
   
        \param type [in] The set identifier of the set to get the members for
        
        \return A Cursor containing the collection of member records
    
        \par Locking Requirements in Shared-Strict Mode
        None
      
        \par Library
        rdmcppapi-12
    */
    Cursor _GetSiblingsAtRecord (
        setType type 
        ) const throw (const rdm_exception&);
    
    /*! \internal 
      
        \brief Get a Cursor collection containing all of the member records 
        related to current record of the source Cursor by the specified set.

        Applications should not directly call this method, a set type specific
        method will be generated for each set member record in the database.

        This method will return a Cursor contain a collection of all the member
        records related to the source Cursor's current record by the specified
        set.  The current record of the source Cursor must be a valid member of
        the specified set.  The new Cursor will initially be positioned to
        'BeforeFirst'.
    
        \param type [in] The set identifier of the set to get the siblings for

        \return A Cursor containing the collection of member records
    
        \par Locking Requirements in Shared-Strict Mode
        None
      
        \par Library
        rdmcppapi-12
    */
    Cursor _GetSiblings (
        setType type
        ) const throw (const rdm_exception&);

    /*! \internal 
      
        \brief Get the number of members related the source Cursor's current
        record for the specified set

        Applications should not directly call this method, a set type specific
        method will be generated for each set member record in the database.

        This method will return then number of records related to the record
        the source Cursor is positioned to by the specified set.  The source 
        Cursor must be positioned to a record that is a valid owner of the
        specified set.
   
        \param type [in] The set identifier of the set to get the siblings for
        
        \return The number of records related to the owner by the specified set
    
        \par Locking Requirements in Shared-Strict Mode
        A Read transaction with read lock on record type of the cursor
      
        \par Library
        rdmcppapi-12
    */
    uint64_t _GetMemberCount (
        setType type
        ) const throw (const rdm_exception&);

    /*! \internal 
      
        \brief Connect the Source cursor to passed in Cursor though the 
        specified set

        Applications should not directly call this method, a set type specific
        method will be generated for each set member record in the database.

        This method will connect the Current source cursors record to the current
        record of the passed in Cursor via the specfied set.

        The source Cursor must be positioned to a valid member record of the 
        specified set.
        
        The owner Cursor must be positioned to a valid owner record of the 
        specified set.

        If the source Cursor is already connect to the specified set then
        reconnect must be true or an exception will be thrown.
  
        \param type [in] The set identifier of the set to add a member to
        \param owner [in] A Cursor positioned to the owner record to connect the source cursor to
        \param reconnect [in] set to true if the source cursor should be disconnected from an existing member
        
        \par Locking Requirements in Shared-Strict Mode
        An Update transaction with a lock on the record type of the the owner
        type and all member types of the specified set
      
        \par Library
        rdmcppapi-12
    */
    void _Connect (
        setType type, 
        const Cursor& owner,
        bool reconnect
        ) const throw (const rdm_exception&);
    
    /*! \internal 
      
        \brief Connect the Source cursor to a system owned set

        Applications should not directly call this method, a set type specific
        method will be generated for each set member record in the database.

        This method will connect the passed in cursors current record to the specified
        system owned set

        The source Cursor must be positioned to a valid member record of the 
        specified set.
        
        If the source Cursor is already connect to the specified set then
        reconnect must be true or an exception will be thrown.

        \param type [in] The set identifier of the set to add a member to
        \param reconnect [in] set to true if the source cursor should be disconnected from an existing member
   
        \par Locking Requirements in Shared-Strict Mode
        An Update transaction with a lock on the record type of the the owner
        type and all member types of the specified set
      
        \par Library
        rdmcppapi-12
    */
    void _Connect (
        setType type,
        bool reconnect
        ) const throw (const rdm_exception&);
    
    /*! \internal 
      
        \brief Disconnect a record from the specified set

        Applications should not directly call this method, a set type specific
        method will be generated for each set member record in the database.

        This method will remove the record at the current position of the 
        source Cursor from the specified set.

        The source Cursor must be positioned to a valid member record of the 
        specified set.
        
        \param type [in] The set identifier of the set to remove a member from

        \par Locking Requirements in Shared-Strict Mode
        An Update transaction with a lock on the record type of the the owner
        type and all member types of the specified set
      
        \par Library
        rdmcppapi-12
    */
    void _Disconnect (
        setType type
        ) const throw (const rdm_exception&);
    
    /*! \internal 
      
        \brief Get a Cursor collection for a record type by a key

        Applications should not directly call this method, a key specific
        method will be generated for each key defined in the database.

        The Cursor returned will be ordered by key value and will be
        initially positioned to 'BeforeFirst'.
   
        \return A Cursor containing the collection of records
    
        \par Locking Requirements in Shared-Strict Mode
        None
      
        \par Library
        rdmcppapi-12
    */
    Cursor _GetRecordsByKey (keyId id) const throw (const rdm_exception&);
    
    /*! \internal 
      
        \brief Get a Cursor collection for a record type by a key

        Applications should not directly call this method, a key specific
        method will be generated for each key defined in the database.

        The Cursor returned will be ordered by key value and will be
        initially positioned to the same record as the source Cursor.
   
        \return A Cursor containing the collection of records
    
        \par Locking Requirements in Shared-Strict Mode
        None
      
        \par Library
        rdmcppapi-12
    */
    Cursor _GetRecordsByKeyAtRecord (keyId id) const throw (const rdm_exception&);

    /*! \internal 
      
        \brief Position a Cursor to the specified key value

        Applications should not directly call this method, a key specific
        method will be generated for each key defined in the database.

        The Cursor will be positioned to the first record that has the 
        specified key value.  If no record in the Cursor has the specified
        value and the Cursor is based on the key used for the search then
        the Cursor will be positioned to BETWEEN_RECORDS and the navigation
        position will be where the value would have been if it was found.

        If there is not an exact match and the source Cursor is not based on
        the specified key then an exception will be thrown.
   
        \param id [in] the key identifer for the key to do the search on
        \param value [in] The value to use for the lookup
        \param len [in] The length of the value buffer, if len is 0 the engine will not validate the length
        \param nfields [in] The number of key fields to use for the lookup.  If this parameter is a non-zero value the mothod only considers the number of fields indictated.  The parameter is intentded only for compound keys, although specifying '1' for a non-compound key is safe
        \param partialStrLen [in] The partial string length.  If this parameter is a non-zero value the method only uses this many characters of the last string field being considered (depending on nfields)

        \par Locking Requirements in Shared-Strict Mode
        A Read transaction with read lock on record type of the cursor
      
        \par Library
        rdmcppapi-12
    */
    void _FindRecordsByKey (
        keyId id,
        const void *value,
        uint32_t len = 0,
        uint16_t nfields = 0,
        uint16_t partialStrLen = 0
        ) const throw (const rdm_exception&);

    /*! \internal 
      
        \brief Set all of the field values for a record

        Applications should not directly call this method, a record specific
        method will be generated for each record defined in the database.

        The field values for the Cursor's current record will be set to the
        specified values.
   
        \param type [in] The record type that will be updated
        \param fields [in] The new field values
        \param len [in] The size of fields (if this is 0 the engine will not validate the size)

        \par Locking Requirements in Shared-Strict Mode
        An Update transaction with a lock on the record type of the cursor's 
        curent record
      
        \par Library
        rdmcppapi-12
    */
    void SetFieldValues (
        recordType type,
        const void *fields,
        uint32_t len = 0
        ) const throw (const rdm_exception&);
    
    /*! \internal 
      
        \brief Get all of the field values for a record

        Applications should not directly call this method, a record specific
        method will be generated for each record defined in the database.

        The field values for the Cursor's current record will be read into the
        specified buffer.
   
        \param type [in] The record type that will be read
        \param fields [out] The buffer to place the field values
        \param len [in] The size of fields (if this is 0 the engine will not validate the size)
        \param bytes_read [out] The number of bytes written to fields

        \par Locking Requirements in Shared-Strict Mode
        An read transaction with a lock on the record type of the cursor's 
        curent record
      
        \par Library
        rdmcppapi-12
    */
    void GetFieldValues (
        recordType type,
        void *fields,
        uint32_t len = 0,
        uint32_t *bytes_read = NULL
        ) const throw (const rdm_exception&);
    
    /*! \internal 
      
        \brief Update the value of a single field

        Applications should not directly call this method, a field specific
        method will be generated for each field defined in the database.

        The specified field for the Cursor's current record will be set to
        value.
   
        \param id [in] The field that will be updated
        \param field [in] The new value for the field
        \param len [in] The size of field (if this is 0 the engine will not validate the size)

        \par Locking Requirements in Shared-Strict Mode
        An Update transaction with a lock on the record type of the cursor's 
        curent record
      
        \par Library
        rdmcppapi-12
    */
    void _SetField (
        fieldId id,
        const void *field,
        uint32_t len = 0
        ) const throw (const rdm_exception&);
    
    /*! \internal 
      
        \brief Read the value of a single field

        This method reads the value of a single field from the record at
        the current record of cursor.
       
        Applications should not directly call this protected method, a field 
        specific method will be generated for each field defined in the 
        database.

        \param id [in] The identifier for the field to be read
        \param field [out] The buffer to put the field value
        \param len [in] The length of field (if this is 0 the engine will not validate the size)
        \param bytes_read [out] The number of bytes written to field

        \par Locking Requirements in Shared-Strict Mode
        An read transaction with a lock on the record type of the cursor's 
        curent record
      
        \par Library
        rdmcppapi-12
    */
    void _GetField (
        fieldId id,
        void *field,
        uint32_t len = 0,
        uint32_t *bytes_read = NULL
        ) const throw (const rdm_exception&);

    /*! \internal 
      
        \brief Update the value of a blob field

        Applications should not directly call this method, a field specific
        method will be generated for each blob field defined in the database.

        The blob field will be updated with the specified values.  The update will
        begin at offset.  If offset is beyond the current size of the blob the blob
        will be padded with NULL bytes.
   
        \param id [in] The field identifer of the blob field to update
        \param offset [in] The offset into the blob to begin writing
        \param buf [in] The contents to write to the blob
        \param size [in] The size of buf

        \par Locking Requirements in Shared-Strict Mode
        An Update transaction with a lock on the record type of the cursor's 
        curent record
      
        \par Library
        rdmcppapi-12
    */
    void _SetBlobField (
        fieldId id,
        uint32_t offset,
        const void *buf,
        uint32_t size
        ) const throw (const rdm_exception&);
    
    /*! \internal 
      
        \brief Read the value of a blob field

        Applications should not directly call this method, a field specific
        method will be generated for each blob field defined in the database.

        The blob will be read into the specified buffer.  The data read will 
        start from the specified offset.  If there are not enough bytes to 
        completely fill the buffer and the size parameter is NULL then an
        exception will be thrown.
   
        \param id [in] The field identifer of the blob field to be read
        \param offset [in] The offset into the blob to start reading from
        \param buf [out] The buffer to put the blob data into
        \param len [in] The number of bytes to read
        \param size [out] The number of bytes read
        
        \par Locking Requirements in Shared-Strict Mode
        A Read transaction with a lock on the record type of the cursor's 
        curent record
      
        \par Library
        rdmcppapi-12
    */
    void _GetBlobField (
        fieldId id,
        uint32_t offset,
        void *buf,
        uint32_t len,
        uint32_t *size=NULL
        ) const throw (const rdm_exception&);
    
    /*! \internal 
      
        \brief Update the size of a blob field

        Applications should not directly call this method, a field specific
        method will be generated for each blob field defined in the database.

        The blob field will be set to the specified size.  The the size is less
        than the current size of the blob it will be truncated.  If the size is
        larger than the current size of the blob it will be padded with NULL
        bytes.
   
        \param id [in] The field identifer of the blob to set the size for
        \param size [out] The new size of the blob field

        \par Locking Requirements in Shared-Strict Mode
        An Update transaction with a lock on the record type of the cursor's 
        curent record
      
        \par Library
        rdmcppapi-12
    */
    void _SetBlobFieldSize (
        fieldId id,
        uint32_t size
        ) const throw (const rdm_exception&);
    
    /*! \internal 
      
        \brief Get the current size of a blob field

        Applications should not directly call this method, a field specific
        method will be generated for each blob field defined in the database.

        The size blob will be read into the specified buffer.
   
        \param id [in] The field identifier for the blob to get the size of
        \param size [out] The buffer to put the current blob size

        \par Locking Requirements in Shared-Strict Mode
        A Read transaction with a lock on the record type of the cursor's 
        curent record
      
        \par Library
        rdmcppapi-12
    */
    void _GetBlobFieldSize (
        fieldId id,
        uint32_t *size
        ) const throw (const rdm_exception&);

    /*! \internal 
      
        \brief Validate that the cursor has a valid ICursor smart pointer
    */
    void _ValidateICursor() const throw (const rdm_exception&);

private:
    //! Cursor reference operator
    const Cursor* operator & (void) const;
    
    friend class Db;
};
}
#endif
