1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/persistentdata/persistentstorage/sql/SRC/Server/SqlSrvBlob.cpp Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,301 @@
1.4 +// Copyright (c) 2008-2010 Nokia Corporation and/or its subsidiary(-ies).
1.5 +// All rights reserved.
1.6 +// This component and the accompanying materials are made available
1.7 +// under the terms of "Eclipse Public License v1.0"
1.8 +// which accompanies this distribution, and is available
1.9 +// at the URL "http://www.eclipse.org/legal/epl-v10.html".
1.10 +//
1.11 +// Initial Contributors:
1.12 +// Nokia Corporation - initial contribution.
1.13 +//
1.14 +// Contributors:
1.15 +//
1.16 +// Description:
1.17 +//
1.18 +
1.19 +#include "sqlite3.h"
1.20 +#include "SqlAssert.h"
1.21 +#include "SqlSrvBlob.h"
1.22 +#include "SqliteSymbian.h"
1.23 +#include "SqlSrvUtil.h"
1.24 +#include "SqlSrvStrings.h"
1.25 +#include "SqlDb.h"
1.26 +#include "OstTraceDefinitions.h"
1.27 +#ifdef OST_TRACE_COMPILER_IN_USE
1.28 +#include "SqlSrvBlobTraces.h"
1.29 +#endif
1.30 +#include "SqlTraceDef.h"
1.31 +
1.32 +#define UNUSED_VAR(var) var = var
1.33 +
1.34 +/**
1.35 +Creates a new HBlobBuf instance.
1.36 +
1.37 +@param aDb The database handle
1.38 +@param aDbName The database name, zero-terminated. If the blob belongs to one of the attached databases,
1.39 + then the attached database name should be used as the value of aDbName, otherwise the
1.40 + value should be "main"
1.41 +@param aTableName The name of the table to which the blob belongs, zero-terminated.
1.42 +@param aColumnName The name of the blob column, zero-terminated.
1.43 +@param aRowId The ROWID of the row to which the blob belongs
1.44 +@param aMode Specifies the blob access mode, either HBlobBuf::EReadOnly or HBlobBuf::EReadWrite
1.45 +
1.46 +@leave KErrNoMemory, An out of memory condition has occurred;
1.47 + Note that the function may also leave with some other system wide errors or
1.48 + database specific errors categorised as ESqlDbError.
1.49 +
1.50 +@return A pointer to the created HBlobBuf instance
1.51 +
1.52 +@panic SqlDb 4 In _DEBUG mode. NULL aDb parameter.
1.53 +@panic SqlDb 4 In _DEBUG mode. Negative or zero aRowId.
1.54 +@panic SqlDb 4 In _DEBUG mode. aMode parameter is not HBlobBuf::EReadOnly or HBlobBuf::EReadWrite.
1.55 +*/
1.56 +HBlobBuf* HBlobBuf::NewL(sqlite3* aDb, const TDesC8& aDbName, const TDesC8& aTableName, const TDesC8& aColumnName, TInt64 aRowId, TMode aMode)
1.57 + {
1.58 + __SQLTRACE_BLOBVAR(TBuf<100> des16prnbuf);
1.59 + SQL_TRACE_BLOB(OstTraceExt4(TRACE_INTERNALS, HBLOBBUF_NEWL_ENTRY1, "Entry;0;HBlobBuf::NewL;sqlite3*=0x%X;aDbName=%s;aRowId=%lld;aMode=%d", (TUint)aDb, __SQLPRNSTR8(aDbName, des16prnbuf), aRowId, (TInt)aMode));
1.60 + SQL_TRACE_BLOB(OstTraceExt1(TRACE_INTERNALS, HBLOBBUF_NEWL_ENTRY2, "Entry;0;HBlobBuf::NewL;aTableName=%s", __SQLPRNSTR8(aTableName, des16prnbuf)));
1.61 + SQL_TRACE_BLOB(OstTraceExt1(TRACE_INTERNALS, HBLOBBUF_NEWL_ENTRY3, "Entry;0;HBlobBuf::NewL;aColumnName=%s", __SQLPRNSTR8(aColumnName, des16prnbuf)));
1.62 + __ASSERT_DEBUG(aDb != NULL, __SQLPANIC2(ESqlPanicBadArgument));
1.63 + __ASSERT_DEBUG(aRowId > 0, __SQLPANIC2(ESqlPanicBadArgument));
1.64 + __ASSERT_DEBUG(aMode == HBlobBuf::EReadOnly || aMode == HBlobBuf::EReadWrite, __SQLPANIC2(ESqlPanicBadArgument));
1.65 +
1.66 + HBlobBuf* self = new (ELeave) HBlobBuf;
1.67 + CleanupStack::PushL(self);
1.68 + self->ConstructL(aDb, aDbName, aTableName, aColumnName, aRowId, aMode);
1.69 + CleanupStack::Pop(self);
1.70 + SQL_TRACE_BLOB(OstTraceExt2(TRACE_INTERNALS, HBLOBBUF_NEWL_EXIT, "Exit;0x%X;HBlobBuf::NewL;sqlite3_blob*=0x%X", (TUint)self, (TUint)self->iBlobHandle));
1.71 + return self;
1.72 + }
1.73 +
1.74 +/**
1.75 +Initializes HBlobBuf data members with their default values.
1.76 +*/
1.77 +HBlobBuf::HBlobBuf() :
1.78 + iBlobHandle(NULL),
1.79 + iWrPos(KMinTInt),
1.80 + iRdPos(KMinTInt)
1.81 + {
1.82 + }
1.83 +
1.84 +/**
1.85 +Initializes a new HBlobBuf instance.
1.86 +
1.87 +@param aDb The database handle
1.88 +@param aDbName The database name, zero-terminated. If the blob belongs to one of the attached databases,
1.89 + then the attached database name should be used as a value of aDbName, otherwise the
1.90 + value should be "main"
1.91 +@param aTableName The name of the table to which the blob belongs, zero-terminated.
1.92 +@param aColumnName The name of the blob column, zero-terminated.
1.93 +@param aRowId The ROWID of the row to which the blob belongs
1.94 +@param aMode Specifies the blob access mode, either HBlobBuf::EReadOnly or HBlobBuf::EReadWrite
1.95 +
1.96 +@leave KErrNoMemory, An out of memory condition has occurred;
1.97 + Note that the function may also leave with some other system wide errors or
1.98 + database specific errors categorised as ESqlDbError.
1.99 +
1.100 +@panic SqlDb 4 In _DEBUG mode. NULL aDb parameter.
1.101 +@panic SqlDb 4 In _DEBUG mode. Negative or zero aRowId.
1.102 +@panic SqlDb 4 In _DEBUG mode. aMode parameter is not HBlobBuf::EReadOnly or HBlobBuf::EReadWrite.
1.103 +@panic SqlDb 7 In _DEBUG mode. NULL blob handle.
1.104 +*/
1.105 +void HBlobBuf::ConstructL(sqlite3* aDb, const TDesC8& aDbName, const TDesC8& aTableName, const TDesC8& aColumnName, TInt64 aRowId, TMode aMode)
1.106 + {
1.107 + __ASSERT_DEBUG(aDb != NULL, __SQLPANIC(ESqlPanicBadArgument));
1.108 + __ASSERT_DEBUG(aRowId > 0, __SQLPANIC(ESqlPanicBadArgument));
1.109 + __ASSERT_DEBUG(aMode == HBlobBuf::EReadOnly || aMode == HBlobBuf::EReadWrite, __SQLPANIC(ESqlPanicBadArgument));
1.110 +
1.111 + (void)sqlite3SymbianLastOsError();//clear last OS error
1.112 +
1.113 + TInt err = sqlite3_blob_open(aDb, (const char*)aDbName.Ptr(), (const char*)aTableName.Ptr(), (const char*)aColumnName.Ptr(),
1.114 + aRowId, aMode & HBlobBuf::EReadWrite, &iBlobHandle);
1.115 + __SQLLEAVE_IF_ERROR(::Sql2OsErrCode(err, sqlite3SymbianLastOsError()));
1.116 + __ASSERT_DEBUG(iBlobHandle != NULL, __SQLPANIC(ESqlPanicInternalError));
1.117 + iBlobSize = sqlite3_blob_bytes(iBlobHandle);
1.118 + iWrPos = iRdPos = 0;
1.119 + }
1.120 +
1.121 +/**
1.122 +Closes the blob handle as part of the HBlobBuf object being destroyed.
1.123 +*/
1.124 +void HBlobBuf::DoRelease()
1.125 + {
1.126 + SQL_TRACE_BLOB(OstTraceExt2(TRACE_INTERNALS, HBLOBBUF_DORELEASE_ENTRY, "Entry;0x%X;HBlobBuf::DoRelease;sqlite3_blob*=0x%X", (TUint)this, (TUint)iBlobHandle));
1.127 + TRAPD(err, DoSynchL());
1.128 + SQL_TRACE_BLOB(OstTraceExt2(TRACE_INTERNALS, HBLOBBUF_DORELEASE_EXIT, "Exit;0x%X;HBlobBuf::DoRelease;err=%d", (TUint)this, err));
1.129 + UNUSED_VAR(err);
1.130 + }
1.131 +
1.132 +/**
1.133 +Closes the blob handle.
1.134 +Any buffered data is delivered to the stream.
1.135 +*/
1.136 +void HBlobBuf::DoSynchL()
1.137 + {
1.138 + if(iBlobHandle)
1.139 + {
1.140 + TInt err = sqlite3_blob_close(iBlobHandle);
1.141 + SQL_TRACE_BLOB(OstTraceExt2(TRACE_INTERNALS, HBLOBBUF_DOSYNCHL, "0x%X;HBlobBuf::DoSynchL;err=%d", (TUint)this, err));
1.142 + iBlobHandle = NULL; // the close is unconditional, even if an error occurs
1.143 + __SQLLEAVE_IF_ERROR(::Sql2OsErrCode(err, sqlite3SymbianLastOsError()));
1.144 + }
1.145 + }
1.146 +
1.147 +/**
1.148 +Reads a data block from the blob with the specified length.
1.149 +
1.150 +@param aPtr Pointer to the location where the blob data will be copied
1.151 +@param aMaxLength The length of the data block to be read
1.152 +
1.153 +@leave KErrNoMemory, An out of memory condition has occurred;
1.154 + KErrEof, An attempt has been made to read beyond the end of the blob;
1.155 + KErrBadHandle, NULL blob handle;
1.156 + Note that the function may also leave with some other system
1.157 + wide errors or database specific errors categorised as ESqlDbError.
1.158 +
1.159 +@return The number of bytes read.
1.160 +
1.161 +@panic SqlDb 4 In _DEBUG mode. NULL aPtr parameter.
1.162 +@panic SqlDb 4 In _DEBUG mode. Negative aMaxLength parameter.
1.163 +@panic SqlDb 2 In _DEBUG mode. NULL iBlobHandle.
1.164 +*/
1.165 +TInt HBlobBuf::DoReadL(TAny* aPtr, TInt aMaxLength)
1.166 + {
1.167 + __ASSERT_DEBUG(aPtr != NULL, __SQLPANIC(ESqlPanicBadArgument));
1.168 + __ASSERT_DEBUG(aMaxLength >= 0, __SQLPANIC(ESqlPanicBadArgument));
1.169 + __ASSERT_DEBUG(iBlobHandle != NULL, __SQLPANIC(ESqlPanicInvalidObj));
1.170 +
1.171 + SQL_TRACE_BLOB(OstTraceExt5(TRACE_INTERNALS, HBLOBBUF_DOREADL, "0x%X;HBlobBuf::DoReadL;aMaxLength=%d;iBlobSize=%d;iWrPos=%d;iRdPos=%d", (TUint)this, aMaxLength, iBlobSize, iWrPos, iRdPos));
1.172 +
1.173 + if(aMaxLength <= 0)
1.174 + {
1.175 + return 0;
1.176 + }
1.177 +
1.178 + (void)sqlite3SymbianLastOsError();//clear last OS error
1.179 +
1.180 + if(iRdPos >= iBlobSize)
1.181 + {
1.182 + __SQLLEAVE(KErrEof);
1.183 + }
1.184 + if((aMaxLength + iRdPos) > iBlobSize)
1.185 + {
1.186 + aMaxLength = iBlobSize - iRdPos;
1.187 + }
1.188 + TInt err = sqlite3_blob_read(BlobHandleL(), aPtr, aMaxLength, iRdPos);
1.189 + __SQLLEAVE_IF_ERROR(::Sql2OsErrCode(err, sqlite3SymbianLastOsError()));
1.190 + iRdPos += aMaxLength;
1.191 + return aMaxLength;
1.192 + }
1.193 +
1.194 +/**
1.195 +Writes a data block with the specified length to the blob.
1.196 +
1.197 +@param aPtr Pointer to the location with the blob data to be written
1.198 +@param aLength The length of the data block to be written
1.199 +
1.200 +@leave KErrNoMemory, An out of memory condition has occurred;
1.201 + KErrEof, An attempt has been made to write beyond the end of the blob;
1.202 + KErrBadHandle, NULL blob handle;
1.203 + Note that the function may also leave with some other system
1.204 + wide errors or database specific errors categorised as ESqlDbError.
1.205 +
1.206 +@panic SqlDb 4 In _DEBUG mode. NULL aPtr parameter.
1.207 +@panic SqlDb 4 In _DEBUG mode. Negative aLength parameter.
1.208 +@panic SqlDb 2 In _DEBUG mode. NULL iBlobHandle.
1.209 +*/
1.210 +void HBlobBuf::DoWriteL(const TAny* aPtr, TInt aLength)
1.211 + {
1.212 + __ASSERT_DEBUG(aPtr != NULL, __SQLPANIC(ESqlPanicBadArgument));
1.213 + __ASSERT_DEBUG(aLength >= 0, __SQLPANIC(ESqlPanicBadArgument));
1.214 + __ASSERT_DEBUG(iBlobHandle != NULL, __SQLPANIC(ESqlPanicInvalidObj));
1.215 +
1.216 + SQL_TRACE_BLOB(OstTraceExt5(TRACE_INTERNALS, HBLOBBUF_DOWRITEL, "0x%X;HBlobBuf::DoWriteL;aLength=%d;iBlobSize=%d;iWrPos=%d;iRdPos=%d", (TUint)this, aLength, iBlobSize, iWrPos, iRdPos));
1.217 +
1.218 + if(aLength <= 0)
1.219 + {
1.220 + return;
1.221 + }
1.222 +
1.223 + if((iWrPos + aLength) > iBlobSize)
1.224 + {
1.225 + __SQLLEAVE(KErrEof);
1.226 + }
1.227 +
1.228 + (void)sqlite3SymbianLastOsError();//clear last OS error
1.229 + TInt err = sqlite3_blob_write(BlobHandleL(), aPtr, aLength, iWrPos);
1.230 + err = ::Sql2OsErrCode(err, sqlite3SymbianLastOsError());
1.231 +
1.232 + __SQLLEAVE_IF_ERROR(err);
1.233 + iWrPos += aLength;
1.234 + }
1.235 +
1.236 +/**
1.237 +Positions the mark(s) indicated by aMark at aOffset from aLocation.
1.238 +
1.239 +@leave KErrEof, An attempt has been made to seek beyond the end of the blob;
1.240 + KErrBadHandle, NULL blob handle;
1.241 + Note that the function may also leave with some other system wide errors or
1.242 + database specific errors categorised as ESqlDbError.
1.243 +
1.244 +@return The new stream position (read or write)
1.245 +
1.246 +@panic SqlDb 2 In _DEBUG mode. NULL iBlobHandle.
1.247 +@panic SqlDb 4 In _DEBUG mode. Negative aOffset parameter.
1.248 +@panic SqlDb 8 In _DEBUG mode. Invalid aMark parameter.
1.249 +@panic SqlDb 9 In _DEBUG mode. Invalid aLocation parameter.
1.250 +*/
1.251 +TStreamPos HBlobBuf::DoSeekL(MStreamBuf::TMark aMark, TStreamLocation aLocation, TInt aOffset)
1.252 + {
1.253 + SQL_TRACE_BLOB(OstTraceExt5(TRACE_INTERNALS, HBLOBBUF_DOSEEKL, "0x%X;HBlobBuf::DoSeekL;aMark=%d;aLocation=%d;aOffset=%d;iBlobSize=%d", (TUint)this, (TInt)aMark, (TInt)aLocation, aOffset, iBlobSize));
1.254 + __ASSERT_ALWAYS(!(aMark & ~(ERead | EWrite)), __SQLPANIC(ESqlPanicStreamMarkInvalid));
1.255 + __ASSERT_DEBUG(aOffset >= 0, __SQLPANIC(ESqlPanicBadArgument));
1.256 + __ASSERT_DEBUG(iBlobHandle != NULL, __SQLPANIC(ESqlPanicInvalidObj));
1.257 +
1.258 + TInt newPos = 0;
1.259 + switch(aLocation)
1.260 + {
1.261 + case EStreamBeginning:
1.262 + newPos = aOffset;
1.263 + break;
1.264 + case EStreamMark:
1.265 + newPos = (aMark & MStreamBuf::EWrite ? iWrPos : iRdPos) + aOffset;
1.266 + break;
1.267 + case EStreamEnd:
1.268 + newPos = iBlobSize + aOffset;
1.269 + break;
1.270 + default:
1.271 + __ASSERT_DEBUG(0, __SQLPANIC(ESqlPanicStreamLocationInvalid));
1.272 + newPos = -1;
1.273 + break;
1.274 + }
1.275 + if(newPos < 0 || newPos > iBlobSize)
1.276 + {
1.277 + __SQLLEAVE(KErrEof);
1.278 + }
1.279 + if(aMark & MStreamBuf::EWrite)
1.280 + {
1.281 + iWrPos = newPos;
1.282 + }
1.283 + else if(aMark & MStreamBuf::ERead)
1.284 + {
1.285 + iRdPos = newPos;
1.286 + }
1.287 + return TStreamPos(newPos);
1.288 + }
1.289 +
1.290 +/**
1.291 +Returns the blob handle, if it is not NULL.
1.292 +
1.293 +@leave KErrBadHandle, The blob handle is NULL.
1.294 +
1.295 +@return The blob handle
1.296 +*/
1.297 +sqlite3_blob* HBlobBuf::BlobHandleL()
1.298 + {
1.299 + if(!iBlobHandle)
1.300 + {
1.301 + __SQLLEAVE(KErrBadHandle);
1.302 + }
1.303 + return iBlobHandle;
1.304 + }