diff -r cad71a31b7fc -r e36f3802f733 srsf/nssvasapi/nssvasdb/src/nssvascvasdb.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/srsf/nssvasapi/nssvasdb/src/nssvascvasdb.cpp Wed Sep 01 12:29:17 2010 +0100 @@ -0,0 +1,2810 @@ +/* +* 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: Implementation of VAS database handling +* +*/ + + +#include "nssvascvasdb.h" +#include +#include +#include +#include "rubydebug.h" +#include "nssvascoreconstant.h" +#include "nssvascrrd.h" + +#include "nssvasbackupobserver.h" + +// CONSTANTS + +// Name of the DB lock mutex +_LIT( KLockMutex, "VASDATABASE" ); + +#ifdef _DEBUG +// used in UDEB macros only +_LIT( KVasDbPanic, "VasCNssVasDb.cpp"); +#endif // _UDEB + +// Maximum size of tag array +static const TInt KMaxTagArraySize = 50; + +const TInt KContextListGranularity = 5; + +const TInt KSqlStatementmaxLength = 120; + +// MACROS + +// Complementary macro for TRAPD +#define REACT( err, codeblock ) if ( err != KErrNone ) { codeblock; } + +// ============================ Methods =============================== + +// ----------------------------------------------------------------------------- +// CNssVasDb::NewL +// 2-level constructor +// ----------------------------------------------------------------------------- +// +CNssVasDb* CNssVasDb::NewL( CNssContextBuilder& contextBuilder, + CNssSpeechItemBuilder& speechItemBuilder ) + { + RUBY_DEBUG_BLOCK( "CNssVasDb::NewL" ); + + CNssVasDb* self = new(ELeave) CNssVasDb( contextBuilder, + speechItemBuilder ); + CleanupStack::PushL( self ); + self->ConstructL(); + CleanupStack::Pop( self ); + + return self; + } + +// ----------------------------------------------------------------------------- +// CNssVasDb::~CNssVasDb +// Standard C++ destructor +// ----------------------------------------------------------------------------- +// +CNssVasDb::~CNssVasDb() + { + RUBY_DEBUG0( "CNssVasDb::~CNssVasDb" ); + + if ( iLocked ) + { + RUBY_DEBUG0( "Signalling mutex in CNssVasDb::~CNssVasDb" ); + iMutex.Signal(); + } + else + { + RUBY_DEBUG0( "NOT signalling mutex in CNssVasDb::~CNssVasDb iLocked = EFalse" ); + } + + if ( iClientHasOpenedDatabase ) + { + CloseDatabase(); + } + + iMutex.Close(); + delete iBackupObserver; + iCriticalSection.Close(); + RUBY_DEBUG0( "CNssVasDb::~CNssVasDb Mutex handle closed" ); + } + + +// ----------------------------------------------------------------------------- +// CNssVasDb::CNssVasDb +// Standard C++ contructor +// ----------------------------------------------------------------------------- +// +CNssVasDb::CNssVasDb( CNssContextBuilder& aContextBuilder, + CNssSpeechItemBuilder& aSpeechItemBuilder ) +: iClientHasOpenedDatabase( EFalse ), + iLocked( EFalse ), + iContextBuilder( aContextBuilder ), + iSpeechItemBuilder( aSpeechItemBuilder ) + { + // empty + } + +// ----------------------------------------------------------------------------- +// CNssVasDb::ConstructL +// Symbian second constructor. +// ----------------------------------------------------------------------------- +// +void CNssVasDb::ConstructL() + { + TInt err = iMutex.OpenGlobal( KLockMutex ); + if ( err != KErrNone ) + { + RUBY_DEBUG0( "CNssVasDb::ConstructL Creating new global mutex" ); + iMutex.CreateGlobal( KLockMutex ); + } + else + { + RUBY_DEBUG0( "CNssVasDb::ConstructL Using existing global mutex" ); + } + iCriticalSection.CreateLocal(); + iBackupObserver = CNssVasBackupObserver::NewL( *this ); + } + +// ----------------------------------------------------------------------------- +// CNssVasDb::RollbackCleanupFunction +// This function is used to form iRollbackCleanupItem. When this item is +// popped from the cleanup stack, it makes a rollback on VAS DB. +// ----------------------------------------------------------------------------- +// +void CNssVasDb::RollbackCleanupFunction( TAny* aArg ) + { + RUBY_DEBUG0( "CNssVasDb::RollbackCleanupFunction" ); + + CNssVasDb* me = (CNssVasDb*)aArg; + + me->RollbackTransaction(); + } + +// ----------------------------------------------------------------------------- +// CNssVasDb::CreateDatabaseL +// Creates a new database. +// from a resource file. +// ----------------------------------------------------------------------------- +// +void CNssVasDb::CreateDatabaseL() + { + User::LeaveIfError( iDbSession.Connect() ); + CleanupClosePushL( iDbSession ); + iDbcreator.CreateVasDatabaseL( iDbSession ); + CleanupStack::PopAndDestroy( &iDbSession ); + } + +// ----------------------------------------------------------------------------- +// CNssVasDb::OpenDatabaseL +// Opens the database. Reads the path and file name of the database +// from a resource file. +// ----------------------------------------------------------------------------- +// +void CNssVasDb::OpenDatabaseL() + { + RUBY_DEBUG_BLOCK( "CNssVasDb::OpenDatabaseL" ); + + if ( !iClientHasOpenedDatabase ) + { + RFs fs; + User::LeaveIfError( fs.Connect() ); + CleanupClosePushL ( fs ); // Stack: file session + + // Open the database + User::LeaveIfError( iDbSession.Connect() ); + + User::LeaveIfError( iDatabase.Open( iDbSession, + KVasDatabaseName, KVasDatabaseFormatString ) ); + User::LeaveIfError( fs.CharToDrive( KVasDatabaseDrive, iDrive ) ); + + if ( iDatabase.IsDamaged() ) + { + RUBY_DEBUG0( "CNssVasDb::OpenDatabaseL Recovering" ); + User::LeaveIfError( iDatabase.Recover() ); + } + + CleanupStack::PopAndDestroy( &fs ); + + iClientHasOpenedDatabase = ETrue; + } + } + +// ----------------------------------------------------------------------------- +// CNssVasDb::CloseDatabase +// Closes the database. +// ----------------------------------------------------------------------------- +// +TInt CNssVasDb::CloseDatabase() + { + RUBY_DEBUG0( "CNssVasDb::CloseDatabase" ); + + iDatabase.Close(); + iDbSession.Close(); + iClientHasOpenedDatabase = EFalse; + + return KErrNone; + } + +// ----------------------------------------------------------------------------- +// CNssVasDb::GetModelBankIdLexiconIdL +// Returns the model bank ID and the lexicon ID. +// ----------------------------------------------------------------------------- +// +TBool CNssVasDb::GetModelBankIdLexiconIdL( TUint32& aModelBankId, TUint32& aLexiconId ) + { + TBool ret = EFalse; + RDbView view; + + _LIT( KSQLGetModelBankLexicon, "select modelbankid,lexiconid from contexttable" ); + + User::LeaveIfError( StartTransaction() ); + CreatePushRollbackItemLC(); + + CleanupClosePushL( view ); + + User::LeaveIfError( view.Prepare( iDatabase, TDbQuery( + KSQLGetModelBankLexicon, EDbCompareNormal ) ) ); + User::LeaveIfError( view.EvaluateAll() ); + + // There is no ModelbankId or LexiconId + if ( view.IsEmptyL() ) + { + User::Leave( KErrNotFound ); + } + // There is a ModelBankId and a LexiconId + ret = ETrue; + view.FirstL(); + view.GetL(); + + // Get column set + CDbColSet* columns = view.ColSetL(); + // Get column ordinals + TDbColNo modelbankid_col = columns->ColNo( KModelBankIdCol ); + TDbColNo lexiconid_col = columns->ColNo( KLexiconIdCol ); + // Cleanup column set + delete columns; + + aModelBankId = view.ColUint32( modelbankid_col ); + aLexiconId = view.ColUint32( lexiconid_col ); + + // Close view + CleanupStack::PopAndDestroy( &view ); + + // Release lock + CleanupStack::Pop(); // Rollback cleanup item + CommitTransaction( EFalse ); + + return ret; + } + + +// ----------------------------------------------------------------------------- +// CNssVasDb::TagExistsL +// Checks if a context is empty. +// ----------------------------------------------------------------------------- +// +TBool CNssVasDb::TagExistL( TInt aContextId ) + { + RUBY_DEBUG_BLOCK( "CNssVasDb::TagExistL" ); + + TBool ret( EFalse ); + RDbView view; + + CleanupClosePushL(view); + + _LIT( KSQLGetTags, "select * from tagtable " ); + _LIT( KSQLWhereContextId, "where contextid=" ); + + iSQLStatement = KSQLGetTags; + iSQLStatement.Append( KSQLWhereContextId ); + iSQLStatement.AppendNumUC( aContextId ); + + User::LeaveIfError( view.Prepare( iDatabase, TDbQuery( iSQLStatement, EDbCompareNormal ) ) ); + User::LeaveIfError( view.EvaluateAll() ); + + if ( view.IsEmptyL() ) + { + ret = EFalse; + } + else + { + ret = ETrue; + } + + // Close view + CleanupStack::PopAndDestroy( &view ); + + return ret; + } + +// ----------------------------------------------------------------------------- +// CNssVasDb::TagCountL +// Returns the number of tags. +// ----------------------------------------------------------------------------- +// +TInt CNssVasDb::TagCountL( TInt aContextId ) + { + RUBY_DEBUG_BLOCK( "CNssVasDb::TagCountL" ); + + RDbView view; + TInt numberOfTags = 0; + + CleanupClosePushL( view ); + + _LIT( KSQLGetTags, "select * from tagtable " ); + _LIT( KSQLWhereContextId, "where contextid=" ); + + iSQLStatement = KSQLGetTags; + iSQLStatement.Append( KSQLWhereContextId ); + iSQLStatement.AppendNumUC( aContextId ); + + User::LeaveIfError( view.Prepare( iDatabase, TDbQuery( iSQLStatement, EDbCompareNormal ) ) ); + User::LeaveIfError( view.EvaluateAll() ); + + numberOfTags = view.CountL(); + + view.Close(); + CleanupStack::PopAndDestroy( &view ); + + return numberOfTags; + } + +// ----------------------------------------------------------------------------- +// CNssVasDb::CommitIfSuccess +// Commits or rolls back accoring to success parameter. +// ----------------------------------------------------------------------------- +// +void CNssVasDb::CommitIfSuccess( RDbDatabase /*aDatabase*/, TInt aSuccess, TBool aCompactIfCommit ) + { + if ( aSuccess >= 0 ) + { + CommitTransaction( aCompactIfCommit ); + } + else + { + // Otherwise, roll back the transaction and release the lock. + RollbackTransaction(); + } + } + +// ----------------------------------------------------------------------------- +// CNssVasDb::SaveContextL +// Saves a newly created context. The Context ID is assigned and returned +// using the reference parameter. +// ----------------------------------------------------------------------------- +// +void CNssVasDb::SaveContextL( CNssContext& aContext, TInt& aContextId ) + { + RUBY_DEBUG_BLOCK( "CNssVasDb::SaveContextL" ); + + if ( !iClientHasOpenedDatabase ) + { + RUBY_DEBUG0( "CNssVasDb error: database not opened." ); + + User::Leave( KErrNotReady ); + } + + // Locks the database for the use of this process only + TInt error = StartTransaction(); + + if ( error != KErrNone ) + { + RUBY_DEBUG0( "CNssVasDb error: could not lock database." ); + + User::Leave( KErrGeneral ); + } + + TRAP( error, SaveContextL( &aContext, aContextId ) ); + REACT( error, RUBY_DEBUG0( "Context saving failed" ) ); + + if ( error == KErrNone ) + { + TRAP ( error, DoUpdateContextClientDataL( aContext ) ); + } + + CommitIfSuccess( iDatabase, error, ETrue ); + + User::LeaveIfError( error ); + } + +// ----------------------------------------------------------------------------- +// CNssVasDb::UpdateContextL +// Updates the context to VAS DB. +// ----------------------------------------------------------------------------- +// +void CNssVasDb::UpdateContextL( CNssContext& aContext ) + { + RUBY_DEBUG_BLOCK( "CNssVasDb::UpdateContextL" ); + + if ( !iClientHasOpenedDatabase ) + { + RUBY_DEBUG0( "CNssVasDb error: database not opened." ); + + User::Leave( KErrNotReady ); + } + + TInt error = StartTransaction(); + + if ( error != KErrNone ) + { + RUBY_DEBUG0( "CNssVasDb error: could not lock database." ); + + User::Leave( KErrGeneral ); + } + + TRAP( error, DoUpdateContextL( aContext ) ); + REACT( error, RUBY_DEBUG0( "Context updating failed" ) ); + + CommitIfSuccess( iDatabase, error, ETrue ); + + User::LeaveIfError( error ); + } + +// ----------------------------------------------------------------------------- +// CNssVasDb::UpdateContextInsideTransactionL +// Updates the context to VAS DB. +// ----------------------------------------------------------------------------- +// +void CNssVasDb::UpdateContextInsideTransactionL( CNssContext& aContext ) + { + RUBY_DEBUG_BLOCK( "CNssVasDb::UpdateContextInsideTransactionL" ); + + if ( !iClientHasOpenedDatabase ) + { + RUBY_DEBUG0( "CNssVasDb error: database not opened." ); + + User::Leave( KErrNotReady ); + } + + DoUpdateContextL( aContext ); + } + +// ----------------------------------------------------------------------------- +// CNssVasDb::UpdateContextClientDataL +// Updates the client data of the context. +// ----------------------------------------------------------------------------- +// +void CNssVasDb::UpdateContextClientDataL( CNssContext& aContext ) + { + RUBY_DEBUG_BLOCK( "CNssVasDb::UpdateContextClientDataL" ); + + if ( !iClientHasOpenedDatabase ) + { + RUBY_DEBUG0( "CNssVasDb error: database not opened." ); + + User::Leave( KErrNotReady ); + } + + TInt error = StartTransaction(); + + if ( error != KErrNone ) + { + RUBY_DEBUG0( "CNssVasDb error: could not lock database." ); + + User::Leave( KErrGeneral ); + } + + TRAP( error, DoUpdateContextClientDataL( aContext ) ); + + CommitIfSuccess( iDatabase, error, ETrue ); + + User::LeaveIfError( error ); + } + +// ----------------------------------------------------------------------------- +// CNssVasDb::GetDefaultModelBankIdL +// Usually, all contexts use the same Model Bank. This function +// returns the first model bank ID it finds. +// ----------------------------------------------------------------------------- +// +void CNssVasDb::GetDefaultModelBankIdL( TUint32& aId ) + { + RUBY_DEBUG_BLOCK( "CNssVasDb::GetDefaultModelBankIdL" ); + + _LIT( KSQLGetAll,"select modelbankid from contexttable"); + + iSQLStatement = KSQLGetAll; + + if ( !iClientHasOpenedDatabase ) + { + User::Leave( KErrDbNotSet ); + } + + StartTransaction(); + CreatePushRollbackItemLC(); + + RDbView view; + + CleanupClosePushL(view); + + User::LeaveIfError( view.Prepare( iDatabase, TDbQuery( iSQLStatement, EDbCompareNormal ) ) ); + User::LeaveIfError( view.EvaluateAll() ); + + if ( view.IsEmptyL() ) + { + User::Leave( KErrNotFound ); + } + + // Get column set + CDbColSet* columns = view.ColSetL(); + // Get model bank id column ordinal + TDbColNo modelbankid_col= columns->ColNo( KModelBankIdCol ); + delete columns; + + view.FirstL(); + view.GetL(); // Retrieve the current row - actually reads the row from the database. + + aId = view.ColUint32( modelbankid_col ); + + CleanupStack::PopAndDestroy( &view );// close view + + // Rollback cleanup + CleanupStack::Pop(); // Rollback cleanup item + CommitTransaction( EFalse ); + } + +// ----------------------------------------------------------------------------- +// CNssVasDb::ResetModelBankL +// Usually, all contexts use the same Model Bank. When the model bank is reseted, +// (=speaker independent models are resotred and speaker adaptation is destroyed) +// the model bank ID changes for all contexts. +// ----------------------------------------------------------------------------- +// +void CNssVasDb::ResetModelBankL( TUint32 aNewId ) + { + RUBY_DEBUG_BLOCK( "CNssVasDb::ResetModelBankL" ); + + _LIT( KSQLUpdateModelbank,"update contexttable set modelbankid="); + + iSQLStatement = KSQLUpdateModelbank; + iSQLStatement.AppendNumUC( aNewId ); + + + if ( !iClientHasOpenedDatabase ) + { + User::Leave( KErrDbNotSet ); + } + + StartTransaction(); + CreatePushRollbackItemLC(); + + User::LeaveIfError( iDatabase.Execute( iSQLStatement ) ); + + CleanupStack::Pop(); // Rollback cleanup item + + User::LeaveIfError( CommitTransaction( ETrue ) ); + } + +// ----------------------------------------------------------------------------- +// CNssVasDb::GetContextByNameL +// Reads a context from VAS DB by name. +// ----------------------------------------------------------------------------- +// +CArrayPtrFlat* CNssVasDb::GetContextByNameL(const TDesC& aName) + { + RUBY_DEBUG_BLOCK("CNssVasDb::GetContextByNameL"); + + _LIT( KSQLGetAll,"select * from contexttable "); + _LIT( KSQLWhereName,"where name='"); + _LIT( KTick,"' "); + + iSQLStatement = KSQLGetAll; + iSQLStatement.Append( KSQLWhereName ); + iSQLStatement.Append( aName ); + iSQLStatement.Append( KTick ); + + return GetContextL( iSQLStatement ); + } + +// ----------------------------------------------------------------------------- +// CNssVasDb::GetGlobalContexts +// Reads all global contexts from VAS DB. +// ----------------------------------------------------------------------------- +// +CArrayPtrFlat* CNssVasDb::GetGlobalContexts() + { + RUBY_DEBUG0("CNssVasDb::GetGlobalContexts"); + + _LIT( KSQLGetAll,"select * from contexttable "); + _LIT( KSQLWhereGlobal,"where global=1"); + + iSQLStatement = KSQLGetAll; + iSQLStatement.Append( KSQLWhereGlobal ); + + CArrayPtrFlat* ret( NULL ); + TRAPD( error, ret = GetContextL( iSQLStatement ) ); + if ( error != KErrNone ) + { + return NULL; + } + return ret; + } + +// ----------------------------------------------------------------------------- +// CNssVasDb::GetAllContexts +// Reads all contexts from VAS DB. +// ----------------------------------------------------------------------------- +// +CArrayPtrFlat* CNssVasDb::GetAllContexts() + { + RUBY_DEBUG0("CNssVasDb::GetAllContexts"); + + _LIT( KSQLGetAll,"select * from contexttable "); + + iSQLStatement = KSQLGetAll; + + CArrayPtrFlat* ret( NULL ); + TRAPD( error, ret = GetContextL( iSQLStatement ) ); + if ( error != KErrNone ) + { + return NULL; + } + return ret; + } + + +// ----------------------------------------------------------------------------- +// CNssVasDb::GetContextL +// Executes the SQL query. After the query has selected a list of contexts, +// these contexts are read from DB to memory. +// ----------------------------------------------------------------------------- +// +CArrayPtrFlat* CNssVasDb::GetContextL(const TDesC& aSQLStatement) + { + RUBY_DEBUG_BLOCK("CNssVasDb::GetContextL"); + + __ASSERT_DEBUG( aSQLStatement.Left( 6 ).Compare( _L("select") ) == 0, + User::Panic( KVasDbPanic, __LINE__ ) ); + + if ( !iClientHasOpenedDatabase ) + { + User::Leave( KErrDbNotSet ); + } + + TInt ret = StartTransaction(); + RUBY_DEBUG1("Started transaction. Error code [%d]", ret); + + CreatePushRollbackItemLC(); + CArrayPtrFlat* contextList = GetContextInsideTransactionL( aSQLStatement ); + + // Rollback cleanup (just to avoid automatic locking) + CleanupStack::Pop(); // Rollback cleanup item + CommitTransaction( EFalse ); + + return contextList; + } + +// ----------------------------------------------------------------------------- +// CNssVasDb::GetContextInsideTransaction +// Reads a context by name. Assumes that a transaction has already been started. +// ----------------------------------------------------------------------------- +// +CArrayPtrFlat* CNssVasDb::GetContextInsideTransactionL( const TDesC& aSQLStatement ) + { + RUBY_DEBUG_BLOCK("CNssVasDb::GetContextInsideTransactionL"); + RDbView view; + + CleanupClosePushL(view); + + User::LeaveIfError( view.Prepare( iDatabase, TDbQuery( aSQLStatement, EDbCompareNormal ) ) ); + RUBY_DEBUG0("CNssVasDb::GetContextInsideTransactionL Prepared query"); + User::LeaveIfError( view.EvaluateAll() ); + RUBY_DEBUG0("CNssVasDb::GetContextInsideTransactionL Evaluated query"); + + if ( view.IsEmptyL() ) + { + RUBY_DEBUG0("CNssVasDb::GetContextInsideTransactionL Empty view. Leaving with KErrNotFound"); + User::Leave( KErrNotFound ); + } + + CArrayPtrFlat* contextList = + new (ELeave) CArrayPtrFlat( KContextListGranularity ); + CleanupStack::PushL( contextList ); + CleanupResetAndDestroyPushL( *contextList ); + RUBY_DEBUG0("CNssVasDb::GetContextInsideTransactionL Before FillContextListArrayL"); + + FillContextListArrayL(view, *contextList); + + CleanupStack::Pop( contextList ); // ResetAndDestroy + CleanupStack::Pop( contextList ); // array itself + CleanupStack::PopAndDestroy( &view );// close view + + return( contextList ); + } + +// ----------------------------------------------------------------------------- +// CNssVasDb::GetTagReferenceList +// Fetches tag references for all tags in a context. +// ----------------------------------------------------------------------------- +// +TNssTagReferenceListArray* CNssVasDb::GetTagReferenceListL( TInt aContextId ) + { + RUBY_DEBUG_BLOCK( "CNssVasDb::GetTagReferenceListL" ); + + RDbView view; + TNssTagReference tagRef; + + TNssTagReferenceListArray* tagArray = + new (ELeave) TNssTagReferenceListArray( KMaxTagArraySize ); + CleanupStack::PushL( tagArray ); + + if ( !iClientHasOpenedDatabase ) + { + User::Leave( KErrDbNotSet ); + } + + // Start transaction - lock database + StartTransaction(); + CreatePushRollbackItemLC(); + + // Make a query, which lists all tags in the context. + // Making a CNssTagReferece only requires tagid and name. + _LIT( KSQLGetTag, "select tagid,name from tagtable where contextid=" ); + iSQLStatement = KSQLGetTag; + iSQLStatement.AppendNumUC( aContextId ); + + CleanupClosePushL(view); + + User::LeaveIfError( view.Prepare( iDatabase, TDbQuery( iSQLStatement, EDbCompareNormal ) ) ); + User::LeaveIfError( view.EvaluateAll() ); + + if ( view.IsEmptyL() ) + { + User::Leave( KErrNotFound ); + } + + // Get column set + CDbColSet* columns = view.ColSetL(); + // Get column ordinals + TDbColNo name_col = columns->ColNo( KNameCol ); + TDbColNo tagid_col = columns->ColNo( KTagIdCol ); + + delete columns; + + for( view.FirstL(); view.AtRow(); view.NextL() ) + { + view.GetL(); + tagRef.iTagName = view.ColDes( name_col ); + tagRef.iTagId = view.ColUint32( tagid_col ); + tagArray->AppendL( tagRef ); + } + + // Close view + CleanupStack::PopAndDestroy( &view ); + + // Finish transaction - release lock + CleanupStack::Pop(); // Rollback cleanup item + CommitTransaction( EFalse ); + + // Return result + CleanupStack::Pop( tagArray ); + + return( tagArray ); + } + +// ----------------------------------------------------------------------------- +// CNssVasDb::SaveTagL +// Saves a newly created tag. When a tag is saved, a Tag ID is assigned to it. +// This Tag ID is returned in the reference parameter. +// ----------------------------------------------------------------------------- +// +void CNssVasDb::SaveTagL( CNssTag& aTag, TInt& aNewId ) + { + if ( !iClientHasOpenedDatabase ) + { + RUBY_DEBUG0( "CNssVasDb error: database not opened." ); + + User::Leave( KErrNotReady ); + } + + // Locks the database for the use of this process only + + TInt error = StartTransaction(); + + if ( error != KErrNone ) + { + RUBY_DEBUG0( "CNssVasDb error: could not lock database." ); + + User::Leave( KErrGeneral ); + } + + TInt contextId; // Discard context ID + + CNssContext* context = static_cast ( aTag.Context() ); + TRAP( error, SaveContextL( context, contextId ) ); + + if ( error == KErrItemAlreadyExist || error == KErrNone ) + { + TRAP( error, SaveTagL( &aTag, aNewId ) ); + } + else + { + RollbackTransaction(); + User::Leave( error ); + } + + // Check SavetagL result + if ( error != KErrNone ) + { + RollbackTransaction(); + User::Leave( error ); + } + else + { + CNssRRD* rrd = static_cast( aTag.RRD() ); + rrd->SetTagId( aNewId ); + + TRAPD( error, SaveRRDL( rrd ) ); + REACT( error, RUBY_DEBUG0( "RRD saving failed." ) ); + + CommitIfSuccess( iDatabase, error, ETrue ); + } + + User::LeaveIfError( error ); + } + +// --------------------------------------------------------- +// CNssVasDb::SaveTagsL +// Saves several tags in one commit. +// --------------------------------------------------------- +// +void CNssVasDb::SaveTagsL( CArrayPtrFlat* aTagArray, RArray& aTagIdArray ) + { + CleanupClosePushL( aTagIdArray ); + + TInt k( 0 ); + TInt error( KErrNone ); + + if ( !iClientHasOpenedDatabase ) + { + User::Leave( KErrDbNotSet ); + } + + // Locks the database for the use of this process only + User::LeaveIfError( StartTransaction() ); + + CreatePushRollbackItemLC(); // Stack: rollback cleanup + + RArray contextIds; + CleanupClosePushL( contextIds ); // Stack: rollback cleanup, contextIds + + for ( k = 0; k < aTagArray->Count(); k++ ) + { + CNssTag* tag = (*aTagArray)[k]; + CNssContext* context = static_cast ( tag->Context() ); + + if ( contextIds.Find( context->ContextId() ) == KErrNotFound ) + { + TInt contextId; + TRAP( error, SaveContextL( context, contextId ) ); + + // We accept leaves with error KErrAlreadyExists + if ( error != KErrNone && error != KErrAlreadyExists ) + { + break; + } + + contextIds.Append( context->ContextId() ); + } + } + + // Close context id array + CleanupStack::PopAndDestroy( &contextIds ); // Stack: Rollback cleanup + + // We accept leaves with error KErrAlreadyExists + if ( error != KErrNone && error != KErrAlreadyExists ) + { + User::Leave( error ); + } + + TInt id; + for ( k = 0; k < aTagArray->Count(); k++ ) + { + CNssTag* tag = (*aTagArray)[k]; + + if ( tag->TagId() == KNssVASDbDefaultValue ) + { + SaveTagL( tag, id ); + + CNssRRD* rrd = static_cast( tag->RRD() ); + rrd->SetTagId( id ); + + SaveRRDL( rrd ); + User::LeaveIfError( aTagIdArray.Append( id ) ); + } + else{ + UpdateTagInTransactionL( *tag ); + User::LeaveIfError( aTagIdArray.Append( tag->TagId() ) ); + } + } + + User::LeaveIfError( CommitTransaction( ETrue ) ); + + // Pop rollback cleanup + // (which would have made database rollback, if a leave had happened) + CleanupStack::Pop(); // Rollback cleanup item + CleanupStack::Pop(); + } + +// --------------------------------------------------------- +// CNssVasDb::DeleteTagsL +// Deletes several tags in one commit. +// --------------------------------------------------------- +// +void CNssVasDb::DeleteTagsL( const RArray& aTagIdArray ) + { + TInt k( 0 ); + + if ( !iClientHasOpenedDatabase ) + { + User::Leave( KErrDbNotSet ); + } + + // Locks the database for the use of this process only + User::LeaveIfError( StartTransaction() ); + + CreatePushRollbackItemLC(); + + for ( k = 0; k < aTagIdArray.Count(); k++ ) + { + DeleteTagInsideTransactionL( aTagIdArray[k] ); + } + + User::LeaveIfError( CommitTransaction( ETrue ) ); + + // Pop rollback cleanup + // (which would have made database rollback, if a leave had happened) + CleanupStack::Pop(); // Rollback cleanup item + } + +// ----------------------------------------------------------------------------- +// CNssVasDb::UpdateTagL +// Updates the data of an existing tag. +// ----------------------------------------------------------------------------- +// +void CNssVasDb::UpdateTagL( CNssTag& aTag ) + { + RUBY_DEBUG_BLOCK( "CNssVasDb::UpdateTagL" ); + + if ( !iClientHasOpenedDatabase ) + { + RUBY_DEBUG0( "CNssVasDb error: database not opened." ); + + User::Leave( KErrNotReady ); + } + + // Locks the database for the use of this process only + User::LeaveIfError( StartTransaction() ); + + TRAPD( error, UpdateTagInTransactionL( aTag ) ); + + CommitIfSuccess( iDatabase, error, ETrue ); + + User::LeaveIfError( error ); + } + + +// ----------------------------------------------------------------------------- +// CNssVasDb::UpdateTagRuleIDs +// Changes the Rule IDs of some tags. The Rule ID changes, when +// and already trained tags is retrained. +// ----------------------------------------------------------------------------- +// +void CNssVasDb::UpdateTagRuleIDsL( const RArray& aRetrainedTags ) + { + TInt error( KErrNone ); + if ( !iClientHasOpenedDatabase ) + { + User::Leave( KErrDbNotSet ); + } + + _LIT( KSQLUpdateTag,"update tagtable set "); + _LIT( KEqual,"="); + _LIT( KSQLWhereTagIdIs," where tagid = "); + + TInt count = aRetrainedTags.Count(); + + if ( count > 0 ) + { + return; + } + + // Start transaction + User::LeaveIfError( StartTransaction() ); + CreatePushRollbackItemLC(); + + // Make the changes to Rule IDs + for ( TInt k( 0 ); k < count; k++ ) + { + // "update tagtable set " + iSQLStatement = KSQLUpdateTag; + + // "ruleid=1234" + iSQLStatement.Append( KRuleIdCol ); + iSQLStatement.Append( KEqual ); + iSQLStatement.AppendNumUC( aRetrainedTags[k].iRuleId ); + + // " where tagid = 5678" + iSQLStatement.Append( KSQLWhereTagIdIs ); + iSQLStatement.AppendNumUC( aRetrainedTags[k].iTagId ); + + error = iDatabase.Execute( iSQLStatement ); + if ( error < KErrNone ) + { + ReleaseDiskSpace(); + User::Leave( error ); + } + } + + // Commit transaction + error = CommitTransaction( ETrue ); + if ( error ) + { + ReleaseDiskSpace(); + User::Leave( error ); + } + + // Pop rollback cleanup object + CleanupStack::Pop(); // Rollback cleanup item + + ReleaseDiskSpace(); + } + + +// ----------------------------------------------------------------------------- +// CNssVasDb::SaveContextL +// Saves a newly created context. When a context is saved, a Context ID is +// assigned to it. This id is returned using the reference parameter. +// ----------------------------------------------------------------------------- +// +void CNssVasDb::SaveContextL( CNssContext* aContext, TInt& aContextId ) + { + TBuf name; + RDbView view1; + + _LIT( KSQLAdd, "select * from contexttable " ); + _LIT( KSQLWhereName, "where name='" ); + _LIT( KTick, "' " ); + + //Check to see if a context already exist with the new name + iSQLStatement = KSQLAdd; + iSQLStatement.Append( KSQLWhereName ); + iSQLStatement.Append( aContext->ContextName() ); + iSQLStatement.Append( KTick ); + + CleanupClosePushL( view1 ); + + User::LeaveIfError( view1.Prepare( iDatabase, TDbQuery( iSQLStatement, EDbCompareNormal ) ) ); + User::LeaveIfError( view1.EvaluateAll() ); + + if ( !view1.IsEmptyL() ) // context with that name already exist so return status + { + // Get column set + CDbColSet* columns1 = view1.ColSetL(); + TDbColNo contextid_col = columns1->ColNo( KContextIdCol ); + + delete columns1; + + view1.FirstL(); + view1.GetL(); + //Get the unique contextid key just generated + aContextId = view1.ColUint32(contextid_col); + aContext->SetContextId( aContextId ); + + view1.Close(); + CleanupStack::PopAndDestroy( &view1 ); + + User::Leave( KErrAlreadyExists ); + } + else{ + view1.Close(); + CleanupStack::PopAndDestroy( &view1 ); + + RDbView view2; + + CleanupClosePushL( view2 ); + + User::LeaveIfError( view2.Prepare( iDatabase, TDbQuery(KSQLAdd,EDbCompareNormal))); + User::LeaveIfError( view2.EvaluateAll() ); + + // Get column set + CDbColSet* columns = view2.ColSetL(); + // Get column ordinals + TDbColNo name_col = columns->ColNo( KNameCol ); + TDbColNo global_col = columns->ColNo( KGlobalCol ); + TDbColNo grammarid_col = columns->ColNo( KGrammarIdCol ); + TDbColNo lexiconid_col = columns->ColNo( KLexiconIdCol ); + TDbColNo modelbankid_col = columns->ColNo( KModelBankIdCol ); + TDbColNo contextid_col = columns->ColNo( KContextIdCol ); + + delete columns; + + // Begin process of inserting a row... + view2.InsertL(); + // set column values... + view2.SetColL( name_col, aContext->ContextName() ); + view2.SetColL( global_col, aContext->IsGlobal() ); + view2.SetColL( lexiconid_col, aContext->LexiconId() ); + view2.SetColL( grammarid_col, aContext->GrammarId() ); + view2.SetColL( modelbankid_col, aContext->ModelBankId() ); + + // add the row to the table... + view2.PutL(); + + view2.GetL(); + //Get the unique contextid key just generated + aContextId = view2.ColUint32( contextid_col ); + + aContext->SetContextId( aContextId ); + + name = view2.ColDes( name_col ); + + view2.Close(); + CleanupStack::PopAndDestroy( &view2 ); + } + } + +// ----------------------------------------------------------------------------- +// CNssVasDb::SaveTagL +// Saves a newly created tag. When a tag is saved, a Tag ID is assigned to it. +// This id is returned using the reference parameter. +// ----------------------------------------------------------------------------- +// +void CNssVasDb::SaveTagL( CNssTag* aTag, TInt& aNewId ) + { + RDbView view; + + _LIT( KSQLGet,"select * from tagtable"); + + CleanupClosePushL(view); + + User::LeaveIfError( view.Prepare( iDatabase, TDbQuery(KSQLGet,EDbCompareNormal))); + User::LeaveIfError( view.EvaluateAll()); + + // Get column set + CDbColSet* columns = view.ColSetL(); + // Get column ordinals + TDbColNo name_col = columns->ColNo( KNameCol ); + TDbColNo tagid_col = columns->ColNo( KTagIdCol ); + TDbColNo contextid_col = columns->ColNo( KContextIdCol ); + TDbColNo ruleid_col = columns->ColNo( KRuleIdCol ); + + delete columns; + + // Begin process of inserting a row... + view.InsertL(); + // set column values... + + CNssContext* context = static_cast ( aTag->Context() ); + CNssSpeechItem* speechItem = static_cast ( aTag->SpeechItem() ); + + #ifdef __SIND_EXTENSIONS + view.SetColL( name_col, aTag->SpeechItem()->RawText() ); + #else + view.SetColL( name_col, aTag->SpeechItem()->Text() ); + #endif // __SIND_EXTENSIONS + view.SetColL( contextid_col, context->ContextId() ); + view.SetColL( ruleid_col, speechItem->RuleID() ); + + // add the row to the table... + view.PutL(); + + aNewId = view.ColUint32( tagid_col ); + + // finished - so close the view + view.Close(); + CleanupStack::PopAndDestroy( &view ); + } + + +// ----------------------------------------------------------------------------- +// CNssVasDb::SaveRRDL +// Reads RRD from DB to memory. Utility function when reading tags. +// ----------------------------------------------------------------------------- +// +void CNssVasDb::SaveRRDL( CNssRRD* aRRD ) + { + TInt position; + RDbView view1,view2; + + _LIT( KSQLAddRRDText, "select * from rrdtexttable"); + _LIT( KSQLAddRRDId, "select * from rrdinttable"); + + // Save the integer array, if we have one. + if ( aRRD->IntArray() ) + { + CleanupClosePushL(view1); + + User::LeaveIfError( view1.Prepare( iDatabase, TDbQuery( KSQLAddRRDId, EDbCompareNormal ) ) ); + User::LeaveIfError( view1.EvaluateAll()); + + // Get column set + CDbColSet* columns1 = view1.ColSetL(); + // Get column ordinals + TDbColNo tagid_col = columns1->ColNo( KTagIdCol ); + TDbColNo rrdint_col = columns1->ColNo( KRRDIntCol ); + TDbColNo rrdposition_col1 = columns1->ColNo( KRRDPositionCol ); + + delete columns1; + + // Begin process of inserting a row... + // set column values for id table... + for( position=0; positionIntArray()->Count(); position++ ) + { + view1.InsertL(); + view1.SetColL( tagid_col,aRRD->TagId() ); + view1.SetColL(rrdint_col,aRRD->IntArray()->At( position ) ); + view1.SetColL(rrdposition_col1,position); + // add the row to the table... + view1.PutL(); + } + + // finished - so close the view + view1.Close(); + CleanupStack::PopAndDestroy( &view1 ); + } + + // Save the text array, if we have one + if ( aRRD->TextArray() ) + { + CleanupClosePushL( view2 ); + + User::LeaveIfError( view2.Prepare( iDatabase, + TDbQuery( KSQLAddRRDText, EDbCompareNormal ) ) ); + User::LeaveIfError( view2.EvaluateAll() ); + + // Get column set + CDbColSet* columns2 = view2.ColSetL(); + // Get column ordinals + TDbColNo tagid_col2 = columns2->ColNo( KTagIdCol ); + TDbColNo rrdtext_col2 = columns2->ColNo( KRRDTextCol ); + TDbColNo rrdposition_col2 = columns2->ColNo( KRRDPositionCol ); + + delete columns2; + + //set colum values for text table + for( position = 0; position < aRRD->TextArray()->Count(); position++ ) + { + view2.InsertL(); + view2.SetColL( tagid_col2, aRRD->TagId() ); + view2.SetColL( rrdtext_col2, aRRD->TextArray()->At( position ) ); + view2.SetColL( rrdposition_col2, position ); + view2.PutL(); + } + // add the row to the table... + + // finished - so close the view + view2.Close(); + CleanupStack::PopAndDestroy( &view2 ); + } + } + +// ----------------------------------------------------------------------------- +// CNssVasDb::FillRRDL +// Reads RRD from DB to memory. Utility function when reading tags. +// ----------------------------------------------------------------------------- +// +void CNssVasDb::FillRRDL( TUint32 aTagId, CNssRRD& aRRD ) + { + RUBY_DEBUG_BLOCK( "CNssVasDb::FillRRDL" ); + + TInt position; + RDbView view1,view2; + + _LIT( KSQLAddRRDText, "select * from rrdtexttable "); + _LIT( KSQLAddRRDId, "select * from rrdinttable "); + _LIT( KSQLWhereTagId,"where tagid="); + + iSQLStatement = KSQLAddRRDId; + iSQLStatement.Append( KSQLWhereTagId ); + iSQLStatement.AppendNumUC( aTagId ); + + CleanupClosePushL(view1); + + User::LeaveIfError( view1.Prepare( iDatabase, TDbQuery( iSQLStatement, EDbCompareNormal ) ) ); + User::LeaveIfError( view1.EvaluateAll()); + + // Get column set + CDbColSet* columns1 = view1.ColSetL(); + // Get column ordinals + TDbColNo tagid_col = columns1->ColNo( KTagIdCol ); + TDbColNo rrdint_col = columns1->ColNo( KRRDIntCol ); + TDbColNo rrdposition_col1 = columns1->ColNo( KRRDPositionCol ); + // Cleanup column1 set + delete columns1; + + // Begin process of inserting a row... + TInt intarraysize = view1.CountL(); + if ( intarraysize > 0 ) + { + CArrayFixFlat* intArray = new (ELeave) CArrayFixFlat(intarraysize); + CleanupStack::PushL( intArray ); + intArray->ResizeL( intarraysize ); + + // set column values for id table... + for ( view1.FirstL(); view1.AtRow(); view1.NextL() ) + { + view1.GetL(); + aRRD.SetTagId( view1.ColUint32( tagid_col ) ); + position = view1.ColUint32( rrdposition_col1 ); + if ( position < 0 || position >= intarraysize ) + { + RUBY_ERROR2("CNssVasDb::FillRRDL position out of bounds. 0 < %i < %i", + position, intarraysize ); + User::Leave( KErrCorrupt ); + } + intArray->At( position ) = view1.ColUint32( rrdint_col ); + } + + aRRD.SetIntArrayL( intArray ); + CleanupStack::Pop( intArray ); + intArray->Reset(); + delete intArray; + } + + // finished - so close the view + view1.Close(); + CleanupStack::PopAndDestroy( &view1 ); + + CleanupClosePushL(view2); + + iSQLStatement = KSQLAddRRDText; + iSQLStatement.Append( KSQLWhereTagId ); + iSQLStatement.AppendNumUC( aTagId ); + User::LeaveIfError( view2.Prepare( iDatabase, TDbQuery( iSQLStatement, EDbCompareNormal ) ) ); + User::LeaveIfError( view2.EvaluateAll() ); + + // Get column set + CDbColSet* columns2 = view2.ColSetL(); + // Get column ordinals + TDbColNo tagid_col2 = columns2->ColNo( KTagIdCol ); + TDbColNo rrdtext_col2 = columns2->ColNo( KRRDTextCol ); + TDbColNo rrdposition_col2 = columns2->ColNo( KRRDPositionCol ); + + delete columns2; + + TInt textarraysize = view2.CountL(); + if ( textarraysize > 0 ) + { + CArrayFixFlat* textArray = + new (ELeave) CArrayFixFlat(textarraysize); + CleanupStack::PushL( textArray ); + textArray->ResizeL( textarraysize ); + + //set colum values for text table + for ( view2.FirstL(); view2.AtRow(); view2.NextL() ) + { + view2.GetL(); + aRRD.SetTagId( view2.ColUint32( tagid_col2 ) ); + position = view2.ColUint32( rrdposition_col2 ); + if ( position < 0 || position >= textarraysize ) + { + RUBY_ERROR2("CNssVasDb::FillRRDL position out of bounds. 0 < %i < %i", + position, textarraysize ); + User::Leave( KErrCorrupt ); + } + textArray->At( position ) = view2.ColDes( rrdtext_col2 ); + } + + aRRD.SetTextArrayL( textArray ); + CleanupStack::Pop( textArray ); + textArray->Reset(); + delete textArray; + } + + // finished - so close the view + view2.Close(); + + CleanupStack::PopAndDestroy( &view2 ); + } + +// ----------------------------------------------------------------------------- +// CNssVasDb::GetTagL +// Gets a tag by grammar ID and rule ID. +// ----------------------------------------------------------------------------- +// +CArrayPtrFlat* CNssVasDb::GetTagL( TNssGrammarIdRuleId aGrammarIdRuleId ) + { + CNssContext* context = iContextBuilder.CreateContextL(); + CleanupStack::PushL( context ); + RDbView view; + + User::LeaveIfError( StartTransaction() ); + CreatePushRollbackItemLC(); + + CleanupClosePushL(view); + + _LIT( KSQLGetContext, "select * from contexttable where grammarid="); + iSQLStatement.Copy(KSQLGetContext); + iSQLStatement.AppendNumUC(aGrammarIdRuleId.iGrammarId); + + TDbQuery dbQuery(iSQLStatement, EDbCompareNormal); + User::LeaveIfError( view.Prepare( iDatabase, dbQuery ) ); + User::LeaveIfError( view.EvaluateAll() ); + + view.FirstL(); + FillContextL(view, *context); + + _LIT( KSQLGetTag, "select * from tagtable where ruleid="); + _LIT( KSQLAnd," and contextid="); + iSQLStatement = KSQLGetTag; + iSQLStatement.AppendNumUC( aGrammarIdRuleId.iRuleId ); + iSQLStatement.Append( KSQLAnd ); + iSQLStatement.AppendNumUC( context->ContextId() ); + + // Close view + CleanupStack::PopAndDestroy( &view ); + + CArrayPtrFlat* res = GetTagListByQueryL( iSQLStatement ); + + // Pop rollback cleanup item + CleanupStack::Pop(); // Rollback cleanup item + CommitTransaction( EFalse ); + + CleanupStack::PopAndDestroy( context ); + + return( res ); + } + +// ----------------------------------------------------------------------------- +// CNssVasDb::GetTagsL +// Gets a list of tags by grammar ID and rule ID. +// ----------------------------------------------------------------------------- +// +CArrayPtrFlat* CNssVasDb::GetTagsL( TNssGrammarIdRuleIdListArray& aGrammarIdRuleIds ) + { + CNssContext* context = iContextBuilder.CreateContextL(); + CleanupStack::PushL( context ); + RDbView view; + + User::LeaveIfError( StartTransaction() ); + CreatePushRollbackItemLC(); + + Mem::FillZ( context, sizeof(*context) ); + + CleanupClosePushL(view); + + _LIT( KSQLGetContext, "select * from contexttable where "); + _LIT( KGrammarIdParam, "grammarid=" ); + _LIT( KOr, " OR "); + iSQLStatement.Copy(KSQLGetContext); + + for( TInt i = 0; i < aGrammarIdRuleIds.Count(); i++) + { + if( i !=0 ) + { + iSQLStatement.Append(KOr); + } + iSQLStatement.Append(KGrammarIdParam); + iSQLStatement.AppendNumUC(aGrammarIdRuleIds[i].iGrammarId); + // same grammar ids usually appear, but that's ok and should not decrease performance + } + + TDbQuery dbQuery(iSQLStatement, EDbCompareNormal); + User::LeaveIfError( view.Prepare( iDatabase, dbQuery )); + User::LeaveIfError( view.EvaluateAll()); + + _LIT( KSQLGetTags, "select * from tagtable where ("); + _LIT( KRuleId, "ruleid="); + _LIT( KContextId,"contextid="); + _LIT( KBracketAnd, " AND ("); + _LIT( KBracketOr, ") OR ("); + _LIT( KFinalBracket, ")"); + + // Get column set + CDbColSet* columns = view.ColSetL(); + TDbColNo contextid_col= columns->ColNo( KContextIdCol ); + TDbColNo grammarid_col= columns->ColNo( KGrammarIdCol ); + delete columns; + TUint32 currContextId; + TUint32 currGrammarId; + TUint32 currRuleId; + + iSQLStatement = KSQLGetTags; + TBool firstPair = ETrue; + while( view.NextL()) + { + view.GetL(); + // before each iteration, but first, we add ") OR (" + if( firstPair ) + { + firstPair = EFalse; + } + else + { + iSQLStatement.Append(KBracketOr); + } + currContextId = view.ColUint32( contextid_col ); + currGrammarId = view.ColUint32( grammarid_col ); + iSQLStatement.Append( KContextId ); + iSQLStatement.AppendNumUC( currContextId ); + iSQLStatement.Append( KBracketAnd ); + // we need to find corresponding rule id + TBool someGrammarFoundAlready = EFalse; + for( TInt i=0; i* res = GetTagListByQueryL( iSQLStatement ); + + // Pop rollback cleanup item + CleanupStack::Pop(); // Rollback cleanup item + CommitTransaction( EFalse ); + + CleanupStack::PopAndDestroy( context ); + + return( res ); + } + +// ----------------------------------------------------------------------------- +// CNssVasDb::GetTagListByQuery +// Executes the query and reads matches from DB to memory. +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +// CNssVasDb::GetTagListByQuery +// Executes the query and reads matches from DB to memory. +// ----------------------------------------------------------------------------- +// +CArrayPtrFlat* CNssVasDb::GetTagListByQueryL( const TDesC& aSqlQuery ) + { + RUBY_DEBUG_BLOCK( "CNssVasDb::GetTagListByQueryL" ); + + __ASSERT_DEBUG( aSqlQuery.Left(6).Compare( _L("select") ) == 0, User::Panic( KVasDbPanic, __LINE__ ) ); + + CNssContext* context = NULL; + CNssSpeechItem* speechItem = NULL; + CNssRRD* rrd = NULL; + TInt contextId = -1; + + // 'context' variable is the context of the previous tag. + // When a new tag is read, 'context' is updated only if context changes. + // Set the ID invalid value in order to force the first tag to read a context. + //context.iContextId = (TUint32)-1; + //context->SetContextId( -1 ); + + RDbView view; + CleanupClosePushL( view ); + + CArrayPtrFlat* tagList = new(ELeave)CArrayPtrFlat( KMaxTagArraySize ); + CleanupStack::PushL( tagList ); + CleanupResetAndDestroyPushL( *tagList ); + + User::LeaveIfError( view.Prepare( iDatabase, TDbQuery( aSqlQuery, EDbCompareNormal ) ) ); + User::LeaveIfError( view.EvaluateAll() ); + + if ( !view.IsEmptyL() ) + { + for (view.FirstL(); view.AtRow(); view.NextL()) + { + context = iContextBuilder.CreateContextL(); + CleanupStack::PushL( context ); + + speechItem = iSpeechItemBuilder.CreateEmptySpeechItemL( *context ); + CleanupStack::PushL( speechItem ); + + FillSpeechItemL( view, *speechItem, contextId ); + + // Get context, if we haven't already done it. + if ( context->ContextId() != (TUint32)contextId ) + { + _LIT( KContextQuery, "select * from contexttable where contextid=" ); + + iSQLStatement.Copy( KContextQuery ); + iSQLStatement.AppendNumUC( contextId ); + + CArrayPtrFlat* contextList = + GetContextInsideTransactionL( iSQLStatement ); + CleanupStack::PushL( contextList ); + + User::LeaveIfNull( contextList ); + + if ( contextList->Count() != 1 ) + { + User::Leave( KErrCorrupt ); + } + + CleanupStack::Pop( contextList ); + CleanupStack::PopAndDestroy( speechItem ); + CleanupStack::PopAndDestroy( context ); + + context = (*contextList)[0]; + delete contextList; + + CleanupStack::PushL( context ); + + speechItem = iSpeechItemBuilder.CreateEmptySpeechItemL( *context ); + CleanupStack::PushL( speechItem ); + + FillSpeechItemL( view, *speechItem, contextId ); + } + + rrd = CNssRRD::NewL(); + CleanupStack::PushL( rrd ); + + FillRRDL( speechItem->TagId(), *rrd ); + + // Append tag to the array + FillTagListArrayL( *tagList, context, speechItem, rrd ); + CleanupStack::PopAndDestroy( rrd ); + CleanupStack::PopAndDestroy( speechItem ); + CleanupStack::PopAndDestroy( context ); + } + } + else + { + User::Leave( KErrNotFound ); + } + + CleanupStack::Pop( tagList ); // ResetAndDestroy + CleanupStack::Pop( tagList ); // array itself + // Finished with the view - so close it. + CleanupStack::PopAndDestroy( &view ); + + return tagList; + } + +// ----------------------------------------------------------------------------- +// CNssVasDb::GetTagL +// Gets a tag by name. +// ----------------------------------------------------------------------------- +// +CArrayPtrFlat* CNssVasDb::GetTagL(const TDesC& aName) + { + _LIT( KTick,"' "); + _LIT( KSQLGetTag, "select * from tagtable where name='"); + + iSQLStatement = KSQLGetTag; + iSQLStatement.Append( aName ); + iSQLStatement.Append( KTick ); + + User::LeaveIfError( StartTransaction() ); + + CArrayPtrFlat* arr = GetTagListByQueryL( iSQLStatement ); + + CommitTransaction( EFalse ); + + return arr; + } + +// ----------------------------------------------------------------------------- +// CNssVasDb::GetTagL +// Gets all tags from a specified context. +// ----------------------------------------------------------------------------- +// +CArrayPtrFlat* CNssVasDb::GetTagL( const CNssContext& aContext) + { + RDbView view; + + User::LeaveIfError( StartTransaction() ); + CreatePushRollbackItemLC(); + + CleanupClosePushL( view ); + + // Validate the context + _LIT( KSQLGetContext, "select * from contexttable where contextid="); + iSQLStatement = KSQLGetContext; + iSQLStatement.AppendNumUC( aContext.ContextId() ); + + User::LeaveIfError( view.Prepare( iDatabase, TDbQuery( iSQLStatement, EDbCompareNormal ) ) ); + User::LeaveIfError( view.EvaluateAll() ); + + if ( view.IsEmptyL() ) + { + User::Leave( KErrNotFound ); + } + + // Finished with the view - so close it. + CleanupStack::PopAndDestroy( &view ); + + _LIT( KSQLGetTag, "select * from tagtable where contextid=" ); + iSQLStatement.Copy( KSQLGetTag ); + iSQLStatement.AppendNumUC( aContext.ContextId() ); + + CArrayPtrFlat* result = GetTagListByQueryL( iSQLStatement ); + + // Transaction finished - free the transaction lock + CleanupStack::Pop(); // Rollback cleanup item + CommitTransaction( EFalse ); + + return result; + } + +// ----------------------------------------------------------------------------- +// CNssVasDb::GetTagListFromViewL +// Reads the tags from DB to memory and appends them to the array. +// Earlier, the caller has made an SQL query and placed the matches in RDbView. +// ----------------------------------------------------------------------------- +// +void CNssVasDb::GetTagListFromViewL( RDbView& aView, CArrayPtrFlat* aTagList, + CNssContext* aContext ) + { + TInt discardable( 0 ); + + for ( aView.FirstL(); aView.AtRow(); aView.NextL() ) + { + CNssSpeechItem* speechItem = iSpeechItemBuilder.CreateEmptySpeechItemL( *aContext ); + CleanupStack::PushL( speechItem ); + + FillSpeechItemL( aView, *speechItem, discardable ); + CNssRRD* rrd = CNssRRD::NewL(); + CleanupStack::PushL( rrd ); + FillRRDL( speechItem->TagId(), *rrd ); + + FillTagListArrayL( *aTagList, aContext, speechItem, rrd ); + + CleanupStack::PopAndDestroy( rrd ); + CleanupStack::PopAndDestroy( speechItem ); + } + } + +// ----------------------------------------------------------------------------- +// CNssVasDb::DeleteTagL +// Gets a list of tags by RRD data. +// ----------------------------------------------------------------------------- +// +CArrayPtrFlat* CNssVasDb::GetTagL( TInt aContextId, TInt aNum, TInt aPosition ) + { + RDbView view; + TUint32 tagId; + CNssContext* context = iContextBuilder.CreateContextL(); + CleanupStack::PushL( context ); + + User::LeaveIfError( StartTransaction() ); + CreatePushRollbackItemLC(); + + CArrayPtrFlat* tagArray = new(ELeave)CArrayPtrFlat(1); + CleanupStack::PushL( tagArray ); + CleanupResetAndDestroyPushL( *tagArray ); + + // Get the context based on ContextId + CleanupClosePushL(view); + + _LIT( KSQLGetContext, "select * from contexttable where contextid=" ); + iSQLStatement.Copy( KSQLGetContext ); + iSQLStatement.AppendNumUC( aContextId ); + + User::LeaveIfError( view.Prepare( iDatabase, TDbQuery( iSQLStatement, EDbCompareNormal ) ) ); + User::LeaveIfError( view.EvaluateAll() ); + view.FirstL(); + view.GetL(); + TRAPD( error, FillContextL( view, *context ) ); + // Finished with the view - so close it. + view.Close(); + CleanupStack::PopAndDestroy( &view ); + + // If filling of the context failed, return with Not Found + if ( error != KErrNone ) + { + User::Leave( KErrNotFound ); + } + + // Get the list of TagId from the RRD table based on Num and Position + RDbView view1; + CleanupClosePushL( view1 ); + + _LIT( KSQLGetRRDInt, "select * from rrdinttable where rrdposition=" ); + _LIT( KSQLAndRRDInt, " and rrdint=" ); + iSQLStatement = KSQLGetRRDInt; + iSQLStatement.AppendNumUC( aPosition ); + iSQLStatement.Append( KSQLAndRRDInt ); + iSQLStatement.AppendNumUC( aNum ); + + User::LeaveIfError( view1.Prepare( iDatabase, TDbQuery( iSQLStatement, EDbCompareNormal ) ) ); + User::LeaveIfError( view1.EvaluateAll() ); + + if ( view1.IsEmptyL() ) + { + + User::Leave( KErrNotFound ); + } + + // Get column set + CDbColSet* columns = view1.ColSetL(); + // Get column ordinals + TDbColNo tagid_col= columns->ColNo( KTagIdCol ); + // Cleanup column set + delete columns; + + // Select the valid tagId from the list + for ( view1.FirstL(); view1.AtRow(); view1.NextL() ) + { + view1.GetL(); + tagId = view1.ColUint32( tagid_col ); + + // Get the SpeechItem based on the tagId and ContextId + RDbView view2; + CleanupClosePushL( view2 ); + + _LIT( KSQLGetSpeechItem, "select * from tagtable where tagid=" ); + _LIT( KSQLAndContextId," and contextid=" ); + iSQLStatement = KSQLGetSpeechItem; + iSQLStatement.AppendNumUC( tagId ); + iSQLStatement.Append( KSQLAndContextId ); + iSQLStatement.AppendNumUC( aContextId ); + + User::LeaveIfError( view2.Prepare( iDatabase, + TDbQuery( iSQLStatement, EDbCompareNormal ) ) ); + User::LeaveIfError( view2.EvaluateAll() ); + + if ( !view2.IsEmptyL() ) + { + GetTagListFromViewL( view2, tagArray, context ); + } + view2.Close(); + CleanupStack::PopAndDestroy( &view2 ); + } + + // close the view 1 + view1.Close(); + CleanupStack::PopAndDestroy( &view1 ); + + CleanupStack::Pop( tagArray ); // ResetAndDestroy + CleanupStack::Pop( tagArray ); // array itself + + // Rollback cleanup + CleanupStack::Pop(); // Rollback cleanup item + CommitTransaction( EFalse ); + + CleanupStack::PopAndDestroy( context ); + + return tagArray; + } + +// ----------------------------------------------------------------------------- +// CNssVasDb::DeleteTagL +// Gets a list of tags by RRD data. +// ----------------------------------------------------------------------------- +// +CArrayPtrFlat* CNssVasDb::GetTagL( TInt aContextId, + const TDesC& aText, TInt aPosition ) + { + RDbView view; + TUint32 tagId; + CNssContext* context = iContextBuilder.CreateContextL(); + CleanupStack::PushL( context ); + + CArrayPtrFlat* tagArray = new(ELeave)CArrayPtrFlat(1); + CleanupStack::PushL( tagArray ); + CleanupResetAndDestroyPushL( *tagArray ); + + User::LeaveIfError( StartTransaction() ); + CreatePushRollbackItemLC(); + + // Get the context based on ContextId + CleanupClosePushL( view ); + + _LIT( KSQLGetContext, "select * from contexttable where contextid=" ); + iSQLStatement.Copy( KSQLGetContext ); + iSQLStatement.AppendNumUC( aContextId ); + + User::LeaveIfError( view.Prepare(iDatabase, TDbQuery(iSQLStatement, EDbCompareNormal))); + User::LeaveIfError( view.EvaluateAll()); + view.FirstL(); + view.GetL(); + TRAPD( error, FillContextL( view, *context ) ); + // Finished with the view - so close it. + view.Close(); + CleanupStack::PopAndDestroy( &view ); + + // If filling of the context failed, return with Not Found + if ( error != KErrNone ) + { + User::Leave( KErrNotFound ); + } + + // Get the list of TagId from the RRD table based on text and Position + RDbView view1; + CleanupClosePushL( view1 ); + + _LIT( KSQLGetRRDText, "select * from rrdtexttable where rrdposition=" ); + _LIT( KSQLAndRRDText, " and rrdtext='" ); + _LIT( KSQLTick, "'" ); + + iSQLStatement = KSQLGetRRDText; + iSQLStatement.AppendNumUC( aPosition ); + iSQLStatement.Append( KSQLAndRRDText ); + iSQLStatement.Append( aText ); + iSQLStatement.Append( KSQLTick ); + + User::LeaveIfError( view1.Prepare( iDatabase, TDbQuery( iSQLStatement, EDbCompareNormal ) ) ); + User::LeaveIfError( view1.EvaluateAll() ); + + if ( view1.IsEmptyL() ) + { + User::Leave( KErrNotFound ); + } + + // Get column set + CDbColSet* columns = view1.ColSetL(); + // Get column ordinals + TDbColNo tagid_col= columns->ColNo( KTagIdCol ); + // Cleanup column set + delete columns; + + // Select the valid tagId from the list + for ( view1.FirstL(); view1.AtRow(); view1.NextL() ) + { + view1.GetL(); + tagId = view1.ColUint32( tagid_col ); + + // Get the SpeechItem based on the tagId and ContextId + RDbView view2; + CleanupClosePushL( view2 ); + + _LIT( KSQLGetSpeechItem, "select * from tagtable where tagid=" ); + _LIT( KSQLAndContextId, " and contextid=" ); + iSQLStatement = KSQLGetSpeechItem; + iSQLStatement.AppendNumUC( tagId ); + iSQLStatement.Append( KSQLAndContextId ); + iSQLStatement.AppendNumUC( aContextId ); + + User::LeaveIfError( view2.Prepare( iDatabase, + TDbQuery( iSQLStatement, EDbCompareNormal ) ) ); + User::LeaveIfError( view2.EvaluateAll() ); + + if ( !view2.IsEmptyL() ) + { + GetTagListFromViewL( view2, tagArray, context ); + } + CleanupStack::PopAndDestroy( &view2 ); + } + // close the view 1 + CleanupStack::PopAndDestroy( &view1 ); + + // Roll back transaction + CleanupStack::Pop(); // Rollback cleanup item + CommitTransaction( EFalse ); + + CleanupStack::Pop( tagArray ); // ResetAndDestroyPushL + CleanupStack::Pop( tagArray ); // array itself + CleanupStack::PopAndDestroy( context ); + + return tagArray; + } + +// ----------------------------------------------------------------------------- +// CNssVasDb::DeleteTagL +// Get a tag by ID. +// ----------------------------------------------------------------------------- +// +CArrayPtrFlat* CNssVasDb::GetTagL( TUint32 aTagId ) + { + RDbView view; + + User::LeaveIfError( StartTransaction() ); + CreatePushRollbackItemLC(); + + CleanupClosePushL( view ); + + + _LIT( KSQLGetTag, "select * from tagtable where tagid="); + + iSQLStatement = KSQLGetTag; + iSQLStatement.AppendNumUC( aTagId ); + + CArrayPtrFlat* result = GetTagListByQueryL( iSQLStatement ); + + // Close view + CleanupStack::PopAndDestroy( &view ); + + // Roll back transaction + CleanupStack::Pop(); // Rollback cleanup item + CommitTransaction( EFalse ); + + return( result ); + } + + +// ----------------------------------------------------------------------------- +// CNssVasDb::DeleteTagL +// Deletes a tag by name +// ----------------------------------------------------------------------------- +// +void CNssVasDb::DeleteTagL( const TDesC& aName ) + { + if ( !iClientHasOpenedDatabase ) + { + RUBY_DEBUG0( "CNssVasDb error: database not opened." ); + + User::Leave( KErrNotReady ); + } + + User::LeaveIfError( StartTransaction() ); + CreatePushRollbackItemLC(); + + TUint32 tagId; + RDbView view; + + CleanupClosePushL(view); + + _LIT( KTick,"' "); + _LIT( KSQLGetTag, "select * from tagtable where name='"); + + iSQLStatement = KSQLGetTag; + iSQLStatement.Append( aName ); + iSQLStatement.Append( KTick ); + + User::LeaveIfError( view.Prepare( iDatabase, TDbQuery(iSQLStatement, EDbCompareNormal))); + User::LeaveIfError( view.EvaluateAll()); + + // Get column set + CDbColSet* columns = view.ColSetL(); + // Get column ordinals + TDbColNo tagid_col= columns->ColNo( KTagIdCol ); + // Cleanup column set + delete columns; + + view.FirstL(); + view.GetL(); + tagId = view.ColUint32( tagid_col ); + + // Close view + CleanupStack::PopAndDestroy( &view ); + + // Pop rollback item and do commit + CleanupStack::Pop(); // Rollback cleanup item + CommitTransaction( ETrue ); + + DeleteTagL( tagId ); + } + +// ----------------------------------------------------------------------------- +// CNssVasDb::DeleteTagL +// Deletes a tag by ID +// ----------------------------------------------------------------------------- +// +void CNssVasDb::DeleteTagL( TUint32 aTagId ) + { + if ( !iClientHasOpenedDatabase ) + { + RUBY_DEBUG0( "CNssVasDb error: database not opened." ); + + User::Leave( KErrNotReady ); + } + + // Lock database + User::LeaveIfError( StartTransaction() ); + CreatePushRollbackItemLC(); + + DeleteTagInsideTransactionL( aTagId ); + + // Commit transaction - unlock databaes + CleanupStack::Pop(); // Rollback cleanup item + CommitTransaction( ETrue ); + } + + +// ----------------------------------------------------------------------------- +// CNssVasDb::DeleteTagInsideTransactionL +// Deletes the RRD information of a tag. +// ----------------------------------------------------------------------------- +// +void CNssVasDb::DeleteTagInsideTransactionL( TUint32 aTagId ) + { + TInt error( KErrNone ); + + _LIT( KSQLDeleteTag, "delete from tagtable where tagid="); + + ReserveDiskSpaceL( sizeof(CNssTag) ); + + iSQLStatement = KSQLDeleteTag; + iSQLStatement.AppendNumUC(aTagId); + + error = iDatabase.Execute( iSQLStatement ); + if ( error < KErrNone ) + { + ReleaseDiskSpace(); + User::Leave( error ); + } + + TRAP( error, DeleteRRDL( aTagId ) ); + + ReleaseDiskSpace(); + + User::LeaveIfError( error ); + } + + +// ----------------------------------------------------------------------------- +// CNssVasDb::DeleteRRDL +// Deletes the RRD information of a tag. +// ----------------------------------------------------------------------------- +// +void CNssVasDb::DeleteRRDL(TUint32 aTagId) + { + TInt error( KErrNone ); + + _LIT( KSQLAddRRDText, "delete from rrdtexttable "); + _LIT( KSQLAddRRDId, "delete from rrdinttable "); + _LIT( KSQLWhereTagId,"where tagid="); + + iSQLStatement = KSQLAddRRDId; + iSQLStatement.Append( KSQLWhereTagId ); + iSQLStatement.AppendNumUC( aTagId ); + + error = iDatabase.Execute( iSQLStatement ); + + if ( error < KErrNone && error != KErrNotFound ) + { + User::Leave( error ); + } + + iSQLStatement = KSQLAddRRDText; + iSQLStatement.Append( KSQLWhereTagId ); + iSQLStatement.AppendNumUC( aTagId ); + + error = iDatabase.Execute( iSQLStatement ); + + if ( error < KErrNone && error != KErrNotFound ) + { + User::Leave( error ); + } + } + +// ----------------------------------------------------------------------------- +// CNssVasDb::DeleteContextL +// Deletes a context. +// ----------------------------------------------------------------------------- +// +void CNssVasDb::DeleteContextL( const TDesC& aName ) + { + RUBY_DEBUG_BLOCK( "CNssVasDb::DeleteContextL" ); + + TInt error( KErrNone ); + TUint32 contextId; + TUint32 tagId; + RDbView view1,view2; + + // Begin transaction + User::LeaveIfError( StartTransaction() ); + CreatePushRollbackItemLC(); + + CleanupClosePushL( view1 ); + + // Search the context from DB + _LIT( KTick, "' " ); + _LIT( KSQLGetContext, "select * from contexttable where name='" ); + + iSQLStatement = KSQLGetContext; + iSQLStatement.Append( aName ); + iSQLStatement.Append( KTick ); + + User::LeaveIfError( view1.Prepare( iDatabase, TDbQuery( iSQLStatement, EDbCompareNormal ) ) ); + User::LeaveIfError( view1.EvaluateAll() ); + + // Get column set + CDbColSet* columns1 = view1.ColSetL(); + // Get column ordinals + TDbColNo contextid_col= columns1->ColNo( KContextIdCol ); + // Cleanup column set + delete columns1; + + view1.FirstL(); + + // Doesn't exists, can't delete + if ( !view1.AtRow() ) + { + User::Leave( KErrNotFound ); + } + + view1.GetL(); + contextId = view1.ColUint32( contextid_col ); + + view1.DeleteL(); + view1.Close(); + CleanupStack::PopAndDestroy( &view1 ); + + // Delete all tags, which were in the context. + _LIT( KSQLGetTag, "select * from tagtable where contextid=" ); + + iSQLStatement = KSQLGetTag; + iSQLStatement.AppendNumUC( contextId ); + + CleanupClosePushL( view2 ); + + User::LeaveIfError( view2.Prepare( iDatabase, TDbQuery( iSQLStatement, EDbCompareNormal ) ) ); + User::LeaveIfError( view2.EvaluateAll() ); + + ReserveDiskSpaceL( (sizeof(CNssTag) * view2.CountL()) + sizeof(CNssContext) ); + + view2.FirstL(); + + // If this context has any tags, remove the RRD entries from the RRD table. + if ( view2.AtRow() ) + { + // Get column set + CDbColSet* columns2 = view2.ColSetL(); + + // Get column ordinals + TDbColNo tagid_col = columns2->ColNo( KTagIdCol ); + // Cleanup column2 set + delete columns2; + + for ( view2.FirstL(); view2.AtRow(); view2.NextL() ) + { + view2.GetL(); + tagId = view2.ColUint32( tagid_col ); + RUBY_DEBUG0( "CNssVasDb::DeleteContextL deleting RRD" ); + // Return value ignored since other tag ids should be iterated through + // even though one RRD deletion fails + TRAP( error, DeleteRRDL( tagId ) ); + } + + view2.Close(); + } + + // Remove tags from tag table + _LIT( KSQLDeleteTag, "delete from tagtable where contextid="); + iSQLStatement = KSQLDeleteTag; + iSQLStatement.AppendNumUC( contextId ); + + error = iDatabase.Execute( iSQLStatement ); + + CleanupStack::PopAndDestroy( &view2 ); + + if ( error < KErrNone && error != KErrNotFound ) + { + ReleaseDiskSpace(); + // Roll back transaction + CleanupStack::PopAndDestroy(); // Rollback cleanup item + User::Leave( error ); + } + + CleanupStack::Pop(); // Rollback cleanup item + CommitTransaction( ETrue ); + + ReleaseDiskSpace(); + } + +// ----------------------------------------------------------------------------- +// CNssVasDb::UpdateTagInTransactionL +// Updates a tag. Assumes that a transaction has been started earlier. +// ----------------------------------------------------------------------------- +// +void CNssVasDb::UpdateTagInTransactionL( CNssTag& aTag ) + { + CNssContext* context = static_cast ( aTag.Context() ); + UpdateContextInsideTransactionL( *context ); + CNssSpeechItem* speechItem = static_cast + ( aTag.SpeechItem() ); + UpdateSpeechItemL( *speechItem ); + CNssRRD* rrd = static_cast ( aTag.RRD() ); + UpdateRRDL( *rrd ); + } + +// ----------------------------------------------------------------------------- +// CNssVasDb::DoUpdateContextL +// Updates an existing context. +// ----------------------------------------------------------------------------- +// +void CNssVasDb::DoUpdateContextL( CNssContext& aContext ) + { + _LIT( KSQLUpdateContext,"update contexttable set "); + _LIT( KEqual,"="); + _LIT( KCommon,","); + _LIT( KTick,"'"); + _LIT( KSQLWhereContextId," where contextid = "); + + iSQLStatement = KSQLUpdateContext; + + iSQLStatement.Append( KNameCol ); + iSQLStatement.Append( KEqual ); + iSQLStatement.Append( KTick ); + iSQLStatement.Append( aContext.ContextName() ); + iSQLStatement.Append( KTick ); + + iSQLStatement.Append( KCommon ); + iSQLStatement.Append( KGlobalCol ); + iSQLStatement.Append( KEqual ); + iSQLStatement.AppendNumUC( aContext.IsGlobal() ); + + iSQLStatement.Append( KCommon ); + iSQLStatement.Append( KGrammarIdCol ); + iSQLStatement.Append( KEqual ); + iSQLStatement.AppendNumUC( aContext.GrammarId() ); + + iSQLStatement.Append( KCommon ); + iSQLStatement.Append( KLexiconIdCol ); + iSQLStatement.Append( KEqual ); + iSQLStatement.AppendNumUC( aContext.LexiconId() ); + + iSQLStatement.Append( KCommon ); + iSQLStatement.Append( KModelBankIdCol ); + iSQLStatement.Append( KEqual ); + iSQLStatement.AppendNumUC( aContext.ModelBankId() ); + + iSQLStatement.Append( KSQLWhereContextId ); + iSQLStatement.AppendNumUC( aContext.ContextId() ); + + User::LeaveIfError( iDatabase.Execute( iSQLStatement ) ); + } + +// ----------------------------------------------------------------------------- +// CNssVasDb::DoUpdateUpdateContextClientDataL +// Updates the client data of a context. +// ----------------------------------------------------------------------------- +// +void CNssVasDb::DoUpdateContextClientDataL( CNssContext& aContext ) + { + __UHEAP_MARK; + + // Declare a literal string to hold the SQL statement + // SELECT KBinaryLexiconColumn , KBinaryLexiconColumn FROM KLexiconName + + _LIT( KSQLSelect1, "select clientdata from contexttable where name='" ); + + TBuf sqlStatement; + sqlStatement.Append( KSQLSelect1 ); + sqlStatement.Append( aContext.ContextName() ); + sqlStatement.Append( '\'' ); + + // create a view on the database + RDbView view; + CleanupClosePushL( view ); // Stack: view + + User::LeaveIfError( view.Prepare( iDatabase, TDbQuery( sqlStatement, EDbCompareNormal ) ) ); + User::LeaveIfError( view.EvaluateAll() ); + + // Get the structure of rowset + CDbColSet* colSet = view.ColSetL(); + CleanupStack::PushL( colSet ); // Stack: view, colset + TInt error( KErrNone ); + + if( view.FirstL() ) + { + view.UpdateL(); + + + // add binary buffer by Using the stream + + //RDbColWriteStream out; + TDbColNo col = colSet->ColNo( _L("clientdata") ); // Ordinal position of client data + + if ( col == KDbNullColNo ) + { + User::Leave( KErrCorrupt ); + } + + view.SetColL( col, aContext.ClientData() ); + + view.PutL(); + + // close the view + view.Close(); + } + else + { + error = KErrNotFound; + } + + CleanupStack::PopAndDestroy( colSet ); + CleanupStack::PopAndDestroy( &view ); + + __UHEAP_MARKEND; + + User::LeaveIfError( error ); + } + +// ----------------------------------------------------------------------------- +// CNssVasDb::UpdateRRDL +// Updates an existing RRD. +// ----------------------------------------------------------------------------- +// +void CNssVasDb::UpdateRRDL( CNssRRD& aRRD ) + { + TRAPD( error, DeleteRRDL( aRRD.TagId() ) ); + + if ( error != KErrNotFound) + { + error = KErrNone; + } + + User::LeaveIfError( error ); + + SaveRRDL( &aRRD ); + } + +// ----------------------------------------------------------------------------- +// CNssVasDb::UpdateSpeechItemL +// Updates an existing speech item. +// ----------------------------------------------------------------------------- +// +void CNssVasDb::UpdateSpeechItemL( CNssSpeechItem& aSpeechItem ) + { + RDbView view; + CleanupClosePushL( view ); + + _LIT( KSQLGet, "select * from tagtable where tagid=" ); + + iSQLStatement = KSQLGet; + iSQLStatement.AppendNumUC( aSpeechItem.TagId() ); + + User::LeaveIfError( view.Prepare( iDatabase, TDbQuery( iSQLStatement, EDbCompareNormal ) ) ); + User::LeaveIfError( view.EvaluateAll()); + + // Get column set + CDbColSet* columns = view.ColSetL(); + // Get column ordinals + TDbColNo name_col= columns->ColNo( KNameCol ); + + delete columns; + + if ( view.FirstL() ) + { + // Begin process of updating a row... + view.UpdateL(); + // set column values... +#ifdef __SIND_EXTENSIONS + view.SetColL( name_col, aSpeechItem.RawText() ); +#else + view.SetColL( name_col, aSpeechItem.Text() ); +#endif + + // add the row to the table... + view.PutL(); + + // finished - so close the view + view.Close(); + } + else + { + User::Leave( KErrNotFound ); + } + + CleanupStack::PopAndDestroy( &view ); + } + +// ----------------------------------------------------------------------------- +// CNssVasDb::FillSpeechItemL +// Reads a TNssSpeechItem from DB to memory. Earlier, the caller has run an SQL +// query and specifies the matching context in RDbView. +// ----------------------------------------------------------------------------- +// +void CNssVasDb::FillSpeechItemL( RDbView& aView, CNssSpeechItem& aSpeechItem, TInt& aContextId ) + { + RUBY_DEBUG_BLOCK( "CNssVasDb::FillSpeechItemL" ); + + if ( aView.IsEmptyL() ) + { + User::Leave( KErrNotFound ); + } + + // Get column set + CDbColSet* columns = aView.ColSetL(); + // Get column ordinals + TDbColNo tagid_col = columns->ColNo( KTagIdCol ); + TDbColNo contextid_col= columns->ColNo( KContextIdCol ); + TDbColNo ruleid_col = columns->ColNo( KRuleIdCol ); + TDbColNo name_col = columns->ColNo( KNameCol ); + + // Cleanup column set + delete columns; + + // Retrieve the current row + aView.GetL(); + aSpeechItem.SetTagId( aView.ColUint32( tagid_col ) ); + aSpeechItem.SetRuleID( aView.ColUint32( ruleid_col ) ); + aSpeechItem.SetTextL( aView.ColDes( name_col ) ); + aContextId = aView.ColUint32( contextid_col ); + } + + +// ----------------------------------------------------------------------------- +// CNssVasDb::FillContextL +// Reads a context from DB to memory. Earlier, the caller has run an SQL query +// and specifies the matching context in RDbView. +// ----------------------------------------------------------------------------- +// +void CNssVasDb::FillContextL( RDbView& aView, CNssContext& aContext ) + { + if ( aView.IsEmptyL() ) + { + User::Leave( KErrNotFound ); + } + + // Get column set + CDbColSet* columns = aView.ColSetL(); + // Get column ordinals + TDbColNo contextid_col= columns->ColNo( KContextIdCol ); + TDbColNo name_col = columns->ColNo( KNameCol ); + TDbColNo global_col = columns->ColNo( KGlobalCol ); + TDbColNo grammarid_col= columns->ColNo( KGrammarIdCol ); + TDbColNo lexiconid_col= columns->ColNo( KLexiconIdCol ); + TDbColNo modelbankid_col= columns->ColNo( KModelBankIdCol ); + // Cleanup column set + delete columns; + + // Retrieve the current row + aView.GetL(); + aContext.SetContextId( aView.ColUint32( contextid_col ) ); + aContext.SetGlobal( aView.ColUint32( global_col ) ); + aContext.SetGrammarId( aView.ColUint32( grammarid_col ) ); + aContext.SetLexiconId( aView.ColUint32( lexiconid_col ) ); + aContext.SetModelBankId( aView.ColUint32( modelbankid_col ) ); + aContext.SetNameL( aView.ColDes( name_col ) ); + } + +// ----------------------------------------------------------------------------- +// CNssVasDb::FillTagListArrayL +// Creates a TNssTag from context, speech item and RRD information. +// Adds a tag to aTagList. +// ----------------------------------------------------------------------------- +// +void CNssVasDb::FillTagListArrayL( CArrayPtrFlat& aTagList, CNssContext* aContext, + CNssSpeechItem* aSpeechItem, CNssRRD* aRRD ) + { + CNssContext* contextCopy = aContext->CopyL(); + CNssSpeechItem* speechItenCopy = aSpeechItem->CopyL( contextCopy ); + CNssRRD* rrdCopy = aRRD->CopyL(); + CNssTag* tag = new (ELeave) CNssTag( contextCopy, rrdCopy, speechItenCopy ); + tag->SetTagId( aSpeechItem->TagId() ); + + aTagList.AppendL( tag ); + } + +// ----------------------------------------------------------------------------- +// CNssVasDb::FillContextListArrayL +// Utility function to read contexts from DB to memory. Earlier, the caller has +// run an SQL query and the matches are listed in an RDbView. +// ----------------------------------------------------------------------------- +// +void CNssVasDb::FillContextListArrayL( RDbView& aView, CArrayPtrFlat& aContextList ) + { + RUBY_DEBUG_BLOCK("CNssVasDb::FillContextListArrayL"); + TInt pos( 0 ); + + // Clear the previous array. + aContextList.Reset(); + + // Get column set + CDbColSet* columns = aView.ColSetL(); + + // Get column ordinals + TDbColNo name_col = columns->ColNo( KNameCol ); + TDbColNo global_col = columns->ColNo( KGlobalCol ); + TDbColNo grammarid_col = columns->ColNo( KGrammarIdCol ); + TDbColNo lexiconid_col = columns->ColNo( KLexiconIdCol ); + TDbColNo modelbankid_col= columns->ColNo( KModelBankIdCol ); + TDbColNo contextid_col = columns->ColNo( KContextIdCol ); + + // New in 2.8 + TDbColNo clientdata_col = columns->ColNo( KClientDataCol ); + + delete columns; + + for (aView.FirstL(); aView.AtRow(); aView.NextL()) + { + aView.GetL(); // Retrieve the current row - actually reads the row from the database. + + CNssContext* oneContext = iContextBuilder.CreateContextL(); + CleanupStack::PushL( oneContext ); + + oneContext->SetNameL( aView.ColDes( name_col ) ); + oneContext->SetGlobal( aView.ColUint32( global_col ) ); + oneContext->SetContextId( aView.ColUint32( contextid_col ) ); + oneContext->SetLexiconId( aView.ColUint32( lexiconid_col ) ); + oneContext->SetGrammarId( aView.ColUint32( grammarid_col ) ); + oneContext->SetModelBankId( aView.ColUint32( modelbankid_col ) ); + oneContext->SetClientData( aView.ColDes8( clientdata_col ) ); + + // Now add the context object to the list (array) of context. + aContextList.InsertL( pos++, oneContext ); + + // Copy has been created in aContextList, no need for pointer anymore + CleanupStack::Pop( oneContext ); + } +} + +// ----------------------------------------------------------------------------- +// CNssVasDb::StartTransactionL +// Starts a new transaction. +// ----------------------------------------------------------------------------- +// +TInt CNssVasDb::StartTransaction() + { + RUBY_DEBUG0( "CNssVasDb::StartTransaction" ); + + if ( !iClientHasOpenedDatabase ) + { + RUBY_DEBUG0( "No open DB. E.g. backup/restore in progress" ); + return KErrNotReady; + } + + __ASSERT_DEBUG( iLocked == iDatabase.InTransaction(), User::Panic( KVasDbPanic, __LINE__ ) ); + + iCriticalSection.Wait(); + if ( iLocked ) + { + // If we already have the lock, no need to take it again + RUBY_DEBUG0( "CNssVasDb::StartTransaction DB is already locked by current process" ); + return KErrNone; + } + + // Wait for the mutex so that two processes don't try get the lock simultaneously + RUBY_DEBUG0( "Waiting for mutex in CNssVasDb::StartTransaction" ); + iMutex.Wait(); + + // check if backup is ongoing + + TInt readLockErr = iDatabase.Begin(); + + // Mutex should make it sure that we have exclusive lock to Database + // Thus iDatabase.Begin() should succeed every time + __ASSERT_DEBUG( readLockErr == KErrNone, User::Panic( KVasDbPanic, __LINE__ ) ); + + if ( readLockErr == KErrNone ) + { + iLocked = ETrue; + } + + RUBY_DEBUG0( "CNssVasDb::StartTransaction completed" ); + + return readLockErr; + } + +// ----------------------------------------------------------------------------- +// CNssVasDb::CommitTransaction +// Commits changes and releases the lock. If iShouldBeLocked flag is set, +// opens a new tranaction in order to keep the database locked. +// ----------------------------------------------------------------------------- +// +TInt CNssVasDb::CommitTransaction( TBool aCompact ) + { + RUBY_DEBUG0( "CNssVasDb::CommitTransaction" ); + + __ASSERT_DEBUG( iLocked == iDatabase.InTransaction(), User::Panic( KVasDbPanic, __LINE__ ) ); + //__ASSERT_DEBUG( iLocked, User::Panic( _L("VasCNssVasDb.cpp"), __LINE__ ) ); + + TInt ret = KErrNone; + + if ( iLocked ) + { + ret = iDatabase.Commit(); + + if ( iDatabase.IsDamaged() ) + { + RUBY_DEBUG0( "CNssVasDb::CommitTransaction Recovering" ); + ret = iDatabase.Recover(); + } + + if ( aCompact ) + { + RUBY_DEBUG0( "CNssVasDb::CommitTransaction compacting DB" ); + iDatabase.Compact(); + } + + iLocked = EFalse; + + RUBY_DEBUG0( "Signalling mutex in CNssVasDb::CommitTransaction" ); + iMutex.Signal(); + } + else + { + RUBY_DEBUG0( "ERROR: CNssVasDb::CommitTransaction does nothing, not locked" ); + } + + iCriticalSection.Signal(); + return( ret ); + } + +// ----------------------------------------------------------------------------- +// CNssVasDb::RollbackTransaction +// Discards changes and releases the lock. +// ----------------------------------------------------------------------------- +// +TInt CNssVasDb::RollbackTransaction() + { + __ASSERT_DEBUG( iLocked == iDatabase.InTransaction(), User::Panic( KVasDbPanic, __LINE__ ) ); + __ASSERT_DEBUG( iLocked, User::Panic( KVasDbPanic, __LINE__ ) ); + + TInt ret = KErrNone; + + iDatabase.Rollback(); + + iLocked = EFalse; + + if ( iDatabase.IsDamaged() ) + { + RUBY_DEBUG0( "CNssVasDb::RollbackTransaction Recovering" ); + ret = iDatabase.Recover(); + } + + + RUBY_DEBUG0( "Signalling mutex in CNssVasDb::RollbackTransaction" ); + iMutex.Signal(); + iCriticalSection.Signal(); + + return( ret ); + } + + +// ----------------------------------------------------------------------------- +// CNssVasDb::LockTransactionsL +// Permit transactions and release database +// ----------------------------------------------------------------------------- +// +void CNssVasDb::LockTransactionsL() + { + // lock transactions + RUBY_DEBUG_BLOCK( "CNssVasDb::LockTransactionsL" ); + + iCriticalSection.Wait(); // wait until a possible transaction ends + + // release a database + CloseDatabase(); + } + +// ----------------------------------------------------------------------------- +// CNssVasDb::UnlockTransactionsL +// Allow transactions and reserve database +// ----------------------------------------------------------------------------- +// +void CNssVasDb::UnlockTransactionsL() + { + // unlock transactions + RUBY_DEBUG_BLOCK( "CNssVasDb::UnlockTransactionsL" ); + OpenDatabaseL(); // open database + + if ( iCriticalSection.IsBlocked() ) + { + iCriticalSection.Signal(); // allow to do transactions + } + } + +// ----------------------------------------------------------------------------- +// CNssVasDb::ReserveDiskSpaceL( +// Reserves disk space. Leaves (KErrDiskFull), if not +// enough space. +// ----------------------------------------------------------------------------- +// +void CNssVasDb::ReserveDiskSpaceL( TInt aRequestSize ) + { + RUBY_DEBUG_BLOCK( "CNssVasDb::ReserveDiskSpaceL" ); + +#ifdef _DEBUG + TInt error = iDbSession.ReserveDriveSpace( iDrive, aRequestSize ); + if ( error ) + { + RUBY_DEBUG1( "CNssVasDb::ReserveDiskSpaceL fails %d", error ); + User::Leave( error ); + } +#else + User::LeaveIfError( iDbSession.ReserveDriveSpace( iDrive, aRequestSize ) ); +#endif // _DEBUG + } + + +// ----------------------------------------------------------------------------- +// CNssVasDb::ReleaseDiskSpace +// Releases the disk space +// ----------------------------------------------------------------------------- +// +void CNssVasDb::ReleaseDiskSpace() + { + RUBY_DEBUG0( "CNssVasDb::ReleaseDiskSpace" ); + iDbSession.FreeReservedSpace( iDrive ); + } + +// ----------------------------------------------------------------------------- +// CNssVasDb::CreateRollbackItemLC +// Creates a cleanup item and pushes it to the cleanup stack. In case of a +// leave, PopAndDestroying this item will call RollbackCleanupFunction +// ----------------------------------------------------------------------------- +void CNssVasDb::CreatePushRollbackItemLC() + { + TCleanupItem item( RollbackCleanupFunction, this ); + CleanupStack::PushL( item ); + } + +// End of file