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

#ifndef _DB_H
#define _DB_H

#include "DbTypes.h"

namespace RDM_CPP {

/** \brief The Db base class
   
   This Db class provides the base database implmentation.
  
   This is a class with very little overhead - a single pointer - that
   is a 'smart pointer' (i.e. will automatically get destroyed when the last
   reference is removed).
  
   To keep the overhead down this class should have no virtual functions.
*/
/*lint -esym(1790,RDM_CPP::Db) */
class PUBLIC_CLASS Db {
public:
    /* Handle more than one reference to the underlying database */
    
    /*! \brief Db Default Constructor
        
        The default constructor, copy constructor, assignment operator, and 
        destructor implement a smart pointer for the Db interface and it's
        generated subclasses.  The number of references to the underlying 
        implemention object will be maintained.  When the number of references 
        to an implementation object is down to zero the object will be released.

        The default constructor will initialize the number of references to the 
        underlying implementation object to one.
    */
    Db (void) throw ();

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

        The copy constructor will increment the number of references to the 
        underlying implementation object by one.
    */
    Db (const Db& db) throw ();

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

        The assignment operator will increment the number of references to the 
        underlying implementation object by one.
    */
    Db& operator = (const Db& db) throw ();

    /** \brief Initialize or reinitialize the database
      
       This method initilizes (or reinitializes) the database files.  The files
       do not need to exist for this method to be successful.  If the files do
       exist all contents will be truncated and the database will be put into
       the initial empty state.

       An initialize must be the only change operations in an update transaction.
       An exception will be thrown if an update transaction is not active or if
       any other change operations have occured in the update transaction prior
       to calling the Initialize method.
     
       \par Locking Requirements in Shared/Shared-Strict Modes
       An Update transaction with locks on all record types in the database
     
       \throws
       rdm_exception (CPP_INVALID_DB, S_NOTRANS, S_IN_CHANGE_TRANS)

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

    /** \brief Begin reading from a database
      
       Use this method before reading data from the database.  Specify
       the record types you want access to or NULL for every record
       type.  You are not allowed to combine this method with
       BeginUpdate or BeginSnapshot.  Call End when you are done
       reading.
      
       If the types parameter is NULL terminated there is no need to specify 
       the number of items in the array in the num parameter.  However if the 
       types parameter is not NULL terminated an exception can occur if the 
       correct value for num is not provided.
      
       \par Locking Requirements
       None.
       
       \throws
       rdm_exception (CPP_INVALID_DB, CPP_INVALID_TRANSACTION, S_UNAVAIL, S_STATIC, S_INVNUM)
      
       \par Library
       rdmcppapi-12
    */
    void BeginRead (
        const recordType types[]= NULL, /**< [in] An array of record types to be read locked */
        int16_t num = 0 /**< [in] The number of records to be locked */
        ) const throw (const rdm_exception&);

    /** \brief Begin updating a database
        \param types An array of record types to be write locked
        \param num The number of records to be locked
        
       Use this method before making any updates to the database.
       Specify the record types you want access to or NULL for every
       record type.  You are not allowed to combine this method with
       BeginRead or BeginSnapshot.  Call End when you are done with
       the update
      
       If the types parameter is NULL terminated there is no need to specify 
       the number of items in the array in the num parameter.  However if the 
       types parameter is not NULL terminated an exception can occur if the 
       correct value for num is not provided.
      
       \par Locking Requirements
       None.
       
       \throws
       rdm_exception (CPP_INVALID_DB, CPP_INVALID_TRANSACTION, S_UNAVAIL, S_STATIC, S_INVNUM, S_READONLY)
      
       \par Library
       rdmcppapi-12
    */
    void BeginUpdate (
        const recordType types[]= NULL,  /**< [in] An array of record types to be read locked */
        int16_t num = 0 /**< [in] The number of records to be locked */
        ) const throw (const rdm_exception&);

    /** \brief Create a static snapshot of the database
       
       Take a snapshot of the databases for reading data from the
       database.  You are not allowed to combine this method with
       BeginRead or BeginSnapshot.  Call End when you are done
       reading 
      
       \par Locking Requirements
       None.
      
       \throws
       rdm_exception (CPP_INVALID_DB, CPP_INVALID_TRANSACTION)
      
       \par Library
       rdmcppapi-12
    */
    void BeginSnapshot () const throw (const rdm_exception&);

    /** \brief Precommit a database transaction
      
       This methods prepares to commit a transaction by writing to the 
       database log file all changes made since the most recent call to 
       BeginUpdate. Following soon after this call, a End should be 
       called to finally commit the transaction, or Abort to throw it away. 
       The difference between calling Precommit prior to End is that all file 
       I/O necessary to prepare the transaction will be done during the 
       Precommit, and the End has a minimal task, essentially flipping a switch
       to commit the prepared transaction.
      
       This call does not change the status of locks, so it shouldn't be held 
       in this state indefinitely.
      
       No updates or reads should be performed on the database after the 
       Precommit until the end of the transaction.
      
       \par Locking Requirements
       None
       
       \throws
       rdm_exception (CPP_INVALID_DB, CPP_INVALID_TRANSACTION)
       
       \par Library
       rdmcppapi-12
    */
    void Precommit (void) const throw (const rdm_exception&);

    /** \brief End a transaction
      
       This method ends an update, read or snapshot transaction.
      
       If the current transaction is an update all changes since the 
       BeginUpdate will be written to the database. The changes are 
       first written to the log file to support recovery and are then written 
       to the database by the TFS.
      
       End frees all locked files for the database
      
       \par Locking Requirements
       None

       \throws 
       rdm_exception (CPP_INVALID_DB, CPP_INVALID_TRANSACTION)
      
       \par Library
       rdmcppapi-12
    */
    void End (void) const throw (const rdm_exception&);

    /** \brief Abort an update transaction
      
       The method discards all database changes made between the call to 
       BeginUpdate and the call to Abort. 
      
       Abort frees all locked files for the database
      
       Abort is only valid for Update transactions.  If a Read or Snapshot
       transaction is active Abort will throw an exception with the
       CPP_INVALID_TRANSACTION status code.
      
       \par Locking Requirements
       None
      
       \throws 
       rdm_exception (CPP_INVALID_DB, CPP_INVALID_TRANSACTION)
       
       \par Library
       rdmcppapi-12
    */
    void Abort (void) const throw (const rdm_exception&);
    
    /** \brief Destroy a database
      
       This method deletes the entire contents of the directory containing the
       database, including the database dictionary file, log/archive files, and
       the database directory. It will fail if the database is open by any 
       user.
      
       There is no way to undo the effects of this method.
     
       \par Locking Requirements
       None, but the database must not be opened in any other tasks/sessions
      
       \throws 
       rdm_exception (CPP_INVALID_DB, S_DBOPENED, S_READONLY)
       
       \par Library
       rdmcppapi-12
    */
    void Destroy (void) const throw (const rdm_exception&);

    /** \brief Check to see the database is opened exclusively
      
       \returns A boolean value
       \retval true the database is opened in exclusive mode
       \retval false the database is not opened in exclusive mode
       
       \par Locking Requirements
       None
      
       \throws 
       rdm_exception (CPP_INVALID_DB)
       
       \par Library
       rdmcppapi-12
    */
    bool IsExclusiveTask (void) const throw (const rdm_exception&);

    /** \brief Check to see the database is opened in shared mode
      
       \returns A boolean value
       \retval true the database is opened in shared mode
       \retval false the database is not opened in shared mode
       
       \par Locking Requirements
       None
      
       \throws 
       rdm_exception (CPP_INVALID_DB)
       
       \par Library
       rdmcppapi-12
    */
    bool IsSharedTask (void) const throw (const rdm_exception&);

    /** \brief Check to see the database is opened in read-only mode
      
       \returns A boolean value
       \retval true the database is opened in read-only mode
       \retval false the database is not opened in read-only mode
       
       \par Locking Requirements
       None
      
       \throws 
       rdm_exception (CPP_INVALID_DB)
       
       \par Library
       rdmcppapi-12
    */
    bool IsReadOnlyTask (void) const throw (const rdm_exception&);

    /** \brief Run a consistency check on the database
     
       This method runs a consistency check on the database. See d_dbcheck for
       full details.
      
       \par Locking Requirements in ReadOnly-Strict/Shared-Strict Modes
       A Snapshot transaction or a Read transaction with locks on all the database records that
       will be checked

       \throws 
       rdm_exception (CPP_INVALID_DB, S_NOTLOCKED, S_NOMEMORY)
       
       \par Library
       rdmcpputil-12
    */
    void CheckConsistency (
        const DBCHECK_PARAMS &params, /**< [in] Consistency check options structure */
        uint32_t             &num_errors, /**< [out] Number of errors found in the database */
        uint32_t             &num_warnings  /**< [out] Number of warnings found in the database */
    ) throw (const rdm_exception&);

#if !defined(RDM_NO_UNICODE)
    /** \copydoc Db::CheckConsistency(const DBCHECK_PARAMS&,uint32_t&,uint32_t&) */
    void CheckConsistency (
        const DBCHECK_PARAMSW &params,
        uint32_t              &num_errors,
        uint32_t              &num_warnings
    ) throw (const rdm_exception&);
#endif

    /** \brief Defragment a database
     
       This method defragments a database image. See d_defrag for
       full details.
      
       Normally, whenever a record is deleted from the database, it is marked 
       for reuse and put on the delete chain, but not physically removed from
       the file. These free (deleted) records can occupy a substantial amount
       of disk space, especially if a database has had numerous records 
       inserted and subsequently many of them marked as deleted.

       The Defrag method moves all valid records to the front of a data file 
       and all deleted slots to the end of the data file. The data file is 
       then truncated in order to reclaim disk space.
       
       \par Locking Requirements
       This method requires exclusive access to the database (opened in 
       exclusive mode)
      
       \throws 
       rdm_exception (CPP_INVALID_DB, S_EXCLUSIVE, S_NOMEMORY, S_READONLY)
       
       \par Library
       rdmcpputil-12
    */
    void Defrag (
        const DBDEFRAG_PARAMS &params /**< [in] Defragment options structure */
    ) throw (const rdm_exception&);

#if !defined(RDM_NO_UNICODE)
    /** \copydoc Db::Defrag(const DBDEFRAG_PARAMS&) */
    void Defrag (
        const DBDEFRAG_PARAMSW &params
    ) throw (const rdm_exception&);
#endif

    /** \brief Cluster related records in a database
     
       This method relocates related records to be stored contingulously in
       a database file. See d_cluster for full details.
      
       \par Locking Requirements
       This method requires exclusive access to the database (opened in 
       exclusive mode)
      
       \throws 
       rdm_exception (CPP_INVALID_DB, S_EXCLUSIVE, S_NOMEMORY, S_READONLY)
       
       \par Library
       rdmcpputil-12
    */
    void Cluster (
        const DBCLUSTER_PARAMS &params /**< [in] Cluster options structure */
    ) throw (const rdm_exception&);

#if !defined(RDM_NO_UNICODE)
    /** \copydoc Db::Cluster(const DBCLUSTER_PARAMS&) */
    void Cluster (
        const DBCLUSTER_PARAMSW &params
    ) throw (const rdm_exception&);
#endif

    /** \brief Repair a database image
     
       This method repairs corruption found in a database image. See dbrepair 
       for full details.
      
       \par Locking Requirements
       This method requires exclusive access to the database (opened in 
       exclusive mode)
      
       \throws 
       rdm_exception (CPP_INVALID_DB, S_EXCLUSIVE, S_NOMEMORY, S_READONLY)
       
       \par Library
       rdmcpputil-12
    */
    void Repair (
        const DBREPAIR_PARAMS &params /**< [in] Repair options structure */
    ) throw (const rdm_exception&);

#if !defined(RDM_NO_UNICODE)
    /** \copydoc Db::Repair(const DBREPAIR_PARAMS&) */
    void Repair (
        const DBREPAIR_PARAMSW &params
    ) throw (const rdm_exception&);
#endif

    /** \brief Generate database source files
    
       This method generates source files related to the database.  These 
       source files are typically created when running the schema through
       the DDLP processor, but this utility can generate them if the schema
       file is not available.

       The following files can be generated
            * C header files contain database defines and structures
            * C++ API source and header files
            * Objective-C API source and header files
            * C array containing the database dictionary
     
      The DBD does not store all information contained in the original schema,
      while the structure of the generated files will be identical to the 
      original there may be some differences.

      For example the DBD does not store any typedefs, \#define, or const values
      so the generate files will use base types and magic numbers instead of
      the typedef, define or const.

      \par Locking Requirements
      None
       
      \throws 
      rdm_exception (CPP_INVALID_DB, S_NOMEMORY)
      
      \par Library
      rdmcpputil-12
    */
    void Generate (
        const DBGEN_PARAMS &params /**< [in] Generate options structure */
    ) throw (const rdm_exception&);

#if !defined(RDM_NO_UNICODE)
    /** \copydoc Db::Generate(const DBGEN_PARAMS&) */
    void Generate (
        const DBGEN_PARAMSW &params
    ) throw (const rdm_exception&);
#endif

    /** \brief Regenerate the database delete chain
    
       This method sorts the deleted record slots on the delete chains of the 
       database files in database address order.

       The purpose of this method is to increase the probability that newly 
       created records in the same file will be placed close together. The 
       extent of any performance improvement, however, will depend upon the 
       application. The most likely time to use this utility is after a 
       periodic purge of a particular set of record types, many of which were 
       entered together; thus there would be many contiguous record slots on 
       the delete chain.

       This utility can be used to regenerate a delete chain when dbcheck reports
       a dchain inconsistency.

       \par Locking Requirements
       This method requires exclusive access to the database (opened in 
       exclusive mode)
      
       \throws 
       rdm_exception (CPP_INVALID_DB, S_EXCLUSIVE, S_NOMEMORY, S_READONLY)
       
       \par Library
       rdmcpputil-12
    */
    void DeleteChain (
        const DCHAIN_PARAMS &params /**< [in] Delete chain regeneration options structure */
    ) throw (const rdm_exception&);

#if !defined(RDM_NO_UNICODE)
    /** \copydoc Db::DeleteChain(const DCHAIN_PARAMS&) */
    void DeleteChain (
        const DCHAIN_PARAMSW &params
    ) throw (const rdm_exception&);
#endif

    /** \brief Rebuild a key file
    
       This method rebuilds a key file for the database.  Rebuilding key files 
       is a two-step process. First, the file is reinitialized. Then, each 
       record that has a key stored in the key file is sequentially read from 
       the data file, and the key file is re-created from the record contents.

       This utility can be used to regenerate a key  files when dbcheck reports
       an inconsistency.
       
       See keybuild for full details

       \par Locking Requirements
       This method requires exclusive access to the database (opened in 
       exclusive mode)
      
       \throws 
       rdm_exception (CPP_INVALID_DB, S_EXCLUSIVE, S_NOMEMORY, S_READONLY)
       
       \par Library
       rdmcpputil-12
    */
    void KeyFileBuild (
        const char *key_file /**< [in] The name of the key file to rebuild */
    ) throw (const rdm_exception&);

#if !defined(RDM_NO_UNICODE)
    /** \copydoc Db::KeyFileBuild(const char*) */
    void KeyFileBuild (
        const wchar_t *key_file
    ) throw (const rdm_exception&);
#endif

    /** \brief Rebuild a key file
    
       This method rebuilds all key files for the database.  Rebuilding key files 
       is a two-step process. First, the file is reinitialized. Then, each 
       record that has a key stored in the key file is sequentially read from 
       the data file, and the key file is re-created from the record contents.

       This utility can be used to regenerate key files when dbcheck reports
       inconsistencies.
       
       See keybuild for full details

       \par Locking Requirements
       This method requires exclusive access to the database (opened in 
       exclusive mode)
      
       \throws 
       rdm_exception (CPP_INVALID_DB, S_EXCLUSIVE, S_NOMEMORY, S_READONLY)
       
       \par Library
       rdmcpputil-12
    */
    void KeyBuild (
        const KEYBUILD_PARAMS &params /**< [in] Key build options structure */
    ) throw (const rdm_exception&);

#if !defined(RDM_NO_UNICODE)
    /** \copydoc Db::KeyBuild(const KEYBUILD_PARAMS&) */
    void KeyBuild (
        const KEYBUILD_PARAMSW &params
    ) throw (const rdm_exception&);
#endif

    /** \brief Export database into CSV files
   
    This method exports data from the database to  ASCII text files. The 
    method writes all data from each record type to a separate file; it is the 
    record name with file extension ".txt". If a record name is specified in 
    the parameter structure then only that record type's occurrences are 
    exported. The created files will consist of one text line per record 
    occurrence with sep_char (default ',') characters separating the data 
    fields.

    The ExportCSV method has two ways of printing extended ASCII characters to 
    the output files. The default is to write out the octal value. Since the
    ImportCSV method cannot handle this, the extended option can be used to 
    print the extended ASCII character as the character. For example, ASCII 2 
    would be printed as "\002" without the extended and as a smiley face with 
    the extended option.
    
    See dbexp for full details

    \par Locking Requirements in ReadOnly-Strict/Shared-Strict Modes
    A Snapshot transaction or a Read transaction with locks on all the database records that
    will be exported
      
    \throws 
    rdm_exception (CPP_INVALID_DB, S_NOTLOCKED, S_NOMEMORY)
       
    \par Library
    rdmcppexp-12
    */
    void ExportCSV (
        const DBEXPCSV_PARAMS *params /**< [in] CSV export options structure */
    ) throw (const rdm_exception&);

#if !defined(RDM_NO_UNICODE)
    /** \copydoc Db::ExportCSV(const DBEXPCSV_PARAMS*) */
    void ExportCSV (
        const DBEXPCSV_PARAMSW *params
    ) throw (const rdm_exception&);
#endif

    /** \brief Export database into an XML file

    This method exports data from the database to an XML file. By exporting data
    into XML format, consumers of the data can be RDM (e.g. for database 
    restructuring or archiving), RDM Server, or other XML consumers, including 
    other database products such as ADO.NET. The XML content created by the 
    ExportXML method will allow reconstruction of sets (in the case of RDM as 
    the consumer), or interpretation by any normal XML consumer.
   
    See dbexp for full details

    \par Locking Requirements in ReadOnly-Strict/Shared-Strict Modes
    A Snapshot transaction or a Read transaction with locks on all the database records that
    will be exported
      
    \throws 
    rdm_exception (CPP_INVALID_DB, S_NOTLOCKED, S_NOMEMORY)
       
    \par Library
    rdmcppexp-12
    */
    void ExportXML (
        const DBEXPXML_PARAMS *params /**< [in] XML export options structure */
    ) throw (const rdm_exception&);

#if !defined(RDM_NO_UNICODE)
    /** \copydoc Db::ExportXML(const DBEXPXML_PARAMS*) */
    void ExportXML (
        const DBEXPXML_PARAMSW *params
    ) throw (const rdm_exception&);
#endif

    /** \brief Import data from CSV files
   
    This method imports data into the database from ASCII text files.  The 
    import functionality is simple enough to allow great quantities of raw 
    ASCII data to be entered into an RDM database with very little 
    specification. With more complex requirements, ImportXML can be instructed 
    to perform mappings between the input data and RDM records and to make set 
    connections based upon matching field values.

    All instructions to ImportCSV are placed into a text file in the form of an
    import specification language (ISL). An ISL specification identifies the 
    database and the files containing ASCII data to be imported. It also contains 
    mappings between the ASCII data fields and the RDM record fields. 

    see dbimp for full details

    \par Locking Requirements in Shared/Shared-Strict Modes
    An Update transaction with locks on all record types that will be imported
      
    \throws 
    rdm_exception (CPP_INVALID_DB, S_NOTRANS, S_NOTLOCKED, S_DUPLICATE)
       
    \par Library
    rdmcppimp-12
    */
    void ImportCSV (
        const DBIMPCSV_PARAMS *params /**< [in] CSV import options structure */
    ) const throw (const rdm_exception&);
#if !defined(RDM_NO_UNICODE)
    /** \copydoc Db::ImportCSV() */
    void ImportCSV (
        const DBIMPCSV_PARAMSW *params
    ) const throw (const rdm_exception&);
#endif

    /** \brief Import data from an XML file
   
    This method imports data into the database from an XML file.  The 
    import functionality for the ImportXML method requires a complete
    XML document structured in the RDM format.  See the documentation 
    on the XML Import/Export for details on the XML format RDM requires.

    see dbimp for full details

    \par Locking Requirements in Shared/Shared-Strict Modes
    An Update transaction with locks on all record types that will be imported
      
    \throws 
    rdm_exception (CPP_INVALID_DB, S_NOTRANS, S_NOTLOCKED, S_DUPLICATE)
      
    \par Library
    rdmcppimp-12
    */
    void ImportXML (
        const DBIMPXML_PARAMS *params /**< [in] XML import options structure */
    ) const throw (const rdm_exception&);

#if !defined(RDM_NO_UNICODE)
    /** \copydoc Db::ImportXML() */
    void ImportXML (
        const DBIMPXML_PARAMSW *params
    ) const throw (const rdm_exception&);
#endif

    //! Get the internal DB_ENTRY pointer
    /*!
    \return The internal RDM DB_ENTRY pointer
    */
    RDM_DB GetDb() throw (const rdm_exception&);
    
    /** \brief Set a database ini value
   
    This method sets a value in the database specific ini file

    \par Locking Requirements in Shared/Shared-Strict Modes
    An Update transaction with locks on all record types
      
    \throws 
    rdm_exception (CPP_INVALID_DB, S_NOTRANS, S_NOTLOCKED)
      
    \par Library
    rdmcpp-12
    */
    void SetIni(
        const char *section, /**< [in] The name of the section containing the key name.  If the section does not exist, it is created. */
        const char *key,     /**< [in] The name of the key to be associated with a value.  If the key does not exist in the specified section, it is created. */
        const char *value    /**< [in] A null terminated value to be written to the ini file */
            ) throw (const rdm_exception&);

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

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

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

protected:
    //! Internal IDb pointer
    IDb *m_idb;
    
    /** \brief Constructor
    
      Applications should not directly create Db classes.  They should use
      the static Open method to get a database specific Db class.
    */
    Db (
        IDb *idb  /**< [in] The internal IDb to use with this instance */
        ) throw ();  
    
    /** \brief Constructor
      
      Applications should not directly create Db classes.  They should use
      the static Open method to get a database specific Db class.
     */
    Db (
        const Db& db, /**< [in] an existing Db to base this instance on */
        dbType type   /**< [in] the database type */
        ) throw (const rdm_exception&);

    /** \brief Create a new record with field values

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

    This method will use the specified field values for the new record. If
    fields is NULL the method will attempt to use default values (a record 
    structure initialized to all 0s)
   
    \return A singleton Cursor object positioned to the new record
    
    \par Locking Requirements
    An Update transaction on the record to be created
      
    \par Library
    rdmcppapi-12
    */
    Cursor _NewRecords (
        recordType type, /**< [in] The type of record to create */
        const void *fields = NULL /**< The field values for the new record */
        ) const throw (const rdm_exception&);

    /** \brief Obtain a Cursor for a singleton record

        Applications should not directly call this method, a record type specific
        method will be generated for each singleton record in the database.
        Currently the only singleton record support by the engine is the
        'System' record.

        \return A singleton Cursor object positioned at the singleton instance
    
        \par Locking Requirements
        None, a Read or Snapshot transaction will ensure data consistency
      
        \par Library
        rdmcppapi-12
    */
    Cursor _GetRecord (
        recordType type /**< [in] The record identifier for the singleton record type we want a Cursor for */
        ) const throw (const rdm_exception&);

    /** \brief Obtain a Cursor collection for a record type

        The Cursor returned will be ordered by database address and will be
        initially positioned to the record at dba.  If dba is NULL the cursor
        will be initially positioned to 'BeforeFirst'

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

        \return A recscan Cursor object.
    
        \par Locking Requirements
        None, a Read or Snapshot transaction will ensure data consistency
      
        \par Library
        rdmcppapi-12
    */
    Cursor _GetRecords (
        recordType type, /**< [in] The record identifier for the singleton record type we want a Cursor for */
        const DB_ADDR *dba = NULL /**< [in] The database address of the record the Cursor will be initially positioned to */
        ) const throw (const rdm_exception&);
    
    /** \brief Obtain a Cursor collection for a record type by a key

        The Cursor returned will be ordered by key value and will be
        initially positioned to the first record record with the specified
        key value.  If no record has the specified value the Cursor will be
        positioned between records where the value would have been located.  If
        value is not specified the Cursor will be initially positioned to
        'BeforeFirst'

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

        \return A keyscan Cursor object based on the specified key
    
        \par Locking Requirements
        None, a Read or Snapshot transaction will ensure data consistency
      
        \par Library
        rdmcppapi-12
    */
    Cursor _GetRecordsByKey(
        keyId id,  /**< [in] The id of the indexed field for the Cursor to be based on */
        const void *value = NULL, /**< The optional key value used to position the Cursor */
        uint32_t len=0 /**< The optional length of the key value, if len is 0 the engine will not validate the length */
        ) const throw (const rdm_exception&);
    
    /** \brief Obtain a Cursor collection for a record type containing records
        in the specified key range.

        The Cursor returned will be ordered by key value and will be
        initially positioned to the first record record with the specified
        start key value.  If no record has the specified start value the Cursor
        will be positioned between records and right before the first record in
        the specified range.

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

        \return A keyscan Cursor object positioned to the first record 
        containing the specified start key value.
    
        \par Locking Requirements
        None, a Read or Snapshot transaction will ensure data consistency
      
        \par Library
        rdmcppapi-12
    */
    Cursor _GetRecordsByKeyInRange (
        keyId id, /**< [in] The id of the indexed field for the Cursor to be based on */
        const void *start_value, /**< [in] The key value used for the start of the Cursor range */
        uint32_t start_len = 0, /**< [in] The length of start_value, if the len is 0 the engine will not validate the length. */
        uint16_t start_num_flds = 0, /**< [in] The number of key fields to use for the start of the range.  If this parameter is a non-zero value the method only considers the number of fields indicated.  The parameter is intended only for compound keys, although specifying '1' for non-compound key is safe */
        uint16_t start_str_len = 0, /**< [in] The partial string length for the start of the range.  If this parameter is a non-zero value the method uses only this many characters of the last field being considered (depending on start_num_flds) */
        const void *end_value=NULL, /**< [in] The key value used for the end of the Cursor range, if NULL the range will extend to the last record */ 
        uint32_t end_len=0, /**< [in] The length of end_value, if the len is 0 the engine will not validate the length. */
        uint16_t end_num_flds=0, /**< [in] The number of key fields to use for the end of the range.  If this parameter is a non-zero value the method only considers the number of fields indicated.  The parameter is intended only for compound keys, although specifying '1' for non-compound key is safe */
        uint16_t end_str_len=0 /**< [in] The partial string length for the end of the range.  If this parameter is a non-zero value the method uses only this many characters of the last field being considered (depending on end_num_flds) */
        ) const throw (const rdm_exception&);
    
    /** \brief Open a database and obtain a Db object
     
        Applications should not directly call this method, a Database specific
        method will be generated for the database.

        \par Locking Requirements
        None
      
        \par Library
        rdmcppapi-12
    */
    static Db _OpenDatabase (
        dbType type, /**< [in] The database type */
        const char *name, /**< [in] The name of the database */
        RDM_OPEN_MODE mode, /**< [in] The database open mode */
        const void *dbd_array=NULL, /**< [in] A dbd array (generated by the ddlp -c option */
        int32_t dbdsize=0, /**< [in] The size of the dbd array */
        const ENC *enc=NULL /**< [in] The encryption context to use to open the database */
        ) throw (const rdm_exception&);

#if !defined(RDM_NO_UNICODE)
    /** \copydoc Db::_OpenDatabase(dbType, const char*, RDM_OPEN_MODE, const void*, int32_t, const ENC*) */
    static Db _OpenDatabase (
        dbType type, 
        const wchar_t *name, 
        RDM_OPEN_MODE mode, 
        const void *dbd_array=NULL, 
        int32_t dbdsize=0, 
        const ENC *enc=NULL) throw (const rdm_exception&);
#endif
   
    /** \brief Get the dbType for a Db object

        This is an internal function and should never be called by an end user
        
        \return The dbType for the Db object
    
        \par Library
        rdmcppapi-12
    */
    dbType _GetType (void) const throw (const rdm_exception&);
    
    /** \brief Validate a Db object's dbType

        If type does not match the internal type then a CPP_INVALID_DB_TYPE
        exception will be thrown

        This is an internal function and should never be called by an end user

        \par Library
        rdmcppapi-12
    */
    void _VerifyType (
        dbType type /**< [in] the dbType to validate against */
        ) const throw (const rdm_exception&);
    
    //! Validate the IDb
    void _ValidateIDb () const throw (const rdm_exception&);
    
    /** \brief Validate a Db object's dbType and assign this to Db

        If the dbType matches this will be assigned to the passed in Db

        This is an internal function and should never be called by an end user
        
        \par Library
        rdmcppapi-12
    */
    Db& _AssignAndVerifyType (
        dbType type,  /**< [in] The dbType to validate against */
        const Db& db /**< [in] The db object to assign to this */
        ) throw (const rdm_exception&);
private:
    int16_t __countLocks(
        const recordType types[],
        int16_t          num
        ) const throw (const rdm_exception&);

    //! Db reference operator
    const Db* operator & (void) const;

    friend class Cursor;
};
}
#endif
