--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/srsf/sisrscontrollerplugin/src/sidatabase.cpp Thu Dec 17 08:46:30 2009 +0200
@@ -0,0 +1,514 @@
+/*
+* Copyright (c) 2004-2006 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description: This class implements the SI Controller Plugin database.
+*
+*/
+
+
+// INCLUDE FILES
+#include "sidatabase.h"
+#include "rubydebug.h"
+#include "nssbackupobserver.h"
+
+
+// CONSTANTS
+// Estimate size in bytes for an empty database
+// const TInt KSizeEstimateDb = 650;
+
+// Plugin database format string for secure DBMS
+_LIT( KPluginDatabaseFormatString, "SECURE[10201AFF]" );
+
+// Name of the DB lock mutex
+_LIT( KLockMutex, "SIDATABASE" );
+
+// ============================ MEMBER FUNCTIONS ===============================
+
+// -----------------------------------------------------------------------------
+// CSIDatabase::CSIDatabase
+// C++ default constructor can NOT contain any code, that
+// might leave.
+// -----------------------------------------------------------------------------
+//
+CSIDatabase::CSIDatabase( TFileName aDatabaseFileName )
+ : iOpenTransaction( EFalse ),
+ iDatabaseFileName( aDatabaseFileName ),
+ iDatabaseOpen( EFalse )
+ {
+ // Nothing
+ }
+
+// -----------------------------------------------------------------------------
+// CSIDatabase::ConstructL
+// Symbian 2nd phase constructor can leave.
+// -----------------------------------------------------------------------------
+//
+void CSIDatabase::ConstructL()
+ {
+ RUBY_DEBUG_BLOCKL( "CSIDatabase::ConstructL" );
+ // Checks to see if the Database already exists. If not, it creates one.
+ User::LeaveIfError( iDbSession.Connect() );
+ CreateDatabaseL();
+ OpenDatabaseL();
+
+ TInt err = iMutex.OpenGlobal( KLockMutex );
+ if ( err != KErrNone )
+ {
+ RUBY_DEBUG0( "CSIDatabase::ConstructL Creating new global mutex" );
+ iMutex.CreateGlobal( KLockMutex );
+ }
+ else
+ {
+ RUBY_DEBUG0( "CSIDatabase::ConstructL Using existing global mutex" );
+ }
+
+ iCriticalSection.CreateLocal();
+ iBackupObserver = CNssBackupObserver::NewL( *this );
+
+ }
+
+// -----------------------------------------------------------------------------
+// CSIDatabase::NewL
+// Two-phased constructor.
+// -----------------------------------------------------------------------------
+//
+CSIDatabase* CSIDatabase::NewL( TFileName aSDDatabaseFileName )
+ {
+ RUBY_DEBUG_BLOCKL( "CSIDatabase::NewL" );
+
+ CSIDatabase* self = new( ELeave ) CSIDatabase( aSDDatabaseFileName );
+ CleanupStack::PushL( self );
+ self->ConstructL();
+ CleanupStack::Pop();
+
+ return self;
+ }
+
+// -----------------------------------------------------------------------------
+// CSIDatabase::Rollback
+// Rollback all changes to the database.
+// -----------------------------------------------------------------------------
+//
+void CSIDatabase::Rollback()
+ {
+ RUBY_DEBUG0( "CSIDatabase::Rollback" );
+ if ( iOpenTransaction )
+ {
+ iDb.Rollback();
+ // Try to recover the database, if it is damaged
+ if( iDb.IsDamaged() )
+ {
+ iDb.Recover();
+ }
+ iMutex.Signal();
+ iCriticalSection.Signal();
+ iOpenTransaction = EFalse;
+ }
+
+ }
+
+// -----------------------------------------------------------------------------
+// CSIDatabase::~CSIDatabase
+// Destructor
+// -----------------------------------------------------------------------------
+//
+CSIDatabase::~CSIDatabase()
+ {
+ // Rollback if there are any changes not commited
+ if ( iOpenTransaction )
+ {
+ iDb.Rollback();
+ // Try to recover the database, if it is damaged
+ if( iDb.IsDamaged() )
+ {
+ iDb.Recover();
+ }
+ // Signal mutex if somebody happens to be waiting in BeginTransactionL()
+ iMutex.Signal();
+ }
+
+ delete iBackupObserver;
+ iCriticalSection.Close();
+
+ iDb.Close();
+ iDbSession.Close();
+ iDatabaseOpen = EFalse;
+ }
+
+// -----------------------------------------------------------------------------
+// CSIDatabase::BeginTransactionL
+// Begins a database transaction if not already. Waits until exclusive write lock
+// has been gained.
+// -----------------------------------------------------------------------------
+//
+void CSIDatabase::BeginTransactionL()
+ {
+
+
+ if ( iOpenTransaction )
+ {
+ // If we already have the lock, no need to take it again
+ RUBY_DEBUG0( "CSIDatabase::BeginTransactionL DB is already locked by current process" );
+ return;
+ }
+
+ // Take mutex to ensure that only one process tries to gain the lock
+ iMutex.Wait();
+ iCriticalSection.Wait();
+
+ // Taking the global mutex makes it sure that this should succeed every time
+ TInt readLockErr = iDb.Begin();
+
+ if ( readLockErr == KErrNone )
+ {
+ iOpenTransaction = ETrue;
+ }
+ }
+
+// -----------------------------------------------------------------------------
+// CSIDatabase::CommitChangesL
+// Commits all changes to the database.
+// -----------------------------------------------------------------------------
+//
+void CSIDatabase::CommitChangesL( TBool aCompact )
+ {
+ if ( iOpenTransaction )
+ {
+ TInt err = iDb.Commit();
+
+ RUBY_DEBUG1( "CSIDatabase::CommitChangesL iDb.Commit() [%d]", err );
+
+ if ( err != KErrNone )
+ {
+ iDb.Rollback();
+ // Try to recover the database, if it is damaged
+ if( iDb.IsDamaged() )
+ {
+ iDb.Recover();
+ }
+
+ iMutex.Signal();
+ iCriticalSection.Signal();
+ iOpenTransaction = EFalse;
+ User::Leave( err );
+ }
+
+ if ( aCompact )
+ {
+ RUBY_DEBUG0( "CSIDatabase::CommitChangesL compacting DB" );
+ TInt error = iDb.Compact();
+ if ( error != KErrNone )
+ {
+ RUBY_DEBUG1( "CSIDatabase::CommitChangesL compact error: [%d]", error );
+ }
+ }
+
+ // Signal waiting BeginTransactionL()
+ iMutex.Signal();
+ iCriticalSection.Signal();
+ iOpenTransaction = EFalse;
+
+ User::LeaveIfError( err );
+ }
+
+
+ }
+
+// -----------------------------------------------------------------------------
+// CSIDatabase::DoIDTablesExistL
+// Checks to see if ID tables exist.
+// -----------------------------------------------------------------------------
+//
+TBool CSIDatabase::DoIDTablesExistL()
+ {
+ // Get db table names list
+ CDbTableNames* table_names = iDb.TableNamesL();
+ TInt count = table_names->Count();
+ delete table_names;
+ // 1 is for the lock table!
+ return ( count > 1 );
+ }
+
+// -----------------------------------------------------------------------------
+// CSIDatabase::DoesLockTableExistL
+// Checks to see if lock table exists
+// -----------------------------------------------------------------------------
+//
+TBool CSIDatabase::DoesLockTableExistL()
+ {
+ // Get db table names list
+ CDbTableNames* table_names = iDb.TableNamesL();
+ TInt count = table_names->Count();
+
+ for ( TInt counter = 0 ; counter < count ; counter++ )
+ {
+ if ( (*table_names)[counter] == _L( "writelocktable" ) )
+ {
+ delete table_names;
+ return ETrue;
+ }
+ }
+
+ delete table_names;
+ return EFalse;
+ }
+
+// -----------------------------------------------------------------------------
+// CSIDatabase::DoesModelBankTableExistL
+// Checks to see if model bank table exists
+// -----------------------------------------------------------------------------
+//
+TBool CSIDatabase::DoesModelBankTableExistL()
+ {
+ // Get db table names list
+ CDbTableNames* table_names = iDb.TableNamesL();
+ TInt count = table_names->Count();
+
+ for ( TInt counter = 0 ; counter < count ; counter++ )
+ {
+ if ( (*table_names)[counter] == _L( "siModelBankIdTable" ) )
+ {
+ delete table_names;
+ return ETrue;
+ }
+ }
+
+ delete table_names;
+ return EFalse;
+ }
+
+// -----------------------------------------------------------------------------
+// CSIDatabase::DoesLexiconTableExistL
+// Checks if lexicon table exists
+// -----------------------------------------------------------------------------
+//
+TBool CSIDatabase::DoesLexiconTableExistL()
+ {
+ // Get db table names list
+ CDbTableNames* table_names = iDb.TableNamesL();
+ TInt count = table_names->Count();
+
+ for ( TInt counter = 0 ; counter < count ; counter++ )
+ {
+ if ( (*table_names)[counter] == _L( "siLexiconIdTable" ) )
+ {
+ delete table_names;
+ return ETrue;
+ }
+ }
+
+ delete table_names;
+ return EFalse;
+ }
+
+// -----------------------------------------------------------------------------
+// CSIDatabase::DoesGrammarTableExistL
+// Checks if grammar table exists
+// -----------------------------------------------------------------------------
+//
+TBool CSIDatabase::DoesGrammarTableExistL()
+ {
+ // Get db table names list
+ CDbTableNames* table_names = iDb.TableNamesL();
+ TInt count = table_names->Count();
+
+ for ( TInt counter = 0 ; counter < count ; counter++ )
+ {
+ if ( (*table_names)[counter] == _L( "siGrammarIdTable" ) )
+ {
+ delete table_names;
+ return ETrue;
+ }
+ }
+
+ delete table_names;
+ return EFalse;
+ }
+
+
+// -----------------------------------------------------------------------------
+// CSIDatabase::SIDatabase
+// Returns a reference to the database.
+// -----------------------------------------------------------------------------
+//
+RDbNamedDatabase& CSIDatabase::SIDatabase()
+ {
+ return iDb;
+ }
+
+// -----------------------------------------------------------------------------
+// CSIDatabase::CreateDatabaseL
+// Creates a database file if one does not exist yet.
+// -----------------------------------------------------------------------------
+//
+void CSIDatabase::CreateDatabaseL()
+ {
+ RUBY_DEBUG_BLOCKL( "CSIDatabase::CreateDatabaseL" );
+
+ // Get the drive of the database file
+ iDatabaseDrive = EDriveC;
+ if ( iDatabaseFileName.Locate( 'c' ) == 0 || iDatabaseFileName.Locate( 'C' ) == 0 )
+ {
+ iDatabaseDrive = EDriveC;
+ }
+ else if ( iDatabaseFileName.Locate( 'd' ) == 0 || iDatabaseFileName.Locate( 'D' ) == 0 )
+ {
+ iDatabaseDrive = EDriveD;
+ }
+ else if ( iDatabaseFileName.Locate( 'z' ) == 0 || iDatabaseFileName.Locate( 'Z' ) == 0 )
+ {
+ iDatabaseDrive = EDriveZ;
+ }
+
+ else if ( iDatabaseFileName.Locate( 'e' ) == 0 || iDatabaseFileName.Locate( 'E' ) == 0 )
+ {
+ iDatabaseDrive = EDriveE;
+ }
+ else
+ {
+ User::Leave( KErrPathNotFound );
+ }
+
+ RDbNamedDatabase database;
+ TInt ret = database.Create( iDbSession, iDatabaseFileName, KPluginDatabaseFormatString );
+ if ( ret == KErrAlreadyExists )
+ {
+ // Ignore KErrAlreadyExists, we will use the existing one if it is there
+ ret = KErrNone;
+ }
+ database.Close();
+ User::LeaveIfError( ret );
+ }
+
+// -----------------------------------------------------------------------------
+// CSIDatabase::OpenDatabaseL
+// Opens the database.
+// -----------------------------------------------------------------------------
+//
+void CSIDatabase::OpenDatabaseL()
+ {
+ if ( !iDatabaseOpen )
+ {
+
+ User::LeaveIfError( iDb.Open( iDbSession, iDatabaseFileName, KPluginDatabaseFormatString ) );
+
+ // Try to recover the database, if it is damaged
+ if( iDb.IsDamaged() )
+ {
+ RUBY_DEBUG0( "CSIDatabase::OpenDatabaseL - Db is damaged. Attempt to recover." );
+
+ User::LeaveIfError( iDb.Recover() );
+ }
+
+ iDatabaseOpen = ETrue;
+ }
+ }
+
+// -----------------------------------------------------------------------------
+// CSIDatabase::CloseDatabase
+// Closes the database.
+// -----------------------------------------------------------------------------
+//
+TInt CSIDatabase::CloseDatabase()
+ {
+ RUBY_DEBUG0( "CSIDatabase::CloseDatabase" );
+
+ iDb.Close();
+ iDatabaseOpen = EFalse;
+
+ return KErrNone;
+ }
+
+// -----------------------------------------------------------------------------
+// CSIDatabase::DbSession
+// Return reference to DB session.
+// -----------------------------------------------------------------------------
+//
+RDbs& CSIDatabase::DbSession()
+ {
+ return iDbSession;
+ }
+
+// -----------------------------------------------------------------------------
+// CSIDatabase::DbDrive
+// Returns a drive for DB file.
+// -----------------------------------------------------------------------------
+//
+TInt CSIDatabase::DbDrive()
+ {
+ return iDatabaseDrive;
+ }
+
+// -----------------------------------------------------------------------------
+// CSIDatabase::CreateLockTableL
+// Creates a dummy table to gain write-lock at the beginning of each transaction.
+// -----------------------------------------------------------------------------
+//
+void CSIDatabase::CreateLockTableL()
+ {
+ // Create writelocktable
+ // This table is accessed every time when transaction starts to gain
+ // exclusive locking of the DB
+ _LIT( KWriteLockTable, "writelocktable" );
+
+ _LIT( KCol1, "temporary" );
+
+ OpenDatabaseL();
+
+ // Create the rrd tables definition (columnset).
+ CDbColSet* columns = CDbColSet::NewLC();
+
+ // The tag id
+ TDbCol dbCol1( KCol1, EDbColUint32 );
+ columns->AddL( dbCol1 );
+
+ User::LeaveIfError( iDb.CreateTable( KWriteLockTable, *columns ) );
+
+ // Cleanup columns
+ CleanupStack::PopAndDestroy( columns );
+ }
+
+// -----------------------------------------------------------------------------
+// CSIDatabase::LockTransactionsL
+// Permit transactions and release database
+// -----------------------------------------------------------------------------
+//
+void CSIDatabase::LockTransactionsL()
+ {
+ // lock transactions
+ RUBY_DEBUG_BLOCK( "CSIDatabase::LockTransactionsL" );
+
+ iCriticalSection.Wait(); // wait until a possible transaction ends
+
+ // release a database
+ CloseDatabase();
+ }
+
+// -----------------------------------------------------------------------------
+// CSIDatabase::UnlockTransactionsL
+// Allow transactions and reserve database
+// -----------------------------------------------------------------------------
+//
+void CSIDatabase::UnlockTransactionsL()
+ {
+ // unlock transactions
+ RUBY_DEBUG_BLOCK( "CSIDatabase::UnlockTransactionsL" );
+ OpenDatabaseL(); // open database
+
+ if ( iCriticalSection.IsBlocked() )
+ {
+ iCriticalSection.Signal(); // allow to do transactions
+ }
+ }
+
+// End of File