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

#ifndef DCURSORPROTO_H
#define DCURSORPROTO_H

#include "rdm.h"

/** \file dcursorproto.h
 *  \brief Header for the Raima Cursor API prototypes
 */

/*!
 * \mainpage Raima Cursor Interface
 * \author Jeffrey R. Parsons, Raima Sr. Engineer
 * \date 2012
 *
 * \section Description
 * Raima Cursor API
 *
 * The library provides a set of  APIs for utilizing cursor operations as an alternative to the 
 * RDM record APIs.  The purpose of the API is to provide a modern C interface to the RDM engine 
 * which will be as (or more) efficient than the current record interface.
 */

/** \defgroup alloc Cursor Creation Functions */
/** \defgroup association Cursor Record Association Functions */
/** \defgroup navigation Cursor Navigation Functions */
/** \defgroup position Cursor Position and Compare Functions */
/** \defgroup read Cursor Record Read Functions */
/** \defgroup update Cursor Record Insert and Update Functions */
/** \defgroup delete Cursor Record Deletion Functions */
/** \defgroup set Cursor Set Functions */
/** \defgroup getdb Get Database (handle) functions */
/** \defgroup optkey Optional key functions */

/* Cursor creation/cleanup functions */
RDM_EXPORT int32_t EXTERNAL_FCN d_cursorAlloc (RDM_CURSOR *cursor, RDM_TASK task, int32_t dbn);

/** \brief Allocate a RDM_CURSOR
 *
    This function allocates and initializes a cursor.  The new cursor
    is associated with the database specified in the db parameter.
    Once a cursor has been initialized it can by used in other RDM
    cursor function calls.

    An allocated cursor is not associated with any records.  One of
    the dc_get* functions need to be called to associate the cursor
    with a collection of records.  Most of the other cursor APIs will
    return an error of S_INVCURSOR_OP if called with a cursor that is
    allocated but not yet associated with records.

    It is possible to allocate a cursor without associating it with a
    database (pass in NULL for the RDM_DB).  When the cursor is
    associated to a set of records it will also be associated to the
    database hosting those records.  The benefit of associating a
    cursor with a database prior to associating it to any records is
    that if a database is closed all of the cursor’s associated with
    it will be cleaned up automatically.

    \par Locking Requirements
    None
    
    \returns A RDM status code
    \retval S_OKAY Success
    \retval S_INVPTR
    \retval S_TRPRECOMMITTED
    \retval S_DBOPEN
    \retval S_INVDB
    \retval S_NOMEMORY

    \ingroup alloc

    \see dh_createRecord
    \see association
    \see dc_cursorFree
 */
RDM_EXPORT int32_t EXTERNAL_FCN dh_cursorAlloc (
    RDM_DB db, /**< [in] A valid RDM database */
    RDM_CURSOR *cursor /**< [out] A pointer to the created cursor */
    );

/** \brief Free a RDM_CURSOR

    This function will free all resources associated with a cursor.
    Attempting to use a cursor after it has been freed may result in
    an application crash.
    
    \par Locking Requirements
    None

    \returns A RDM status code
    \retval S_OKAY Success
    \retval S_INVCURSOR

    \ingroup alloc

    \see dh_cursorAlloc
*/
RDM_EXPORT int32_t EXTERNAL_FCN dc_cursorFree (
    RDM_CURSOR cursor /**< [in] The cursor to be freed  */
    );

RDM_EXPORT int32_t EXTERNAL_FCN d_getRecords (
    int32_t rec_id,
    RDM_CURSOR cursor,
    RDM_TASK task,
    int32_t dbn
    );

/** \brief Associate a RDM cursor with records based on a record id

    This function associates a cursor with a set of records in
    database address order. The record set contains all of the
    record instances for the record type specified by record
    id.  The cursor will be initially positioned in the 'BeforeFirst'
    position.

    The cursor will be associated with the specified database.  If the
    cursor was previously associated with another RDM database that
    association will be removed prior to adding the cursor to the new
    database.

    If the cursor previously held a different set of records then
    memory may need to be reallocated to handle the new set of
    records.  If you are interacting with more than one set of records
    it can be more efficient to use multiple cursors than to share a
    single cursor across all of them.

    \par Locking Requirements
    None

    \returns A RDM status code
    \retval S_OKAY Success
    \retval S_TRPRECOMMITTED
    \retval S_INVDB
    \retval S_INVCURSOR
    \retval S_INVREC
    \retval S_NOMEMORY

    \ingroup  association

    \see dh_cursorAlloc
    \see association
    \see navigation
    \see position
    \see read
    \see update
    \see delete
    \see set
 */
RDM_EXPORT int32_t EXTERNAL_FCN dh_getRecords (
    RDM_DB db, /**< [in] A valid RDM database */
    int32_t rec_id, /**< [in] The record id for the set of records */
    RDM_CURSOR cursor /**< [out] The RDM cursor for the resulting cursor */
    );

/** \brief Associate a RDM cursor with records based on a record id positioned at a record

    This function associates a cursor with a set of records in
    database address order. The record set for cursor contains all of
    the record instances for the record type of the current record of
    source_cursor.  The cursor will be initially positioned at the
    current record of source_cursor.

    The cursor will be associated with the same database as
    source_cursor.  If the cursor was previously associated with
    another RDM database that association will be removed prior to
    adding the cursor to the new database.

    If the cursor previously held a different set of records then
    memory may need to be reallocated to handle the new set of
    records.  If you are interacting with more than one set of records
    it can be more efficient to use multiple cursors than to share a
    single cursor across all of them.

    \par Locking Requirements
    None

    \returns A RDM status code
    \retval S_OKAY Success
    \retval S_TRPRECOMMITTED
    \retval S_INVDB
    \retval S_INVCURSOR
    \retval S_INVCURSOR_OP
    \retval S_INVREC
    \retval S_NOMEMORY

    \ingroup  association

    \see dh_cursorAlloc
    \see association
    \see navigation
    \see position
    \see read
    \see update
    \see delete
    \see set
 */
RDM_EXPORT int32_t EXTERNAL_FCN dc_getRecordsAtRecord (
    RDM_CURSOR_C source_cursor, /**< [in] The cursor whose current record will be used for the associated record type and resulting cursor position */
    RDM_CURSOR cursor /**< [out] The cursor that is being associated */
    );

RDM_EXPORT int32_t EXTERNAL_FCN d_getRecordsAtDBA (int32_t rec_id, const DB_ADDR *dba, RDM_CURSOR cursor, RDM_TASK task, int32_t dbn);

/** \brief Associate a RDM cursor with records based on the database address.

    This function associates a cursor with a set of records in
    database address order.  The record set contains all of
    the record instances for the record type of the record at
    the database address specified by dba.  The cursor will be
    initially positioned to the record identified by dba.

    If dba is not a valid database address for the specified record
    type an error will be returned and no records will be associated
    with cursor.

    If dba is a valid database address for the specified record type
    but there is no record at that exact database address then the
    function will return S_NOTFOUND and the cursor will be placed in
    the CURSOR_BETWEEN_RECORDS position.  Navigating forward (dc_next)
    from that position will position the cursor at the next DBA larger
    than the specified DBA.  Navigating backward (dc_prev) from that
    position will position the cursor at the next DBA smaller than the
    specified DBA.
    
    The cursor will be associated with the specified database.  If the
    cursor was previously associated with another RDM database that
    association will be removed prior to adding the cursor to the new
    database.

    If the cursor previously held a different set of records then
    memory may need to be reallocated to handle the new set of
    records.  If you are interacting with more than one set of records
    it can be more efficient to use multiple cursors than to share a
    single cursor across all of them.

    \par Locking Requirements in Shared-Strict Mode
    None

    \returns A RDM status code
    \retval S_OKAY Success
    \retval S_TRPRECOMMITTED
    \retval S_INVDB
    \retval S_INVREC
    \retval S_INVCURSOR
    \retval S_INVPTR
    \retval S_INVADDR
    \retval S_NOT_IN_CURSOR
    \retval S_DELETED
    \retval S_NOMEMORY

    \ingroup  association

    \see dh_cursorAlloc
    \see association
    \see navigation
    \see position
    \see read
    \see update
    \see delete
    \see set
 */
RDM_EXPORT int32_t EXTERNAL_FCN dh_getRecordsAtDBA (
    RDM_DB db, /**< [in] A valid RDM database */
    int32_t rec_id,  /**< [in] The record id for the set of records */
    const DB_ADDR *dba, /**< [in] A database address */
    RDM_CURSOR cursor /**< [out] The cursor that is being associated */
    );

RDM_EXPORT int32_t EXTERNAL_FCN d_getRecordsByKey (int32_t key_id, RDM_CURSOR cursor, RDM_TASK task, int32_t dbn);

/** \brief Associate a RDM cursor with records based on a key

    This function associates a cursor with a set of records ordered
    by the specified key. The record set contains all of the
    record instances for the record type of the key specified.
    The cursor will be initially positioned in the 'BeforeFirst'
    position.

    The cursor will be associated with the specified database.  If the
    cursor was previously associated with another RDM database that
    association will be removed prior to adding the cursor to the new
    database.

    If the cursor previously held a different set of records then
    memory may need to be reallocated to handle the new set of
    records.  If you are interacting with more than one set of records
    it can be more efficient to use multiple cursors than to share a
    single cursor across all of them.

    \par Locking Requirements in Shared-Strict Mode
    None

    \returns A RDM status code
    \retval S_OKAY Success
    \retval S_TRPRECOMMITTED
    \retval S_INVDB
    \retval S_NOTKEY
    \retval S_INVCURSOR
    \retval S_INVREC
    \retval S_NOMEMORY

    \ingroup  association

    \see dh_cursorAlloc
    \see association
    \see navigation
    \see position
    \see read
    \see update
    \see delete
    \see set
 */
RDM_EXPORT int32_t EXTERNAL_FCN dh_getRecordsByKey (
    RDM_DB db, /**< [in] A valid RDM database */
    int32_t key_id, /**< [in] The RDM field or compound key id */
    RDM_CURSOR cursor /**< [out] The cursor that is being associated */
    );

/** \brief Associate a RDM cursor with records based on a key positioned at a record

    This function associates a cursor with a set of records ordered by
    the specified key. The record set contains all of the records
    instances for the record type that the specified key field is in.
    The cursor will be positioned at the current record of
    source_cursor.

    If source_cursor is not at a record that is a valid record of the
    specified key field an error will be returned and cursor will not
    be associated.

    source_cursor can be any type of cursor as long as the current
    record of source_cursor is a valid record for the specified key
    field.

    The cursor will be associated with the same database as
    source_cursor.  If the cursor was previously associated with
    another RDM database that association will be removed prior to
    adding the cursor to the new database.

    If the cursor previously held a different set of records then
    memory may need to be reallocated to handle the new set of
    records.  If you are interacting with more than one set of records
    it can be more efficient to use multiple cursors than to share a
    single cursor across all of them.

    \par Locking Requirements in ReadOnly-Strict/Shared-Strict Mode
    Read lock on the record(s) associated with the cursor

    \returns A RDM status code
    \retval S_OKAY Success
    \retval S_TRPRECOMMITTED
    \retval S_INVDB
    \retval S_NOTKEY
    \retval S_INVCURSOR
    \retval S_INVREC
    \retval S_NOMEMORY
    \retval S_NOTLOCKED

    \ingroup  association

    \see dh_cursorAlloc
    \see association
    \see navigation
    \see position
    \see read
    \see update
    \see delete
    \see set
 */
RDM_EXPORT int32_t EXTERNAL_FCN dc_getRecordsByKeyAtRecord (
    RDM_CURSOR_C source_cursor, /**< [in] The cursor whose current record will be used for the resulting cursor position */
    int32_t key_id, /**< [in] The RDM field or compound key id  */
    RDM_CURSOR cursor /**< [out] The cursor that is being associated */
    );

RDM_EXPORT int32_t EXTERNAL_FCN d_getRecordsByKeyAtValue (int32_t key_id, const void *key_value, uint32_t len, RDM_CURSOR cursor, RDM_TASK task, int32_t dbn);

/** \brief Associate a RDM cursor with records based on a key positioned at a key value

    This function associates a cursor with a set of records ordered by
    the specified key. The record set contains all of the records
    instances for the record type that the specified key field is in.

    The cursor will be initially positioned at the first record that
    matches the specified key value.  If there is not an exact match
    then the cursor will be placed in the CURSOR_BETWEEN_KEYS
    position.  Navigating forward (dc_next) from that position will
    position the cursor at the next key value larger than the specified
    key value.  Navigating backward (dc_prev) from that position will
    position the cursor at the next key value smaller than the specified
    key value.

    The cursor will be associated with the specified database.  If the
    cursor was previously associated with another RDM database that
    association will be removed prior to adding the cursor to the new
    database.

    If the cursor previously held a different set of records then
    memory may need to be reallocated to handle the new set of
    records.  If you are interacting with more than one set of records
    it can be more efficient to use multiple cursors than to share a
    single cursor across all of them.

    \par Locking Requirements in ReadOnly-Strict/Shared-Strict Mode
    Read lock on the record(s) associated with the cursor

    \returns A RDM status code
    \retval S_OKAY Success
    \retval S_NOTFOUND Success, but no exact key value match, the cursor position to CURSOR_BETWEEN_KEYS
    \retval S_TRPRECOMMITTED
    \retval S_DBOPEN
    \retval S_INVDB
    \retval S_INVCURSOR
    \retval S_INVPTR
    \retval S_NOTKEY
    \retval S_NOTLOCKED
    \retval S_INVINDEX
    \retval S_INV_KEYLEN
    \retval S_NOMEMORY

    \ingroup  association

    \see dh_cursorAlloc
    \see association
    \see navigation
    \see position
    \see read
    \see update
    \see delete
    \see set
 */
RDM_EXPORT int32_t EXTERNAL_FCN dh_getRecordsByKeyAtValue (
    RDM_DB db, /**< [in] A valid RDM database */
    int32_t key_id, /**< [in]  */
    const void *key_value, /**< [in] The key value used to position the cursor */
    uint32_t len, /**< [in] The length of the key value buffer */
    RDM_CURSOR cursor /**< [out] The cursor that is being associated */
    );

RDM_EXPORT int32_t EXTERNAL_FCN d_getRecordsByKeyInRange (
    int32_t key_id, /**< [in] The key field type on which to base the cursor range */
    const void *start_key_value, /**< [in] The value for the start of the range */ 
    uint32_t start_key_len, /**< [in] The length of start_key_value */
    uint16_t start_num_key_flds, /**< [in] The number of fields to use for the start of the range.  If this parameter is zero the function uses all fields.  If this parameter is a non-zero value the function only uses the number of fields indicated.  This parameter is intended only for compound keys, although specifying '1' for a non-compound key is safe */
    uint16_t start_str_len, /**< [in] The partial string length in characters for the start key values.  If this parameter is s non-zero value, the function uses only this many characters of the last field being considered (depending on start_num_key_flds  above) */
    const void *end_key_value, /**< [in] The value for the end of the range */ 
    uint32_t end_key_len, /**< [in] The length of end_key_value */
    uint16_t end_num_key_flds, /**< [in] The number of fields to use for the end of the range.  If this parameter is zero the function uses all fields.  If this parameter is a non-zero value the function only uses the number of fields indicated.  This parameter is intended only for compound keys, although specifying '1' for a non-compound key is safe */
    uint16_t end_str_len, /**< [in] The partial string length in characters for the end key values.  If this parameter is s non-zero value, the function uses only this many characters of the last field being considered (depending on start_num_key_flds  above) */
    RDM_CURSOR cursor, /**< [out] The cursor that is being associated */
    RDM_TASK task, 
    int32_t dbn
    );

/** \brief Associate a RDM cursor with records a specified key range.

    This function associates a cursor with a set of records ordered by
    the specified key. The record set contains all of the records
    instances for the record type that have a key value that is in the range 
    specified by the start and end values.  If the specified start value is
    NULL then the start of the range will be the first index value stored in
    the database.  If the end value is NULL then the end of the range will be
    the last index value stored in the database.  Specifying a start value of 
    NULL and an end value of NULL is equivalent to dh_getRecordsByKey.

    For an index that allows multiple values it can be useful to specify the same
    value for the start and the end range.  For example the foreign side of a  
    primary foreign key relationship can be retrieved by specifying the primary
    key value as the start and end value of a key on the foreign table that 
    references the primary key of the primary table.  If the index is unique then
    specifying the same start and end value will result in at most one record
    in the cursor collection.

    The cursor will be initially positioned to the 'BeforeFirst' location.

    The cursor will be associated with the specified database.  If the
    cursor was previously associated with another RDM database that
    association will be removed prior to adding the cursor to the new
    database.

    If the cursor previously held a different set of records then
    memory may need to be reallocated to handle the new set of
    records.  If you are interacting with more than one set of records
    it can be more efficient to use multiple cursors than to share a
    single cursor across all of them.

    \par Locking Requirements in ReadOnly-Strict/Shared-Strict Mode
    A read-lock on the record containing the key

    \returns A RDM status code
    \retval S_OKAY Success
    \retval S_NOTFOUND Success, but no exact key value match, the cursor position to CURSOR_BETWEEN_KEYS
    \retval S_TRPRECOMMITTED
    \retval S_DBOPEN
    \retval S_INVDB
    \retval S_INVCURSOR
    \retval S_INVPTR
    \retval S_NOTKEY
    \retval S_NOTLOCKED
    \retval S_INVINDEX
    \retval S_INV_KEYLEN
    \retval S_NOMEMORY

    \ingroup  association

    \see dh_cursorAlloc
    \see association
    \see navigation
    \see position
    \see read
    \see update
    \see delete
    \see set
 */
RDM_EXPORT int32_t EXTERNAL_FCN dh_getRecordsByKeyInRange (
    RDM_DB db, /**< [in] A valid RDM database */
    int32_t key_id, /**< [in] The key field type on which to base the cursor 
                    range */
    const void *start_key_value, /**< [in] The value for the start of the 
                                 range */ 
    uint32_t start_len, /**< [in] The length of start_key_value */
    uint16_t start_num_key_flds, /**< [in] The number of fields to use for the 
                                 start of the range.  If this parameter is zero
                                 the function uses all fields.  If this 
                                 parameter is a non-zero value the function only
                                 uses the number of fields indicated.  This 
                                 parameter is intended only for compound keys, 
                                 although specifying '1' for a non-compound key
                                 is safe */
    uint16_t start_str_len, /**< [in] The partial string length in characters 
                            for the start key values.  If this parameter is a 
                            non-zero value, the function uses only this many 
                            characters of the last field being considered 
                            (depending on start_num_key_flds  above) */
    const void *end_key_value, /**< [in] The value for the end of the range */ 
    uint32_t end_len, /**< [in] The length of end_key_value */
    uint16_t end_num_key_flds, /**< [in] The number of fields to use for the 
                               end of the range.  If this parameter is zero the
                               function uses all fields.  If this parameter is a
                               non-zero value the function only uses the number 
                               of fields indicated.  This parameter is intended 
                               only for compound keys, although specifying '1' 
                               for a non-compound key is safe */
    uint16_t end_str_len,  /**< [in] The partial string length in characters for
                           the start key values.  If this parameter is a 
                           non-zero value, the function uses only this many 
                           characters of the last field being considered 
                           (depending on start_num_key_flds  above) */
    RDM_CURSOR cursor /**< [out] The cursor that is being associated */
    );

/** \brief Associate a cursor with members

    This function associates a cursor with a set of records containing
    all the member records related (as owner/member) to the current
    record of owner_cursor for the set identified by set_id.  The
    resulting cursor will be positioned at 'BeforeFirst'.

    If owner_cursor is not at a record that is a valid owner of the
    set identified by set_id an error will be returned and cursor will
    not be associated.

    owner_cursor can be any type of cursor as long as the current
    record of owner_cursor is a valid owner of the set identified by
    set_id.

    Cursor will be associated with the same database that owner_cursor
    is associated with.  If cursor was previously associated with
    another RDM database that association will be removed prior to
    adding cursor to the new database.

    If the cursor previously held a different set of records then
    memory may need to be reallocated to handle the new set of
    records.  If you are interacting with more than one set of records
    it can be more efficient to use multiple cursors than to share a
    single cursor across all of them.

    \par Locking Requirements in ReadOnly-Strict/Shared-Strict Mode
    Read lock on the record(s) associated with the cursor
    
    \returns A RDM status code
    \retval S_OKAY Success
    \retval S_TRPRECOMMITTED
    \retval S_INVCURSOR
    \retval S_INVCURSOR_OP
    \retval S_SET_GONE
    \retval S_RECORD_GONE
    \retval S_INVSET
    \retval S_NOCR
    \retval S_DELETED
    \retval S_INVOWN
    \retval S_NOMEMORY
    \retval S_NOTLOCKED

    \ingroup  association
    \ingroup  set

    \see dh_cursorAlloc
    \see association
    \see navigation
    \see position
    \see read
    \see update
    \see delete
    \see set
 */
RDM_EXPORT int32_t EXTERNAL_FCN dc_getMembers (
    RDM_CURSOR_C owner_cursor, /**< [in] The cursor for the owner record */
    int32_t set_id, /**< [in] The set identifier for the requesting set of members */
    RDM_CURSOR cursor /**< [out] The cursor that is being associated */
    );

/** \brief Associate a cursor with siblings

    This function associate a cursor with a set of records containing
    all the member records related (as member/member) to the
    current record of member_cursor for the set identified by set_id.
    The resulting cursor will be positioned at 'BeforeFirst'

    If member_cursor is not at a record that is a valid member of the
    set identified by set_id an error will be returned and cursor will
    not be associated.

    member_cursor can be any type of cursor as long as its
    current record is a valid member of the set identified by set_id.

    Cursor will be associated with the same database that
    member_cursor is associated with.  If cursor was previously
    associated with another RDM database that association will be
    removed prior to adding cursor to the new database.

    If the cursor previously held a different set of records then
    memory may need to be reallocated to handle the new set of
    records.  If you are interacting with more than one set of records
    it can be more efficient to use multiple cursors than to share a
    single cursor across all of them.

    \par Locking Requirements in ReadOnly-Strict/Shared-Strict Mode
    Read lock on the record(s) associated with the set
    
    \returns A RDM status code
    \retval S_OKAY Success
    \retval S_TRPRECOMMITTED
    \retval S_INVCURSOR
    \retval S_INVCURSOR_OP
    \retval S_SET_GONE
    \retval S_RECORD_GONE
    \retval S_INVSET
    \retval S_NOCR
    \retval S_DELETED
    \retval S_INVOWN
    \retval S_NOMEMORY
    \retval S_NOTLOCKED

    \ingroup  association
    \ingroup set

    \see dh_cursorAlloc
    \see association
    \see navigation
    \see position
    \see read
    \see update
    \see delete
    \see set
 */
RDM_EXPORT int32_t EXTERNAL_FCN dc_getSiblings (
    RDM_CURSOR_C member_cursor, /**< [in] The cursor for the member record */
    int32_t set_id, /**< [in] The set identifier for the requesting set of siblings */
    RDM_CURSOR cursor /**< [out] The cursor that is being associated */
    );

/** \brief Associate a cursor with siblings positioned at a record

    This function associate a cursor with a set of records containing
    all the member records related (as member/member) to the
    current record of member_cursor for the set identified by set_id.
    The cursor will be positioned at the current record of
    member_cursor.

    If member_cursor is not at a record that is a valid member of the
    set identified by set_id an error will be returned and cursor will
    not be associated.

    member_cursor can be any type of cursor as long as the cursors
    current record is a valid member of the set identified by set_id.

    Cursor will be associated with the same database that
    member_cursor is associated with.  If cursor was previously
    associated with another RDM database that association will be
    removed prior to adding cursor to the new database.

    If the cursor previously held a different set of records then
    memory may need to be reallocated to handle the new set of
    records.  If you are interacting with more than one set of records
    it can be more efficient to use multiple cursors than to share a
    single cursor across all of them.
    
    \par Locking Requirements in ReadOnly-Strict/Shared-Strict Mode
    Read lock on the record(s) associated with the set

    \returns A RDM status code
    \retval S_OKAY Success
    \retval S_TRPRECOMMITTED
    \retval S_INVCURSOR
    \retval S_INVCURSOR_OP
    \retval S_SET_GONE
    \retval S_RECORD_GONE
    \retval S_INVSET
    \retval S_NOCR
    \retval S_DELETED
    \retval S_INVOWN
    \retval S_NOMEMORY
    \retval S_NOTLOCKED

    \ingroup  association
    \ingroup set

    \see dh_cursorAlloc
    \see association
    \see navigation
    \see position
    \see read
    \see update
    \see delete
    \see set
 */
RDM_EXPORT int32_t EXTERNAL_FCN dc_getSiblingsAtRecord (
    RDM_CURSOR_C member_cursor, /**< [in] The cursor for the member record */
    int32_t set_id, /**< [in] The set identifier for the requesting set of siblings */
    RDM_CURSOR cursor /**< [out] The cursor that is being associated */
    );

/** \brief Associate a cursor with the current record

    This function associates a cursor with the current record of
    source_cursor.  The cursor will be positioned at this record.

    If the source_cursor is not at a valid record then an error will
    be returned and cursor will not be associated.

    Cursor will be associated with the same database that
    source_cursor is associated with.  If cursor was previously
    associated with another RDM database that association will be
    removed prior to adding cursor to the new database.

    If the cursor previously held a different set of records then
    memory may need to be reallocated to handle the new set of
    records.  If you are interacting with more than one set of records
    it can be more efficient to use multiple cursors than to share a
    single cursor across all of them.

    \par Locking Requirements
    None
    
    \returns A RDM status code
    \retval S_OKAY Success
    \retval S_TRPRECOMMITTED
    \retval S_INVCURSOR
    \retval S_INVCURSOR_OP
    \retval S_SET_GONE
    \retval S_RECORD_GONE
    \retval S_NOCR
    \retval S_NOMEMORY

    \ingroup  association

    \see dh_cursorAlloc
    \see association
    \see navigation
    \see position
    \see read
    \see update
    \see delete
    \see set
 */
RDM_EXPORT int32_t EXTERNAL_FCN dc_getSelf (
    RDM_CURSOR_C source_cursor, /**< [in] The cursor for the record */
    RDM_CURSOR cursor /**< [out] The cursor that is being associated */
    );

/** \brief Associate a cursor with the owner

    This function associates a cursor with the set owner of current
    record of source_cursor for the set identified by set_id.  The
    cursor will be positioned at this record.  If the source_cursor is
    not at a valid member of the set identified by set_id an error will
    be returned and cursor will not be associated.

    Cursor will be associated with the same database that
    source_cursor is associated with.  If cursor was previously
    associated with another RDM database that association will be
    removed prior to adding cursor to the new database.

    If the cursor previously held a different set of records then
    memory may need to be reallocated to handle the new set of
    records.  If you are interacting with more than one set of records
    it can be more efficient to use multiple cursors than to share a
    single cursor across all of them.
    
    \par Locking Requirements in ReadOnly-Strict/Shared-Strict Mode
    Read lock on the record(s) associated with the set

    \returns A RDM status code
    \retval S_OKAY Success
    \retval S_TRPRECOMMITTED
    \retval S_INVCURSOR
    \retval S_INVCURSOR_OP
    \retval S_SET_GONE
    \retval S_RECORD_GONE
    \retval S_NOCR
    \retval S_INVSET
    \retval S_NOTCON
    \retval S_DELETED
    \retval S_NOMEMORY
    \retval S_NOTLOCKED

    \ingroup  association
    \ingroup set

    \see dh_cursorAlloc
    \see association
    \see read
    \see update
    \see delete
    \see set
 */
RDM_EXPORT int32_t EXTERNAL_FCN dc_getOwner (
    RDM_CURSOR_C source_cursor, /**< [in] The cursor for the member */
    int32_t set_id, /**< [in] The set identifier for the requesting owner */
    RDM_CURSOR cursor /**< [out] The cursor that is being associated */
    );

/** \brief Associate a cursor as a clone of a cursor

    This function associates a cursor as a clone of a cursor.  The
    resulting cursor will be of the same type, contain the same
    records, and will have the same position and current record as
    src_cursor.

    Cursor will be associated with the same database that
    source_cursor is associated with.  If cursor was previously
    associated with another RDM database that association will be
    removed prior to adding cursor to the new database.

    If the cursor previously held a different set of records then
    memory may need to be reallocated to handle the new set of
    records.  If you are interacting with more than one set of records
    it can be more efficient to use multiple cursors than to share a
    single cursor across all of them.

    \par Locking Requirements
    None
    
    \returns A RDM status code
    \retval S_OKAY Success
    \retval S_TRPRECOMMITTED
    \retval S_INVCURSOR
    \retval S_INVCURSOR_OP
    \retval S_SET_GONE
    \retval S_RECORD_GONE
    \retval S_NOMEMORY

    \ingroup  association

    \see dh_cursorAlloc
    \see association
    \see navigation
    \see position
    \see read
    \see update
    \see delete
    \see set
*/    
RDM_EXPORT int32_t EXTERNAL_FCN dc_clone (
    RDM_CURSOR_C src_cursor, /**< [in] The cursor to clone */
    RDM_CURSOR new_cursor /**< [out] The cursor that is being associated */
    );

/** \brief Get the special 'BeforeFirst' cursor

    This function returns the special 'BeforeFirst' cursor.  The
    'BeforeFirst' cursor can be used as the second argument to
    dc_comparePosition.  This cursor is positioned at the
    'BeforeFirst' position and can not be changed.

    The special cursors are static and can not be freed.  The
    parameter should not point to an allocated cursor.

    \par Locking Requirements
    None
    
    \returns A RDM status code
    \retval S_OKAY Success
    \retval S_INVPTR

    \ingroup  association
    \ingroup alloc

    \see dc_getAfterLast
    \see dc_comparePosition
 */
RDM_EXPORT int32_t EXTERNAL_FCN dc_getBeforeFirst (
    RDM_CURSOR *cursor /**< [out] A pointer to the returned beforeFirst cursor */
    );

/** \brief Get the special 'AfterLast' cursor

    This function returns the special 'AfterLast' cursor.  The
    'AfterLast' cursor can be used as the second argument to
    dc_comparePosition.  The cursor is positioned at the 'AfterLast'
    position and can not be changed.

    The special cursors are static and can not be freed.  The
    parameter should not point to an allocated cursor.

    \par Locking Requirements
    None
    
    \returns A RDM status code
    \retval S_OKAY Success
    \retval S_INVPTR

    \ingroup association
    \ingroup alloc

    \see dc_getAfterLast
    \see dc_comparePosition
 */
RDM_EXPORT int32_t EXTERNAL_FCN dc_getAfterLast (
    RDM_CURSOR *cursor /**< [out] A pointer to the returned afterLast cursor */
    );
RDM_EXPORT int32_t EXTERNAL_FCN d_getRecord (
    int32_t rec_id, /**< [in]  */
    RDM_CURSOR cursor, /**< [in]  */
    RDM_TASK task, /**< [in]  */
    int32_t dbn /**< [in]  */
    );

/** \brief Associate a singleton cursor with the specified singleton record

    This function creates a singleton cursor containing a singleton
    record.  The resulting singleton cursor will be positioned at the
    singleton record.  Currently the only singleton record type that
    is supported is the SYSTEM record.  This cursor can be used to
    retrieve members of sets that have the system record as an owner.

    If the database does not have a system record then an error will
    be returned and the cursor will not be associated.

    Cursor will be associated with the specified database.  If cursor
    was previously associated with another RDM database that
    association will be removed prior to adding cursor to the new
    database.

    If the cursor previously held a different set of records then
    memory may need to be reallocated to handle the new set of
    records.  If you are interacting with more than one set of records
    it can be more efficient to use multiple cursors than to share a
    single cursor across all of them.

    \returns A RDM status code
    \retval S_OKAY Success
    \retval S_TRPRECOMMITTED
    \retval S_INVDB
    \retval S_INVCURSOR
    \retval S_NOTSINGLETON
    \retval S_NOMEMORY

    \ingroup  association

    \see dh_cursorAlloc
    \see set
*/
RDM_EXPORT int32_t EXTERNAL_FCN dh_getRecord (
    RDM_DB db, /**< [in] A valid RDM database */
    int32_t rec_id,  /**< [in] The record id for the singleton record */
    RDM_CURSOR cursor /**< [out] The cursor that is being associated */
    );

/** \brief Position a cursor to the first record in the collection

    This function 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 and the function will
    return S_EOC.

    \par Locking Requirements in ReadOnly-Strict/Shared-Strict Mode
    Read lock on the record(s) associated with the cursor
    
    \returns A RDM status code
    \retval S_OKAY Success
    \retval S_EOC No records in the collection
    \retval S_TRPRECOMMITTED
    \retval S_INVCURSOR
    \retval S_INVCURSOR_OP
    \retval S_SET_GONE
    \retval S_RECORD_GONE
    \retval S_NOTLOCKED

    \ingroup  navigation

    \see association
    \see navigation
    \see position
    \see read
    \see update
    \see delete
    \see set
 */
RDM_EXPORT int32_t EXTERNAL_FCN dc_first(
    RDM_CURSOR cursor /**< [in] The cursor to be positioned */
    );

/** \brief Position a cursor to the last record in the collection

    This function 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 and the function will
    return S_EOC.
    
    \par Locking Requirements in ReadOnly-Strict/Shared-Strict Mode
    Read lock on the record(s) associated with the cursor

    \returns A RDM status code
    \retval S_OKAY Success
    \retval S_EOC No records in the collection
    \retval S_TRPRECOMMITTED
    \retval S_INVCURSOR
    \retval S_INVCURSOR_OP
    \retval S_SET_GONE
    \retval S_RECORD_GONE
    \retval S_NOTLOCKED

    \ingroup  navigation

    \see association
    \see navigation
    \see position
    \see read
    \see update
    \see delete
    \see set
 */
RDM_EXPORT int32_t EXTERNAL_FCN dc_last(
    RDM_CURSOR cursor /**< [in] The cursor to be positioned */
    );

/** \brief Position a cursor to the next record in the collection

    This function 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 and the function will
    return the status S_EOC.

    If cursor was positioned to AfterLast then the function will
    return the error S_INVALID_ITERATION.
    
    \par Locking Requirements in ReadOnly-Strict/Shared-Strict Mode
    Read lock on the record(s) associated with the cursor

    \returns A RDM status code
    \retval S_OKAY Success
    \retval S_EOC Reached the end of the collection
    \retval S_INVALID_ITERATION
    \retval S_LOST_POSITION
    \retval S_TRPRECOMMITTED
    \retval S_INVCURSOR
    \retval S_INVCURSOR_OP
    \retval S_SET_GONE
    \retval S_RECORD_GONE
    \retval S_NOTLOCKED

    \ingroup  navigation

    \see association
    \see navigation
    \see position
    \see read
    \see update
    \see delete
    \see set
 */
RDM_EXPORT int32_t EXTERNAL_FCN dc_next(
    RDM_CURSOR cursor /**< [in] The cursor to be positioned */
    );

/** \brief Position a cursor to the previous record in the collection

    This function 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 and the function
    will return the status S_EOC.

    If cursor was positioned to BeforeFirst then the function will
    return the error S_INVALID_ITERATION.

    \par Locking Requirements in ReadOnly-Strict/Shared-Strict Mode
    Read lock on the record(s) associated with the cursor
    
    \returns A RDM status code
    \retval S_OKAY Success
    \retval S_EOC Reached the end of the collection
    \retval S_INVALID_ITERATION
    \retval S_LOST_POSITION
    \retval S_TRPRECOMMITTED
    \retval S_INVCURSOR
    \retval S_INVCURSOR_OP
    \retval S_SET_GONE
    \retval S_RECORD_GONE
    \retval S_NOTLOCKED

    \ingroup  navigation

    \see association
    \see navigation
    \see position
    \see read
    \see update
    \see delete
    \see set
 */
RDM_EXPORT int32_t EXTERNAL_FCN dc_prev(
    RDM_CURSOR cursor /**< [in] The cursor to be positioned */
    );

/** \brief Position a cursor based on a key value

    This function will position a cursor to the first record in the
    collection that has the key value specified by the
    key_value parameter.  cursor can be any type of cursor and does
    not need to be a key scan cursor based on key_id.

    If there is no exact match then:

    - If the cursor is a key scan cursor based on the same key as the
      provided key then the function will return S_NOTFOUND and the
      cursor will be placed in the CURSOR_BETWEEN_KEYS position.
      Navigating forward (dc_next) from that position will position
      the cursor at the next key value larger than the specified key
      value.  Navigating backward (dc_prev) from that position will
      position the cursor at the next key value smaller than the
      specified key value. 

    - Otherwise the function will return S_NOT_IN_CURSOR and the
      cursor position will be left unchanged.

    \par Locking Requirements in ReadOnly-Strict/Shared-Strict Mode
    Read lock on the record(s) associated with the cursor
    
    \returns A RDM status code
    \retval S_OKAY Success
    \retval S_NOTFOUND Did not find an exact match, but positioned cursor between keys
    \retval S_TRPRECOMMITTED
    \retval S_INVCURSOR
    \retval S_INVCURSOR_OP
    \retval S_SET_GONE
    \retval S_RECORD_GONE
    \retval S_INVPTR
    \retval S_NOTKEY
    \retval S_INV_KEYLEN
    \retval S_INVCURSOR_FLD
    \retval S_NOT_IN_CURSOR
    \retval S_NOTLOCKED

    \ingroup  navigation

    \see association
    \see navigation
    \see position
    \see read
    \see update
    \see delete
    \see set
 */
RDM_EXPORT int32_t EXTERNAL_FCN dc_findByKey(
    RDM_CURSOR cursor, /**< [in] The cursor to be positioned */
    int32_t key_id, /**< [in] The field or compound key id */
    const void *key_value, /**< [in] The key value to position to */
    uint32_t len /**< [in] The key value length */
    );

/** \brief Position a cursor based on a partial key value

    This function will position a cursor to the first record in the
    collection that has the key value specified by the
    key_value parameter.  cursor can be any type of cursor and does
    not need to be a key scan cursor based on key_id.  Using the partial
    key allows not all of the fields in a compound key to be considered
    in the search.

    If there is no exact match then:

    - If the cursor is a key scan cursor based on the same key as the
      provided key then the function will return S_NOTFOUND and the
      cursor will be placed in the CURSOR_BETWEEN_KEYS position.
      Navigating forward (dc_next) from that position will position
      the cursor at the next key value larger than the specified key
      value.  Navigating backward (dc_prev) from that position will
      position the cursor at the next key value smaller than the
      specified key value. 

    \par Locking Requirements in ReadOnly-Strict/Shared-Strict Mode
    Read lock on the record(s) associated with the cursor

    \returns A RDM status code
    \retval S_OKAY Success
    \retval S_NOTFOUND Did not find an exact match, but positioned cursor between keys
    \retval S_TRPRECOMMITTED
    \retval S_INVCURSOR
    \retval S_INVCURSOR_OP
    \retval S_SET_GONE
    \retval S_RECORD_GONE
    \retval S_INVPTR
    \retval S_NOTKEY
    \retval S_INV_KEYLEN
    \retval S_INVCURSOR_FLD
    \retval S_NOT_IN_CURSOR
    \retval S_NOTLOCKED

    \ingroup  navigation

    \see association
    \see navigation
    \see position
    \see read
    \see update
    \see delete
    \see set
 */
RDM_EXPORT int32_t EXTERNAL_FCN dc_findByPartialKey(
    RDM_CURSOR cursor,  /**< [in] The cursor to be positioned */
    int32_t key_id, /**< [in] The field or compound key id */
    const void *key_value, /**< [in] The key value to position to */
    uint32_t len, /**< [in] The key value length */
    uint16_t num_key_flds, /**< [in] The number of columns in a compound key to consider (0 to use all of them) */
    uint16_t str_len /**< [in] The number of characters to use in the search if the last column is a string (0 to use all characters) */
    );

/** \brief Position a cursor based on a database address

    This function will position a cursor to the record at database
    address specified by dba.  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 (dc_next)
      from that position will position the cursor at the next DBA
      larger than the specified DBA.  Navigating backward (dc_prev)
      from that position will position the cursor at the next DBA
      smaller than the specified DBA.

    - Otherwise the function will return S_NOT_IN_CURSOR and the
      cursor position will be left unchanged.

    \par Locking Requirements in ReadOnly-Strict/Shared-Strict Mode
    Read lock on the record(s) associated with the cursor
    
    \returns A RDM status code
    \retval S_OKAY Success
    \retval S_NOTFOUND Did not find an exact match, but positioned cursor between records
    \retval S_TRPRECOMMITTED
    \retval S_INVCURSOR
    \retval S_INVCURSOR_OP
    \retval S_SET_GONE
    \retval S_RECORD_GONE
    \retval S_INVPTR
    \retval S_NOTKEY
    \retval S_INVADDR
    \retval S_NOT_IN_CURSOR
    \retval S_NOTLOCKED

    \ingroup  navigation

    \see association
    \see navigation
    \see position
    \see read
    \see update
    \see delete
    \see set
 */
RDM_EXPORT int32_t EXTERNAL_FCN dc_findByDBA(
    RDM_CURSOR cursor, /**< [in] The cursor to be positioned */
    const DB_ADDR *dba /**< [in] The database address to position to */
    );

/** \brief Position a cursor to the BeforeFirst position

    This function will position a cursor to the BeforeFirst position.

    \par Locking Requirements
    None
    
    \returns A RDM status code
    \retval S_OKAY Success
    \retval S_TRPRECOMMITTED
    \retval S_INVCURSOR
    \retval S_INVCURSOR_OP
    \retval S_SET_GONE
    \retval S_RECORD_GONE
    \retval S_NOT_RELATED

    \ingroup  navigation

    \see navigation
    \see position
 */
RDM_EXPORT int32_t EXTERNAL_FCN dc_beforeFirst(
    RDM_CURSOR cursor /**< [in] The cursor to be positioned */
    );

/** \brief Position a cursor to the AfterLast position

    This function will position a cursor to the AfterLast position.

    \par Locking Requirements
    None
    
    \returns A RDM status code
    \retval S_OKAY Success
    \retval S_TRPRECOMMITTED
    \retval S_INVCURSOR
    \retval S_INVCURSOR_OP
    \retval S_SET_GONE
    \retval S_RECORD_GONE

    \ingroup  navigation

    \see navigation
    \see position
 */
RDM_EXPORT int32_t EXTERNAL_FCN dc_afterLast(
    RDM_CURSOR cursor /**< [in] The cursor to be positioned */
    );

/** \brief Position a cursor based on a record

    This function will position a cursor to the current record of
    another cursor. If the record is not in the collection an
    error (S_NOT_IN_CURSOR) will be returned and the cursor position will be
    left unchanged.

    If the exact cursor position and not the current record is wanted
    (the two cursors have to be of the same type) one would need to
    use dc_clone instead.

    \par Locking Requirements in ReadOnly-Strict/Shared-Strict Mode
    Read lock on the record(s) associated with the cursor
    
    \returns A RDM status code
    \retval S_OKAY Success
    \retval S_TRPRECOMMITTED
    \retval S_INVCURSOR
    \retval S_INVCURSOR_OP
    \retval S_SET_GONE
    \retval S_RECORD_GONE
    \retval S_NOT_RELATED
    \retval S_NOCR
    \retval S_NOT_IN_CURSOR
    \retval S_NOTLOCKED

    \ingroup  navigation

    \see association
    \see navigation
    \see position
    \see read
    \see update
    \see delete
    \see set
 */
RDM_EXPORT int32_t EXTERNAL_FCN dc_findByRecord(
    RDM_CURSOR cursor1, /**< [in] The cursor to be positioned */
    RDM_CURSOR_C cursor2 /**< [in] The record to position to */
    );

/** \brief Check a cursor for special conditions

    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 dc_next, dc_prev, dc_first, dc_last,
    dc_beforeFirst, dc_afterLast, or any of the dc_find* functions),
    use d_createRecord, or associate a cursor using any of the d_get*
    functions the cursor will be in any of these states (special
    conditions); 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 dc_next and
    dc_prev. Other types of navigation based on this cursor is using
    the current record and not the virtual position. dc_clone will make
    an exact copy with the exact same state, position, and current
    record.
    
    \par Locking Requirements
    None
    
    \returns A RDM status code
    \retval S_OKAY Success
    \retval S_TRPRECOMMITTED
    \retval S_INVCURSOR
    \retval S_INVCURSOR_OP
    \retval S_SET_GONE
    \retval S_RECORD_GONE
    \retval S_NOT_RELATED

    \ingroup  position

    \see association
    \see navigation
    \see position
    \see read
    \see update
    \see delete
    \see set
 */
RDM_EXPORT int32_t EXTERNAL_FCN dc_checkPosition(
    RDM_CURSOR cursor, /**< [in] The cursor whose position is being checked */
    RDM_CURSOR_POSITION *position /**< [out] The check position result value */
    );

/** \brief Check to see if a cursor is positioned before the first record in a collection

    This function will set is_before_first to RDM_TRUE if the cursor
    is positioned before the first record in the cursor colleciton.

    \par Locking Requirements
    None
    
    \returns A RDM status code
    \retval S_OKAY Success
    \retval S_TRPRECOMMITTED
    \retval S_INVCURSOR
    \retval S_INVCURSOR_OP
    \retval S_SET_GONE
    \retval S_RECORD_GONE
    \retval S_LOST_POSITION

    \ingroup  position

    \see association
    \see navigation
    \see position
    \see read
    \see update
    \see delete
    \see set
 */
RDM_EXPORT int32_t EXTERNAL_FCN dc_isBeforeFirst(
    RDM_CURSOR_C cursor, /**< [in] The cursor whose position is being checked */
    RDM_BOOLEAN *is_before_first /**< [out] A pointer to the returned condition */
    );

/** \brief Check to see if a cursor is positioned after the last record in a collection

    This function will set is_after_last to RDM_TRUE if the cursor is
    positioned after the last record in the cursor colleciton.

    \par Locking Requirements
    None
    
    \returns A RDM status code
    \retval S_OKAY Success
    \retval S_TRPRECOMMITTED
    \retval S_INVCURSOR
    \retval S_INVCURSOR_OP
    \retval S_SET_GONE
    \retval S_RECORD_GONE
    \retval S_LOST_POSITION

    \ingroup  position

    \see association
    \see navigation
    \see position
    \see read
    \see update
    \see delete
    \see set
 */
RDM_EXPORT int32_t EXTERNAL_FCN dc_isAfterLast(
    RDM_CURSOR_C cursor, /**< [in] The cursor whose position is being checked */
    RDM_BOOLEAN *is_after_last /**< [out] A pointer to the returned condition */
    );

/** \brief compare the position of a cursor reletive to another cursur

    This function compares the current position of cursor_primary
    relative to cursor_secondary.

    If the cursor types are not the same the current record of the
    secondary will be used and then converted to a position in the
    cursor type of cursor_primary. If the current record of the
    secondary is not a valid cursor position in the primary an error
    will be returned.
    
    This more specifically means:

    - If cursor_primary is a key cursor the comparison will be based
      on key value.

    - If cursor_primary is a record cursor the comparison will be
      based on database address value

    - If cursor_primary is a set member cursor the comparison will be
      based on the order in the set chain

    - If cursor_primary is a singleton cursor the comparison is only
      valid if cursor_secondary and cursor_primary are the same record
      (there is no order for a singleton)

    - If the record at the current position of cursor_secondary is not
      in the collection of cursor_primary an error will be
      returned.

    - There are two distinct types of errors to be returned when the
      record in cursor_secondary is not found in the collection of
      cursor_primary:

       - If records in cursor_secondary can never be in the collection
         of cursor_primary based on the schema information (it is a
         different record type or from another database) then
         S_NOT_RELATED will be returned.

       - If the record in cursor_secondary could be found in the
         collecion cursor_primary but is not (it has a different set
         owner) then S_NOT_IN_CURSOR is returned.

    - 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.

    \par Locking Requirements
    None
    
    \returns A RDM status code
    \retval S_OKAY Success
    \retval S_TRPRECOMMITTED
    \retval S_INVCURSOR
    \retval S_INVCURSOR_OP
    \retval S_SET_GONE
    \retval S_RECORD_GONE
    \retval S_LOST_POSITION
    \retval S_NOT_RELATED
    \retval S_NOT_IN_CURSOR

    \ingroup position

    \see association
    \see navigation
    \see position
    \see read
    \see update
    \see delete
    \see set
 */
RDM_EXPORT int32_t EXTERNAL_FCN dc_comparePosition(
    RDM_CURSOR_C cursor_primary, /**< [in] The cursor whose current record is being checked relative to cursor_secondary */
    RDM_CURSOR_C cursor_secondary, /**< [in] The cursor whose current record is being check against  */
    RDM_CURSOR_COMPARE *comparison /**< [in] A pointer to the returned comparison result value */
    );


/** \brief Create a new database record

    This function adds a new record to the database.  It can
    optionally return a singleton cursor containing the newly created
    record.

    The record created will be of the type specified by rec_id.

    If the size of the buffer is smaller than the size required to
    fully define a record then the S_BUFFER_TOO_SMALL error will be
    returned an no record will be created.  If the value of len is 0
    then no buffer checking will be done.

    If the size of the buffer is larger than the size required to
    fully define a record then the extra bytes will be ignored and no
    status will be returned.

    If field_values is NULL and len is 0 then an attempt to create an
    empty record will be made.  This will allow the cursor library to
    create a record that does not contain any user data.  If the
    record to be created does have fields and has a unique index on
    one (or more) of those fields then only one empty record can
    exist.

    If a cursor is returned it will be a singleton positioned to the
    newly created record.

    The cursor will be associated with the specified database.  If the
    cursor was previously associated with another RDM database that
    association will be removed prior to adding the cursor to the new
    database.

    If the cursor previously held a different set of records then
    memory may need to be reallocated to handle the new set of
    records.  If you are interacting with more than one set of records
    it can be more efficient to use multiple cursors than to share a
    single cursor across all of them.
    
    \par Locking Requirements in Shared/Shared-Strict Mode
    Write lock on the record type a record is being created for

    \returns A RDM status code
    \retval S_OKAY Success
    \retval S_TRPRECOMMITTED
    \retval S_INVDB
    \retval S_INVCURSOR
    \retval S_DELSYS
    \retval S_INVREC
    \retval S_INVPTR
    \retval S_NOTLOCKED
    \retval S_NOTRANS
    \retval S_NOMEMORY
    \retval S_DUPLICATE
    \retval S_BUFFER_TOO_SMALL

    \ingroup insert

    \see dh_cursorAlloc
    \see association
    \see update
    \see set
 */
RDM_EXPORT int32_t EXTERNAL_FCN dh_createRecord(
    RDM_DB db, /**< [in] A valid RDM database */
    int32_t rec_id, /**< [in] The record id for the record to create */
    const void *field_values, /**< [in] A buffer that contains the field values of the record to be inserted.  If field_values is NULL then an attempt to create an empty record will be made. */
    uint32_t len, /**< [in] The length of the field_values buffer.  If field_values is NULL this value should be 0. */
    RDM_CURSOR cursor /**< [out] Pointer to the allocated cursor for the newly created record. */
    );
RDM_EXPORT int32_t EXTERNAL_FCN d_createRecord(int32_t rec_id, const void *field_values, uint32_t len, RDM_CURSOR cursor, RDM_TASK task, int32_t dbn);

/** \brief Create a new database record

    This function adds a new record to the database at a specific database 
    address.  It can optionally return a singleton cursor containing the newly 
    created record.

    The record created will be of the type specified by rec_id.

    If the size of the buffer is smaller than the size required to
    fully define a record then the S_BUFFER_TOO_SMALL error will be
    returned an no record will be created.  If the value of len is 0
    then no buffer checking will be done.

    If the size of the buffer is larger than the size required to
    fully define a record then the extra bytes will be ignored and no
    status will be returned.

    If field_values is NULL and len is 0 then an attempt to create an
    empty record will be made.  This will allow the cursor library to
    create a record that does not contain any user data.  If the
    record to be created does have fields and has a unique index on
    one (or more) of those fields then only one empty record can
    exist.

    An error will be returned if the specified database address is not valid
    for the record type specified or is already in use.  This is a specialized
    function and should only be used by developers with a specific need.  The
    more generalized dh_createRecord is the recommended API for creating new
    records in the database.

    If a cursor is returned it will be a singleton positioned to the
    newly created record.

    The cursor will be associated with the specified database.  If the
    cursor was previously associated with another RDM database that
    association will be removed prior to adding the cursor to the new
    database.

    If the cursor previously held a different set of records then
    memory may need to be reallocated to handle the new set of
    records.  If you are interacting with more than one set of records
    it can be more efficient to use multiple cursors than to share a
    single cursor across all of them.
    
    \par Locking Requirements in Shared/Shared-Strict Mode
    Write lock on the record type a record is being created for

    \returns A RDM status code
    \retval S_OKAY Success
    \retval S_TRPRECOMMITTED
    \retval S_INVDB
    \retval S_INVCURSOR
    \retval S_DELSYS
    \retval S_INVREC
    \retval S_INVPTR
    \retval S_NOTLOCKED
    \retval S_NOTRANS
    \retval S_NOMEMORY
    \retval S_DUPLICATE
    \retval S_BUFFER_TOO_SMALL

    \ingroup insert

    \see dh_cursorAlloc
    \see dh_createRecord
    \see association
    \see update
    \see set
 */
RDM_EXPORT int32_t EXTERNAL_FCN dh_createRecordAt(
    RDM_DB db, /**< [in] A valid RDM database */
    int32_t rec_id, /**< [in] The record id for the record to create */
    const void *field_values, /**< [in] A buffer that contains the field values of the record to be inserted.  If field_values is NULL then an attempt to create an empty record will be made. */
    uint32_t len, /**< [in] The length of the field_values buffer.  If field_values is NULL this value should be 0. */
    const DB_ADDR *dba,  /**< [in] The database address to place the new record */
    RDM_CURSOR cursor /**< [out] Pointer to the allocated cursor for the newly created record. */
    );
RDM_EXPORT int32_t EXTERNAL_FCN d_createRecordAt(int32_t rec_id, const void *field_values, uint32_t len, const DB_ADDR *, RDM_CURSOR cursor, RDM_TASK task, int32_t dbn);

/** \brief Read a single field from a record

    This function reads the value of a single field from the record at
    the current record of cursor.

    If the size of the buffer is smaller than the field size then the
    function will write as much field data as possible into buffer and
    return a S_READ_TRUNCATE status code.  There is no guarantee that
    the contents of a truncated field will have valid/useful data (or
    be NULL terminated if the field is a string).

    If the size of the buffer is larger than the field size then the
    function will write the full field values and return S_OKAY.

    The bytes_read parameter can be used to determine how much data
    was read into the buffer.

    \par Locking Requirements in ReadOnly-Strict/Shared-Strict Mode
    Read lock on the record(s) associated with the cursor

    \returns A RDM status code
    \retval S_OKAY Success
    \retval S_TRPRECOMMITTED
    \retval S_INVCURSOR
    \retval S_INVCURSOR_OP
    \retval S_SET_GONE
    \retval S_RECORD_GONE
    \retval S_INVPTR
    \retval S_INVFLD
    \retval S_INVCURSOR_FLD
    \retval S_NOCR
    \retval S_READ_TRUNCATE
    \retval S_NOTLOCKED

    \ingroup read

    \see association
    \see navigation
    \see position
    \see read
    \see update
    \see set
 */
RDM_EXPORT int32_t EXTERNAL_FCN dc_getField(
    RDM_CURSOR_C cursor, /**< [in] The cursor to read data from */
    int32_t field_id, /**< [in] The field identifier of the field to read */
    void *field_value, /**< [in] A pointer to the buffer where the field value will be read */
    uint32_t len, /**< [in] The length of the field_value buffer (in bytes) */
    uint32_t *bytes_read /**< [out] A pointer to the number of bytes actually read */
    );

/** \brief Read all fields from a record

    This function reads all the (non blob) field values from the
    current record of cursor.

    If the size of the buffer is smaller than the record size then the
    function will write as much data as possible into buffer and
    return a S_READ_TRUNCATE status code.  There is no guarantee that
    the contents of a truncated fields will have valid/useful data (or
    be NULL terminated if the field is a string).

    If the size of the buffer is larger than the record size then the
    function will initialize the entire buffer to NULL bytes and then
    write the full record and return S_OKAY.

    The bytes_read parameter can be used to determine how many bytes
    were actually read into the buffer.

    \par Locking Requirements in ReadOnly-Strict/Shared-Strict Mode
    Read lock on the record(s) associated with the cursor

    \returns A RDM status code
    \retval S_OKAY Success
    \retval S_TRPRECOMMITTED
    \retval S_INVCURSOR
    \retval S_INVCURSOR_OP
    \retval S_SET_GONE
    \retval S_RECORD_GONE
    \retval S_INVPTR
    \retval S_NOCR
    \retval S_READ_TRUNCATE
    \retval S_NOTLOCKED

    \ingroup read

    \see association
    \see navigation
    \see position
    \see read
    \see update
    \see set
 */
RDM_EXPORT int32_t EXTERNAL_FCN dc_getFields(
    RDM_CURSOR_C cursor, /**< [in] The cursor to read data from */
    int32_t rec_id, /**< [in] The record id for the current record */
    void *record_values, /**< [in] A pointer to the buffer where record values will be read */
    uint32_t len, /**< [in] The length of the field_value buffer (in bytes) */
    uint32_t *bytes_read /**< [out] A pointer to the number of bytes actually read */
    );

/** \brief Read database blob values

    This function reads contents of a blob field from the current
    record of cursor.

    The read will start from the offset position and will attempt to
    read up to len bytes.  If there are not len bytes left to read and
    the bytes_read parameter is NULL then the function will return the
    S_BLOB_BAD_SIZE error code.  If bytes_read is not NULL then the
    number of bytes actually read into field_value will be returned.

    \par Locking Requirements in ReadOnly-Strict/Shared-Strict Mode
    Read lock on the record(s) associated with the cursor

    \returns A RDM status code
    \retval S_OKAY Success
    \retval S_TRPRECOMMITTED
    \retval S_INVCURSOR
    \retval S_INVCURSOR_OP
    \retval S_SET_GONE
    \retval S_RECORD_GONE
    \retval S_INVPTR
    \retval S_INVFLD
    \retval S_INVCURSOR_FLD
    \retval S_NOTBLOB
    \retval S_NOCR
    \retval S_BLOB_BAD_SIZE
    \retval S_NOTLOCKED

    \ingroup read

    \see association
    \see navigation
    \see position
    \see read
    \see update
    \see delete
    \see set
 */
RDM_EXPORT int32_t EXTERNAL_FCN dc_getBlob(
    RDM_CURSOR_C cursor, /**< [in] The cursor to read data from */
    int32_t field_id, /**< [in] The field identifier of the blob field to read */
    uint32_t offset, /**< [in] Offset into the blob to read */
    void *field_value, /**< [in] A pointer to the buffer where the the blob data will be read */
    uint32_t len, /**< [in] The length the the field_value buffer (max num of bytes to read) */
    uint32_t *bytes_read /**< [out] A pointer to the number of bytes actually read */
    );

/** \brief Get the current size of a blob field

    This function retrieves the current size of a blob field from the
    current record of cursor.

    \par Locking Requirements in ReadOnly-Strict/Shared-Strict Mode
    Read lock on the record(s) associated with the cursor

    \returns A RDM status code
    \retval S_OKAY Success
    \retval S_TRPRECOMMITTED
    \retval S_INVCURSOR
    \retval S_INVCURSOR_OP
    \retval S_SET_GONE
    \retval S_RECORD_GONE
    \retval S_INVPTR
    \retval S_INVFLD
    \retval S_INVCURSOR_FLD
    \retval S_NOTBLOB
    \retval S_NOCR
    \retval S_NOTLOCKED

    \ingroup read

    \see association
    \see navigation
    \see position
    \see read
    \see update
    \see delete
    \see set
 */
RDM_EXPORT int32_t EXTERNAL_FCN dc_getBlobSize(
    RDM_CURSOR_C cursor, /**< [in] The cursor to get the blob size from */
    int32_t field_id, /**< [in] The field identifier of the blob field to get the size of */
    uint32_t *size /**< [out] A pointer to the returned size (in bytes) of the blob */
    );

/** \brief Get the database address of a record

    This function retrieve the database address from the current
    record of cursor.  If the cursor is not at a valid record an error
    will be returned.

    \par Locking Requirements
    None
    
    \returns A RDM status code
    \retval S_OKAY Success
    \retval S_TRPRECOMMITTED
    \retval S_INVCURSOR
    \retval S_INVCURSOR_OP
    \retval S_SET_GONE
    \retval S_RECORD_GONE
    \retval S_INVPTR

    \ingroup read

    \see association
    \see navigation
    \see position
    \see read
    \see update
    \see delete
    \see set
 */
RDM_EXPORT int32_t EXTERNAL_FCN dc_getDBA(
    RDM_CURSOR_C cursor, /**< [in] The cursor to get the database address from  */
    DB_ADDR *dba /**< [out] A pointer to the returned database address */
    );

/** \brief Get the database address of a set owner

    This function retrieve the database address of set owner of
    current record of cursor for the set identified by set_id.  If the
    cursor is not at a valid member of the set identified by set_id an
    error will be returned.

    \par Locking Requirements in ReadOnly-Strict/Shared-Strict Mode
    Read lock on the record(s) associated with the cursor
    
    \returns A RDM status code
    \retval S_OKAY Success
    \retval S_TRPRECOMMITTED
    \retval S_INVCURSOR
    \retval S_INVCURSOR_OP
    \retval S_SET_GONE
    \retval S_RECORD_GONE
    \retval S_INVSET
    \retval S_NOCR
    \retval S_INVMEM
    \retval S_NOMEMORY
    \retval S_NOTLOCKED

    \ingroup read

    \see association
    \see navigation
    \see position
    \see read
    \see update
    \see delete
    \see set
 */
RDM_EXPORT int32_t EXTERNAL_FCN dc_getOwnerDBA(
    RDM_CURSOR_C cursor, /**< [in] The cursor to get the owner database address from  */
    int32_t set_id, /**< [in] The set identifier of the set to get the owner of */
    DB_ADDR *dba /**< [in] A pointer to the returned database address */
    );

/** \brief Update a single field in a record

    This function updates the value of a single field in the current
    record of cursor.

    If the size of the buffer is smaller than the field size an error
    of S_BUFFER_TOO_SMALL will be return and the field will not be
    updated.

    If the size of the buffer is larger than the field size the extra
    bytes will silently be ignored.

    If the cursor is a key scan cursor based on the field that is
    updated then the cursor will maintain the original position but
    current record is kept the same.  Calling dc_next/dc_previous
    will position the cursor relative to the original position and not
    the updated position.  The updated position will be in the
    collection.

    \par Locking Requirements in Shared/Shared-Strict Mode
    Write lock on all the record type for the current record of the cursor

    \returns A RDM status code
    \retval S_OKAY Success
    \retval S_TRPRECOMMITTED
    \retval S_INVCURSOR
    \retval S_INVCURSOR_OP
    \retval S_SET_GONE
    \retval S_RECORD_GONE
    \retval S_INVPTR
    \retval S_INVFLD
    \retval S_INVCURSOR_FLD
    \retval S_BLOBUPD
    \retval S_NOCR
    \retval S_NOTLOCKED
    \retval S_NOTRANS
    \retval S_BUFFER_TOO_SMALL
    \retval S_DUPLICATE

    \ingroup update

    \see association
    \see navigation
    \see position
    \see read
    \see update
    \see delete
    \see set
*/
RDM_EXPORT int32_t EXTERNAL_FCN dc_setField(
    RDM_CURSOR cursor, /**< [in] The cursor containing the record to be updated */
    int32_t field_id, /**< [in] The field identifier of the field to be updated */
    const void *field_value, /**< [in] A pointer to the buffer containing the new field value */
    uint32_t len /**< [in] The length of the field_value buffer */
    );

/** \brief Update all fields in a record

    This function updates all field values except for blobs in current
    record of cursor.

    If the size of the buffer is smaller than the size required to
    full define a record then an error code of S_BUFFER_TOO_SMALL will
    be return and no fields will be updated.

    If the size of the buffer is larger than the size required to
    fully define a record then the extra bytes will silently be
    ignored.

    If the cursor is a key scan cursor then the cursor will maintain
    the original position but current record is kept the same.
    Calling dc_next/dc_previous will position the cursor relative to
    the original position and not the updated position.  The updated
    position will be in the collection.

    \par Locking Requirements in Shared/Shared-Strict Mode
    Write lock on the record type for the current record of the cursor

    \returns A RDM status code
    \retval S_OKAY Success
    \retval S_TRPRECOMMITTED
    \retval S_INVCURSOR
    \retval S_INVCURSOR_OP
    \retval S_SET_GONE
    \retval S_RECORD_GONE
    \retval S_NOCR
    \retval S_INVPTR
    \retval S_NOTLOCKED
    \retval S_NOTRANS
    \retval S_BUFFER_TOO_SMALL
    \retval S_DUPLICATE

    \ingroup update

    \see association
    \see navigation
    \see position
    \see read
    \see update
    \see delete
    \see set
 */
RDM_EXPORT int32_t EXTERNAL_FCN dc_setFields(
    RDM_CURSOR cursor, /**< [in] The cursor containing the record to be updated */
    int32_t rec_id, /**< [in] The record id for the current record */
    const void *record_values, /**< [in] A pointer to the buffer containing the new field values  */
    uint32_t len /**< [in] The length of the field_values buffer */
    );

/** \brief Update a blob field in a record

    This function updates the value of a blob field in current record
    of cursor.

    If offset is smaller than the current size of the blob existing
    data will be overwritten.

    If offset is larger than the current size of the blob the blob
    will be padded with NULL bytes to extend the size of the blob to
    offset.

    \par Locking Requirements in Shared/Shared-Strict Mode
    Write lock on all record type for the current record of the cursor

    \returns A RDM status code
    \retval S_OKAY Success
    \retval S_TRPRECOMMITTED
    \retval S_INVCURSOR
    \retval S_INVCURSOR_OP
    \retval S_SET_GONE
    \retval S_RECORD_GONE
    \retval S_INVPTR
    \retval S_INVFLD
    \retval S_INVCURSOR_FLD
    \retval S_NOTBLOB
    \retval S_NOCR
    \retval S_NOTLOCKED
    \retval S_NOTRANS

    \ingroup update

    \see association
    \see navigation
    \see position
    \see read
    \see update
    \see delete
    \see set
*/
RDM_EXPORT int32_t EXTERNAL_FCN dc_setBlob(
    RDM_CURSOR_C cursor, /**< [in] The cursor containing the record with blob to be updated */
    int32_t field_id, /**< [in] The field identifier of the blob field to be updated  */
    uint32_t offset, /**< [in] The offset into the blob to write the updated content */
    const void *blob_value, /**< [in] A pointer to the content to be written to the blob field */
    uint32_t size /**< [in] The length of the blob_value buffer */
    );

/** \brief Set the size of a blob field in a record

    This function updates the size of a blob field in current record
    of cursor.

    If size is smaller than the current size of the blob existing data
    will be truncated.

    If size is larger than the current size of the blob the blob will
    be padded with NULL bytes to extend the size of the blob.

    \par Locking Requirements in Shared/Shared-Strict Mode
    Write lock on the record type for the current record of the cursor

    \returns A RDM status code
    \retval S_OKAY Success
    \retval S_TRPRECOMMITTED
    \retval S_INVCURSOR
    \retval S_INVCURSOR_OP
    \retval S_SET_GONE
    \retval S_RECORD_GONE
    \retval S_INVFLD
    \retval S_INVCURSOR_FLD
    \retval S_NOTBLOB
    \retval S_NOCR
    \retval S_NOTLOCKED
    \retval S_NOTRANS

    \ingroup update

    \see association
    \see navigation
    \see position
    \see read
    \see update
    \see delete
    \see set
*/
RDM_EXPORT int32_t EXTERNAL_FCN dc_setBlobSize(
    RDM_CURSOR_C cursor, /**< [in] The cursor containing the record with the blob to change the size of */
    int32_t field_id, /**< [in] The field identifier of the blob field to change the size of */
    uint32_t size /**< [in] The new size of the blob field */
    );

/** \brief Remove a record from the database

    This function 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.

    \par Locking Requirements in Shared/Shared-Strict Mode
    Write lock on the record type for the current record of the cursor

    \returns A RDM status code
    \retval S_OKAY Success
    \retval S_TRPRECOMMITTED
    \retval S_INVCURSOR
    \retval S_INVCURSOR_OP
    \retval S_SET_GONE
    \retval S_RECORD_GONE
    \retval S_NOCR
    \retval S_NOTLOCKED
    \retval S_NOTRANS
    \retval S_DELETED
    \retval S_DELCIRC
    \retval S_HASMEM
    \retval S_ISMEM

    \ingroup delete

    \see association
    \see navigation
    \see position
    \see read
    \see update
    \see delete
    \see set
*/
RDM_EXPORT int32_t EXTERNAL_FCN dc_delete(
    RDM_CURSOR cursor /**< [in] The cursor whose current record will be deleted */
    );

/** \brief Disconnect a record from all sets and remove 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.
    
    \par Locking Requirements in Shared/Shared-Strict Mode
    Write lock on all the record type for associated with set_id


    \returns A RDM status code
    \retval S_OKAY Success
    \retval S_TRPRECOMMITTED
    \retval S_INVCURSOR
    \retval S_INVCURSOR_OP
    \retval S_SET_GONE
    \retval S_RECORD_GONE
    \retval S_NOCR
    \retval S_NOTLOCKED
    \retval S_NOTRANS
    \retval S_DELETED
    \retval S_DELCIRC

    \ingroup set delete

    \see association
    \see navigation
    \see position
    \see read
    \see update
    \see delete
    \see set
*/
RDM_EXPORT int32_t EXTERNAL_FCN dc_disconnectAndDelete(
    RDM_CURSOR cursor /**< [in] The cursor whose current record will be disconnected and deleted */
    );

/** \brief Connect a record to an owner

    This function connects the current record of cursor to the currect
    record of cursor_owner for the set identified by set_id.

    cursor does not need to be a set cursor, but must be a cursor
    whose current record is a valid member of set_id

    cursor_owner does not need to be a set cursor, but must be a
    cursor whose current record is a valid owner of set_id

    \par Locking Requirements in Shared/Shared-Strict Mode
    Write lock on all the record types associated to set_id

    \returns A RDM status code
    \retval S_OKAY Success
    \retval S_TRPRECOMMITTED
    \retval S_INVCURSOR
    \retval S_INVCURSOR_OP
    \retval S_SET_GONE
    \retval S_RECORD_GONE
    \retval S_NOT_RELATED
    \retval S_INVSET
    \retval S_NOCR
    \retval S_LOST_POSITION
    \retval S_NOCO
    \retval S_INVOWN
    \retval S_UNION_MISMATCH
    \retval S_NOTLOCKED
    \retval S_NOTRANS
    \retval S_ISOWNED

    \ingroup set

    \see association
    \see navigation
    \see position
    \see read
    \see update
    \see delete
    \see set
 */
RDM_EXPORT int32_t EXTERNAL_FCN dc_connect(
    RDM_CURSOR_C cursor, /**< [in] The record to connect */
    int32_t set_id, /**< [in] The set identifer for the connection */
    RDM_CURSOR_C cursor_owner /**< [in] The owner to connect to */
    );

/** \brief Disconnect a record from one owner and connect to another

    This function connects the current record of cursor to the currect
    record of cursor_owner for the set identified by set_id.  If the
    record is already connected to a different owner it will be
    disconnect from that owner before being connected to the new
    owner.

    cursor does not need to be a set cursor, but it must be a cursor
    whose current record is a valid member of set_id

    cursor_owner does not need to be a set cursor, but must be a
    cursor whose current record is a valid owner of set_id

    If cursor is a set cursor based on set_id the position of the
    cursor will remain at the same location even though the record is
    no longer in the set chain.  This is considered a virtual position
    CURSOR_RELINKED.  It is not possible to read or write to a record
    when we are in this virtual position, but navigation is possible
    and will act as if we are navigating from the original cursor
    position.

    \par Locking Requirements in Shared/Shared-Strict Mode
    Write lock on all the record types associated to set_id

    \returns A RDM status code
    \retval S_OKAY Success
    \retval S_TRPRECOMMITTED
    \retval S_INVCURSOR
    \retval S_INVCURSOR_OP
    \retval S_SET_GONE
    \retval S_RECORD_GONE
    \retval S_NOT_RELATED
    \retval S_INVSET
    \retval S_LOST_POSITION
    \retval S_NOCR
    \retval S_NOCO
    \retval S_INVOWN
    \retval S_UNION_MISMATCH
    \retval S_NOTLOCKED
    \retval S_NOTRANS
    \retval S_NOTCON

    \ingroup set

    \see association
    \see navigation
    \see position
    \see read
    \see update
    \see delete
    \see set
 */
RDM_EXPORT int32_t EXTERNAL_FCN dc_reconnect(
    RDM_CURSOR cursor, /**< [in] The record to connect */
    int32_t set_id, /**< [in] The set identifer for the connection  */
    RDM_CURSOR_C cursor_owner /**< [in] The owner to connect to */
    );

/** \brief Add a record to a set cursor (connect)

    This function connects the record in the current record of cursor
    to the set associated with set_cursor.

    set_cursor must be a set cursor and cursor must be a valid set
    member for the set.

    \par Locking Requirements in Shared/Shared-Strict Mode
    Write lock on all the record types associated to the set set_cursor is based on

    \returns A RDM status code
    \retval S_OKAY Success
    \retval S_TRPRECOMMITTED
    \retval S_INVCURSOR
    \retval S_INVCURSOR_OP
    \retval S_SET_GONE
    \retval S_RECORD_GONE
    \retval S_NOT_RELATED
    \retval S_NOCR
    \retval S_LOST_POSITION
    \retval S_UNION_MISMATCH
    \retval S_NOTLOCKED
    \retval S_NOTRANS
    \retval S_ISOWNED

    \ingroup set

    \see association
    \see navigation
    \see position
    \see read
    \see update
    \see delete
    \see set
 */
RDM_EXPORT int32_t EXTERNAL_FCN dc_addMember(
    RDM_CURSOR_C set_cursor, /**< [in] The set cursor whose set the record will be added to */
    RDM_CURSOR_C cursor /**< [in] The record to add */
    );

/** \brief Disconnect a record from its owner

    This function disconnects current record of cursor from the owner
    for set identified by set_id.

    If cursor is a set cursor based on the spcified set_id then the
    cursor will maintain the original current record and position even
    though the record is no longer in the set.  Calling
    dc_next/dc_prev will position the cursor relative to the original
    position.

    \par Locking Requirements in Shared/Shared-Strict Mode
    Write lock on all the record types associated to set_id

    \returns A RDM status code
    \retval S_OKAY Success
    \retval S_TRPRECOMMITTED
    \retval S_INVCURSOR
    \retval S_INVCURSOR_OP
    \retval S_SET_GONE
    \retval S_RECORD_GONE
    \retval S_INVSET
    \retval S_NOCR
    \retval S_NOTLOCKED
    \retval S_NOTRANS
    \retval S_NOTCON

    \ingroup set

    \see association
    \see navigation
    \see position
    \see read
    \see update
    \see delete
    \see set
*/
RDM_EXPORT int32_t EXTERNAL_FCN dc_disconnect(
    RDM_CURSOR cursor, /**< [in] The record to disconnect */
    int32_t set_id /**< [in] The set identifer for the connection */
    );

/** \brief Remove a record from a set cursor (disconnect)

    This function disconnects current record of set_cursor from the set
    associated with set_cursor.

    set_cursor must be a set cursor
    
    The set_cursor will maintain the origin current record and
    position even though the current record is no longer in the set.
    Calling dc_next/dc_prev will position the cursor relative to the
    original position.

    \par Locking Requirements in Shared/Shared-Strict Mode
    Write lock on all the record types associated to the set set_cursor is based on

    \returns A RDM status code
    \retval S_OKAY Success
    \retval S_TRPRECOMMITTED
    \retval S_INVCURSOR
    \retval S_INVCURSOR_OP
    \retval S_SET_GONE
    \retval S_RECORD_GONE
    \retval S_INVSET
    \retval S_NOCR
    \retval S_NOTLOCKED
    \retval S_NOTRANS
    \retval S_NOTCON

    \ingroup set

    \see association
    \see navigation
    \see position
    \see read
    \see update
    \see delete
    \see set
*/
RDM_EXPORT int32_t EXTERNAL_FCN dc_removeMember(
    RDM_CURSOR set_cursor /**< [in] The record we want to remove */
    );

/** \brief Get the record type

    This function returns the record identifier of the record that is
    in the current position of cursor

    \par Locking Requirements
    None
    
    \returns A RDM status code
    \retval S_OKAY Success
    \retval S_TRPRECOMMITTED
    \retval S_INVCURSOR
    \retval S_INVCURSOR_OP
    \retval S_SET_GONE
    \retval S_RECORD_GONE
    \retval S_INVPTR

    \ingroup read

    \see association
    \see navigation
    \see position
    \see read
    \see update
    \see delete
    \see set
 */
RDM_EXPORT int32_t EXTERNAL_FCN dc_getRecType(
    RDM_CURSOR_C cursor, /**< [in] The cursor to get the record type for */
    int32_t *rec_id /**< [out] A pointer to the returned record type */
    );

/** \brief Get the member count for a set

    This function calculates the member count for the owner identified
    by current record of cursor for set identified by set_id.

    Current record of cursor must be a valid owner of set_id.

    \par Locking Requirements in ReadOnly-Strict/Shared-Strict Mode
    Read lock on the record(s) associated with the cursor
    
    \returns A RDM status code
    \retval S_OKAY Success
    \retval S_TRPRECOMMITTED
    \retval S_INVCURSOR
    \retval S_INVCURSOR_OP
    \retval S_SET_GONE
    \retval S_RECORD_GONE
    \retval S_INVSET
    \retval S_INVPTR
    \retval S_NOCR
    \retval S_NOTLOCKED

    \ingroup set

    \see association
    \see navigation
    \see position
    \see read
    \see update
    \see delete
    \see set
 */
RDM_EXPORT int32_t EXTERNAL_FCN dc_getMemberCount(
    RDM_CURSOR_C cursor, /**< [in] The cursor to get the member count of */
    int32_t set_id, /**< [in] The set identifier for the requesting count */
    uint64_t *member_count /**< [out] A pointer to the returned set member count */
    );

/** \brief Get the record count for a cursor

    This function returns the record count for the specified cursor.

    A singleton cursor has by definition only one record.

    \returns A RDM status code
    \retval S_OKAY Success
    \retval S_TRPRECOMMITTED
    \retval S_INVCURSOR
    \retval S_INVCURSOR_OP
    \retval S_SET_GONE
    \retval S_RECORD_GONE
    \retval S_INVPTR
    
    \par Locking Requirements in ReadOnly-Strict/Shared-Strict Mode
    Read lock on the record(s) associated with the cursor

    \ingroup read

    \see association
    \see navigation
    \see position
    \see read
    \see update
    \see delete
    \see set
 */
RDM_EXPORT int32_t EXTERNAL_FCN dc_getCount(
    RDM_CURSOR_C cursor, /**< [in] The cursor to get the record count of  */
    uint64_t *count /**< [out] A pointer to the returned record count */
    );

/** \brief Has a record an owner

    This function checks to see if current record of cursor has a set
    owner (is connected) for the set identified by set_id.

    cursor does not need to be a set cursor but its current record
    must be a valid member of the set identified by set_id.

    The returned condition is set to RDM_TRUE if the record has an owned,
    otherwise RDM_FALSE.
    
    \par Locking Requirements in ReadOnly-Strict/Shared-Strict Mode
    Read lock on the record(s) associated with the set_id id

    \returns A RDM status code
    \retval S_OKAY Success
    \retval S_TRPRECOMMITTED
    \retval S_INVCURSOR
    \retval S_INVCURSOR_OP
    \retval S_SET_GONE
    \retval S_RECORD_GONE
    \retval S_INVSET
    \retval S_INVPTR
    \retval S_INVMEM
    \retval S_NOTLOCKED

    \ingroup set

    \see association
    \see navigation
    \see position
    \see read
    \see update
    \see delete
    \see set
 */
RDM_EXPORT int32_t EXTERNAL_FCN dc_hasOwner(
    RDM_CURSOR_C cursor, /**< [in] The cursor to check set ownership status */
    int32_t set_id, /**< [in] The set identifier for the request */
    RDM_BOOLEAN *has_owner /**< [in] A pointer to the returned condition */
    );

/** \brief Get the RDM Database handle

    This function return the RDM database handle for a cursor.

    \par Locking Requirements
    None
    
    \returns A RDM_DB handle
    \retval RDM_DB The database handle associate with the cursor
    \retval NULL An error or no database handle is associated with the cursor

    \ingroup getdb

    \see association
    \see getdb
 */
RDM_EXPORT RDM_DB EXTERNAL_FCN dc_getDb(
    RDM_CURSOR_C cursor /**< [in] The cursor to get the database handle for */
    );

/** \brief Get the RDM task for a cursor

    This function return the RDM task for a cursor.

    \par Locking Requirements
    None
    
    \returns A RDM_TASK
    \retval RDM_TASK The database task associated with the cursor
    \retval NULL An error or no task is associated with the cursor

    \ingroup getdb

    \see association
    \see getdb
 */
RDM_EXPORT RDM_TASK EXTERNAL_FCN dc_getTask(
    RDM_CURSOR_C cursor /**< [in] The cursor to get the database task for */
    );

/** \brief Return the RDM database number

    This function return the RDM database number for a cursor.

    \par Locking Requirements
    None
    
    \returns A RDM database number
    \retval The RDM The database number associated with the cursor
    \retval VOID_DB An error or no database associated with the cursor

    \ingroup getdb

    \see association
    \see getdb
 */
RDM_EXPORT int32_t EXTERNAL_FCN dc_getDBN(
    RDM_CURSOR_C cursor /**< [in] The cursor to get the database number for */
    );

/** \brief Store an optional key value

    This function will add the value for the specified optional key into the 
    index file.  Once stored, and optional key is automatically modified 
    whenever its field contents are modified.

    \par Locking Requirements in Shared/Shared-Strict Mode
    Write lock on all the record type for the current record of the cursor

    \returns A RDM status code
    \retval S_OKAY Success
    \retval S_TRPRECOMMITTED
    \retval S_INVCURSOR
    \retval S_INVCURSOR_OP
    \retval S_NOCR
    \retval S_NOTKEY
    \retval S_NOTRANS
    \retval S_NOTLOCKED
    \retval S_BADFIELD

    \ingroup optkey

    \see dc_keyRemove
    \see dc_keyExist
 */
RDM_EXPORT int32_t EXTERNAL_FCN dc_keyAdd(
    RDM_CURSOR_C cursor, /**< [in] The cursor whose current record will be used to add the key value to the index file */
    int32_t field_id /**< [in] The field identifier of the optional key to add */
    );

/** \brief Remove an optional key value

    This function will remove the value for the specified optional key from the 
    index file.

    \par Locking Requirements in Shared/Shared-Strict Mode
    Write lock on all the record type for the current record of the cursor

    \returns A RDM status code
    \retval S_OKAY Success
    \retval S_TRPRECOMMITTED
    \retval S_INVCURSOR
    \retval S_INVCURSOR_OP
    \retval S_NOCR
    \retval S_NOTKEY
    \retval S_NOTRANS
    \retval S_NOTLOCKED
    \retval S_BADFIELD

    \ingroup optkey

    \see dc_keyAdd
    \see dc_keyExist
 */
RDM_EXPORT int32_t EXTERNAL_FCN dc_keyRemove(
    RDM_CURSOR_C cursor, /**< [in] The cursor whose current record will be checked for existence in the index file */
    int32_t field_id /**< [in] The field identifier of the optional key to check for existence */
    );

/** \brief Determine whether an optional key exists

    This function determines if the key for optional key field field_id in the current
    record of cursor has been stored.

    \par Locking Requirements in ReadOnly-Strict/Shared-Strict Mode
    Read lock on the record(s) associated with the cursor

    \returns A RDM status code
    \retval S_OKAY The optional key has been stored
    \retval S_NOTFOUND The optional key has not been stored
    \retval S_TRPRECOMMITTED
    \retval S_INVCURSOR
    \retval S_INVCURSOR_OP
    \retval S_NOCR
    \retval S_NOTOPTKEY
    \retval S_BADFIELD
    \retval S_NOTLOCKED

    \ingroup optkey

    \see dc_keyAdd
    \see dc_keyExist
 */
RDM_EXPORT int32_t EXTERNAL_FCN dc_keyExist(
    RDM_CURSOR_C cursor, /**< [in] The cursor whose current record will checked to see if the optional key field eists*/
    int32_t field_id /**< [in] The field identifier of the optional key to check */
    );

#endif /* ! DCURSORPROTO_H */
