--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/persistentstorage/sql/SRC/Client/SqlBlob.cpp Fri Jan 22 11:06:30 2010 +0200
@@ -0,0 +1,467 @@
+// Copyright (c) 2008-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:
+//
+
+#include <s32mem.h>
+#include "SqlDb.h"
+#include "SqlPanic.h"
+#include "SqlDatabaseImpl.h"
+#include "IPCBuf.h"
+
+// The maximum time (100 milliseconds) that a block of data is allowed to take to be read/written by TSqlBlob.
+// If the time taken is longer than this value then the next block size used will be less
+const TInt KTimeThresholdInMicroSecs = 100000;
+// The largest block size used by TSqlBlob is 32Kb
+const TInt KLargestBlockSize = 32 * 1024;
+// The client-side buffer will be used instead if the calculated block size is 2Kb or less
+const TInt KUseClientBufferThreshold = 2 * 1024;
+
+// Prepare an IPC buffer containing the parameter values
+static HBufC8* PrepareIpcParamBufLC(const TDesC& aTableName, const TDesC& aColumnName, TInt64 aRowId,
+ TBool aReadOnly, const TDesC& aDbName)
+ {
+ HBufC8* ipcPrmBuf = HBufC8::NewLC(aTableName.Size() + sizeof(TDesC) +
+ aColumnName.Size() + sizeof(TDesC) +
+ sizeof(aRowId) + sizeof(aReadOnly) +
+ aDbName.Size() + sizeof(TDesC) + sizeof(TInt32) * 3);
+ TPtr8 ipcPrmDes = ipcPrmBuf->Des();
+ RDesWriteStream strm(ipcPrmDes);
+
+ strm << static_cast <TInt32> (aTableName.Length())
+ << aTableName
+ << static_cast <TInt32> (aColumnName.Length())
+ << aColumnName
+ << aRowId
+ << static_cast<TInt32>(aReadOnly)
+ << static_cast <TInt32> (aDbName.Length())
+ << aDbName;
+ strm.CommitL();
+ strm.Close();
+ return ipcPrmBuf;
+ }
+
+// Create an IPC stream, sending the IPC buffer containing the parameter values
+static MStreamBuf* CreateIpcStreamL(RSqlDbSession& aDbSession, const TDesC8& aIpcPrmBuf)
+ {
+ TIpcArgs ipcArgs;
+ ipcArgs.Set(0, aIpcPrmBuf.Length());
+ ipcArgs.Set(1, &aIpcPrmBuf);
+ HIpcBuf* ipcBuf = HIpcBuf::NewL(aDbSession, ::MakeMsgCode(ESqlSrvDbBlobSource, ESqlSrvNoHandle, 0), ipcArgs);
+ return ipcBuf;
+ }
+
+// Used by TSqlBlob to calculate the appropriate block size to use for the next transfer of blob data
+static TInt CalculateBlockSize(TInt aRemainingDataSize, TInt aPreviousBlockSize, TBool aTimeThresholdBreached)
+ {
+ TInt blockSize = aPreviousBlockSize;
+ if(aTimeThresholdBreached)
+ {
+ // The time threshold was breached using the previous block size
+ // so we will reduce the block size by a factor of 2
+ blockSize /= 2;
+ if(blockSize <= KUseClientBufferThreshold)
+ {
+ // Just use the client-side IPC buffer size if things get to this stage
+ blockSize = KIpcBufSize;
+ }
+ }
+ return aRemainingDataSize <= blockSize ? aRemainingDataSize : blockSize;
+ }
+
+// Retrieve the data in blocks
+static void DoReadInBlocksL(RSqlBlobReadStream& aStrm, TDes8& aDestBuffer, TInt aBlobSize)
+ {
+ TInt remainingDataSize = aBlobSize;
+ TBool timeThresholdBreached = EFalse;
+ TInt blockSize = KLargestBlockSize;
+ TPtr8 ptr((TUint8*)aDestBuffer.Ptr(), aDestBuffer.MaxSize());
+
+ while(remainingDataSize > 0)
+ {
+ // Calculate the block size to use for this iteration, based on
+ // how much data is remaining and how fast the previous read was
+ blockSize = CalculateBlockSize(remainingDataSize, blockSize, timeThresholdBreached);
+
+ // Read the block of data, timing how long it takes
+ TTime t1, t2;
+ t1.HomeTime();
+ aStrm.ReadL(ptr, blockSize);
+ t2.HomeTime();
+ TTimeIntervalMicroSeconds readTime = t2.MicroSecondsFrom(t1);
+ timeThresholdBreached = (readTime.Int64() > KTimeThresholdInMicroSecs);
+
+ // Update how much data is still to be read, and the buffer pointer
+ remainingDataSize -= blockSize;
+ __SQLASSERT(remainingDataSize >= 0, ESqlPanicInternalError);
+ ptr.Set((TUint8*)(ptr.Ptr() + blockSize), 0, remainingDataSize);
+ }
+ aDestBuffer.SetLength(aBlobSize);
+ }
+
+// Send the data in blocks
+static void DoWriteInBlocksL(RSqlBlobWriteStream& aStrm, const TDesC8& aData, TInt aDataSize)
+ {
+ TInt remainingDataSize = aDataSize;
+ TBool timeThresholdBreached = EFalse;
+ TInt blockSize = KLargestBlockSize;
+
+ while(remainingDataSize > 0)
+ {
+ // Calculate the block size to use for this iteration, based on
+ // how much data is remaining and how fast the previous write was
+ blockSize = CalculateBlockSize(remainingDataSize, blockSize, timeThresholdBreached);
+
+ // Write the block of data, timing how long it takes
+ TTime t1, t2;
+ t1.HomeTime();
+ aStrm.WriteL(aData.Right(remainingDataSize), blockSize);
+ t2.HomeTime();
+ TTimeIntervalMicroSeconds writeTime = t2.MicroSecondsFrom(t1);
+ timeThresholdBreached = (writeTime.Int64() > KTimeThresholdInMicroSecs);
+
+ // Update how much data is still to be written
+ remainingDataSize -= blockSize;
+ __SQLASSERT(remainingDataSize >= 0, ESqlPanicInternalError);
+ }
+ aStrm.CommitL();
+ }
+
+// The data is returned in a UTF-8 buffer that is allocated on the heap
+static HBufC8* ReadLC(RSqlDatabase& aDb,
+ const TDesC& aTableName,
+ const TDesC& aColumnName,
+ TInt64 aRowId,
+ const TDesC& aDbName)
+ {
+ RSqlBlobReadStream strm;
+ CleanupClosePushL(strm);
+ strm.OpenL(aDb, aTableName, aColumnName, aRowId, aDbName);
+ TInt blobSize = strm.SizeL(); // size of the blob, in bytes
+ HBufC8* buf = HBufC8::NewLC(blobSize);
+ TPtr8 ptr = buf->Des();
+ DoReadInBlocksL(strm, ptr, blobSize);
+ CleanupStack::Pop(); // buf
+ CleanupStack::PopAndDestroy(); // strm
+ CleanupStack::PushL(buf);
+ return buf;
+ }
+
+// The data is returned in the UTF-8 buffer passed in
+static void ReadL(RSqlDatabase& aDb,
+ const TDesC& aTableName,
+ const TDesC& aColumnName,
+ TDes8& aBuffer,
+ TInt64 aRowId,
+ const TDesC& aDbName)
+ {
+ RSqlBlobReadStream strm;
+ CleanupClosePushL(strm);
+ strm.OpenL(aDb, aTableName, aColumnName, aRowId, aDbName);
+ TInt blobSize = strm.SizeL(); // size of the blob, in bytes
+ if(blobSize > aBuffer.MaxSize())
+ {
+ __SQLLEAVE(KErrOverflow);
+ }
+ DoReadInBlocksL(strm, aBuffer, blobSize);
+ CleanupStack::PopAndDestroy(); // strm
+ }
+
+// The data in the client-specified UTF-8 buffer is written
+static void WriteL(RSqlDatabase& aDb,
+ const TDesC& aTableName,
+ const TDesC& aColumnName,
+ const TDesC8& aData,
+ TInt64 aRowId,
+ const TDesC& aDbName)
+ {
+ RSqlBlobWriteStream strm;
+ CleanupClosePushL(strm);
+ strm.OpenL(aDb, aTableName, aColumnName, aRowId, aDbName);
+ TInt dataSize = aData.Size(); // size of the data, in bytes
+ TInt blobSize = strm.SizeL(); // size of the blob, in bytes
+ if(dataSize > blobSize)
+ {
+ __SQLLEAVE(KErrEof);
+ }
+ if(dataSize > 0)
+ {
+ DoWriteInBlocksL(strm, aData, dataSize);
+ }
+ CleanupStack::PopAndDestroy(); // strm
+ }
+
+////////////////////////////////////////////////////////////////////////////////
+
+/**
+Gives access to a blob as a read-only stream of bytes.
+
+@param aDb A connection to the database that contains the blob
+@param aTableName The name of the table that contains the blob
+@param aColumnName The name of the column that contains the blob
+@param aRowId The ROWID of the record that contains the blob,
+ or KSqlLastInsertedRowId if the last inserted ROWID
+ of the specified database connection is to be used
+@param aDbName The name of the attached database if the blob is
+ contained in an attached database
+
+@leave KSqlErrGeneral, Invalid database connection or table name or column name
+ or column type or ROWID or database name;
+ KErrNoMemory, An out of memory condition occurred;
+ KErrArgument, The ROWID is zero or negative or a UTF-16 to UTF-8 string conversion failed;
+ KErrBadName, The table name, column name or database name has an invalid length;
+ KErrPermissionDenied, The client does not have the required security capabilites for this operation;
+ Note that the function may also leave with some other system wide errors or
+ database specific errors categorised as ESqlDbError.
+
+@panic SqlDb 2 The database object is not yet created
+@panic SqlDb 3 Server failed to create a handle to the blob
+@panic SqlDb 4 In _DEBUG mode. Bad parameter value
+@panic SqlDb 7 In _DEBUG mode. NULL blob handle
+
+@capability None, if the aDb parameter represents a handle which operates on a non-secure database;
+ RSqlSecurityPolicy::EReadPolicy or
+ RSqlSecurityPolicy::ESchemaPolicy database policy type, if the blob belongs to a secure database;
+*/
+EXPORT_C void RSqlBlobReadStream::OpenL(RSqlDatabase& aDb, const TDesC& aTableName, const TDesC& aColumnName,
+ TInt64 aRowId, const TDesC& aDbName)
+ {
+ SQLUTRACE_PROFILER(this);
+ SYMBIAN_TRACE_SQL_EVENTS_ONLY(UTF::Printf(UTF::TTraceContext(UTF::EInternals), KRSqlBlobParam16, &aDb, &aTableName,
+ &aColumnName, aRowId, &aDbName));
+
+ HBufC8* ipcPrmBuf = ::PrepareIpcParamBufLC(aTableName, aColumnName, aRowId, ETrue, aDbName);
+ MStreamBuf* strm = ::CreateIpcStreamL(aDb.Impl().Session(), ipcPrmBuf->Des());
+ Attach(strm);
+ CleanupStack::PopAndDestroy(ipcPrmBuf);
+ }
+
+/**
+Returns the size of the blob object, in bytes.
+
+@return The size of the blob object, in bytes
+
+@leave One of the system-wide error codes
+
+@panic SqlDb 2 The stream buffer is NULL
+
+@capability None
+*/
+EXPORT_C TInt RSqlBlobReadStream::SizeL()
+ {
+ SQLUTRACE_PROFILER(this);
+
+ MStreamBuf* src = Source();
+ __SQLASSERT_ALWAYS(src != NULL, ESqlPanicInvalidObj);
+ return src->SizeL();
+ }
+
+/**
+Gives access to a blob as a writeable stream of bytes.
+
+@param aDb A connection to the database that contains the blob
+@param aTableName The name of the table that contains the blob
+@param aColumnName The name of the column that contains the blob
+@param aRowId The ROWID of the record that contains the blob,
+ or KSqlLastInsertedRowId if the last inserted ROWID
+ of the specified database connection is to be used
+@param aDbName The name of the attached database if the blob is
+ contained in an attached database
+
+@leave KSqlErrGeneral, Invalid database connection or table name or column name or column
+ type or ROWID or database name, or the specified column is indexed;
+ KErrNoMemory, An out of memory condition occurred;
+ KErrArgument, The ROWID is zero or negative or a UTF-16 to UTF-8 string conversion failed;
+ KErrBadName, The table name, column name or database name has an invalid length;
+ KErrPermissionDenied, The client does not have the required security capabilites for this operation;
+ Note that the function may also leave with some other system wide errors or
+ database specific errors categorised as ESqlDbError.
+
+@panic SqlDb 2 The database object is not yet created
+@panic SqlDb 3 Server failed to create a handle to the blob
+@panic SqlDb 4 In _DEBUG mode. Bad parameter value
+@panic SqlDb 7 In _DEBUG mode. NULL blob handle
+
+@capability None, if the aDb parameter represents a handle which operates on a non-secure database;
+ RSqlSecurityPolicy::EWritePolicy or
+ RSqlSecurityPolicy::ESchemaPolicy database policy type, if the blob belongs to a secure database;
+*/
+EXPORT_C void RSqlBlobWriteStream::OpenL(RSqlDatabase& aDb, const TDesC& aTableName, const TDesC& aColumnName,
+ TInt64 aRowId, const TDesC& aDbName)
+ {
+ SQLUTRACE_PROFILER(this);
+ SYMBIAN_TRACE_SQL_EVENTS_ONLY(UTF::Printf(UTF::TTraceContext(UTF::EInternals), KRSqlBlobParam16, &aDb, &aTableName,
+ &aColumnName, aRowId, &aDbName));
+
+ HBufC8* ipcPrmBuf = ::PrepareIpcParamBufLC(aTableName, aColumnName, aRowId, EFalse, aDbName);
+ MStreamBuf* strm = ::CreateIpcStreamL(aDb.Impl().Session(), ipcPrmBuf->Des());
+ Attach(strm);
+ CleanupStack::PopAndDestroy(ipcPrmBuf);
+ }
+
+/**
+Returns the size of the blob object, in bytes.
+
+@return The size of the blob object, in bytes
+
+@leave One of the system-wide error codes
+
+@panic SqlDb 2 The stream buffer is NULL
+
+@capability None
+*/
+EXPORT_C TInt RSqlBlobWriteStream::SizeL()
+ {
+ SQLUTRACE_PROFILER(this);
+
+ MStreamBuf* sink = Sink();
+ __SQLASSERT_ALWAYS(sink != NULL, ESqlPanicInvalidObj);
+ return sink->SizeL();
+ }
+
+/**
+Retrieves the entire content of a blob and returns it to the client
+in a heap allocated buffer which has been placed on the cleanup stack.
+It is the responsibility of the client to destroy the returned buffer.
+
+@param aDb A connection to the database that contains the blob
+@param aTableName The name of the table that contains the blob
+@param aColumnName The name of the column that contains the blob
+@param aRowId The ROWID of the record that contains the blob,
+ or KSqlLastInsertedRowId if the last inserted ROWID
+ of the specified database connection is to be used
+@param aDbName The name of the attached database if the blob is
+ contained in an attached database
+
+@leave KSqlErrGeneral, Invalid database connection or table name or column name
+ or column type or ROWID or database name;
+ KErrNoMemory, An out of memory condition occurred;
+ KErrArgument, The ROWID is zero or negative or a UTF-16 to UTF-8 string conversion failed;
+ KErrBadName, The table name, column name or database name has an invalid length;
+ KErrPermissionDenied, The client does not have the required security capabilites for this operation;
+ Note that the function may also leave with some other system wide errors or
+ database specific errors categorised as ESqlDbError.
+
+@panic SqlDb 2 The database object is not yet created
+@panic SqlDb 3 Server failed to create a handle to the blob
+@panic SqlDb 4 In _DEBUG mode. Bad parameter value
+@panic SqlDb 7 In _DEBUG mode. NULL blob handle or miscalculation of remaining data to be read
+
+@capability None, if the aDb parameter represents a handle which operates on a non-secure database;
+ RSqlSecurityPolicy::EReadPolicy or
+ RSqlSecurityPolicy::ESchemaPolicy database policy type, if the blob belongs to a secure database;
+*/
+EXPORT_C HBufC8* TSqlBlob::GetLC(RSqlDatabase& aDb,
+ const TDesC& aTableName,
+ const TDesC& aColumnName,
+ TInt64 aRowId,
+ const TDesC& aDbName)
+ {
+ SQLUTRACE_PROFILER(0);
+ SYMBIAN_TRACE_SQL_EVENTS_ONLY(UTF::Printf(UTF::TTraceContext(UTF::EInternals), KRSqlBlobParam16, &aDb, &aTableName,
+ &aColumnName, aRowId, &aDbName));
+
+ return ReadLC(aDb, aTableName, aColumnName, aRowId, aDbName);
+ }
+
+/**
+Retrieves the entire content of a blob into a client specified buffer.
+
+@param aDb A connection to the database that contains the blob
+@param aTableName The name of the table that contains the blob
+@param aColumnName The name of the column that contains the blob
+@param aRowId The ROWID of the record that contains the blob,
+ or KSqlLastInsertedRowId if the last inserted ROWID
+ of the specified database connection is to be used
+@param aDbName The name of the attached database if the blob is
+ contained in an attached database
+
+@return KSqlErrGeneral, Invalid database connection or table name or column name
+ or column type or ROWID or database name;
+ KErrNoMemory, An out of memory condition occurred;
+ KErrArgument, The ROWID is zero or negative or a UTF-16 to UTF-8 string conversion failed;
+ KErrOverflow, The specified buffer is not big enough to hold the entire blob;
+ KErrBadName, The table name, column name or database name has an invalid length;
+ KErrPermissionDenied, The client does not have the required security capabilites for this operation;
+ Note that the function may also leave with some other system wide errors or
+ database specific errors categorised as ESqlDbError.
+
+@panic SqlDb 2 The database object is not yet created
+@panic SqlDb 3 Server failed to create a handle to the blob
+@panic SqlDb 4 In _DEBUG mode. Bad parameter value
+@panic SqlDb 7 In _DEBUG mode. NULL blob handle or miscalculation of remaining data to be read
+
+@capability None, if the aDb parameter represents a handle which operates on a non-secure database;
+ RSqlSecurityPolicy::EReadPolicy or
+ RSqlSecurityPolicy::ESchemaPolicy database policy type, if the blob belongs to a secure database;
+*/
+EXPORT_C TInt TSqlBlob::Get(RSqlDatabase& aDb,
+ const TDesC& aTableName,
+ const TDesC& aColumnName,
+ TDes8& aBuffer,
+ TInt64 aRowId,
+ const TDesC& aDbName)
+ {
+ SQLUTRACE_PROFILER(0);
+ SYMBIAN_TRACE_SQL_EVENTS_ONLY(UTF::Printf(UTF::TTraceContext(UTF::EInternals), KRSqlBlobParam16, &aDb, &aTableName,
+ &aColumnName, aRowId, &aDbName));
+
+ TRAPD(err, ReadL(aDb, aTableName, aColumnName, aBuffer, aRowId, aDbName));
+ return err;
+ }
+
+/**
+Writes the data in a client specified buffer to a blob.
+
+@param aDb A connection to the database that contains the blob
+@param aTableName The name of the table that contains the blob
+@param aColumnName The name of the column that contains the blob
+@param aRowId The ROWID of the record that contains the blob,
+ or KSqlLastInsertedRowId if the last inserted ROWID
+ of the specified database connection is to be used
+@param aDbName The name of the attached database if the blob is
+ contained in an attached database
+
+@leave KSqlErrGeneral, Invalid database connection or table name or column name or column
+ type or ROWID or database name, or the specified column is indexed;
+ KErrNoMemory, An out of memory condition occurred;
+ KErrArgument, The ROWID is zero or negative or a UTF-16 to UTF-8 string conversion failed;
+ KErrEof, The data in the specified buffer is larger in size than the blob object;
+ KErrBadName, The table name, column name or database name has an invalid length;
+ KErrPermissionDenied, The client does not have the required security capabilites for this operation;
+ Note that the function may also leave with some other system wide errors or
+ database specific errors categorised as ESqlDbError.
+
+@panic SqlDb 2 The database object is not yet created
+@panic SqlDb 3 Server failed to create a handle to the blob
+@panic SqlDb 4 In _DEBUG mode. Bad parameter value
+@panic SqlDb 7 In _DEBUG mode. NULL blob handle or miscalculation of remaining data to be written
+
+@capability None, if the aDb parameter represents a handle which operates on a non-secure database;
+ RSqlSecurityPolicy::EWritePolicy or
+ RSqlSecurityPolicy::ESchemaPolicy database policy type, if the blob belongs to a secure database;
+*/
+EXPORT_C void TSqlBlob::SetL(RSqlDatabase& aDb,
+ const TDesC& aTableName,
+ const TDesC& aColumnName,
+ const TDesC8& aData,
+ TInt64 aRowId,
+ const TDesC& aDbName)
+ {
+ SQLUTRACE_PROFILER(0);
+ SYMBIAN_TRACE_SQL_EVENTS_ONLY(UTF::Printf(UTF::TTraceContext(UTF::EInternals), KRSqlBlobParam16, &aDb, &aTableName,
+ &aColumnName, aRowId, &aDbName));
+
+ WriteL(aDb, aTableName, aColumnName, aData, aRowId, aDbName);
+ }
+