--- /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<TReal32>( 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;
+ }
+ }
+