srsf/nssvasapi/nssvasdb/src/nssvascvasdb.cpp
author Pat Downey <patd@symbian.org>
Wed, 01 Sep 2010 12:29:17 +0100
branchRCL_3
changeset 19 e36f3802f733
permissions -rw-r--r--
Revert incorrect RCL_3 drop: Revision: 201033 Kit: 201035

/*
* 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 <e32test.h>
#include <e32std.h>
#include <e32svr.h>
#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<CNssContext>* 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<CNssContext>* CNssVasDb::GetGlobalContexts()
    {
	RUBY_DEBUG0("CNssVasDb::GetGlobalContexts");
	    
    _LIT( KSQLGetAll,"select * from contexttable ");
    _LIT( KSQLWhereGlobal,"where global=1");

    iSQLStatement = KSQLGetAll;
    iSQLStatement.Append( KSQLWhereGlobal );

    CArrayPtrFlat<CNssContext>* ret( NULL );
    TRAPD( error, ret = GetContextL( iSQLStatement ) );
    if ( error != KErrNone )
        {
        return NULL;
        }
    return ret;
    }

// -----------------------------------------------------------------------------
// CNssVasDb::GetAllContexts
// Reads all contexts from VAS DB.
// -----------------------------------------------------------------------------
//
CArrayPtrFlat<CNssContext>* CNssVasDb::GetAllContexts()
    {   
    RUBY_DEBUG0("CNssVasDb::GetAllContexts");
    
    _LIT( KSQLGetAll,"select * from contexttable ");

    iSQLStatement = KSQLGetAll;

    CArrayPtrFlat<CNssContext>* 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<CNssContext>* 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<CNssContext>* 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<CNssContext>* 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<CNssContext>* contextList = 
            new (ELeave) CArrayPtrFlat<CNssContext>( 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<CNssContext*> ( 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<CNssRRD*>( 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<CNssTag>* aTagArray, RArray<TInt>& 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<TInt> contextIds;
    CleanupClosePushL( contextIds ); // Stack: rollback cleanup, contextIds

    for ( k = 0; k < aTagArray->Count(); k++ )
        {
        CNssTag* tag = (*aTagArray)[k];
        CNssContext* context = static_cast<CNssContext*> ( 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<CNssRRD*>( 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<TUint32>& 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<TNssSpeechItem>& 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<KNssVasDbContextName> 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<CNssContext*> ( aTag->Context() );
	CNssSpeechItem* speechItem = static_cast<CNssSpeechItem*> ( 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; position<aRRD->IntArray()->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<TInt>* intArray = new (ELeave) CArrayFixFlat<TInt>(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<NssRRDText>* textArray = 
                    new (ELeave) CArrayFixFlat<NssRRDText>(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<CNssTag>* 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<CNssTag>* 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<CNssTag>* 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<aGrammarIdRuleIds.Count(); i++)
			{
			if( currGrammarId == aGrammarIdRuleIds[i].iGrammarId )
				{
				if( someGrammarFoundAlready )
					{
					iSQLStatement.Append( KOr );
					}
				else 
					{
					someGrammarFoundAlready = ETrue;
					}
				currRuleId = aGrammarIdRuleIds[i].iRuleId;
				iSQLStatement.Append( KRuleId );
				iSQLStatement.AppendNumUC( currRuleId );	
				}
			}  // for
		iSQLStatement.Append(KFinalBracket);  // closing ruleid ORs
		}  // while
	// Close view
    CleanupStack::PopAndDestroy( &view );
    iSQLStatement.Append( KFinalBracket );
    
    CArrayPtrFlat<CNssTag>* 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<CNssTag>* 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<CNssTag>* tagList = new(ELeave)CArrayPtrFlat<CNssTag>( 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<CNssContext>* 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<CNssTag>* 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<CNssTag>* arr = GetTagListByQueryL( iSQLStatement );

    CommitTransaction( EFalse );

    return arr;
    }

// -----------------------------------------------------------------------------
// CNssVasDb::GetTagL
// Gets all tags from a specified context.
// -----------------------------------------------------------------------------
//
CArrayPtrFlat<CNssTag>* 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<CNssTag>* 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<CNssTag>* 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<CNssTag>* CNssVasDb::GetTagL( TInt aContextId, TInt aNum, TInt aPosition )
    {
  	RDbView     view;
	TUint32     tagId;
	CNssContext* context = iContextBuilder.CreateContextL();
	CleanupStack::PushL( context );

    User::LeaveIfError( StartTransaction() );
    CreatePushRollbackItemLC();

    CArrayPtrFlat<CNssTag>* tagArray = new(ELeave)CArrayPtrFlat<CNssTag>(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<CNssTag>* CNssVasDb::GetTagL( TInt aContextId, 
                                            const TDesC& aText, TInt aPosition )
    {
  	RDbView view;
	TUint32 tagId;
	CNssContext* context = iContextBuilder.CreateContextL();
	CleanupStack::PushL( context );
	
    CArrayPtrFlat<CNssTag>* tagArray = new(ELeave)CArrayPtrFlat<CNssTag>(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<CNssTag>* 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<CNssTag>* 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<CNssContext*> ( aTag.Context() );
    UpdateContextInsideTransactionL( *context );
    CNssSpeechItem* speechItem = static_cast<CNssSpeechItem*>
        ( aTag.SpeechItem() );
    UpdateSpeechItemL( *speechItem );
    CNssRRD* rrd = static_cast<CNssRRD*> ( 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<KSqlStatementmaxLength> 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<CNssTag>& 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<CNssContext>& 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