--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/presetserver/serversrc/Psdatabase.cpp Mon Apr 19 14:01:53 2010 +0300
@@ -0,0 +1,924 @@
+/*
+* Copyright (c) 2006-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: Implementation of the preset database
+*
+*/
+
+
+#include <bautils.h>
+#include <pscommon.h>
+
+#include "psdebug.h"
+#include "pspendingpreset.h"
+#include "psdatabase.h"
+#include "pspresetobserver.h"
+
+// Uncomment the line below to get database print outs.
+// Warning! This may cause a lot of debug messages, so use with caution.
+// #define PS_DATABASE_PRINT_DEBUG
+
+#ifdef PS_DATABASE_PRINT_DEBUG
+ #define PS_PRINT_DATABASE RPSDatabase::PrintDatabaseL()
+#else
+ #define PS_PRINT_DATABASE
+#endif
+
+const TInt KPSDatabaseVersion = 1; // The latest version of the database. Must be kept up to date when adding new versions.
+
+const TInt KPSDatabaseVersion1 = 1; // Database version 1 identifier.
+
+// This array contains function pointers to all database update packages. One update corresponds to one function call, therefore
+// when adding new database updates it is imperative that this array be updated as well.
+
+const RPSDatabase::KPSDatabaseUpdateFunction RPSDatabase::iDatabaseUpdateFunctions[] =
+ {
+ &RPSDatabase::CreateTablesL
+ };
+
+// Table and columns literals.
+
+_LIT( KPSPresetsTable, "Presets" );
+_LIT( KPSPresetsIdColumn, "Id" );
+_LIT( KPSPresetsNameColumn, "Name" );
+_LIT( KPSPresetsIndexColumn, "Index" );
+_LIT( KPSPresetsDataHandlerColumn, "DataHandler" );
+_LIT( KPSPresetsDataColumn, "Data" );
+
+_LIT( KPSVersionsTable, "Versions" );
+_LIT( KPSVersionsVersionColumn, "Version" );
+
+// ======== LOCAL FUNCTIONS ========
+
+// ======== MEMBER FUNCTIONS ========
+
+// ---------------------------------------------------------------------------
+// Constructor.
+// ---------------------------------------------------------------------------
+//
+RPSDatabase::RPSDatabase( MPSPresetObserver& aObserver )
+ : RDbNamedDatabase(), iObserver( aObserver )
+ {
+ }
+
+// ---------------------------------------------------------------------------
+// Opens the database.
+// ---------------------------------------------------------------------------
+//
+void RPSDatabase::OpenL( RFs& aFs, const TDesC& aFileName )
+ {
+ Close(); // Ensure that the database is closed before trying to open it.
+
+ BaflUtils::EnsurePathExistsL( aFs, aFileName );
+
+ TInt err = RDbNamedDatabase::Create( aFs, aFileName );
+
+ if ( err == KErrAlreadyExists )
+ {
+ // The database already existed, need to open it.
+ User::LeaveIfError( RDbNamedDatabase::Open( aFs, aFileName ) );
+ }
+ else
+ {
+ User::LeaveIfError( err );
+ }
+
+ if ( IsDamaged() || !InTransaction() )
+ {
+ err = Recover();
+
+ if ( !err )
+ {
+ err = Compact();
+ }
+ }
+
+ if ( err )
+ {
+ Close();
+ User::Leave( err );
+ }
+
+ // The database is now open and functional, check if the structure needs to be updated.
+ TRAP( err, UpdateDatabaseL() )
+
+ if ( err )
+ {
+ Destroy();
+ User::Leave( err );
+ }
+
+ PS_PRINT_DATABASE;
+ }
+
+// ---------------------------------------------------------------------------
+// Deletes all presets whose data handler is no longer available.
+// ---------------------------------------------------------------------------
+//
+void RPSDatabase::DeleteOrphanedPresetsL( const RArray<TInt>& aDataHandlers )
+ {
+ PS_PRINT_DATABASE;
+
+ _LIT( sql, "DELETE FROM %S" );
+ _LIT( sqlWhere, " WHERE %S <> %d" );
+ _LIT( sqlAnd, " AND %S <> %d" );
+
+ TInt count = aDataHandlers.Count();
+
+ // Constructs the query that selects all presets that have no registered data handlers.
+
+ HBufC* sqlBuf = HBufC::NewLC( sql().Length() + KPSPresetsTable().Length() + count * KDefaultRealWidth +
+ Min( 1, count ) * (sqlWhere().Length() + KPSPresetsDataHandlerColumn().Length()) +
+ Max( 0, count - 1 ) * (sqlAnd().Length() + KPSPresetsDataHandlerColumn().Length()) );
+
+ TPtr sqlPtr( sqlBuf->Des() );
+ sqlPtr.Format( sql, &KPSPresetsTable );
+
+ if ( count > 0 )
+ {
+ HBufC* tempBuf = HBufC::NewLC( sqlWhere().Length() + KPSPresetsDataHandlerColumn().Length() + KDefaultRealWidth );
+ tempBuf->Des().Format( sqlWhere, &KPSPresetsDataHandlerColumn, aDataHandlers[0] );
+ sqlPtr.Append( *tempBuf );
+ CleanupStack::PopAndDestroy( tempBuf );
+
+ for ( TInt i = 1; i < count; i++ )
+ {
+ tempBuf = HBufC::NewLC( sqlAnd().Length() + KPSPresetsDataHandlerColumn().Length() + KDefaultRealWidth );
+ tempBuf->Des().Format( sqlAnd, &KPSPresetsDataHandlerColumn, aDataHandlers[i] );
+ sqlPtr.Append( *tempBuf );
+ CleanupStack::PopAndDestroy( tempBuf );
+ }
+ }
+
+ TInt rowsDeleted = Execute ( sqlPtr );
+ User::LeaveIfError(rowsDeleted);
+
+ CleanupStack::PopAndDestroy( sqlBuf );
+
+ if (rowsDeleted > 0)
+ {
+ User::LeaveIfError( Compact() );
+ }
+
+ PS_PRINT_DATABASE;
+ }
+
+// ---------------------------------------------------------------------------
+// Gets all presets matching the supplied data handler.
+// ---------------------------------------------------------------------------
+//
+void RPSDatabase::GetPresetListL( RArray<TInt>& aPresets, TUid aDataHandler )
+ {
+ HBufC* sqlBuf = NULL;
+
+ if ( aDataHandler == KNullUid )
+ {
+ _LIT( sql, "SELECT %S FROM %S" );
+
+ sqlBuf = HBufC::NewLC( sql().Length() + KPSPresetsIdColumn().Length() + KPSPresetsTable().Length() );
+
+ sqlBuf->Des().Format( sql, &KPSPresetsIdColumn, &KPSPresetsTable );
+ }
+ else
+ {
+ _LIT( sql, "SELECT %S FROM %S WHERE %S = %d" );
+
+ sqlBuf = HBufC::NewLC( sql().Length() + KPSPresetsIdColumn().Length() + KPSPresetsTable().Length() +
+ KPSPresetsDataHandlerColumn().Length() + KDefaultRealWidth );
+
+ sqlBuf->Des().Format( sql, &KPSPresetsIdColumn, &KPSPresetsTable, &KPSPresetsDataHandlerColumn, aDataHandler.iUid );
+ }
+
+ RDbView view;
+ User::LeaveIfError( view.Prepare( *this, *sqlBuf, RDbView::EReadOnly ) );
+ CleanupStack::PopAndDestroy( sqlBuf );
+ CleanupClosePushL( view );
+
+ CDbColSet* columns = view.ColSetL();
+ TInt idColumn = columns->ColNo( KPSPresetsIdColumn );
+ delete columns;
+
+ for ( view.FirstL(); view.AtRow(); view.NextL() )
+ {
+ view.GetL();
+ aPresets.AppendL( view.ColInt32( idColumn ) );
+ }
+
+ CleanupStack::PopAndDestroy( &view );
+ }
+
+// ---------------------------------------------------------------------------
+// Creates a preset.
+// ---------------------------------------------------------------------------
+//
+TInt RPSDatabase::CreatePresetL( TInt aIndex, TUid aDataHandler )
+ {
+ PS_PRINT_DATABASE;
+
+ _LIT( sql, "SELECT * FROM %S WHERE %S = %d AND %S = %d" );
+
+ HBufC* sqlBuf = HBufC::NewLC( sql().Length() + KPSPresetsTable().Length() + KPSPresetsIndexColumn().Length() +
+ KPSPresetsDataHandlerColumn().Length() + 2 * KDefaultRealWidth );
+
+ sqlBuf->Des().Format( sql, &KPSPresetsTable, &KPSPresetsIndexColumn, aIndex, &KPSPresetsDataHandlerColumn, aDataHandler.iUid );
+
+ RDbView view;
+ User::LeaveIfError( view.Prepare( *this, *sqlBuf ) );
+ CleanupStack::PopAndDestroy( sqlBuf );
+ CleanupClosePushL( view );
+ User::LeaveIfError( view.EvaluateAll() );
+
+ TInt id = KErrNotFound;
+
+ if ( view.FirstL() )
+ {
+ User::Leave( KErrAlreadyExists );
+ }
+ else
+ {
+ view.InsertL();
+
+ CDbColSet* columns = view.ColSetL();
+ TInt indexColumn = columns->ColNo( KPSPresetsIndexColumn );
+ TInt dataHandlerColumn = columns->ColNo( KPSPresetsDataHandlerColumn );
+ TInt idColumn = columns->ColNo( KPSPresetsIdColumn );
+ delete columns;
+
+ view.SetColL( indexColumn, aIndex );
+ view.SetColL( dataHandlerColumn, aDataHandler.iUid );
+
+ view.PutL();
+
+ id = view.ColInt32( idColumn );
+
+ iObserver.HandlePresetChangedL( id, aDataHandler, MPSPresetObserver::EPSCreated );
+ }
+
+ CleanupStack::PopAndDestroy( &view );
+
+ PS_PRINT_DATABASE;
+
+ return id;
+ }
+
+// ---------------------------------------------------------------------------
+// Deletes a preset.
+// ---------------------------------------------------------------------------
+//
+void RPSDatabase::DeletePresetL( TInt aId )
+ {
+ PS_PRINT_DATABASE;
+
+ _LIT( sql, "SELECT %S FROM %S WHERE %S = %d" );
+
+ HBufC* sqlBuf = HBufC::NewLC( sql().Length() + KPSPresetsTable().Length() + KPSPresetsDataHandlerColumn().Length() +
+ KPSPresetsIdColumn().Length() + KDefaultRealWidth );
+ sqlBuf->Des().Format( sql, &KPSPresetsDataHandlerColumn, &KPSPresetsTable, &KPSPresetsIdColumn, aId );
+
+ RDbView view;
+ User::LeaveIfError( view.Prepare( *this, *sqlBuf ) );
+ CleanupStack::PopAndDestroy( sqlBuf );
+ CleanupClosePushL( view );
+
+ User::LeaveIfError( view.EvaluateAll() );
+
+ if ( view.FirstL() )
+ {
+ view.GetL();
+ CDbColSet* columns = view.ColSetL();
+ TUid uid = TUid::Uid( view.ColInt32( columns->ColNo( KPSPresetsDataHandlerColumn ) ) );
+ delete columns;
+ view.DeleteL();
+ iObserver.HandlePresetChangedL( aId, uid, MPSPresetObserver::EPSDeleted );
+ }
+
+ CleanupStack::PopAndDestroy( &view );
+
+ PS_PRINT_DATABASE;
+ }
+
+// ---------------------------------------------------------------------------
+// Commits a preset to the database.
+// ---------------------------------------------------------------------------
+//
+void RPSDatabase::CommitPresetL( const CPSPendingPreset& aPreset )
+ {
+ PS_PRINT_DATABASE;
+
+ _LIT( sql, "SELECT * FROM %S WHERE %S = %d" );
+
+ HBufC* sqlBuf = HBufC::NewLC( sql().Length() + KPSPresetsTable().Length() + KPSPresetsIdColumn().Length() + KDefaultRealWidth );
+ sqlBuf->Des().Format( sql, &KPSPresetsTable, &KPSPresetsIdColumn, aPreset.Id() );
+
+ RDbView view;
+ User::LeaveIfError( view.Prepare( *this, *sqlBuf ) );
+ CleanupStack::PopAndDestroy( sqlBuf );
+ CleanupClosePushL( view );
+
+ User::LeaveIfError( view.EvaluateAll() );
+
+ if ( view.FirstL() )
+ {
+ CDbColSet* columns = view.ColSetL();
+ CleanupStack::PushL( columns );
+
+ view.UpdateL();
+
+ RDbColWriteStream stream;
+
+ stream.OpenLC( view, columns->ColNo( KPSPresetsNameColumn ) );
+ stream.WriteL( aPreset.Name() );
+ stream.CommitL();
+
+ CleanupStack::PopAndDestroy( &stream );
+
+ view.SetColL( columns->ColNo( KPSPresetsIndexColumn ), aPreset.Index() );
+
+ stream.OpenLC( view, columns->ColNo( KPSPresetsDataColumn ) );
+ stream.WriteL( aPreset.Data() );
+ stream.CommitL();
+ CleanupStack::PopAndDestroy( &stream );
+
+ view.PutL();
+
+ TUid uid = TUid::Uid( view.ColInt32( columns->ColNo( KPSPresetsDataHandlerColumn ) ) );
+
+ CleanupStack::PopAndDestroy( columns );
+
+ iObserver.HandlePresetChangedL( aPreset.Id(), uid, MPSPresetObserver::EPSModified );
+ }
+
+ CleanupStack::PopAndDestroy( &view );
+
+ PS_PRINT_DATABASE;
+ }
+
+// ---------------------------------------------------------------------------
+// Moves a preset to the supplied index.
+// ---------------------------------------------------------------------------
+//
+void RPSDatabase::MovePresetL( TInt aId, TInt aDestinationIndex )
+ {
+ PS_PRINT_DATABASE;
+
+ if ( aDestinationIndex < 0 )
+ {
+ User::Leave( KErrArgument );
+ }
+
+ // First, fetch the index and data handler of the preset that is about to be moved.
+
+ _LIT( selectPreset, "SELECT %S, %S FROM %S WHERE %S = %d" );
+
+ HBufC* selectPresetBuf = HBufC::NewLC( selectPreset().Length() + KPSPresetsIndexColumn().Length() + KPSPresetsDataHandlerColumn().Length() +
+ KPSPresetsTable().Length() + KPSPresetsIdColumn().Length() + KDefaultRealWidth );
+
+ selectPresetBuf->Des().Format( selectPreset, &KPSPresetsIndexColumn, &KPSPresetsDataHandlerColumn, &KPSPresetsTable, &KPSPresetsIdColumn, aId );
+
+ RDbView view;
+ User::LeaveIfError( view.Prepare( *this, *selectPresetBuf, RDbView::EReadOnly ) );
+ CleanupStack::PopAndDestroy( selectPresetBuf );
+ CleanupClosePushL( view );
+
+ if ( !view.FirstL() )
+ {
+ User::Leave( KErrNotFound );
+ }
+
+ view.GetL();
+ CDbColSet* columns = view.ColSetL();
+ TInt sourceIndex = view.ColInt32( columns->ColNo( KPSPresetsIndexColumn ) );
+ TUid dataHandler = TUid::Uid( view.ColInt32( columns->ColNo( KPSPresetsDataHandlerColumn ) ) );
+ delete columns;
+ CleanupStack::PopAndDestroy( &view );
+
+ TInt minIndex = Min( sourceIndex, aDestinationIndex );
+ TInt maxIndex = Max( sourceIndex, aDestinationIndex );
+
+ TBool direction = ( aDestinationIndex > sourceIndex ); // EFalse means that the preset is to be moved up, ETrue means that it is to be moved down.
+
+ _LIT( asc, "ASC" );
+ _LIT( desc, "DESC" );
+
+ TPtrC sortPtr( direction ? desc() : asc() );
+
+ // Selects all preset in between the source and destination indices.
+ _LIT( sql, "SELECT * FROM %S WHERE %S >= %d AND %S <= %d AND %S = %d ORDER BY %S %S" );
+
+ HBufC* sqlBuf = HBufC::NewLC( sql().Length() + KPSPresetsIndexColumn().Length() * 3 + KPSPresetsTable().Length() +
+ KPSPresetsDataHandlerColumn().Length() + sortPtr.Length() + KDefaultRealWidth * 3 );
+
+ sqlBuf->Des().Format( sql, &KPSPresetsTable, &KPSPresetsIndexColumn, minIndex, &KPSPresetsIndexColumn,
+ maxIndex, &KPSPresetsDataHandlerColumn, dataHandler.iUid, &KPSPresetsIndexColumn, &sortPtr );
+
+ User::LeaveIfError( view.Prepare( *this, *sqlBuf ) );
+ CleanupStack::PopAndDestroy( sqlBuf );
+ CleanupClosePushL( view );
+
+ User::LeaveIfError( view.EvaluateAll() );
+
+ TInt lastIndex = aDestinationIndex;
+
+ if ( view.LastL() ) // Handle the preset that is to be moved first.
+ {
+ view.GetL();
+ view.UpdateL();
+
+ columns = view.ColSetL();
+ CleanupStack::PushL( columns );
+
+ view.SetColL( columns->ColNo( KPSPresetsIndexColumn ), aDestinationIndex );
+ view.PutL();
+
+ iObserver.HandlePresetChangedL( view.ColInt32( columns->ColNo( KPSPresetsIdColumn ) ),
+ TUid::Uid( view.ColInt32( columns->ColNo( KPSPresetsDataHandlerColumn ) ) ),
+ MPSPresetObserver::EPSModified );
+
+ view.FirstL(); // Start iterating the presets from the beginning (the last element is always the preset that is to be moved).
+
+ for ( TInt i = 0; i < view.CountL() - 1; i++ ) // The preset that was moved has already been handled.
+ {
+ view.GetL();
+ view.UpdateL();
+
+ TInt index = view.ColInt32( columns->ColNo( KPSPresetsIndexColumn ) );
+
+ if ( lastIndex != index )
+ {
+ // If there was no preset with the index that the previous preset was moved to, there's no need to continue.
+ /*lint -save -e960 (Note -- Violates MISRA Required Rule 58, non-switch break used)*/
+ break;
+ /*lint -restore*/
+ }
+ else
+ {
+ // Preset was moved on top of another preset, continue iterating through the presets.
+ index += direction ? -1 : 1; // If moving up, all preset indices are incremented by one, otherwise they are decremented by one.
+ lastIndex = index;
+ view.SetColL( columns->ColNo( KPSPresetsIndexColumn ), index );
+ view.PutL();
+
+ iObserver.HandlePresetChangedL( view.ColInt32( columns->ColNo( KPSPresetsIdColumn ) ),
+ TUid::Uid( view.ColInt32( columns->ColNo( KPSPresetsDataHandlerColumn ) ) ),
+ MPSPresetObserver::EPSModified );
+ }
+
+ view.NextL();
+ }
+
+ CleanupStack::PopAndDestroy( columns );
+ }
+
+ CleanupStack::PopAndDestroy( &view );
+
+ PS_PRINT_DATABASE;
+ }
+
+// ---------------------------------------------------------------------------
+// Returns the name of a preset.
+// ---------------------------------------------------------------------------
+//
+HBufC* RPSDatabase::PresetNameL( TInt aId )
+ {
+ _LIT( sql, "SELECT %S FROM %S WHERE %S = %d" );
+
+ HBufC* sqlBuf = HBufC::NewLC( sql().Length() + KPSPresetsNameColumn().Length() + KPSPresetsTable().Length() +
+ KPSPresetsIdColumn().Length() + KDefaultRealWidth );
+
+ sqlBuf->Des().Format( sql, &KPSPresetsNameColumn, &KPSPresetsTable, &KPSPresetsIdColumn, aId );
+
+ RDbView view;
+ User::LeaveIfError( view.Prepare( *this, *sqlBuf, RDbView::EReadOnly ) );
+ CleanupStack::PopAndDestroy( sqlBuf );
+ CleanupClosePushL( view );
+
+ TInt nameLength = PresetNameLengthL( aId );
+ HBufC* name = HBufC::NewLC( nameLength );
+
+ if ( view.FirstL() )
+ {
+
+ view.GetL();
+ CDbColSet* columns = view.ColSetL();
+ TInt nameColumn = columns->ColNo( KPSPresetsNameColumn );
+ delete columns;
+
+ RDbColReadStream stream;
+ TPtr namePtr = name->Des();
+ stream.OpenLC( view, nameColumn );
+ stream.ReadL( namePtr, nameLength );
+ CleanupStack::PopAndDestroy( &stream);
+ }
+ else
+ {
+ User::Leave( KErrNotFound );
+ }
+
+ CleanupStack::Pop( name );
+ CleanupStack::PopAndDestroy( &view );
+
+ return name;
+ }
+
+// ---------------------------------------------------------------------------
+// Returns the length of the name field for a preset.
+// ---------------------------------------------------------------------------
+//
+TInt RPSDatabase::PresetNameLengthL( TInt aId )
+ {
+ return ColumnLengthL( KPSPresetsNameColumn, aId );
+ }
+
+// ---------------------------------------------------------------------------
+// Returns the index of a preset.
+// ---------------------------------------------------------------------------
+//
+TInt RPSDatabase::PresetIndexL( TInt aId )
+ {
+ _LIT( sql, "SELECT %S FROM %S WHERE %S = %d" );
+
+ HBufC* sqlBuf = HBufC::NewLC( sql().Length() + KPSPresetsIndexColumn().Length() + KPSPresetsTable().Length() +
+ KPSPresetsIdColumn().Length() + KDefaultRealWidth );
+
+ sqlBuf->Des().Format( sql, &KPSPresetsIndexColumn, &KPSPresetsTable, &KPSPresetsIdColumn, aId );
+
+ RDbView view;
+ User::LeaveIfError( view.Prepare( *this, *sqlBuf, RDbView::EReadOnly ) );
+ CleanupStack::PopAndDestroy( sqlBuf );
+ CleanupClosePushL( view );
+
+ TInt index = KErrNotFound;
+
+ if ( view.FirstL() )
+ {
+ view.GetL();
+ CDbColSet* columns = view.ColSetL();
+ index = view.ColInt32( columns->ColNo( KPSPresetsIndexColumn ) );
+ delete columns;
+ }
+ else
+ {
+ User::Leave( KErrNotFound );
+ }
+
+ CleanupStack::PopAndDestroy( &view );
+
+ return index;
+ }
+
+// ---------------------------------------------------------------------------
+// Returns the data handler of a preset.
+// ---------------------------------------------------------------------------
+//
+TUid RPSDatabase::PresetDataHandlerL( TInt aId )
+ {
+ _LIT( sql, "SELECT %S FROM %S WHERE %S = %d" );
+
+ HBufC* sqlBuf = HBufC::NewLC( sql().Length() + KPSPresetsDataHandlerColumn().Length() + KPSPresetsTable().Length() +
+ KPSPresetsIdColumn().Length() + KDefaultRealWidth );
+
+ sqlBuf->Des().Format( sql, &KPSPresetsDataHandlerColumn, &KPSPresetsTable, &KPSPresetsIdColumn, aId );
+
+ RDbView view;
+ User::LeaveIfError( view.Prepare( *this, *sqlBuf, RDbView::EReadOnly ) );
+ CleanupStack::PopAndDestroy( sqlBuf );
+ CleanupClosePushL( view );
+
+ TUid dataHandler = KNullUid;
+
+ if ( view.FirstL() )
+ {
+ view.GetL();
+ CDbColSet* columns = view.ColSetL();
+ dataHandler.iUid = view.ColInt32( columns->ColNo( KPSPresetsDataHandlerColumn ) );
+ delete columns;
+ }
+ else
+ {
+ User::Leave( KErrNotFound );
+ }
+
+ CleanupStack::PopAndDestroy( &view );
+
+ return dataHandler;
+ }
+
+// ---------------------------------------------------------------------------
+// Returns the binary data of a preset.
+// ---------------------------------------------------------------------------
+//
+HBufC8* RPSDatabase::PresetDataL( TInt aId )
+ {
+ _LIT( sql, "SELECT %S FROM %S WHERE %S = %d" );
+
+ HBufC* sqlBuf = HBufC::NewLC( sql().Length() + KPSPresetsDataColumn().Length() + KPSPresetsTable().Length() +
+ KPSPresetsIdColumn().Length() + KDefaultRealWidth );
+
+ sqlBuf->Des().Format( sql, &KPSPresetsDataColumn, &KPSPresetsTable, &KPSPresetsIdColumn, aId );
+
+ RDbView view;
+ User::LeaveIfError( view.Prepare( *this, *sqlBuf, RDbView::EReadOnly ) );
+ CleanupStack::PopAndDestroy( sqlBuf );
+ CleanupClosePushL( view );
+
+ HBufC8* data = NULL;
+
+ if ( view.FirstL() )
+ {
+ view.GetL();
+ CDbColSet* columns = view.ColSetL();
+ TInt columnNo = columns->ColNo( KPSPresetsDataColumn );
+ delete columns;
+
+ data = HBufC8::NewLC( view.ColLength( columnNo ) );
+ TPtr8 ptr( data->Des() );
+
+ RDbColReadStream stream;
+ stream.OpenLC( view, columnNo );
+ stream.ReadL( ptr, view.ColLength( columnNo ) );
+ CleanupStack::PopAndDestroy( &stream );
+ CleanupStack::Pop( data );
+ }
+ else
+ {
+ User::Leave( KErrNotFound );
+ }
+
+ CleanupStack::PopAndDestroy( &view );
+
+ return data;
+ }
+
+// ---------------------------------------------------------------------------
+// Returns the length of the binary data of a preset.
+// ---------------------------------------------------------------------------
+//
+TInt RPSDatabase::PresetDataLengthL( TInt aId )
+ {
+ return ColumnLengthL( KPSPresetsDataColumn, aId );
+ }
+
+// ---------------------------------------------------------------------------
+// Returns the current database version number.
+// ---------------------------------------------------------------------------
+//
+TInt RPSDatabase::CurrentDatabaseVersionL()
+ {
+ TInt version = 0;
+
+ RDbTable table;
+ TInt err = table.Open( *this, KPSVersionsTable, RDbTable::EReadOnly );
+
+ if ( err != KErrNotFound )
+ {
+ User::LeaveIfError( err );
+
+ CleanupClosePushL( table );
+
+ if ( table.FirstL() )
+ {
+ table.GetL();
+
+ CDbColSet* columns = table.ColSetL();
+ version = table.ColInt32( columns->ColNo( KPSVersionsVersionColumn ) );
+ delete columns;
+ }
+
+ CleanupStack::PopAndDestroy( &table );
+ }
+
+ return version;
+ }
+
+// ---------------------------------------------------------------------------
+// Updates the database version number.
+// ---------------------------------------------------------------------------
+//
+void RPSDatabase::UpdateDatabaseVersionL( TInt aVersion )
+ {
+ RDbTable table;
+ User::LeaveIfError( table.Open( *this, KPSVersionsTable ) );
+ CleanupClosePushL( table );
+
+ CDbColSet* columns = table.ColSetL();
+ CleanupStack::PushL( columns );
+
+ table.Reset();
+ table.FirstL() ? table.UpdateL() : table.InsertL(); // If a row exists open it for update, otherwise create a new one.
+ table.SetColL( columns->ColNo( KPSVersionsVersionColumn ), aVersion );
+ table.PutL();
+
+ CleanupStack::PopAndDestroy( 2, &table );
+ }
+
+// ---------------------------------------------------------------------------
+// Updates the whole database to the latest version.
+// ---------------------------------------------------------------------------
+//
+void RPSDatabase::UpdateDatabaseL()
+ {
+ TInt currentVersion = CurrentDatabaseVersionL();
+
+ if ( currentVersion < KPSDatabaseVersion )
+ {
+ for ( TInt i = currentVersion; i < KPSDatabaseVersion; i++ )
+ {
+ ((*this).*iDatabaseUpdateFunctions[i])(); // All of these function calls can leave.
+ }
+ }
+ }
+
+// ---------------------------------------------------------------------------
+// Creates the tables.
+// ---------------------------------------------------------------------------
+//
+void RPSDatabase::CreateTablesL()
+ {
+ // Creates the preset table.
+ TDbCol presetsIdColumn( KPSPresetsIdColumn, EDbColInt32 );
+ presetsIdColumn.iAttributes = TDbCol::EAutoIncrement;
+
+ CDbColSet* columns = CDbColSet::NewLC();
+ columns->AddL( presetsIdColumn );
+ columns->AddL( TDbCol( KPSPresetsNameColumn, EDbColLongText ) );
+ columns->AddL( TDbCol( KPSPresetsIndexColumn, EDbColInt32 ) );
+ columns->AddL( TDbCol( KPSPresetsDataHandlerColumn, EDbColInt32 ) );
+ columns->AddL( TDbCol( KPSPresetsDataColumn, EDbColLongText8 ) );
+
+ User::LeaveIfError( CreateTable( KPSPresetsTable, *columns ) );
+
+ CleanupStack::PopAndDestroy( columns );
+
+ // This is a hack to circumvent problems with Publish & Subscribe, as it initializes all data properties to zero,
+ // causing a notification to fire with the value of zero. This is the reason why most users of the API have defined
+ // zero to be the uninitialized state of the property. The problem caused by this is that the DBMS API's auto increment
+ // field starts from zero, and should there exist a preset with such an ID, it could not be properly conveyed to the
+ // interested parties. Thus, we will make a dummy preset now that the preset table is created and remove it instantly,
+ // thereby making the auto increment column to start from one instead of zero.
+
+ _LIT( selectAll, "SELECT * FROM %S" );
+
+ HBufC* sqlBuf = HBufC::NewLC( selectAll().Length() + KPSPresetsTable().Length() );
+ sqlBuf->Des().Format( selectAll, &KPSPresetsTable );
+
+ RDbView view;
+ User::LeaveIfError( view.Prepare( *this, *sqlBuf ) );
+ CleanupStack::PopAndDestroy( sqlBuf );
+ CleanupClosePushL( view );
+ User::LeaveIfError( view.EvaluateAll() );
+
+ view.FirstL();
+ view.InsertL();
+ view.PutL();
+ view.DeleteL();
+
+ CleanupStack::PopAndDestroy( &view );
+
+ // Creates the version table.
+ columns = CDbColSet::NewLC();
+ columns->AddL( TDbCol( KPSVersionsVersionColumn, EDbColInt32 ) );
+
+ User::LeaveIfError( CreateTable( KPSVersionsTable, *columns ) );
+
+ CleanupStack::PopAndDestroy( columns );
+
+ UpdateDatabaseVersionL( KPSDatabaseVersion1 ); // Version 1 of the database successfully created.
+ }
+
+// ---------------------------------------------------------------------------
+// Returns the length of a column.
+// ---------------------------------------------------------------------------
+//
+TInt RPSDatabase::ColumnLengthL( const TDesC& aColumn, TInt aId )
+ {
+ _LIT( sql, "SELECT %S FROM %S WHERE %S = %d" );
+
+ TInt length = KErrNotFound;
+
+ HBufC* sqlBuf = HBufC::NewLC( sql().Length() + aColumn.Length() + KPSPresetsTable().Length() + KPSPresetsIdColumn().Length() + KDefaultRealWidth );
+ sqlBuf->Des().Format( sql, &aColumn, &KPSPresetsTable, &KPSPresetsIdColumn, aId );
+
+ RDbView view;
+ User::LeaveIfError( view.Prepare( *this, *sqlBuf, RDbView::EReadOnly ) );
+ CleanupStack::PopAndDestroy( sqlBuf );
+ CleanupClosePushL( view );
+
+ if ( view.FirstL() )
+ {
+ view.GetL();
+ CDbColSet* columns = view.ColSetL();
+ length = view.ColLength( columns->ColNo( aColumn ) );
+ delete columns;
+ }
+ else
+ {
+ User::Leave( KErrNotFound );
+ }
+
+ CleanupStack::PopAndDestroy( &view );
+
+ return length;
+ }
+
+// ---------------------------------------------------------------------------
+// Debug method that prints the contents of the database.
+// ---------------------------------------------------------------------------
+//
+void RPSDatabase::PrintDatabaseL()
+ {
+ PSDEBUG( "RPSDatabase::PrintDatabaseL() - Versions:" );
+
+ RDbTable table;
+ TInt err = table.Open( *this, KPSVersionsTable, RDbTable::EReadOnly );
+
+ if ( err == KErrNotFound )
+ {
+ PSDEBUG( "\tYarr, thar database be not in this world, mate!" );
+ }
+ else
+ {
+ User::LeaveIfError( err );
+
+ CleanupClosePushL( table );
+
+ if ( table.FirstL() )
+ {
+ CDbColSet* columns = table.ColSetL();
+ TInt versionColumn = columns->ColNo( KPSVersionsVersionColumn );
+ delete columns;
+
+ do
+ {
+ table.GetL();
+ PSDEBUG2( "\t%d", table.ColInt32( versionColumn ) );
+ } while ( table.NextL() );
+ }
+ else
+ {
+ PSDEBUG( "\tYarr, thar table be empty!" );
+ }
+
+ CleanupStack::PopAndDestroy( &table );
+ }
+
+ PSDEBUG( "RPSDatabase::PrintDatabaseL() - Presets:" );
+
+ err = table.Open( *this, KPSPresetsTable, RDbTable::EReadOnly );
+
+ if ( err == KErrNotFound )
+ {
+ PSDEBUG( "\tYarr, thar database be not in this world, mate!" );
+ }
+ else
+ {
+ User::LeaveIfError( err );
+
+ CleanupClosePushL( table );
+
+ if ( table.FirstL() )
+ {
+ CDbColSet* columns = table.ColSetL();
+ TInt idColumn = columns->ColNo( KPSPresetsIdColumn );
+ TInt dataHandlerColumn = columns->ColNo( KPSPresetsDataHandlerColumn );
+ TInt indexColumn = columns->ColNo( KPSPresetsIndexColumn );
+ TInt nameColumn = columns->ColNo( KPSPresetsNameColumn );
+ delete columns;
+
+ do
+ {
+ table.GetL();
+ // stream is needed for long columns
+ RDbColReadStream stream;
+ TInt nameLength = PresetNameLengthL( table.ColInt32( idColumn ) );
+ HBufC* name = HBufC::NewLC( nameLength );
+ TPtr namePtr = name->Des();
+ stream.OpenLC( table, nameColumn );
+ stream.ReadL( namePtr, nameLength );
+
+ CleanupStack::PopAndDestroy( &stream );
+
+ PSDEBUG5( "\tId: %10u\tData Handler: 0x%x\tIndex: %10u\tName: %S", table.ColInt32( idColumn ), table.ColInt32( dataHandlerColumn ), table.ColInt32( indexColumn ), name );
+
+ CleanupStack::PopAndDestroy( name );
+ } while ( table.NextL() );
+ }
+ else
+ {
+ PSDEBUG( "\tYarr, thar table be empty!" );
+ }
+
+ CleanupStack::PopAndDestroy( &table );
+ }
+ }
+
+// ======== GLOBAL FUNCTIONS ========