/**********************************************************************
**
** File name : OLEDatabase.cpp
**
** Contents : Database routines to access OLEDB
**
**********************************************************************/
#include "stdafx.h"
#include "OLEDatabase.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

//
// Constructor
//
COLEDatabase::COLEDatabase()
{
    m_bOpen = FALSE ;            // Not Open
    m_bSQL = FALSE ;             // Not SQL DB        
    m_bExclusive = FALSE ;      // Not Exclusive Mode
    m_bReadOnly = FALSE ;       // Not Read Only
}

//
// Destructor
//
COLEDatabase::~COLEDatabase()
{
    Close();                     // Make sure it's closed
}

//
// Format a Date Time for the type of DB open
//
CString COLEDatabase::FormatDateTime( COleDateTime &ts )
{
    CString csResult ;

    if ( m_bSQL )
        csResult = ts.Format( _T( "'%Y-%m-%d %H:%M:%S'" ) ) ;
    else
        csResult.Format( _T( "%f" ), ts ) ;

    return csResult ;
}

//
// Return the function to convert a DB field to upper case
//
const TCHAR *COLEDatabase::UpperCaseFunction()
{
    if ( m_bSQL )
        return _T( "UPPER" ) ;

    return _T( "UCase" ) ;
}

//
// return either the pathname of the Access DB
// or >Server>Database for SQL
//
CString COLEDatabase::GetFullPath()
{
    CString csPath ;

    if ( IsSQL() )
        csPath.Format( _T( ">%s>%s" ) , m_csServerName, m_csDatabase ) ;
    else
        csPath = m_csDatabase ;

    return csPath ;
}


//
// Open the database
//
void COLEDatabase::Open(LPCTSTR lpszName, BOOL bExclusive, BOOL bReadOnly , LPCTSTR lpszPassword )
{
    // Close first, in case still open
    CloseConnection();

    if ( *lpszName == '>' )                                 // SQL ?
    {                                                       // Yes
        TCHAR szPath[ _MAX_PATH ] ;

        strscpy( szPath, lpszName+1 ) ;

        TCHAR *pSplit = strchr( szPath, '>' ) ;             // Find Database

        if ( pSplit )                                       // Found ?
        {                                                   // yes
            *pSplit = '\0' ;                                // separate
            m_csServerName = szPath ;                       // And save Server
            m_csDatabase = pSplit+1 ;                       // plus database
            m_bSQL = TRUE ;                                 // Flag SQL
        }
    }
    else
    {
        m_csServerName = "" ;                               // Access - No Server
        m_csDatabase = lpszName ;                           // save path to DB
        m_bSQL = FALSE ;                                    // Not SQL
    }

    //
    // try and open the database
    //
    try
    {
        if ( m_bSQL )
            OpenSQLConnection( bExclusive, bReadOnly ) ;   // No password on SQL
        else
        {
            OpenJETConnection( bExclusive,
                                bReadOnly,
                                lpszPassword ) ;           // All options
        }


        // Open sessions
        HRESULT hr = m_Session.Open(m_DB);                  // Now open the session

        if (FAILED(hr))                                     // ok ?
            throw new COLEDBException(m_Session, hr);      // no

        m_bOpen = TRUE ;                                    // now open
    }
    catch (CException* pException)
    {
        CloseConnection();                                  // In case half open

        throw pException;                                   // Throw to next handler
    }
}

//
// Close the database
//
void COLEDatabase::Close()
{
    // Close the local database

    if ( m_bOpen )                                         // Open ?
    {                                                      // Yes
        if ( m_bExclusive )                                // Exclusive mode ?
        {                                                  // Yes
            m_bExclusive = FALSE ;                         // Not any more !

            if ( m_bSQL )                                  // SQL ?
            {                                              // Yes

                //
                // Execute the sp_dboption stored procedure
                // to disable single user mode
                //

                CNoRecordSetSQLCommand cRS ;

                LONG lRowsAffected = 0 ;

                CString csSQL ;

                csSQL.Format( "EXECUTE sp_dboption '%s','single user','false'",
                            ( const TCHAR * )m_csDatabase ) ;

                HRESULT hr = cRS.Execute( m_Session, csSQL , &lRowsAffected ) ;

                if ( FAILED(hr) )
                    throw ( new COLEDBException( m_Session, hr ) ) ;
            }
        }
        m_bOpen = FALSE ;                                 // Not Open
        m_bReadOnly = FALSE ;                             // Not Read only
        CloseConnection() ;                               // Close the connection
    }
}


//
// Execute some SQL on the database
//
LONG COLEDatabase::Execute(LPCTSTR lpszSQL, int nOptions)
{
    UNUSED( nOptions ) ;

    //
    // A general SQL command that returns no rows
    //

    CGeneralSQLCommand    SQLCmd ;

    LONG lRowsAffected = 0 ;
   
    try
    {
        SQLCmd.Open( m_Session, lpszSQL, &lRowsAffected ) ;
    }
    catch ( CException *e )
    {
        e->Delete() ;
        lRowsAffected = -1 ;
    }

    return lRowsAffected ;
}

//
// Get the number of records affected from the last execute
//
VOID_ COLEDatabase::CloseConnection( VOID_ )
{
    m_Session.Close();             // Close the session
    m_DB.Close();                  // Close the DB

}

//
// Open the database connections (NOTE - this method will throw an COLDBException)
//
VOID_ COLEDatabase::OpenSQLConnection( BOOL bExclusive, BOOL bReadOnly )
{
    // Build properties
    CDBPropSet dbinit;

    // Initialisation properties
    dbinit.SetGUID(DBPROPSET_DBINIT);
    dbinit.AddProperty(DBPROP_AUTH_INTEGRATED, _T("SSPI"));
    dbinit.AddProperty(DBPROP_INIT_CATALOG, m_csDatabase );
    dbinit.AddProperty(DBPROP_INIT_DATASOURCE, m_csServerName ) ;

    if ( bReadOnly )
        dbinit.AddProperty(DBPROP_INIT_MODE, (long)DB_MODE_READ ) ;

    HRESULT hr = m_DB.Open( _T( "SQLOLEDB" ), &dbinit, 1);

    if (FAILED(hr))                                 // Open ok ?
        throw new COLEDBException( m_DB, hr);       // No - throw an exception

    if ( bExclusive )                               // Exclusive mode ?
    {                                               // Yes
        //
        // Execute the sp_dboption stored procedure
        //

        CSession session ;
        session.Open( m_DB ) ;

        CNoRecordSetSQLCommand cRS ;
        LONG lRowsAffected = 0 ;
       
        CString csSQL ;

        csSQL.Format( "EXECUTE sp_dboption '%s','single user','true'",
                    ( const TCHAR * )m_csDatabase ) ;

        HRESULT hr = cRS.Execute( session, csSQL, &lRowsAffected ) ;

        if (FAILED(hr))                             // Ok ?
        {                                           // No
            Close() ;
            throw (new COLEDBException(session, hr));
        }

        session.Close() ;
    }
    m_bExclusive = bExclusive ;                     // Set attributes
    m_bReadOnly = bReadOnly ;
}

//
// Open the database connections (NOTE - this method will throw an COLDBException)
//
VOID_ COLEDatabase::OpenJETConnection( BOOL bExclusive, BOOL bReadOnly, LPCTSTR lpszPassword )
{
    //
    // Build properties
    //
    CDBPropSet dbinit[2];

    // Standard DBINIT properties
    dbinit[0].SetGUID(DBPROPSET_DBINIT);

    dbinit[0].AddProperty(DBPROP_AUTH_CACHE_AUTHINFO, true);
    dbinit[0].AddProperty(DBPROP_AUTH_ENCRYPT_PASSWORD, false);
    dbinit[0].AddProperty(DBPROP_INIT_DATASOURCE, m_csDatabase ) ;

    // Set Jet OLE DB provider specific properties
    dbinit[1].SetGUID(DBPROPSET_JETOLEDB_DBINIT);

    if ( bExclusive || bReadOnly )
    {
        long lMask = 0 ;

        if ( bExclusive )
            lMask |= DB_MODE_SHARE_EXCLUSIVE ;        // Fully exclusive

        if ( bReadOnly )
            lMask |= DB_MODE_READ ;                 // Read Only

        dbinit[0].AddProperty(DBPROP_INIT_MODE, lMask ) ;
    }

    if ( lpszPassword )                 // Password ?
    {
        //Database password
        dbinit[1].AddProperty(DBPROP_JETOLEDB_DATABASEPASSWORD, lpszPassword );
    }

    if ( !bReadOnly )
    {
        //Database Locking Mode - set to row locking !
        dbinit[1].AddProperty(DBPROP_JETOLEDB_DATABASELOCKMODE, (long)DBPROPVAL_DL_ALCATRAZ ) ;
    }
    else
    {
        // No Locking
        dbinit[1].AddProperty(DBPROP_JETOLEDB_MAXLOCKSPERFILE, 0L ) ;
    }


    HRESULT hr = m_DB.Open(_T("Microsoft.JET.OLEDB.4.0"), dbinit, 2);
    if (FAILED(hr))
    {
        throw new COLEDBException( m_DB, hr);
    }
    m_bExclusive = bExclusive ;
    m_bReadOnly = bReadOnly ;
}