srsf/sisrscontrollerplugin/src/sigrammardb.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-2007 Nokia Corporation and/or its subsidiary(-ies). 
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of "Eclipse Public License v1.0"
* which accompanies this distribution, and is available
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
*
* Initial Contributors:
* Nokia Corporation - initial contribution.
*
* Contributors:
*
* Description:  This class handles the storage and access of speaker independent
*               grammars.  It is also responsible for allocating memory when
*               loading grammars into the recognizer.
*
*/


// INCLUDE FILES
#include "sigrammardb.h"
#include "rubydebug.h"

// ============================ MEMBER FUNCTIONS ===============================

// -----------------------------------------------------------------------------
// CSIGrammarDB::CSIGrammarDB
// C++ default constructor can NOT contain any code, that
// might leave.
// -----------------------------------------------------------------------------
//
CSIGrammarDB::CSIGrammarDB( RDbNamedDatabase& aDatabase, 
                            RDbs& aDbSession,
                            TInt aDrive )
: CSICommonDB(aDatabase, aDbSession, aDrive )
    {
    // Nothing
    }

// -----------------------------------------------------------------------------
// CSIGrammarDB::ConstructL
// Symbian 2nd phase constructor can leave.
// -----------------------------------------------------------------------------
//
void CSIGrammarDB::ConstructL()
    {
    // Nothing
    }

// -----------------------------------------------------------------------------
// CSIGrammarDB::NewL
// Two-phased constructor.
// -----------------------------------------------------------------------------
//
CSIGrammarDB* CSIGrammarDB::NewL( RDbNamedDatabase& aDatabase, 
                                  RDbs& aDbSession,
                                  TInt aDrive )
    {
    RUBY_DEBUG_BLOCK( "CSIGrammarDB::NewL" );
    
    CSIGrammarDB* self 
        = new( ELeave ) CSIGrammarDB( aDatabase, aDbSession, aDrive );
    CleanupStack::PushL( self );
    self->ConstructL();
    CleanupStack::Pop( self );	
    return self;
    }
  
// -----------------------------------------------------------------------------
// CSIGrammarDB::~CSIGrammarDB
// Destructor
// -----------------------------------------------------------------------------
//
CSIGrammarDB::~CSIGrammarDB()
    {
    RUBY_DEBUG0( "CSIGrammarDB::~CSIGrammarDB" );
	// Delete all elements of the array before deleting the array
	iGrammarArray.ResetAndDestroy();
	iGrammarArray.Close();	
    }

// -----------------------------------------------------------------------------
// CSIGrammarDB::CreateGrammarL
// Creates a new grammar  in the database.
// -----------------------------------------------------------------------------
//
TSIGrammarID CSIGrammarDB::CreateGrammarL( TUid aClientUid )
    {
    RUBY_DEBUG_BLOCK( "CSIGrammarDB::CreateGrammarL" );

    User::LeaveIfError( iDbSession.ReserveDriveSpace( iDrive, sizeof( CSIGrammar ) ) );
	
	TSIGrammarID grammarID = STATIC_CAST(TSIGrammarID,CreateNewIDL(KGrammarIdTable, KGrammarIdColumn, aClientUid));
	// Construct the table name using the new grammar ID
	TBuf<40> KGrammarName( KSIGrammarTable );
    KGrammarName.AppendNumUC( grammarID );
    RUBY_DEBUG1( "CSIGrammarDB::CreateGrammarL grammar ID: %i", grammarID );
	
	// Create a table definition
	CDbColSet* columns = CDbColSet::NewLC();
	
	// add the columns  
	// 1) Binary data, 2) binary data size
	columns->AddL( TDbCol( KBinaryGrammarColumn, EDbColLongBinary ) );
	columns->AddL( TDbCol( KBinaryGrammarColumnSize, EDbColUint32 ) );
	
	// Create a table
	TInt err =iDb.CreateTable( KGrammarName, *columns );
	
	if ( err != KErrNone )
	    {
		// Failed to create the table.
		// Need to release the new grammar ID and leave.
		ReleaseIdL( KGrammarIdTable, KGrammarIdColumn, grammarID );
		User::Leave( err );
	    }

	// Cleanup the column set
	CleanupStack::PopAndDestroy( columns );
	
	// Construct the table name using the provided grammar ID
	// Declare a literal string to hold the SQL statement
	// SELECT KBinaryGrammarColumn , KBinaryGrammarColumn FROM  KGrammarName
 	_LIT(KSQLSelect1,"select  ");	
	_LIT(KSQLSelect2," from  ");		
	TBuf<120> KSQLStatement;		
	KSQLStatement.Append(KSQLSelect1  );	
	KSQLStatement.Append(KBinaryGrammarColumn );
	KSQLStatement.Append(KNext);
	KSQLStatement.Append(KBinaryGrammarColumnSize );	
	KSQLStatement.Append(KSQLSelect2  );
	KSQLStatement.Append(KGrammarName); 
	
	// Create a view on the database
	RDbView view;
	User::LeaveIfError(view.Prepare(iDb,TDbQuery(KSQLStatement,EDbCompareNormal)));
	User::LeaveIfError(view.EvaluateAll());
	
	// Get the structure of rowset
	CDbColSet* colSet = view.ColSetL(); 
 	// Insert a row
	view.InsertL();
	view.PutL();
 	// Close the view
	view.Close();
	delete colSet; 

	// Put a empty grammar into the database
	CSICompiledGrammar *aSICompiledGrammar=CSICompiledGrammar::NewL(grammarID);
 	CleanupStack::PushL(aSICompiledGrammar);
	UpdateGrammarL(aClientUid,aSICompiledGrammar);
	CleanupStack::PopAndDestroy(aSICompiledGrammar);

    iDbSession.FreeReservedSpace( iDrive );

 	return grammarID;
    } 

// -----------------------------------------------------------------------------
// CSIGrammarDB::UpdateGrammarL
// Inserts the externalized SI compiled grammar  into the specified grammar table.
// Save the grammar into the database
// -----------------------------------------------------------------------------
//
void CSIGrammarDB::UpdateGrammarL( TUid aClientUid, 
                                   CSICompiledGrammar *aSICompiledGrammar )
    {
	RUBY_DEBUG_BLOCK( "CSIGrammarDB::UpdateGrammarL" );

	// verify ownership 
	TSIGrammarID aGrammarID=aSICompiledGrammar->GrammarID();
	VerifyOwnershipL(aClientUid, KGrammarIdTable, KGrammarIndex, aGrammarID);
	
	// Construct the table name using the provided grammar ID
	// Declare a literal string to hold the SQL statement
	// SELECT KBinaryGrammarColumn , KBinaryGrammarColumn FROM  KGrammarName
	TBuf<40> KGrammarName(KSIGrammarTable);
    KGrammarName.AppendNumUC(aGrammarID);	
	_LIT(KSQLSelect1,"select  ");	
	_LIT(KSQLSelect2," from  ");		
	TBuf<120> KSQLStatement;		
	KSQLStatement.Append(KSQLSelect1  );	
	KSQLStatement.Append(KBinaryGrammarColumn );
	KSQLStatement.Append(KNext);
	KSQLStatement.Append(KBinaryGrammarColumnSize );	
	KSQLStatement.Append(KSQLSelect2  );
	KSQLStatement.Append(KGrammarName); 
	
	// Create a view on the database
	RDbView view;
	User::LeaveIfError( view.Prepare( iDb, TDbQuery( KSQLStatement,EDbCompareNormal ) ) );
	User::LeaveIfError( view.EvaluateAll() );
	CleanupClosePushL( view );
	
	// Get the structure of rowset
	CDbColSet* colSet = view.ColSetL();
	CleanupStack::PushL( colSet );
	view.FirstL(); 
	view.UpdateL();
  
	// Externalize a compiled grammar
	CBufFlat* dataCopyBuffer = CBufFlat::NewL( 100 ); // 100 = expand 100 bytes
    CleanupStack::PushL( dataCopyBuffer );              // when the buffer is full
 	RBufWriteStream stream;
	stream.Open( *dataCopyBuffer );
    CleanupClosePushL( stream );
	aSICompiledGrammar->ExternalizeL( stream );
	CleanupStack::PopAndDestroy( &stream );
	
	TPtr8 aWriteBuf( dataCopyBuffer->Ptr( 0 ) );
	TInt BufSize = aWriteBuf.Size();
	
	// add binary buffer by Using the stream  
	RDbColWriteStream out;
	TDbColNo col = colSet->ColNo( KBinaryGrammarColumn ); // Ordinal position of long column	
	out.OpenLC( view, col );
	out.WriteL( aWriteBuf );	
	out.Close();	
	CleanupStack::PopAndDestroy(); // out

	// add  size of the buffer
	col = colSet->ColNo( KBinaryGrammarColumnSize ); // Ordinal position of  size	
	view.SetColL( col, BufSize ); 	
	view.PutL();
 
	CleanupStack::PopAndDestroy( dataCopyBuffer );
	CleanupStack::PopAndDestroy( colSet );

	// close the view
	CleanupStack::PopAndDestroy( &view ); // Close view
    }


// -----------------------------------------------------------------------------
// CSIGrammarDB::FindGrammarL
// Find a grammar from loaded grammar array
// -----------------------------------------------------------------------------
CSICompiledGrammar*  CSIGrammarDB::FindGrammarL(TSIGrammarID aGrammarID) 
    {
    RUBY_DEBUG_BLOCK( "CSIGrammarDB::FindGrammarL" );
    
    TInt i(0);
    CSICompiledGrammar* aGrammar=NULL;
    
    // Check if grammar already loaded
    for ( i = 0; i < iGrammarArray.Count(); i++ )
        {
        if ( iGrammarArray[i]->GrammarID()==aGrammarID  )
            { 
            aGrammar=iGrammarArray[i];
            break;
            }		
        }
    // Can not found in the loaded grammar array
    if(i==iGrammarArray.Count())
        User::Leave(KErrNotFound);
    
    return aGrammar;
    }

// -----------------------------------------------------------------------------
// CSIGrammarDB::GetNewID
// Get a new uniq ID 
// -----------------------------------------------------------------------------
TInt CSIGrammarDB::GetNewID( RArray<TSIRuleID>& aMyIds )
    {
    RArray<TSIRuleID> myIDs = aMyIds;
    TInt Count = myIDs.Count();
    TInt id = 0;
    if ( Count == 0 )
        {
        id = 1; // empty ,first id will be 1
        }
    else
        { 
        // Find a unique  ID
        myIDs.SortUnsigned();
        id = myIDs[myIDs.Count() - 1] + 1; //by default , the last one 
        for ( TInt i = 0; i < myIDs.Count(); i++ )
            {
            TInt index = i + 1; 
            TInt s = myIDs[i];
            if ( s > index )
                {
                id = index;
                break;
                }
            }
        }
    return id;
    }

// -----------------------------------------------------------------------------
// CSIGrammarDB::CreateRuleL
// Creates a new empty rule.
// -----------------------------------------------------------------------------
void CSIGrammarDB::CreateRuleL( TUid aClientUid, TSIGrammarID aGrammarID, 
                                TSIRuleID& aRuleID )
    {
    RUBY_DEBUG_BLOCK( "CSIGrammarDB::CreateRuleL" );

    //__UHEAP_MARK;
    VerifyOwnershipL( aClientUid, KGrammarIdTable, KGrammarIndex, aGrammarID );
    // find the grammar from the database 
    CSICompiledGrammar* aGrammar = (CSICompiledGrammar*) GrammarL( aGrammarID );
    CleanupStack::PushL( aGrammar );
    
    TInt aID = 0;
    TInt Count=aGrammar->Count();
    
    // existing myRuleVariantID
    RArray<TSIRuleID> myIDs;
    myIDs.Reset();
    for(TInt i = 0; i < Count; i++ )
        {
        CSIRule* aRule = &( aGrammar->AtL( i ) );
        myIDs.Append( aRule->RuleID() );
        } 
    
    // Find a uniq new id 
    aID=GetNewID( myIDs );
    myIDs.Close();
    aRuleID=aID;
    
    // add the rule to the grammar	
    CSIRule* rule = CSIRule::NewL( aRuleID );
    CleanupStack::PushL( rule );	
    aGrammar->AddL( rule );
    CleanupStack::Pop( rule );
    
    UpdateGrammarL( aClientUid, aGrammar );
    CleanupStack::PopAndDestroy( aGrammar );
    //__UHEAP_MARKEND;
    } 

// -----------------------------------------------------------------------------
// CSIGrammarDB::AddRuleVariantL
// Add Rule Variant to the array that hold the grammar array
// -----------------------------------------------------------------------------
void CSIGrammarDB::AddRuleVariantL(TUid aClientUid,
								   TSIGrammarID aGrammarID, 								 
								   TSILexiconID aLexiconID,
								   const RArray<TSIPronunciationID>& aPronunciationIDs, 								     
								   TSIRuleID aRuleID,
								   TSIRuleVariantID& aRuleVariantID) 
    {
    VerifyOwnershipL(aClientUid, KGrammarIdTable, KGrammarIndex, aGrammarID);
    
    CSICompiledGrammar* aGrammar=(CSICompiledGrammar*)GrammarL(aGrammarID);
    CleanupStack::PushL(aGrammar);
    
    CSIRule* aRule=&(aGrammar->RuleL(aRuleID));
    // existing myRuleVariantID
    RArray<TSIRuleID> myID;
    myID.Reset();
    for( TInt i = 0; i < aRule->Count(); i++ )
        {
        CSIRuleVariant* aRuleVariant=&(aRule->AtL(i));
        myID.Append(aRuleVariant->RuleVariantID());
        }
    
    // Find a uniq new id 
    aRuleVariantID=STATIC_CAST(TSIRuleVariantID,GetNewID(myID));
    myID.Close();	
    
    // add the rule variant to the rule
    CSIRuleVariant* ruleVariant = CSIRuleVariant::NewL( aRuleVariantID, aLexiconID );
    CleanupStack::PushL( ruleVariant );	
    ruleVariant->SetPronunciationIDsL(aPronunciationIDs);
    aRule->AddL( ruleVariant );
    CleanupStack::Pop( ruleVariant );
    UpdateGrammarL( aClientUid, aGrammar );
    CleanupStack::PopAndDestroy( aGrammar );	  
    }

// -----------------------------------------------------------------------------
// CSIGrammarDB::LoadGrammarL
// Loads all rules within the specified grammar into a grammar object, which
// is loaded into recognizer during recognition session.
// Note : Will leave if already loaded
// -----------------------------------------------------------------------------
//
const CSICompiledGrammar* CSIGrammarDB::LoadGrammarL( TSIGrammarID aGrammarID )
    {
    // Construct the table name using the provided grammar ID
    // Construct the table name using the provided grammar ID
    // Declare a literal string to hold the SQL statement
    // SELECT KBinaryGrammarColumn , KBinaryGrammarColumn FROM  KGrammarName
    TBuf<40> KGrammarName(KSIGrammarTable);
    KGrammarName.AppendNumUC(aGrammarID);
    
    // Create newGrammar object	
    CSICompiledGrammar* grammar = CSICompiledGrammar::NewLC( aGrammarID );	
    _LIT(KSQLSelect1,"select  ");	
    _LIT(KSQLSelect2," from  ");
    TBuf<120> KSQLStatement;		
    KSQLStatement.Append(KSQLSelect1  );		
    KSQLStatement.Append(KBinaryGrammarColumn );
    KSQLStatement.Append(KNext);
    KSQLStatement.Append(KBinaryGrammarColumnSize );
    KSQLStatement.Append(KSQLSelect2  );
    KSQLStatement.Append(KGrammarName); 
    
    // create a view on the database
    RDbView view;
    CleanupClosePushL( view );
    
    User::LeaveIfError(view.Prepare(iDb,TDbQuery(KSQLStatement,EDbCompareNormal)));
    User::LeaveIfError(view.EvaluateAll());
    
    // Get the structure of the rowset 
    CDbColSet* colSet = view.ColSetL();
    CleanupStack::PushL( colSet );
    
    // iterate across the row set, one row only
    for (view.FirstL();view.AtRow();view.NextL())
        {
        
        // retrieve the row
        view.GetL();		
        
        // first retrieve the size of binary package 
        TDbColNo col = colSet->ColNo(KBinaryGrammarColumnSize); // Ordinal position of long column 
        TInt32 size = view.ColUint32( col);
        
        TUint8* buf = new (ELeave) TUint8[size];		
        CleanupStack::PushL( buf);			
        TPtr8 readBuf( buf, size, size);
        CBufFlat* dataCopyBuffer = CBufFlat::NewL( 100 ); // 100 = expand 100 bytes
        CleanupStack::PushL(dataCopyBuffer);              // when the buffer is full
        
        RBufReadStream stream;
        CleanupClosePushL( stream );
        stream.Open(*dataCopyBuffer);
        
        // and a stream for long columns
        RDbColReadStream in;
        CleanupClosePushL( in );
        col = colSet->ColNo(KBinaryGrammarColumn); // Ordinal position of long column 
        
        
        in.OpenLC(view, col);
        in.ReadL( readBuf, view.ColLength(col));
        dataCopyBuffer->InsertL(0,readBuf);
        grammar->InternalizeL( stream );
        
        CleanupStack::PopAndDestroy( col );
        CleanupStack::PopAndDestroy( &in );
        CleanupStack::PopAndDestroy( &stream ); 
        CleanupStack::PopAndDestroy( dataCopyBuffer );
        CleanupStack::PopAndDestroy( buf );
        } 
        
    CleanupStack::PopAndDestroy( colSet );
    CleanupStack::PopAndDestroy( &view );
    
    // Keep the reference of the grammar object
    User::LeaveIfError(iGrammarArray.Append(grammar));
    // Cleanup grammar
    CleanupStack::Pop(grammar );
    return grammar;
    }

// -----------------------------------------------------------------------------
// CSIGrammarDB::GrammarL
// Loads all rules within the specified grammar into a grammar object, which
// is loaded into recognizer during recognition session.
// Note : Will leave if already loaded
// -----------------------------------------------------------------------------
//
const CSICompiledGrammar* CSIGrammarDB::GrammarL( TSIGrammarID aGrammarID )
    {
 	  
    // Construct the table name using the provided grammar ID
    // Construct the table name using the provided grammar ID
    // Declare a literal string to hold the SQL statement
    // SELECT KBinaryGrammarColumn , KBinaryGrammarColumn FROM  KGrammarName
    TBuf<40> KGrammarName(KSIGrammarTable);
    KGrammarName.AppendNumUC(aGrammarID);
    // Create newGrammar object	 
    CSICompiledGrammar* aGrammar = CSICompiledGrammar::NewLC( aGrammarID );
    _LIT(KSQLSelect1,"select  ");
    _LIT(KSQLSelect2," from  ");
    
    TBuf<120> KSQLStatement;		
    KSQLStatement.Append(KSQLSelect1  );		
    KSQLStatement.Append(KBinaryGrammarColumn );
    KSQLStatement.Append(KNext);
    KSQLStatement.Append(KBinaryGrammarColumnSize );
    KSQLStatement.Append(KSQLSelect2  );
    KSQLStatement.Append(KGrammarName); 
    
    // create a view on the database
    RDbView view;
    User::LeaveIfError(view.Prepare(iDb,TDbQuery(KSQLStatement,EDbCompareNormal)));
    
    User::LeaveIfError(view.EvaluateAll());
    
    // Get the structure of the rowset 
    CDbColSet* colSet = view.ColSetL();
    
    // iterate across the row set, one row only
    for (view.FirstL();view.AtRow();view.NextL())
        {
        
        // retrieve the row
        view.GetL();
        
        // first retrieve the size of binary package 
        TDbColNo col = colSet->ColNo(KBinaryGrammarColumnSize); // Ordinal position of long column 
        TInt32 Size = view.ColUint32( col);
        
        TUint8* aBuf = new (ELeave) TUint8[Size];		
        CleanupStack::PushL(aBuf);			
        TPtr8 aReadBuf(aBuf, Size, Size);
        CBufFlat* dataCopyBuffer = CBufFlat::NewL( 100 ); // 100 = expand 100 bytes
        CleanupStack::PushL(dataCopyBuffer);              // when the buffer is full
        
        RBufReadStream stream;
        stream.Open(*dataCopyBuffer);
        
        // and a stream for long columns
        RDbColReadStream in;
        col = colSet->ColNo(KBinaryGrammarColumn); // Ordinal position of long column 
        
        
        in.OpenLC(view, col);
        in.ReadL(aReadBuf, view.ColLength(col));
        dataCopyBuffer->InsertL(0,aReadBuf);
        aGrammar->InternalizeL( stream );
        
        in.Close(); 		
        CleanupStack::PopAndDestroy(3); // in dataCopyBuffer aBuf
        }
    //! clean the memory
    delete colSet;
    view.Close();  
    
    // Keep the reference of the grammar object
    // Cleanup grammar
    CleanupStack::Pop( aGrammar );
    
    return aGrammar;
    }

// -----------------------------------------------------------------------------
// CSIGrammarDB::CreateIDTableL
// Creates a new grammar ID table in the database.
// -----------------------------------------------------------------------------
//
void CSIGrammarDB::CreateIDTableL()
    {
    // Invoke function in the base class CSICommonDB.
    CSICommonDB::CreateIDTableL(KGrammarIdTable, KGrammarIdColumn, KGrammarIndex);
    }

// -----------------------------------------------------------------------------
// CSIGrammarDB::GetAllClientGrammarIDsL
// This function returns all grammar IDs owned by the specified client.
// -----------------------------------------------------------------------------
//
void CSIGrammarDB::GetAllClientGrammarIDsL( TUid aClientUid,
                                            RArray<TSIGrammarID>& aGrammarIDs )
    {
    RArray<TUint32> ix; 
    ix.Reset();	
    GetAllClientIDsL(KGrammarIdTable, KGrammarIdColumn, aClientUid, ix);
    for(TInt i=0;i<ix.Count();i++) {
        aGrammarIDs.Append(STATIC_CAST(TSIGrammarID,ix[i]));
        }
    ix.Close();
    }

// -----------------------------------------------------------------------------
// CSIGrammarDB::GetAllGrammarIDsL
// This function returns all grammar IDs in the database.
// -----------------------------------------------------------------------------
//
void CSIGrammarDB::GetAllGrammarIDsL( RArray<TSIGrammarID>& aGrammarIDs )
    {
    // This is a hack to get the id aligned to 4-byte boundary,
    // for some reason this does not happen in winscw build if 
    // TSIGrammarID is taken from stack.
    TSIGrammarID* id = new (ELeave) TSIGrammarID;
    
    CleanupStack::PushL( id );
    
    RArray<TUint32> ix;
    //! Reset
    ix.Reset(); 
    GetAllIDsL(KGrammarIdTable, KGrammarIdColumn,  ix);
    for(TInt i=0;i<ix.Count();i++) 
        {
        *id = STATIC_CAST( TSIGrammarID, ix[i] );
        aGrammarIDs.Append( *id );
        }
    ix.Close();
    CleanupStack::PopAndDestroy( id );
    }

// -----------------------------------------------------------------------------
// CSIGrammarDB::GetAllRuleIDsL
// This function returns all rule IDs within the specified grammar.
// grammar have to be loaded 
// -----------------------------------------------------------------------------
//
void CSIGrammarDB::GetAllRuleIDsL( TSIGrammarID aGrammarID,
                                   RArray<TSIRuleID>& aRuleIDs )
    {
	CleanupClosePushL( aRuleIDs );
	
    // Construct the table name using the provided grammar ID
    TBuf<40> KGrammarName(KSIGrammarTable);
    KGrammarName.AppendNumUC(aGrammarID);
    
    CSICompiledGrammar* newgrammar =( CSICompiledGrammar* )GrammarL( aGrammarID) ;// Load the grammar from database	
    CleanupStack::PushL(newgrammar);
    TSIRuleID	RuleId;
    
    for (TInt  i=0;i<newgrammar->Count();i++) {
        CSIRule* aRule=&(newgrammar->AtL(i));
        RuleId=aRule->RuleID();		
        User::LeaveIfError(aRuleIDs.Append(RuleId));
        } 
    CleanupStack::PopAndDestroy(newgrammar);
    CleanupStack::Pop();
    }

// -----------------------------------------------------------------------------
// CSIGrammarDB::RemoveGrammarL
// Deletes a grammar table from the database.
// -----------------------------------------------------------------------------
//
void CSIGrammarDB::RemoveGrammarL( TUid aClientUid,
                                   TSIGrammarID aGrammarID )
    {
    VerifyOwnershipL(aClientUid, KGrammarIdTable, KGrammarIndex, aGrammarID);
    
    TInt diskSpace = ( RuleCountL(aGrammarID) * sizeof( CSIRule) ) 
        + sizeof( CSIGrammar );
    User::LeaveIfError( iDbSession.ReserveDriveSpace( iDrive, diskSpace ) );
    
    // Construct the table name using the provided grammar ID
    TBuf<40> KGrammarName(KSIGrammarTable);
    KGrammarName.AppendNumUC(aGrammarID);
    
    TBuf<50> KSQLStatement;
    // Declare a literal string to hold the SQL statement
    // DROP TABLE KGrammarName
    _LIT(KSQLDelete1, "DROP TABLE ");
    
    KSQLStatement = KSQLDelete1;
    KSQLStatement.Append(KGrammarName);
    
    User::LeaveIfError(iDb.Execute(KSQLStatement));
    
    // Release the grammar ID
    ReleaseIdL(KGrammarIdTable, KGrammarIdColumn, aGrammarID);
    
    // Cancel free disk space request
    iDbSession.FreeReservedSpace( iDrive );
    }

// -----------------------------------------------------------------------------
// CSIGrammarDB::RuleCountL
// Returns the number of rules in the specified grammar.
// Grammar have to be loaded
// -----------------------------------------------------------------------------
//
TInt CSIGrammarDB::RuleCountL( TSIGrammarID aGrammarID )
    {
    // Load a grammar
    CSICompiledGrammar* aGrammar=(CSICompiledGrammar*)GrammarL(aGrammarID);
    CleanupStack::PushL(aGrammar);  
    // Count the number of the rules inside the grammar
    TInt RuleCount=aGrammar->Count();	 
    CleanupStack::PopAndDestroy(aGrammar);
    return RuleCount;
    }

// -----------------------------------------------------------------------------
// CSIGrammarDB::RemoveRuleL
// Deletes Rule from the database.
// Grammar have to be loaded
// -----------------------------------------------------------------------------
//  
void CSIGrammarDB::RemoveRuleL( TUid aClientUid, 
                                TSIGrammarID aGrammarID,
                                TSIRuleID aRuleID )
    {
    VerifyOwnershipL(aClientUid, KGrammarIdTable, KGrammarIndex, aGrammarID);
    CSICompiledGrammar* aGrammar=(CSICompiledGrammar*)GrammarL(aGrammarID);	 
    
    CleanupStack::PushL(aGrammar);  
    if (aGrammar->Find(aRuleID)==KErrNotFound)
        {
        User::Leave(KErrNotFound);
        }
    else
        {
        aGrammar->DeleteL(aRuleID);
        }
    UpdateGrammarL(aClientUid,aGrammar);
    CleanupStack::PopAndDestroy(aGrammar);
    }

// -----------------------------------------------------------------------------
// CSIGrammarDB::IsGrammarLoaded
// Checks to see if a valid grammar is loaded into the recognizer.  This is
// useful to check if any rules are still loaded after performing UnloadRule().
// -----------------------------------------------------------------------------
//
TBool CSIGrammarDB::IsGrammarLoaded()
    {
    for ( TInt i = 0; i < iGrammarArray.Count(); i++ )
        {
        if ( iGrammarArray[i]->Count() > 0 )
            {
            // As long as there is still a rule.
            return ETrue;
            }
        }
    return EFalse;
    }

// -----------------------------------------------------------------------------
// CSIGrammarDB::IsRuleValidL
// Checks if the rule is valid or not.
// -----------------------------------------------------------------------------
//
TBool CSIGrammarDB::IsRuleValidL( TSIGrammarID aGrammarID, TSIRuleID aRuleID )
    {
    CSICompiledGrammar* aGrammar=(CSICompiledGrammar*)GrammarL(aGrammarID);
    CleanupStack::PushL(aGrammar);  
    if (aGrammar->Find(aRuleID)==KErrNotFound)
        {
        CleanupStack::PopAndDestroy(aGrammar);
        return EFalse; 
        }
    else {
        CleanupStack::PopAndDestroy(aGrammar);
        return ETrue;	
        }
    }

// -----------------------------------------------------------------------------
// CSIGrammarDB::ResetAndDestroy
// Deallocates the temporary memory containing the grammar object created with
// AllRulesL.
// -----------------------------------------------------------------------------
//
void CSIGrammarDB::ResetAndDestroy()
    {
    iGrammarArray.ResetAndDestroy();
    }

// -----------------------------------------------------------------------------
// CSIGrammarDB::UnloadRule
// Unloads the specified rule from the specified grammar in temporary memory,
// previously loaded with AllRulesL.  The rule in the database remains intact.
// -----------------------------------------------------------------------------
//
void CSIGrammarDB::UnloadRuleL( TSIGrammarID aGrammarID,
                                TSIRuleID aRuleID )
    {
    CSIGrammar* grammar;
    
    for( TInt i = 0; i < iGrammarArray.Count(); i++ )
        {
        grammar = iGrammarArray[i];
        if ( grammar->GrammarID() == aGrammarID )
            {
            grammar->DeleteL(aRuleID);
            return;
            }
        }
    User::Leave(KErrNotFound);
    }

// -----------------------------------------------------------------------------
// CSIGrammarDB::UnloadGrammar
// Unloads  the specified grammar in temporary memory,
// previously loaded with AllRulesL.  The grammar in the database remains intact.
// -----------------------------------------------------------------------------
//
void CSIGrammarDB::UnloadGrammarL( TSIGrammarID aGrammarID)
    {
    CSIGrammar* grammar;
    
    for( TInt i = 0; i < iGrammarArray.Count(); i++ )
        {
        grammar = iGrammarArray[i];
        if ( grammar->GrammarID() == aGrammarID )
            {
            //! delete the object 
            delete iGrammarArray[i];
            // remove the pointer
            iGrammarArray.Remove(i);
            return;
            }
        }
    User::Leave(KErrNotFound);
    }

//  End of File