//   IBPP internal declarations
//
//  'Internal declarations' means everything used to implement ibpp. This
//   file and its contents is NOT needed by users of the library. All those
//   declarations are wrapped in a namespace : 'ibpp_internals'.

/*
  (C) Copyright 2000-2006 T.I.P. Group S.A. and the IBPP Team (www.ibpp.org)

  The contents of this file are subject to the IBPP License (the "License");
  you may not use this file except in compliance with the License.  You may
  obtain a copy of the License at http://www.ibpp.org or in the 'license.txt'
  file which must have been distributed along with this file.

  This software, distributed under the License, is distributed on an "AS IS"
  basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.  See the
  License for the specific language governing rights and limitations
  under the License.
*/
#ifndef __INTERNAL_IBPP_H__
#define __INTERNAL_IBPP_H__

#include "ibpp.h"

#if defined(_MSC_VER) 
#define HAS_HDRSTOP
#endif

#if (defined(__GNUC__) && defined(IBPP_WINDOWS))
//  Setting flags for ibase.h -- using GCC/Cygwin/MinGW on Win32
#ifndef _MSC_VER
#define _MSC_VER 1299
#endif
#ifndef _WIN32
#define _WIN32   1
#endif
#endif

#include "ibase.h"      // From Firebird installation

#if (defined(__GNUC__) && defined(IBPP_WINDOWS))
//  UNSETTING flags used above for ibase.h -- Huge conflicts with libstdc++ !
#undef _MSC_VER
#undef _WIN32
#endif

#ifdef IBPP_WINDOWS
#include <windows.h>
#endif

#include <limits>
#include <string>
#include <vector>
#include <sstream>
#include <cstdarg>
#include <cstring>


#ifdef _DEBUG
#define ASSERTION(x)    {if (!(x)) {throw LogicExceptionImpl("ASSERTION", \
                            "'"#x"' is not verified at %s, line %d", \
                                __FILE__, __LINE__);}}
#else
#define ASSERTION(x)    /* x */
#endif

namespace ibpp_internals
{

enum flush_debug_stream_type {fds};

#ifdef _DEBUG

#if defined (_MSC_VER) && (_MSC_VER >= 1700)
#pragma warning ( push )
#pragma warning ( disable: 4250 )
#endif

struct DebugStream : public std::stringstream
{
    // next two operators fix some g++ and vc++ related problems
    std::ostream& operator<< (const char* p)
        { static_cast<std::stringstream&>(*this)<< p; return *this; }

    std::ostream& operator<< (const std::string& p)
        { static_cast<std::stringstream&>(*this)<< p; return *this; }

    DebugStream& operator=(const DebugStream&) {return *this;}
    DebugStream(const DebugStream&) {}
    DebugStream() {}
};
std::ostream& operator<< (std::ostream& a, flush_debug_stream_type);

#if defined (_MSC_VER) && (_MSC_VER >= 1700)
#pragma warning ( pop )
#endif

#else

struct DebugStream
{
    template<class T> DebugStream& operator<< (const T&) { return *this; }
    // for manipulators
    DebugStream& operator<< (std::ostream&(*)(std::ostream&)) { return *this; }
};

#endif  // _DEBUG

class DatabaseImpl;
class TransactionImpl;
class StatementImpl;
class BlobImpl;
class ArrayImpl;
class EventsImpl;

//  Native data types
typedef enum {ivArray, ivBlob, ivDate, ivTime, ivTimestamp, ivString,
            ivInt16, ivInt32, ivInt64, ivFloat, ivDouble,
            ivBool, ivDBKey, ivByte} IITYPE;

//
//  Those are the Interbase C API prototypes that we use
//  Taken 'asis' from IBASE.H, prefix 'isc_' replaced with 'proto_',
//  and 'typedef' preprended...
//

typedef ISC_STATUS ISC_EXPORT proto_create_database (ISC_STATUS *,
                        short,
                        char *,
                        isc_db_handle *,
                        short,
                        char *,
                        short);

typedef ISC_STATUS ISC_EXPORT proto_attach_database (ISC_STATUS *,
                        short,
                        char *,
                        isc_db_handle *,
                        short,
                        char *);

typedef ISC_STATUS  ISC_EXPORT proto_detach_database (ISC_STATUS *,
                        isc_db_handle *);

typedef ISC_STATUS  ISC_EXPORT proto_drop_database (ISC_STATUS *,
                      isc_db_handle *);

typedef ISC_STATUS  ISC_EXPORT proto_database_info (ISC_STATUS *,
                      isc_db_handle *,
                      short,
                      char *,
                      short,
                      char *);

typedef ISC_STATUS  ISC_EXPORT proto_dsql_execute_immediate (ISC_STATUS *,
                           isc_db_handle *,
                           isc_tr_handle *,
                           unsigned short,
                           char *,
                           unsigned short,
                           XSQLDA *);

typedef ISC_STATUS  ISC_EXPORT proto_open_blob2 (ISC_STATUS *,
                       isc_db_handle *,
                       isc_tr_handle *,
                       isc_blob_handle *,
                       ISC_QUAD *,
                       short,
                       char *);

typedef ISC_STATUS  ISC_EXPORT proto_create_blob2 (ISC_STATUS *,
                    isc_db_handle *,
                    isc_tr_handle *,
                    isc_blob_handle *,
                    ISC_QUAD *,
                    short,
                    char *);

typedef ISC_STATUS  ISC_EXPORT proto_close_blob (ISC_STATUS *,
                       isc_blob_handle *);

typedef ISC_STATUS  ISC_EXPORT proto_cancel_blob (ISC_STATUS *,
                        isc_blob_handle *);

typedef ISC_STATUS  ISC_EXPORT proto_get_segment (ISC_STATUS *,
                        isc_blob_handle *,
                        unsigned short *,
                        unsigned short,
                        char *);

typedef ISC_STATUS  ISC_EXPORT proto_put_segment (ISC_STATUS *,
                    isc_blob_handle *,
                    unsigned short,
                    char *);

typedef ISC_STATUS  ISC_EXPORT proto_blob_info (ISC_STATUS *,
                      isc_blob_handle *,
                      short,
                      char *,
                      short,
                      char *);

typedef ISC_STATUS  ISC_EXPORT proto_array_lookup_bounds (ISC_STATUS *,
                        isc_db_handle *,
                        isc_tr_handle *,
                        char *,
                        char *,
                        ISC_ARRAY_DESC *);

typedef ISC_STATUS  ISC_EXPORT proto_array_get_slice (ISC_STATUS *,
                        isc_db_handle *,
                        isc_tr_handle *,
                        ISC_QUAD *,
                        ISC_ARRAY_DESC *,
                        void *,
                        ISC_LONG *);

typedef ISC_STATUS  ISC_EXPORT proto_array_put_slice (ISC_STATUS *,
                        isc_db_handle *,
                        isc_tr_handle *,
                        ISC_QUAD *,
                        ISC_ARRAY_DESC *,
                        void *,
                        ISC_LONG *);

typedef ISC_LONG    ISC_EXPORT proto_vax_integer (char *,
                    short);

typedef ISC_LONG    ISC_EXPORT proto_sqlcode (ISC_STATUS *);

typedef void        ISC_EXPORT proto_sql_interprete (short,
                       char *,
                       short);

#if defined(FB_API_VER) && FB_API_VER >= 20
typedef ISC_STATUS  ISC_EXPORT proto_interpret (char *,
                                      unsigned int,
                                      const ISC_STATUS * *);
#else
typedef ISC_STATUS  ISC_EXPORT proto_interprete (char *,
                       ISC_STATUS * *);

#endif

typedef ISC_STATUS  ISC_EXPORT proto_que_events (ISC_STATUS *,
                       isc_db_handle *,
                       ISC_LONG *,
                       short,
                       char *,
                       isc_callback,
                       void *);

typedef ISC_STATUS  ISC_EXPORT proto_cancel_events (ISC_STATUS *,
                      isc_db_handle *,
                      ISC_LONG *);

typedef ISC_STATUS  ISC_EXPORT proto_start_multiple (ISC_STATUS *,
                       isc_tr_handle *,
                       short,
                       void *);

typedef ISC_STATUS  ISC_EXPORT proto_commit_transaction (ISC_STATUS *,
                           isc_tr_handle *);

typedef ISC_STATUS  ISC_EXPORT proto_commit_retaining (ISC_STATUS *,
                         isc_tr_handle *);

typedef ISC_STATUS  ISC_EXPORT proto_rollback_transaction (ISC_STATUS *,
                         isc_tr_handle *);

typedef ISC_STATUS  ISC_EXPORT proto_rollback_retaining (ISC_STATUS *,
                         isc_tr_handle *);


typedef ISC_STATUS  ISC_EXPORT proto_dsql_allocate_statement (ISC_STATUS *,
                            isc_db_handle *,
                            isc_stmt_handle *);

typedef ISC_STATUS  ISC_EXPORT proto_dsql_describe (ISC_STATUS *,
                      isc_stmt_handle *,
                      unsigned short,
                      XSQLDA *);

typedef ISC_STATUS  ISC_EXPORT proto_dsql_describe_bind (ISC_STATUS *,
                           isc_stmt_handle *,
                           unsigned short,
                           XSQLDA *);

typedef ISC_STATUS  ISC_EXPORT proto_dsql_execute (ISC_STATUS *,
                     isc_tr_handle *,
                     isc_stmt_handle *,
                     unsigned short,
                     XSQLDA *);

typedef ISC_STATUS  ISC_EXPORT proto_dsql_execute2 (ISC_STATUS *,
                      isc_tr_handle *,
                      isc_stmt_handle *,
                      unsigned short,
                      XSQLDA *,
                      XSQLDA *);

typedef ISC_STATUS  ISC_EXPORT proto_dsql_fetch (ISC_STATUS *,
                       isc_stmt_handle *,
                       unsigned short,
                       XSQLDA *);

typedef ISC_STATUS  ISC_EXPORT proto_dsql_free_statement (ISC_STATUS *,
                        isc_stmt_handle *,
                        unsigned short);

typedef ISC_STATUS  ISC_EXPORT proto_dsql_prepare (ISC_STATUS *,
                     isc_tr_handle *,
                     isc_stmt_handle *,
                     unsigned short,
                     char *,
                     unsigned short,
                     XSQLDA *);

typedef ISC_STATUS  ISC_EXPORT proto_dsql_set_cursor_name (ISC_STATUS *,
                         isc_stmt_handle *,
                         char *,
                         unsigned short);

typedef ISC_STATUS  ISC_EXPORT proto_dsql_sql_info (ISC_STATUS *,
                      isc_stmt_handle *,
                      short,
                      char *,
                      short,
                      char *);

typedef void        ISC_EXPORT proto_decode_date (ISC_QUAD *,
                    void *);

typedef void        ISC_EXPORT proto_encode_date (void *,
                    ISC_QUAD *);

typedef int         ISC_EXPORT proto_add_user (ISC_STATUS *, USER_SEC_DATA *);
typedef int         ISC_EXPORT proto_delete_user (ISC_STATUS *, USER_SEC_DATA *);
typedef int         ISC_EXPORT proto_modify_user (ISC_STATUS *, USER_SEC_DATA *);


typedef ISC_STATUS  ISC_EXPORT proto_service_attach (ISC_STATUS *,
                       unsigned short,
                       char *,
                       isc_svc_handle *,
                       unsigned short,
                       char *);

typedef ISC_STATUS  ISC_EXPORT proto_service_detach (ISC_STATUS *,
                       isc_svc_handle *);

typedef ISC_STATUS  ISC_EXPORT proto_service_query (ISC_STATUS *,
                      isc_svc_handle *,
                                      isc_resv_handle *,
                      unsigned short,
                      char *,
                      unsigned short,
                      char *,
                      unsigned short,
                      char *);

typedef ISC_STATUS ISC_EXPORT proto_service_start (ISC_STATUS *,
                         isc_svc_handle *,
                                 isc_resv_handle *,
                         unsigned short,
                         char*);

typedef void        ISC_EXPORT proto_decode_sql_date (ISC_DATE *,
                    void *);

typedef void        ISC_EXPORT proto_decode_sql_time (ISC_TIME *,
                    void *);

typedef void        ISC_EXPORT proto_decode_timestamp (ISC_TIMESTAMP *,
                    void *);

typedef void        ISC_EXPORT proto_encode_sql_date (void *,
                    ISC_DATE *);

typedef void        ISC_EXPORT proto_encode_sql_time (void *,
                    ISC_TIME *);

typedef void        ISC_EXPORT proto_encode_timestamp (void *,
                    ISC_TIMESTAMP *);

//
//  Internal binding structure to the FBCLIENT DLL
//

struct FBCLIENT
{
    // Attributes
    bool mReady;

#ifdef IBPP_WINDOWS
    HMODULE mHandle;            // The FBCLIENT.DLL HMODULE
    std::string mSearchPaths;   // Optional additional search paths
#endif
#ifdef IBPP_UNIX
#ifdef IBPP_LATE_BIND
               void *mHandle;
#endif
#endif


    FBCLIENT* Call();

    // FBCLIENT Entry Points
    proto_create_database*          m_create_database;
    proto_attach_database*          m_attach_database;
    proto_detach_database*          m_detach_database;
    proto_drop_database*            m_drop_database;
    proto_database_info*            m_database_info;
    proto_dsql_execute_immediate*   m_dsql_execute_immediate;
    proto_open_blob2*               m_open_blob2;
    proto_create_blob2*             m_create_blob2;
    proto_close_blob*               m_close_blob;
    proto_cancel_blob*              m_cancel_blob;
    proto_get_segment*              m_get_segment;
    proto_put_segment*              m_put_segment;
    proto_blob_info*                m_blob_info;
    proto_array_lookup_bounds*      m_array_lookup_bounds;
    proto_array_get_slice*          m_array_get_slice;
    proto_array_put_slice*          m_array_put_slice;

    proto_vax_integer*              m_vax_integer;
    proto_sqlcode*                  m_sqlcode;
    proto_sql_interprete*           m_sql_interprete;
    #if defined(FB_API_VER) && FB_API_VER >= 20
    proto_interpret*                m_interpret;
    #else
    proto_interprete*               m_interprete;
    #endif

    proto_que_events*               m_que_events;
    proto_cancel_events*            m_cancel_events;
    proto_start_multiple*           m_start_multiple;
    proto_commit_transaction*       m_commit_transaction;
    proto_commit_retaining*         m_commit_retaining;
    proto_rollback_transaction*     m_rollback_transaction;
    proto_rollback_retaining*       m_rollback_retaining;
    proto_dsql_allocate_statement*  m_dsql_allocate_statement;
    proto_dsql_describe*            m_dsql_describe;
    proto_dsql_describe_bind*       m_dsql_describe_bind;
    proto_dsql_prepare*             m_dsql_prepare;
    proto_dsql_execute*             m_dsql_execute;
    proto_dsql_execute2*            m_dsql_execute2;
    proto_dsql_fetch*               m_dsql_fetch;
    proto_dsql_free_statement*      m_dsql_free_statement;
    proto_dsql_set_cursor_name*     m_dsql_set_cursor_name;
    proto_dsql_sql_info*            m_dsql_sql_info;
    //proto_decode_date*                m_decode_date;
    //proto_encode_date*                m_encode_date;
    //proto_add_user*                   m_add_user;
    //proto_delete_user*                m_delete_user;
    //proto_modify_user*                m_modify_user;

    proto_service_attach*           m_service_attach;
    proto_service_detach*           m_service_detach;
    proto_service_start*            m_service_start;
    proto_service_query*            m_service_query;
    //proto_decode_sql_date*            m_decode_sql_date;
    //proto_decode_sql_time*            m_decode_sql_time;
    //proto_decode_timestamp*           m_decode_timestamp;
    //proto_encode_sql_date*            m_encode_sql_date;
    //proto_encode_sql_time*            m_encode_sql_time;
    //proto_encode_timestamp*           m_encode_timestamp;

    // Constructor (No need for a specific destructor)
    FBCLIENT()
    {
        mReady = false;
#ifdef IBPP_WINDOWS
        mHandle = 0;
#endif
    }
};

extern FBCLIENT gds;

//
//  Service Parameter Block (used to define a service)
//

class SPB
{
    static const int BUFFERINCR;

    char* mBuffer;              // Dynamically allocated SPB structure
    int mSize;                  // Its used size in bytes
    int mAlloc;                 // Its allocated size in bytes

    void Grow(int needed);      // Alloc or grow the mBuffer

public:
    void Insert(char);          // Insert a single byte code
    void InsertString(char, int, const char*);  // Insert a string, len can be defined as 1 or 2 bytes
    void InsertByte(char type, char data);
    void InsertQuad(char type, int32_t data);
    void Reset();           // Clears the SPB
    char* Self() { return mBuffer; }
    short Size() { return (short)mSize; }

    SPB() : mBuffer(0), mSize(0), mAlloc(0) { }
    ~SPB() { Reset(); }
};

//
//  Database Parameter Block (used to define a database)
//

class DPB
{
    static const int BUFFERINCR;

    char* mBuffer;              // Dynamically allocated DPB structure
    int mSize;                  // Its used size in bytes
    int mAlloc;                 // Its allocated size in bytes

    void Grow(int needed);      // Allocate or grow the mBuffer, so that
                                // 'needed' bytes can be written (at least)

public:
    void Insert(char, const char*); // Insert a new char* 'cluster'
    void Insert(char, int16_t);     // Insert a new int16_t 'cluster'
    void Insert(char, bool);        // Insert a new bool 'cluster'
    void Insert(char, char);        // Insert a new byte 'cluster'
    void Reset();               // Clears the DPB
    char* Self() { return mBuffer; }
    short Size() { return (short)mSize; }

    DPB() : mBuffer(0), mSize(0), mAlloc(0) { }
    ~DPB() { Reset(); }
};

//
//  Transaction Parameter Block (used to define a transaction)
//

class TPB
{
    static const int BUFFERINCR;

    char* mBuffer;                  // Dynamically allocated TPB structure
    int mSize;                      // Its used size in bytes
    int mAlloc;                     // Its allocated size

    void Grow(int needed);          // Alloc or re-alloc the mBuffer

public:
    void Insert(char);              // Insert a flag item
    void Insert(const std::string& data); // Insert a string (typically table name)
    void Reset();               // Clears the TPB
    char* Self() { return mBuffer; }
    int Size() { return mSize; }

    TPB() : mBuffer(0), mSize(0), mAlloc(0) { }
    ~TPB() { Reset(); }
};

//
//  Used to receive (and process) a results buffer in various API calls
//

class RB
{
    char* mBuffer;
    int mSize;

    char* FindToken(char token);
    char* FindToken(char token, char subtoken);

public:
    void Reset();
    int GetValue(char token);
    int GetCountValue(char token);
    void GetDetailedCounts(IBPP::DatabaseCounts& counts, char token);
    int GetValue(char token, char subtoken);
    bool GetBool(char token);
    int GetString(char token, std::string& data);

    char* Self() { return mBuffer; }
    short Size() { return (short)mSize; }

    RB();
    RB(int Size);
    ~RB();
};

//
//  Used to receive status info from API calls
//

class IBS
{
    mutable ISC_STATUS mVector[20];
    mutable std::string mMessage;

public:
    ISC_STATUS* Self() { return mVector; }
    bool Errors() { return (mVector[0] == 1 && mVector[1] > 0) ? true : false; }
    const char* ErrorMessage() const;
    int SqlCode() const;
    int EngineCode() const { return (mVector[0] == 1) ? (int)mVector[1] : 0; }
    void Reset();

    IBS();
    IBS(IBS&);  // Copy Constructor
    ~IBS();
};

///////////////////////////////////////////////////////////////////////////////
//
//  Implementation of the "hidden" classes associated with their public
//  counterparts. Their private data and methods can freely change without
//  breaking the compatibility of the DLL. If they receive new public methods,
//  and those methods are reflected in the public class, then the compatibility
//  is broken.
//
///////////////////////////////////////////////////////////////////////////////

//
// Hidden implementation of Exception classes.
//

/*
                         std::exception
                                |
                         IBPP::Exception
                       /                 \
                      /                   \
  IBPP::LogicException    ExceptionBase    IBPP::SQLException
        |        \         /   |     \     /
        |   LogicExceptionImpl |   SQLExceptionImpl
        |                      |
    IBPP::WrongType            |
               \               |
              IBPP::WrongTypeImpl
*/

class ExceptionBase
{
    //  (((((((( OBJECT INTERNALS ))))))))

protected:
    std::string mContext;           // Exception context ("IDatabase::Drop")
    std::string mWhat;              // Full formatted message

    void buildErrorMessage(const char* message);
    void raise(const std::string& context, const char* message, va_list argptr);

public:

    ExceptionBase() throw();
    ExceptionBase(const ExceptionBase& copied) throw();
    ExceptionBase& operator=(const ExceptionBase& copied) throw();
    ExceptionBase(const std::string& context, const char* message = 0, ...) throw();

    virtual ~ExceptionBase() throw();

    //  (((((((( OBJECT INTERFACE ))))))))

    virtual const char* Origin() const throw();
    virtual const char* what() const throw();
};

class LogicExceptionImpl : public IBPP::LogicException, public ExceptionBase
{
    //  (((((((( OBJECT INTERNALS ))))))))

public:

    LogicExceptionImpl() throw();
    LogicExceptionImpl(const LogicExceptionImpl& copied) throw();
    LogicExceptionImpl& operator=(const LogicExceptionImpl& copied) throw();
    LogicExceptionImpl(const std::string& context, const char* message = 0, ...) throw();

    virtual ~LogicExceptionImpl() throw ();

    //  (((((((( OBJECT INTERFACE ))))))))
    //
    //  The object public interface is partly implemented by inheriting from
    //  the ExceptionBase class.

public:
    virtual const char* Origin() const throw();
    virtual const char* what() const throw();
};

class SQLExceptionImpl : public IBPP::SQLException, public ExceptionBase
{
    //  (((((((( OBJECT INTERNALS ))))))))

private:
    int mSqlCode;
    int mEngineCode;

public:

    SQLExceptionImpl() throw();
    SQLExceptionImpl(const SQLExceptionImpl& copied) throw();
    SQLExceptionImpl& operator=(const SQLExceptionImpl& copied) throw();
    SQLExceptionImpl(const IBS& status, const std::string& context,
                        const char* message = 0, ...) throw();

    virtual ~SQLExceptionImpl() throw ();

    //  (((((((( OBJECT INTERFACE ))))))))
    //
    //  The object public interface is partly implemented by inheriting from
    //  the ExceptionBase class.

public:
    virtual const char* Origin() const throw();
    virtual const char* what() const throw();
    virtual int SqlCode() const throw();
    virtual int EngineCode() const throw();
};

class WrongTypeImpl : public IBPP::WrongType, public ExceptionBase
{
    //  (((((((( OBJECT INTERNALS ))))))))

public:

    WrongTypeImpl() throw();
    WrongTypeImpl(const WrongTypeImpl& copied) throw();
    WrongTypeImpl& operator=(const WrongTypeImpl& copied) throw();
    WrongTypeImpl(const std::string& context, int sqlType, IITYPE varType,
                    const char* message = 0, ...) throw();

    virtual ~WrongTypeImpl() throw ();

    //  (((((((( OBJECT INTERFACE ))))))))
    //
    //  The object public interface is partly implemented by inheriting from
    //  the ExceptionBase class.

public:
    virtual const char* Origin() const throw();
    virtual const char* what() const throw();
};

class ServiceImpl : public IBPP::IService
{
    //  (((((((( OBJECT INTERNALS ))))))))

private:
    int mRefCount;              // Reference counter
    isc_svc_handle mHandle;     // Firebird API Service Handle
    std::string mServerName;    // Server Name
    std::string mUserName;      // User Name
    std::string mUserPassword;  // User Password
    std::string mWaitMessage;   // Progress message returned by WaitMsg()

    isc_svc_handle* GetHandlePtr() { return &mHandle; }
    void SetServerName(const char*);
    void SetUserName(const char*);
    void SetUserPassword(const char*);

public:
    isc_svc_handle GetHandle() { return mHandle; }

    ServiceImpl(const std::string& ServerName, const std::string& UserName,
                    const std::string& UserPassword);
    ~ServiceImpl();

    //  (((((((( OBJECT INTERFACE ))))))))

public:
    void Connect();
    bool Connected() { return mHandle == 0 ? false : true; }
    void Disconnect();

    void GetVersion(std::string& version);

    void AddUser(const IBPP::User&);
    void GetUser(IBPP::User&);
    void GetUsers(std::vector<IBPP::User>&);
    void ModifyUser(const IBPP::User&);
    void RemoveUser(const std::string& username);

    void SetPageBuffers(const std::string& dbfile, int buffers);
    void SetSweepInterval(const std::string& dbfile, int sweep);
    void SetSyncWrite(const std::string& dbfile, bool);
    void SetReadOnly(const std::string& dbfile, bool);
    void SetReserveSpace(const std::string& dbfile, bool);

    void Shutdown(const std::string& dbfile, IBPP::DSM mode, int sectimeout);
    void Restart(const std::string& dbfile);
    void Sweep(const std::string& dbfile);
    void Repair(const std::string& dbfile, IBPP::RPF flags);

    void StartBackup(const std::string& dbfile, const std::string& bkfile,
        IBPP::BRF flags = IBPP::BRF(0));
    void StartRestore(const std::string& bkfile, const std::string& dbfile,
        int pagesize, IBPP::BRF flags = IBPP::BRF(0));

    const char* WaitMsg();
    void Wait();

    IBPP::IService* AddRef();
    void Release();
};

class DatabaseImpl : public IBPP::IDatabase
{
    //  (((((((( OBJECT INTERNALS ))))))))

    int mRefCount;              // Reference counter
    isc_db_handle mHandle;      // InterBase API Session Handle
    std::string mServerName;    // Server name
    std::string mDatabaseName;  // Database name (path/file)
    std::string mUserName;      // User name
    std::string mUserPassword;  // User password
    std::string mRoleName;      // Role used for the duration of the connection
    std::string mCharSet;       // Character Set used for the connection
    std::string mCreateParams;  // Other parameters (creation only)

    int mDialect;                           // 1 if IB5, 1 or 3 if IB6/FB1
    std::vector<TransactionImpl*> mTransactions;// Table of Transaction*
    std::vector<StatementImpl*> mStatements;// Table of Statement*
    std::vector<BlobImpl*> mBlobs;          // Table of Blob*
    std::vector<ArrayImpl*> mArrays;        // Table of Array*
    std::vector<EventsImpl*> mEvents;       // Table of Events*

public:
    isc_db_handle* GetHandlePtr() { return &mHandle; }
    isc_db_handle GetHandle() { return mHandle; }

    void AttachTransactionImpl(TransactionImpl*);
    void DetachTransactionImpl(TransactionImpl*);
    void AttachStatementImpl(StatementImpl*);
    void DetachStatementImpl(StatementImpl*);
    void AttachBlobImpl(BlobImpl*);
    void DetachBlobImpl(BlobImpl*);
    void AttachArrayImpl(ArrayImpl*);
    void DetachArrayImpl(ArrayImpl*);
    void AttachEventsImpl(EventsImpl*);
    void DetachEventsImpl(EventsImpl*);

    DatabaseImpl(const std::string& ServerName, const std::string& DatabaseName,
                const std::string& UserName, const std::string& UserPassword,
                const std::string& RoleName, const std::string& CharSet,
                const std::string& CreateParams);
    ~DatabaseImpl();

    //  (((((((( OBJECT INTERFACE ))))))))

public:
    const char* ServerName() const      { return mServerName.c_str(); }
    const char* DatabaseName() const    { return mDatabaseName.c_str(); }
    const char* Username() const        { return mUserName.c_str(); }
    const char* UserPassword() const    { return mUserPassword.c_str(); }
    const char* RoleName() const        { return mRoleName.c_str(); }
    const char* CharSet() const         { return mCharSet.c_str(); }
    const char* CreateParams() const    { return mCreateParams.c_str(); }

    void Info(int* ODSMajor, int* ODSMinor,
        int* PageSize, int* Pages, int* Buffers, int* Sweep,
        bool* SyncWrites, bool* Reserve, bool* ReadOnly);
    void TransactionInfo(int* Oldest, int* OldestActive,
        int* OldestSnapshot, int* Next);
    void Statistics(int* Fetches, int* Marks, int* Reads, int* Writes, int* CurrentMemory);
    void Counts(int* Insert, int* Update, int* Delete,
        int* ReadIdx, int* ReadSeq);
    void DetailedCounts(IBPP::DatabaseCounts& counts);
    void Users(std::vector<std::string>& users);
    int Dialect() { return mDialect; }

    void Create(int dialect);
    void Connect();
    bool Connected() { return mHandle == 0 ? false : true; }
    void Inactivate();
    void Disconnect();
    void Drop();

    IBPP::IDatabase* AddRef();
    void Release();
};

class TransactionImpl : public IBPP::ITransaction
{
    //  (((((((( OBJECT INTERNALS ))))))))

private:
    int mRefCount;                  // Reference counter
    isc_tr_handle mHandle;          // Transaction InterBase

    std::vector<DatabaseImpl*> mDatabases;      // Table of IDatabase*
    std::vector<StatementImpl*> mStatements;    // Table of IStatement*
    std::vector<BlobImpl*> mBlobs;              // Table of IBlob*
    std::vector<ArrayImpl*> mArrays;            // Table of Array*
    std::vector<TPB*> mTPBs;                    // Table of TPB

    void Init();            // A usage exclusif des constructeurs

public:
    isc_tr_handle* GetHandlePtr() { return &mHandle; }
    isc_tr_handle GetHandle() { return mHandle; }

    void AttachStatementImpl(StatementImpl*);
    void DetachStatementImpl(StatementImpl*);
    void AttachBlobImpl(BlobImpl*);
    void DetachBlobImpl(BlobImpl*);
    void AttachArrayImpl(ArrayImpl*);
    void DetachArrayImpl(ArrayImpl*);
    void AttachDatabaseImpl(DatabaseImpl* dbi, IBPP::TAM am = IBPP::amWrite,
            IBPP::TIL il = IBPP::ilConcurrency,
            IBPP::TLR lr = IBPP::lrWait, IBPP::TFF flags = IBPP::TFF(0));
    void DetachDatabaseImpl(DatabaseImpl* dbi);

    TransactionImpl(DatabaseImpl* db, IBPP::TAM am = IBPP::amWrite,
        IBPP::TIL il = IBPP::ilConcurrency,
        IBPP::TLR lr = IBPP::lrWait, IBPP::TFF flags = IBPP::TFF(0));
    ~TransactionImpl();

    //  (((((((( OBJECT INTERFACE ))))))))

public:
    void AttachDatabase(IBPP::Database db, IBPP::TAM am = IBPP::amWrite,
            IBPP::TIL il = IBPP::ilConcurrency,
            IBPP::TLR lr = IBPP::lrWait, IBPP::TFF flags = IBPP::TFF(0));
    void DetachDatabase(IBPP::Database db);
    void AddReservation(IBPP::Database db,
            const std::string& table, IBPP::TTR tr);

    void Start();
    bool Started() { return mHandle == 0 ? false : true; }
    void Commit();
    void Rollback();
    void CommitRetain();
    void RollbackRetain();

    IBPP::ITransaction* AddRef();
    void Release();
};

class RowImpl : public IBPP::IRow
{
    //  (((((((( OBJECT INTERNALS ))))))))

private:
    int mRefCount;                  // Reference counter

    XSQLDA* mDescrArea;             // XSQLDA descriptor itself
    std::vector<double> mNumerics;  // Temporary storage for Numerics
    std::vector<float> mFloats;     // Temporary storage for Floats
    std::vector<int64_t> mInt64s;   // Temporary storage for 64 bits
    std::vector<int32_t> mInt32s;   // Temporary storage for 32 bits
    std::vector<int16_t> mInt16s;   // Temporary storage for 16 bits
    std::vector<char> mBools;       // Temporary storage for Bools
    std::vector<std::string> mStrings;  // Temporary storage for Strings
    std::vector<bool> mUpdated;     // Which columns where updated (Set()) ?

    int mDialect;                   // Related database dialect
    DatabaseImpl* mDatabase;        // Related Database (important for Blobs, ...)
    TransactionImpl* mTransaction;  // Related Transaction (same remark)

    void SetValue(int, IITYPE, const void* value, int = 0);
    void* GetValue(int, IITYPE, void* = 0);

public:
    void Free();
    short AllocatedSize() { return mDescrArea->sqln; }
    void Resize(int n);
    void AllocVariables();
    bool MissingValues();       // Returns wether one of the mMissing[] is true
    XSQLDA* Self() { return mDescrArea; }

    RowImpl& operator=(const RowImpl& copied);
    RowImpl(const RowImpl& copied);
    RowImpl(int dialect, int size, DatabaseImpl* db, TransactionImpl* tr);
    ~RowImpl();

    //  (((((((( OBJECT INTERFACE ))))))))

public:
    void SetNull(int);
    void Set(int, bool);
    void Set(int, const char*);             // c-strings
    void Set(int, const void*, int);        // byte buffers
    void Set(int, const std::string&);
    void Set(int, int16_t);
    void Set(int, int32_t);
    void Set(int, int64_t);
    void Set(int, float);
    void Set(int, double);
    void Set(int, const IBPP::Timestamp&);
    void Set(int, const IBPP::Date&);
    void Set(int, const IBPP::Time&);
    void Set(int, const IBPP::DBKey&);
    void Set(int, const IBPP::Blob&);
    void Set(int, const IBPP::Array&);

    bool IsNull(int);
    bool Get(int, bool&);
    bool Get(int, char*);       // c-strings, len unchecked
    bool Get(int, void*, int&); // byte buffers
    bool Get(int, std::string&);
    bool Get(int, int16_t&);
    bool Get(int, int32_t&);
    bool Get(int, int64_t&);
    bool Get(int, float&);
    bool Get(int, double&);
    bool Get(int, IBPP::Timestamp&);
    bool Get(int, IBPP::Date&);
    bool Get(int, IBPP::Time&);
    bool Get(int, IBPP::DBKey&);
    bool Get(int, IBPP::Blob&);
    bool Get(int, IBPP::Array&);

    bool IsNull(const std::string&);
    bool Get(const std::string&, bool&);
    bool Get(const std::string&, char*);    // c-strings, len unchecked
    bool Get(const std::string&, void*, int&);  // byte buffers
    bool Get(const std::string&, std::string&);
    bool Get(const std::string&, int16_t&);
    bool Get(const std::string&, int32_t&);
    bool Get(const std::string&, int64_t&);
    bool Get(const std::string&, float&);
    bool Get(const std::string&, double&);
    bool Get(const std::string&, IBPP::Timestamp&);
    bool Get(const std::string&, IBPP::Date&);
    bool Get(const std::string&, IBPP::Time&);
    bool Get(const std::string&, IBPP::DBKey&);
    bool Get(const std::string&, IBPP::Blob&);
    bool Get(const std::string&, IBPP::Array&);

    int ColumnNum(const std::string&);
    const char* ColumnName(int);
    const char* ColumnAlias(int);
    const char* ColumnTable(int);
    IBPP::SDT ColumnType(int);
    int ColumnSubtype(int);
    int ColumnSize(int);
    int ColumnScale(int);
    int Columns();

    bool ColumnUpdated(int);
    bool Updated();

    IBPP::Database DatabasePtr() const;
    IBPP::Transaction TransactionPtr() const;

    IBPP::IRow* Clone();
    IBPP::IRow* AddRef();
    void Release();
};

class StatementImpl : public IBPP::IStatement
{
    //  (((((((( OBJECT INTERNALS ))))))))

private:
    friend class TransactionImpl;

    int mRefCount;              // Reference counter
    isc_stmt_handle mHandle;    // Statement Handle

    DatabaseImpl* mDatabase;        // Attached database
    TransactionImpl* mTransaction;  // Attached transaction
    RowImpl* mInRow;
    //bool* mInMissing;         // Quels paramètres n'ont pas été spécifiés
    RowImpl* mOutRow;
    bool mResultSetAvailable;   // Executed and result set is available
    bool mCursorOpened;         // dsql_set_cursor_name was called
    IBPP::STT mType;            // Type de requète
    std::string mSql;           // Last SQL statement prepared or executed

    // Internal Methods
    void CursorFree();

public:
    // Properties and Attributes Access Methods
    isc_stmt_handle GetHandle() { return mHandle; }

    void AttachDatabaseImpl(DatabaseImpl*);
    void DetachDatabaseImpl();
    void AttachTransactionImpl(TransactionImpl*);
    void DetachTransactionImpl();

    StatementImpl(DatabaseImpl*, TransactionImpl*);
    ~StatementImpl();

    //  (((((((( OBJECT INTERFACE ))))))))

public:
    void Prepare(const std::string& sql);
    void Execute(const std::string& sql);
    inline void Execute()   { Execute(std::string()); }
    void ExecuteImmediate(const std::string&);
    void CursorExecute(const std::string& cursor, const std::string& sql);
    inline void CursorExecute(const std::string& cursor)    { CursorExecute(cursor, std::string()); }
    bool Fetch();
    bool Fetch(IBPP::Row&);
    int AffectedRows();
    void Close();   // Free resources, attachments maintained
    std::string& Sql() { return mSql; }
    IBPP::STT Type() { return mType; }

    void SetNull(int);
    void Set(int, bool);
    void Set(int, const char*);             // c-strings
    void Set(int, const void*, int);        // byte buffers
    void Set(int, const std::string&);
    void Set(int, int16_t);
    void Set(int, int32_t);
    void Set(int, int64_t);
    void Set(int, float);
    void Set(int, double);
    void Set(int, const IBPP::Timestamp&);
    void Set(int, const IBPP::Date&);
    void Set(int, const IBPP::Time&);
    void Set(int, const IBPP::DBKey&);
    void Set(int, const IBPP::Blob&);
    void Set(int, const IBPP::Array&);

    void SetNull(std::string);
    void Set(std::string, bool);
    void Set(std::string, const char*);             // c-strings
    void Set(std::string, const void*, int);        // byte buffers
    void Set(std::string, const std::string&);
    void Set(std::string, int16_t);
    void Set(std::string, int32_t);
    void Set(std::string, int64_t);
    void Set(std::string, float);
    void Set(std::string, double);
    void Set(std::string, const IBPP::Timestamp&);
    void Set(std::string, const IBPP::Date&);
    void Set(std::string, const IBPP::Time&);
    void Set(std::string, const IBPP::DBKey&);
    void Set(std::string, const IBPP::Blob&);
    void Set(std::string, const IBPP::Array&);

private:
    std::string ParametersParser(std::string sql);
    std::vector<std::string> parametersByName_;
    std::vector<std::string> parametersDetailedByName_;
public:
    std::vector<std::string> ParametersByName();//Return a vector list, with the parameter(s) name, starting in 0
    std::vector<int> FindParamsByName(std::string name);  //Return a vector list, with the parameter(s) ID, starting in 1
    int ParameterNum(const std::string& name);

    bool IsNull(int);
    bool Get(int, bool*);
    bool Get(int, bool&);
    bool Get(int, char*);               // c-strings, len unchecked
    bool Get(int, void*, int&);         // byte buffers
    bool Get(int, std::string&);
    bool Get(int, int16_t*);
    bool Get(int, int16_t&);
    bool Get(int, int32_t*);
    bool Get(int, int32_t&);
    bool Get(int, int64_t*);
    bool Get(int, int64_t&);
    bool Get(int, float*);
    bool Get(int, float&);
    bool Get(int, double*);
    bool Get(int, double&);
    bool Get(int, IBPP::Timestamp&);
    bool Get(int, IBPP::Date&);
    bool Get(int, IBPP::Time&);
    bool Get(int, IBPP::DBKey&);
    bool Get(int, IBPP::Blob&);
    bool Get(int, IBPP::Array&);

    bool IsNull(const std::string&);
    bool Get(const std::string&, bool*);
    bool Get(const std::string&, bool&);
    bool Get(const std::string&, char*);        // c-strings, len unchecked
    bool Get(const std::string&, void*, int&);  // byte buffers
    bool Get(const std::string&, std::string&);
    bool Get(const std::string&, int16_t*);
    bool Get(const std::string&, int16_t&);
    bool Get(const std::string&, int32_t*);
    bool Get(const std::string&, int32_t&);
    bool Get(const std::string&, int64_t*);
    bool Get(const std::string&, int64_t&);
    bool Get(const std::string&, float*);
    bool Get(const std::string&, float&);
    bool Get(const std::string&, double*);
    bool Get(const std::string&, double&);
    bool Get(const std::string&, IBPP::Timestamp&);
    bool Get(const std::string&, IBPP::Date&);
    bool Get(const std::string&, IBPP::Time&);
    bool Get(const std::string&, IBPP::DBKey&);
    bool Get(const std::string&, IBPP::Blob&);
    bool Get(const std::string&, IBPP::Array&);

    int ColumnNum(const std::string&);
    int ColumnNumAlias(const std::string&);
    const char* ColumnName(int);
    const char* ColumnAlias(int);
    const char* ColumnTable(int);
    IBPP::SDT ColumnType(int);
    int ColumnSubtype(int);
    int ColumnSize(int);
    int ColumnScale(int);
    int Columns();

    IBPP::SDT ParameterType(int);
    int ParameterSubtype(int);
    int ParameterSize(int);
    int ParameterScale(int);
    int Parameters();

    void Plan(std::string&);

    IBPP::Database DatabasePtr() const;
    IBPP::Transaction TransactionPtr() const;

    IBPP::IStatement* AddRef();
    void Release();
};

class BlobImpl : public IBPP::IBlob
{
    //  (((((((( OBJECT INTERNALS ))))))))

private:
    friend class RowImpl;

    int mRefCount;
    bool                    mIdAssigned;
    ISC_QUAD                mId;
    isc_blob_handle         mHandle;
    bool                    mWriteMode;
    DatabaseImpl*           mDatabase;      // Belongs to this database
    TransactionImpl*        mTransaction;   // Belongs to this transaction

    void Init();
    void SetId(ISC_QUAD*);
    void GetId(ISC_QUAD*);

public:
    void AttachDatabaseImpl(DatabaseImpl*);
    void DetachDatabaseImpl();
    void AttachTransactionImpl(TransactionImpl*);
    void DetachTransactionImpl();

    BlobImpl(const BlobImpl&);
    BlobImpl(DatabaseImpl*, TransactionImpl* = 0);
    ~BlobImpl();

    //  (((((((( OBJECT INTERFACE ))))))))

public:
    void Create();
    void Open();
    void Close();
    void Cancel();
    int Read(void*, int size);
    void Write(const void*, int size);
    void Info(int* Size, int* Largest, int* Segments);

    void Save(const std::string& data);
    void Load(std::string& data);

    IBPP::Database DatabasePtr() const;
    IBPP::Transaction TransactionPtr() const;

    IBPP::IBlob* AddRef();
    void Release();
};

class ArrayImpl : public IBPP::IArray
{
    //  (((((((( OBJECT INTERNALS ))))))))

private:
    friend class RowImpl;

    int                 mRefCount;      // Reference counter
    bool                mIdAssigned;
    ISC_QUAD            mId;
    bool                mDescribed;
    ISC_ARRAY_DESC      mDesc;
    DatabaseImpl*       mDatabase;      // Database attachée
    TransactionImpl*    mTransaction;   // Transaction attachée
    void*               mBuffer;        // Buffer for native data
    int                 mBufferSize;    // Size of this buffer in bytes
    int                 mElemCount;     // Count of elements in this array
    int                 mElemSize;      // Size of an element in the buffer

    void Init();
    void SetId(ISC_QUAD*);
    void GetId(ISC_QUAD*);
    void ResetId();
    void AllocArrayBuffer();

public:
    void AttachDatabaseImpl(DatabaseImpl*);
    void DetachDatabaseImpl();
    void AttachTransactionImpl(TransactionImpl*);
    void DetachTransactionImpl();

    ArrayImpl(const ArrayImpl&);
    ArrayImpl(DatabaseImpl*, TransactionImpl* = 0);
    ~ArrayImpl();

    //  (((((((( OBJECT INTERFACE ))))))))

public:
    void Describe(const std::string& table, const std::string& column);
    void ReadTo(IBPP::ADT, void*, int);
    void WriteFrom(IBPP::ADT, const void*, int);
    IBPP::SDT ElementType();
    int ElementSize();
    int ElementScale();
    int Dimensions();
    void Bounds(int dim, int* low, int* high);
    void SetBounds(int dim, int low, int high);

    IBPP::Database DatabasePtr() const;
    IBPP::Transaction TransactionPtr() const;

    IBPP::IArray* AddRef();
    void Release();
};

//
//  EventBufferIterator: used in EventsImpl implementation.
//

template<class It>
struct EventBufferIterator
{
    It mIt;

public:
    EventBufferIterator& operator++()
        { mIt += 1 + static_cast<int>(*mIt) + 4; return *this; }

    bool operator == (const EventBufferIterator& i) const { return i.mIt == mIt; }
    bool operator != (const EventBufferIterator& i) const { return i.mIt != mIt; }

    std::string get_name() const
    {
        return std::string(mIt + 1, mIt + 1 + static_cast<int32_t>(*mIt));
    }

    uint32_t get_count() const
    {
        return (*gds.Call()->m_vax_integer)
            (const_cast<char*>(&*(mIt + 1 + static_cast<int>(*mIt))), 4);
    }

    // Those container like begin() and end() allow access to the underlying type
    It begin()  { return mIt; }
    It end()    { return mIt + 1 + static_cast<int>(*mIt) + 4; }

    EventBufferIterator() {}
    EventBufferIterator(It it) : mIt(it) {}
};

class EventsImpl : public IBPP::IEvents
{
    static const size_t MAXEVENTNAMELEN;
    static void EventHandler(const char*, short, const char*);

    typedef std::vector<IBPP::EventInterface*> ObjRefs;
    ObjRefs mObjectReferences;

    typedef std::vector<char> Buffer;
    Buffer mEventBuffer;
    Buffer mResultsBuffer;

    int mRefCount;      // Reference counter

    DatabaseImpl* mDatabase;
    ISC_LONG mId;           // Firebird internal Id of these events
    bool mQueued;           // Has isc_que_events() been called?
    bool mTrapped;          // EventHandled() was called since last que_events()

    void FireActions();
    void Queue();
    void Cancel();

    EventsImpl& operator=(const EventsImpl&);
    EventsImpl(const EventsImpl&);

public:
    void AttachDatabaseImpl(DatabaseImpl*);
    void DetachDatabaseImpl();

    EventsImpl(DatabaseImpl* dbi);
    ~EventsImpl();

    //  (((((((( OBJECT INTERFACE ))))))))

public:
    void Add(const std::string&, IBPP::EventInterface*);
    void Drop(const std::string&);
    void List(std::vector<std::string>&);
    void Clear();               // Drop all events
    void Dispatch();            // Dispatch NON async events

    IBPP::Database DatabasePtr() const;

    IBPP::IEvents* AddRef();
    void Release();
};

void encodeDate(ISC_DATE& isc_dt, const IBPP::Date& dt);
void decodeDate(IBPP::Date& dt, const ISC_DATE& isc_dt);

void encodeTime(ISC_TIME& isc_tm, const IBPP::Time& tm);
void decodeTime(IBPP::Time& tm, const ISC_TIME& isc_tm);

void encodeTimestamp(ISC_TIMESTAMP& isc_ts, const IBPP::Timestamp& ts);
void decodeTimestamp(IBPP::Timestamp& ts, const ISC_TIMESTAMP& isc_ts);

struct consts   // See _ibpp.cpp for initializations of these constants
{
    static const double dscales[19];
    static const int Dec31_1899;
    static const int16_t min16;
    static const int16_t max16;
    static const int32_t min32;
    static const int32_t max32;
};

}   // namespace ibpp_internal

#endif // __INTERNAL_IBPP_H__
