diff -r 000000000000 -r c53acadfccc6 metadataengine/server/src/mdssqliteconnection.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/metadataengine/server/src/mdssqliteconnection.cpp Mon Jan 18 20:34:07 2010 +0200 @@ -0,0 +1,582 @@ +/* +* Copyright (c) 2002-2009 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: Adaptation layer to SQLite database* +*/ + +// INCLUDE FILES +#include "mdssqliteconnection.h" +#include "mdslogger.h" + +__USES_LOGGER + +CMdSSqLiteConnection* CMdSSqLiteConnection::NewL() + { + CMdSSqLiteConnection* self = CMdSSqLiteConnection::NewLC(); + CleanupStack::Pop( self ); + return self; + } + + +CMdSSqLiteConnection* CMdSSqLiteConnection::NewLC() + { + CMdSSqLiteConnection* self = new ( ELeave ) CMdSSqLiteConnection( ); + CleanupStack::PushL( self ); + self->ConstructL( ); + return self; + } + + +CMdSSqLiteConnection::CMdSSqLiteConnection() + : iDbFileName( NULL ), iEnableTransaction( ETrue ),iNotFinishFindQuery( NULL ) + { + } + + +CMdSSqLiteConnection::~CMdSSqLiteConnection() + { + CloseDb(); + + delete iDbFileName; + + iNotFinishFindQuery = NULL; + } + +void CMdSSqLiteConnection::DeleteDb( TDesC16* aName ) + { + if( aName ) + { + RSqlDatabase::Delete( *aName ); + } + else + { + RSqlDatabase::Delete( KMdsSqlDbDefaultName ); + } + } + +void CMdSSqLiteConnection::CloseDb() + { + iMdeSqlDb.Close(); + } + +void CMdSSqLiteConnection::ConstructL() + { + } + +void CMdSSqLiteConnection::OpenDbL( const TDesC& aDbFileName ) + { + _LIT8( KMdsSqlDbaConfig, "cache_size=10000; page_size=4096; encoding=\"UTF-16\";"); + + TInt err = KErrNone; + + delete iDbFileName; + iDbFileName = NULL; // in case AllocL leaves + iDbFileName = aDbFileName.AllocL(); + + // we need to set up policy, because we use secure database + TSecurityPolicy defaultPolicy(TSecurityPolicy::EAlwaysPass); + RSqlSecurityPolicy sqlSecurityPolicy; + CleanupClosePushL( sqlSecurityPolicy ); + err = sqlSecurityPolicy.Create( defaultPolicy ); + + if ( err != KErrNone ) + { + _LIT( KMdsSecurityCheckFail, "Security check fail" ); + TraceAndLeaveL( KMdsSecurityCheckFail, err ); + } + /** + * Open database: + * First we try to create new db. If this fails check if db already exists and + * try to open it. Otherwise we cannot open it and we leave + */ + err = iMdeSqlDb.Create( *iDbFileName, sqlSecurityPolicy, &KMdsSqlDbaConfig ); + if ( err != KErrNone ) + { + // it could fail because database exists + if ( err == KErrAlreadyExists ) + { + err = iMdeSqlDb.Open( *iDbFileName, &KMdsSqlDbaConfig ); + if ( err != KErrNone ) + { + __LOG1( ELogDb, "Cannot open database %d", err ); + } + } + else + { + __LOG1( ELogDb, "Unknown error while creating %d", err ); + } + + User::LeaveIfError( err ); + } + CleanupStack::PopAndDestroy( &sqlSecurityPolicy ); + } + +TInt CMdSSqLiteConnection::ExecuteL( const TDesC& aCommand, + const RRowData& aVariables, + RMdsStatement* aStatement ) + { + TInt err = KErrNone; + + if ( aVariables.Size() == 0 ) + { + // no variables + err = iMdeSqlDb.Exec( aCommand ); + + if ( err < KErrNone ) + { + _LIT( KMdSExec, "Exec (no variables)" ); + TraceAndLeaveL( KMdSExec, err ); + } + } + else if ( aStatement ) + { + if ( aStatement->iPrepared == EFalse ) + { + err = aStatement->iStatement.Prepare( iMdeSqlDb, aCommand ); + + if ( err < KErrNone ) + { + _LIT( KMdSPrepare, "Prepare" ); + TraceAndLeaveL( KMdSPrepare, err ); + } + aStatement->iPrepared = ETrue; + } + else + { + err = aStatement->iStatement.Reset(); + if ( err < KErrNone ) + { + _LIT( KMdSResume, "Resume" ); + TraceAndLeaveL( KMdSResume, err ); + } + } + + DoBindL( aStatement->iStatement, aVariables ); + err = aStatement->iStatement.Exec(); + + if ( err < KErrNone ) + { + aStatement->iStatement.Reset(); + aStatement->iPrepared = EFalse; + _LIT( KMdSExec, "Exec" ); + TraceAndLeaveL( KMdSExec, err ); + } + } + else + { + RSqlStatement mdeSqlDbStmt; + CleanupClosePushL( mdeSqlDbStmt ); + err = mdeSqlDbStmt.Prepare( iMdeSqlDb, aCommand ); + + if ( err < KErrNone ) + { + _LIT( KMdsPrepare, "Prepare (no statement)" ); + TraceAndLeaveL( KMdsPrepare, err ); + } + + DoBindL( mdeSqlDbStmt, aVariables ); + + err = mdeSqlDbStmt.Exec(); + + if ( err < KErrNone ) + { + _LIT( KMdsExec, "Exec (no statement)" ); + TraceAndLeaveL( KMdsExec, err ); + } + + CleanupStack::PopAndDestroy( &mdeSqlDbStmt ); + } + return err; + } + +void CMdSSqLiteConnection::ExecuteQueryL( const TDesC& aQuery, + RMdsStatement& aStatement, + const RRowData& aVariables ) + { + TInt stmterr; + if ( aStatement.iPrepared == EFalse ) + { + stmterr = aStatement.iStatement.Prepare( iMdeSqlDb, aQuery ); + if ( stmterr != KErrNone ) + { + _LIT( KMdSQueryPrepare, "Query Prepare" ); + TraceAndLeaveL( KMdSQueryPrepare, stmterr ); + } + aStatement.iPrepared = ETrue; + } + else + { + stmterr = aStatement.iStatement.Reset(); + if ( stmterr != KErrNone ) + { + _LIT( KMdSQueryReset, "Query Reset" ); + TraceAndLeaveL( KMdSQueryReset, stmterr ); + } + } + + DoBindL( aStatement.iStatement, aVariables ); + } + +void CMdSSqLiteConnection::DoBindL( RSqlStatement& aStatement, const RRowData& aVariables ) + { + const TInt count( aVariables.Size() ); + for( TInt i=0; i < count; ++i ) + { + switch ( aVariables.Column( i ).Type() ) + { + case EColumnInt32: + { + TInt32 val = 0; + aVariables.Column( i ).Get( val ); + aStatement.BindInt( i, val ); + break; + } + case EColumnUint32: + { + TUint32 val = 0; + aVariables.Column( i ).Get( val ); + aStatement.BindInt64( i, (TInt64)val ); + break; + } + case EColumnBool: + { + TBool val = 0; + aVariables.Column( i ).Get( val ); + aStatement.BindInt( i, val ); + break; + } + case EColumnInt64: + { + TInt64 val = 0; + aVariables.Column( i ).Get( val ); + aStatement.BindInt64( i, val ); + break; + } + case EColumnReal32: + { + TReal32 val = 0; + aVariables.Column( i ).Get( val ); + aStatement.BindReal( i, val ); + break; + } + case EColumnReal64: + { + TReal64 val = 0; + aVariables.Column( i ).Get( val ); + aStatement.BindReal( i, val ); + break; + } + case EColumnTime: + { + TTime val = TInt64(0); + aVariables.Column( i ).Get( val ); + aStatement.BindInt64( i, val.Int64() ); + break; + } + case EColumnDes16: + { + TPtrC16 val = TPtr16((TUint16*)0, 0); //KNullPtr16; + aVariables.Column( i ).Get( val ); + aStatement.BindText( i, val ); + break; + } + case EColumnNotUsed: + // skip this variable + break; + default: +#ifdef _DEBUG + User::Panic( _L( "MdSSCDoB" ), KErrCorrupt ); +#endif + User::Leave( KErrCorrupt ); + } + } + } + +TBool CMdSSqLiteConnection::NextRowL( RMdsStatement& aQuery, RRowData& aRow ) + { + const TInt qerr = aQuery.iStatement.Next(); + if ( qerr == KSqlAtEnd ) + { + return EFalse; + } + else if ( qerr != KSqlAtRow ) + { + _LIT( KMdsQueryNextRow, "Query NextRow" ); + TraceAndLeaveL( KMdsQueryNextRow, qerr ); + } + + // obtain column data into local storage and row data pointer + ColumnsL( aQuery.iStatement, aRow ); + + return ETrue; + } + +void CMdSSqLiteConnection::CurrentRowL( const RMdsStatement& aQuery, RRowData& aRow ) + { + // obtain column data into local storage and row data pointer + if ( EFalse != aQuery.iStatement.AtRow() ) + { + ColumnsL( aQuery.iStatement, aRow ); + } + else + { + _LIT( KMdsNoProcessableRow, "Wrong row to process" ); + TraceAndLeaveL( KMdsNoProcessableRow, KSqlErrNotFound ); + } + } + +void CMdSSqLiteConnection::ColumnsL( const RSqlStatement& aStatement, RRowData& aRow ) + { + const TInt count( aRow.Size() ); + for( TInt i=0; i < count; ++i ) + { + // get data in column, check for type + const TSqlColumnType actual = aStatement.ColumnType( i ); + + if( actual == ESqlNull ) + { + aRow.Column( i ).Set( (const HBufC16*)NULL ); + + continue; + } + + const TColumnDataType coltype = aRow.Column( i ).Type(); + switch ( coltype ) + { + case EColumnBool: + { + TInt valInt = aStatement.ColumnInt( i ); + const TBool valBool = valInt ? ETrue : EFalse; + aRow.Column( i ).Set( valBool ); + break; + } + case EColumnInt32: + { + TInt32 valInt = aStatement.ColumnInt( i ); + aRow.Column( i ).Set( valInt ); + break; + } + case EColumnUint32: + { + TInt64 valInt64 = aStatement.ColumnInt64( i ); + aRow.Column( i ).Set( (TUint32)valInt64 ); + break; + } + case EColumnInt64: + { + TInt64 valInt64 = aStatement.ColumnInt64( i ); + aRow.Column( i ).Set( valInt64 ); + break; + } + case EColumnReal32: + { + TReal valReal = aStatement.ColumnReal( i ); + aRow.Column( i ).Set( static_cast( valReal ) ); + break; + } + case EColumnReal64: + { + TReal valReal = aStatement.ColumnReal( i ); + aRow.Column( i ).Set( valReal ); + break; + } + case EColumnTime: + { + TTime valTime = aStatement.ColumnInt64( i ); + aRow.Column( i ).Set( valTime ); + break; + } + case EColumnDes16: + { + switch ( actual ) + { + case ESqlText: + { + TPtrC16 valTPtrC16 = aStatement.ColumnTextL( i ); + HBufC16* valHBuf16 = HBufC16::NewL( valTPtrC16.Length() ); + *valHBuf16 = valTPtrC16; + aRow.Column( i ).Set( valHBuf16 ); + break; + } + case ESqlInt: + { + HBufC16* valHBuf16int32 = HBufC16::NewL( 30 ); + TInt valInt = aStatement.ColumnInt( i ); + valHBuf16int32->Des().Num( valInt ); + aRow.Column( i ).Set( valHBuf16int32 ); + break; + } + case ESqlInt64: + { + HBufC16* valHBuf16int64 = HBufC16::NewL( 30 ); + TInt64 valInt64 = aStatement.ColumnInt64( i ); + valHBuf16int64->Des().Num( valInt64 ); + aRow.Column( i ).Set( valHBuf16int64 ); + break; + } + case ESqlReal: + { + HBufC16* valHBuf16real64 = HBufC16::NewL( 40 ); + TReal valReal = aStatement.ColumnReal( i ); + TRealFormat realFormat; + realFormat.iType |= KAllowThreeDigitExp; + valHBuf16real64->Des().Num( valReal, realFormat ); + aRow.Column( i ).Set( valHBuf16real64 ); + break; + } + case ESqlNull: + { + aRow.Column( i ).Set( (HBufC16*)NULL ); + break; + } + default: + { +#ifdef _DEBUG + User::Panic( _L( "MdSSCCo1" ), KErrCorrupt ); +#endif + User::Leave( KErrCorrupt ); + } + } + + break; + } + case EColumnNotUsed: + // skip this round + break; + + default: +#ifdef _DEBUG + User::Panic( _L( "MdSSCCo2" ), KErrCorrupt ); +#endif + User::Leave( KErrCorrupt ); + } + } + } + +void CMdSSqLiteConnection::Terminate( RMdsStatement& aQuery ) + { + aQuery.Close(); + EnableTransaction( ETrue, aQuery ); + } + +void CMdSSqLiteConnection::TransactionBeginL() + { + if ( !iEnableTransaction || iMdeSqlDb.InTransaction() ) + { + return; + } + iEnableTransaction = EFalse; + iTransactionOngoing = ETrue; + _LIT(KBeginTransaction, "BEGIN;"); + RRowData emptyRow; + CleanupClosePushL( emptyRow ); + TRAPD( err, ExecuteL(KBeginTransaction, emptyRow) ); + if (err != KErrNone) + { + _LIT( KMdsTransactionBegin, "Transaction begin error" ); + TraceAndLeaveL( KMdsTransactionBegin, err ); + } + CleanupStack::PopAndDestroy( &emptyRow ); + } + +void CMdSSqLiteConnection::TransactionCommitL() + { + if ( !iTransactionOngoing ) + { + return; + } + _LIT(KCommit, "COMMIT;"); + RRowData emptyRow; + CleanupClosePushL( emptyRow ); + TRAPD( err, ExecuteL(KCommit, emptyRow) ); + if (err != KErrNone) + { + _LIT( KMdsTransactionCommit, "Transaction commit error" ); + TraceAndLeaveL( KMdsTransactionCommit, err ); + } + if( !iNotFinishFindQuery ) + { + iEnableTransaction = ETrue; + } + iTransactionOngoing = EFalse; + CleanupStack::PopAndDestroy( &emptyRow ); + } + +void CMdSSqLiteConnection::TransactionRollbackL() + { + if ( !iTransactionOngoing ) + { + return; + } + _LIT(KRollback, "ROLLBACK;"); + RRowData emptyRow; + CleanupClosePushL( emptyRow ); + TRAPD( err, ExecuteL(KRollback, emptyRow) ); + if( !iNotFinishFindQuery ) + { + iEnableTransaction = ETrue; + } + iTransactionOngoing = EFalse; + if (err != KErrNone) + { + _LIT( KMdsTransactionRollback, "Transaction rollback error" ); + TraceAndLeaveL( KMdsTransactionRollback, err ); + } + CleanupStack::PopAndDestroy( &emptyRow ); + } + +#ifdef _DEBUG +void CMdSSqLiteConnection::TraceAndLeaveL( const TDesC& aFailedCommand, TInt aSqliteError ) + { + TPtrC errorMsg = iMdeSqlDb.LastErrorMessage(); + if ( aFailedCommand.Length() > 0 ) + { + __LOG2( ELogDb, "%S %d", &aFailedCommand, aSqliteError ); + } + __LOG1( ELogDb, "SQLiteError description: %S", &errorMsg ); + User::Leave( aSqliteError ); + } +#else +void CMdSSqLiteConnection::TraceAndLeaveL( const TDesC& /*aFailedCommand*/, TInt aSqliteError ) + { + User::Leave( aSqliteError ); + } +#endif + +const TDesC& CMdSSqLiteConnection::DbFileName() const + { + return *iDbFileName; + } + +void CMdSSqLiteConnection::EnableTransaction( TBool aEnable, RMdsStatement& aQuery ) + { + if( aEnable ) + { + // check whether current query is the query which disabled the transaction when enabling transaction + if( !iEnableTransaction && ( iNotFinishFindQuery == &aQuery ) ) + { + if( !iTransactionOngoing ) + { + iEnableTransaction = aEnable; + } + iNotFinishFindQuery = NULL; + } + } + else + { + iEnableTransaction = aEnable; + // save current find operation which will continue when diable transaction + iNotFinishFindQuery = &aQuery; + } + } +