// 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 <e32test.h>
#include <bautils.h>
#include <sqldb.h>
#include <s32file.h>
RTest TheTest(_L("t_sqlblob test"));
RSqlDatabase TheDb1;
RSqlDatabase TheDb2;
RSqlDatabase ThePrivateDb;
_LIT(KTestDir, "c:\\test\\");
_LIT(KTestDbName1, "c:\\test\\t_blob1.db");
_LIT(KTestDbName2, "c:\\test\\t_blob2.db");
_LIT(KAttachedDbName, "attached_db");
_LIT(KPrivateSecureDb, "c:\\private\\1111C1CC\\ps.db");
const TInt KLargeDataBufLen = 2048;
// A buffer containing 2Kb of data.
// When it is used to write to a blob the data will exceed the size of the client buffer
// (which is 8 bytes in debug, 1.5Kb on target) and will be immediately transferred to the server
TBuf8<KLargeDataBufLen> TheLargeData;
///////////////////////////////////////////////////////////////////////////////////////
// Test database delete functions
void DeleteTestDbs()
{
TheDb1.Close();
TheDb2.Close();
ThePrivateDb.Close();
(void)RSqlDatabase::Delete(KTestDbName1);
(void)RSqlDatabase::Delete(KTestDbName2);
(void)RSqlDatabase::Delete(KPrivateSecureDb);
}
///////////////////////////////////////////////////////////////////////////////////////
// Test macros and functions
void Check(TInt aValue, TInt aLine)
{
if(!aValue)
{
DeleteTestDbs();
TheTest(EFalse, aLine);
}
}
void Check(TInt aValue, TInt aExpected, TInt aLine)
{
if(aValue != aExpected)
{
DeleteTestDbs();
RDebug::Print(_L("*** Expected error: %d, got: %d\r\n"), aExpected, aValue);
TheTest(EFalse, aLine);
}
}
#define TEST(arg) ::Check((arg), __LINE__)
#define TEST2(aValue, aExpected) ::Check(aValue, aExpected, __LINE__)
///////////////////////////////////////////////////////////////////////////////////////
// Test database create functions
void CreateTestDir()
{
RFs fs;
TInt err = fs.Connect();
TEST2(err, KErrNone);
err = fs.MkDir(KTestDir);
TEST(err == KErrNone || err == KErrAlreadyExists);
err = fs.CreatePrivatePath(EDriveC);
TEST(err == KErrNone || err == KErrAlreadyExists);
fs.Close();
}
void CreateTestDbs()
{
// Create t_blob1.db
TInt err = TheDb1.Create(KTestDbName1);
TEST2(err, KErrNone);
err = TheDb1.Exec(_L("CREATE TABLE table1(I INTEGER, T TEXT, B BLOB)"));
TEST(err >= 0);
// Create t_blob2.db
err = TheDb2.Create(KTestDbName2);
TEST2(err, KErrNone);
err = TheDb2.Exec(_L("CREATE TABLE table2(int INTEGER, text TEXT, blob BLOB)"));
TEST(err >= 0);
// Insert a blob value of 'FGFGFGFGFG' (10 characters in size)
err = TheDb2.Exec(_L("INSERT INTO table2 VALUES(1, 'Text Data', x'46474647464746474647')"));
TEST2(err, 1);
// Create private secure db
err = ThePrivateDb.Create(KPrivateSecureDb);
TEST2(err, KErrNone);
err = ThePrivateDb.Exec(_L("CREATE TABLE table3(age INTEGER, name TEXT, picture BLOB)"));
TEST(err >= 0);
// Insert a blob value of 'ABABABABABABABA' (15 characters in size)
err = ThePrivateDb.Exec(_L("INSERT INTO table3 VALUES(31, 'John Smith', x'414241424142414241424142414241')"));
TEST2(err, 1);
}
void CreateIndices()
{
TInt err = TheDb1.Exec(_L("CREATE INDEX textIdx1 on table1(T)"));
TEST(err >= 0);
err = TheDb1.Exec(_L("CREATE INDEX blobIdx1 on table1(B)"));
TEST(err >= 0);
err = TheDb2.Exec(_L("CREATE INDEX textIdx2 on table2(text)"));
TEST(err >= 0);
err = TheDb2.Exec(_L("CREATE INDEX blobIdx2 on table2(blob)"));
TEST(err >= 0);
}
void RemoveIndices()
{
TInt err = TheDb1.Exec(_L("DROP INDEX textIdx1"));
TEST(err >= 0);
err = TheDb1.Exec(_L("DROP INDEX blobIdx1"));
TEST(err >= 0);
err = TheDb2.Exec(_L("DROP INDEX textIdx2"));
TEST(err >= 0);
err = TheDb2.Exec(_L("DROP INDEX blobIdx2"));
TEST(err >= 0);
}
void AttachTestDb2()
{
TInt err = TheDb1.Attach(KTestDbName2, KAttachedDbName);
TEST2(err, KErrNone);
}
void FillLargeDataBuf(TChar aChar = 'Z')
{
TheLargeData.Fill(aChar, KLargeDataBufLen);
}
///////////////////////////////////////////////////////////////////////////////////////
// Unit test functions
void CheckBlobPropertiesL(TInt aBlobSize)
{
// Check properties of the last inserted blob
RSqlStatement stmt;
CleanupClosePushL(stmt);
TInt err = stmt.Prepare(TheDb1, _L("SELECT B FROM table1 WHERE ROWID == :Val"));
TEST2(err, KErrNone);
TInt paramIndex = stmt.ParameterIndex(_L(":Val"));
TEST(paramIndex >= 0);
err = stmt.BindInt(paramIndex, TheDb1.LastInsertedRowId());
TEST2(err, KErrNone);
err = stmt.Next();
TEST2(err, KSqlAtRow);
// Check the 'declared column type' is ESqlBinary
TSqlColumnType declColType;
err = stmt.DeclaredColumnType(0, declColType);
TEST2(declColType, ESqlBinary);
// Check the 'runtime column type' is ESqlBinary
TSqlColumnType colType = stmt.ColumnType(0);
TEST2(colType, ESqlBinary);
// Check the 'column size' is the size of the blob
TInt blobSize = stmt.ColumnSize(0);
TEST2(blobSize, aBlobSize);
// Check the 'column value' is not 'NULL' (even for a zeroblob)
TBool isNull = stmt.IsNull(0);
TEST2(isNull, EFalse);
// Check the 'column value' can be retrieved as a binary value
TPtrC8 binaryPtr = stmt.ColumnBinaryL(0);
TEST2(binaryPtr.Length(), aBlobSize);
// Check the 'column value' cannot be retrieved as a text value (it is of type ESqlBinary)
TPtrC textptr = stmt.ColumnTextL(0);
TEST2(textptr.Length(), 0);
CleanupStack::PopAndDestroy(&stmt);
}
void InsertBindZeroBlob(TInt aBlobSize)
{
// Insert a record that has had a zeroblob bound to it
RSqlStatement stmt;
TInt err = stmt.Prepare(TheDb1, _L("INSERT INTO table1 values(1, 'some text', :Val)"));
TEST2(err, KErrNone);
TInt paramIndex = stmt.ParameterIndex(_L(":Val"));
TEST(paramIndex >= 0);
err = stmt.BindZeroBlob(paramIndex, aBlobSize);
TEST2(err, KErrNone);
err = stmt.Exec();
stmt.Close();
TEST2(err, 1);
}
void InsertSQLiteZeroBlob(TInt aBlobSize)
{
// Insert a record that contains the 'zeroblob()' function
RSqlStatement stmt;
TInt err = stmt.Prepare(TheDb1, _L("INSERT INTO table1 values(2, 'more text', zeroblob(:Val))"));
TEST2(err, KErrNone);
TInt paramIndex = stmt.ParameterIndex(_L(":Val"));
TEST(paramIndex >= 0);
err = stmt.BindInt(paramIndex, aBlobSize);
TEST2(err, KErrNone);
err = stmt.Exec();
stmt.Close();
TEST2(err, 1);
}
void InsertBlobValueL(TInt aBlobSize)
{
// Insert a record that contains an actual blob value
HBufC8* binaryData = HBufC8::NewLC(aBlobSize);
TPtr8 binaryDataPtr(binaryData->Des());
for(TInt i = 0; i < aBlobSize/2; ++i)
{
binaryDataPtr.Append(_L8("DE"));
}
RSqlStatement stmt;
CleanupClosePushL(stmt);
TInt err = stmt.Prepare(TheDb1, _L("INSERT INTO table1 values(3, 'even more text', :Val)"));
TEST2(err, KErrNone);
TInt paramIndex = stmt.ParameterIndex(_L(":Val"));
TEST(paramIndex >= 0);
err = stmt.BindBinary(paramIndex, binaryDataPtr);
TEST2(err, KErrNone);
err = stmt.Exec();
TEST2(err, 1);
CleanupStack::PopAndDestroy(2); // stmt, binaryData
}
void StreamBlob1L(TInt aBlobSize)
{
// Blob 1 is a zeroblob of size aBlobSize
// Read (zero) data from the blob
RSqlBlobReadStream rdStrm;
CleanupClosePushL(rdStrm);
rdStrm.OpenL(TheDb1, _L("table1"), _L("B"));
TInt size = rdStrm.SizeL(); // check the blob's size
TEST2(size, aBlobSize);
_LIT8(KFiveZeros, "\x0\x0\x0\x0\x0");
_LIT8(KTwentyZeros, "\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0");
TBuf8<50> data;
rdStrm.ReadL(data, 5);
TEST(data.Compare(KFiveZeros) == 0); // check 5 bytes of zero have been read
rdStrm.ReadL(data, 20);
TEST(data.Compare(KTwentyZeros) == 0); // check 20 bytes of zero have been read
CleanupStack::PopAndDestroy(&rdStrm);
// Write some actual data to the blob
RSqlBlobWriteStream wrStrm;
CleanupClosePushL(wrStrm);
wrStrm.OpenL(TheDb1, _L("table1"), _L("B"));
size = wrStrm.SizeL(); // check the blob's size
TEST2(size, aBlobSize);
wrStrm.WriteL(_L8("AABBCCDDEE")); // write 10 bytes
wrStrm.WriteL(_L8("FFGGHHIIJJ")); // write another 10 bytes
wrStrm.WriteL(_L8("KKLLMMNNOOPPQQRRSSTTUUVVWWXX")); // write another 28 bytes
wrStrm.CommitL();
CleanupStack::PopAndDestroy(&wrStrm);
// Read back some of the blob data
CleanupClosePushL(rdStrm);
rdStrm.OpenL(TheDb1, _L("table1"), _L("B"));
size = rdStrm.SizeL(); // check the blob's size
TEST2(size, aBlobSize);
rdStrm.ReadL(data, 4);
TEST(data.Compare(_L8("AABB")) == 0); // check the first 4 bytes
rdStrm.ReadL(data, 35);
TEST(data.Compare(_L8("CCDDEEFFGGHHIIJJKKLLMMNNOOPPQQRRSST")) == 0); // check the next 35 bytes
rdStrm.ReadL(data, 19);
_LIT8(KTrailingZeros, "TUUVVWWXX\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0");
TEST(data.Compare(KTrailingZeros) == 0); // check the next 19 bytes (which includes some of the original zero bytes)
CleanupStack::PopAndDestroy(&rdStrm);
}
void StreamText1L()
{
// Read data from the text column -
// the database encoding is UTF-16 so the text is stored as UTF-16
RSqlBlobReadStream rdStrm;
CleanupClosePushL(rdStrm);
rdStrm.OpenL(TheDb1, _L("table1"), _L("T"));
TBuf<50> dataUTF16;
rdStrm.ReadL(dataUTF16, 9);
TEST(dataUTF16.Compare(_L("some text")) == 0);
CleanupStack::PopAndDestroy(&rdStrm);
// Write some data to the text column (as UTF-16)
RSqlBlobWriteStream wrStrm;
CleanupClosePushL(wrStrm);
wrStrm.OpenL(TheDb1, _L("table1"), _L("T"));
wrStrm.WriteL(_L("new text!")); // can only write up to the original size of the data - 9 chars
wrStrm.CommitL();
CleanupStack::PopAndDestroy(&wrStrm);
// Read back some of the text (as UTF-16)
CleanupClosePushL(rdStrm);
rdStrm.OpenL(TheDb1, _L("table1"), _L("T"));
rdStrm.ReadL(dataUTF16, 9);
TEST(dataUTF16.Compare(_L("new text!")) == 0);
CleanupStack::PopAndDestroy(&rdStrm);
// Write some data to the text column (as UTF-8)
CleanupClosePushL(wrStrm);
wrStrm.OpenL(TheDb1, _L("table1"), _L("T"));
wrStrm.WriteL(_L8("try again"));
wrStrm.CommitL();
CleanupStack::PopAndDestroy(&wrStrm);
// Read back some of the text (as UTF-8)
CleanupClosePushL(rdStrm);
rdStrm.OpenL(TheDb1, _L("table1"), _L("T"));
TBuf8<50> dataUTF8;
rdStrm.ReadL(dataUTF8, 9);
TEST(dataUTF8.Compare(_L8("try again")) == 0);
CleanupStack::PopAndDestroy(&rdStrm);
}
void StreamBlob2L(TInt aBlobSize)
{
// Blob 2 is a zeroblob of size aBlobSize
// Read (zero) data from the blob
RSqlBlobReadStream rdStrm;
CleanupClosePushL(rdStrm);
rdStrm.OpenL(TheDb1, _L("table1"), _L("B"));
TInt size = rdStrm.SizeL(); // check the blob's size
TEST2(size, aBlobSize);
_LIT8(KFifteenZeros, "\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0");
_LIT8(KSixtyOneZeros, "\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0");
TBuf8<200> data;
rdStrm.ReadL(data, 15);
TEST(data.Compare(KFifteenZeros) == 0); // check 15 bytes of zero have been read
rdStrm.ReadL(data, 61);
TEST(data.Compare(KSixtyOneZeros) == 0); // check 61 bytes of zero have been read
size = rdStrm.SizeL(); // check the blob's size
TEST2(size, aBlobSize);
CleanupStack::PopAndDestroy(&rdStrm);
// Write some actual data to the blob
RSqlBlobWriteStream wrStrm;
CleanupClosePushL(wrStrm);
wrStrm.OpenL(TheDb1, _L("table1"), _L("B"));
size = wrStrm.SizeL(); // check the blob's size
TEST2(size, aBlobSize);
wrStrm.WriteL(_L8("SOMENEWDATASOMENEWDATAS")); // write 23 bytes
wrStrm.WriteL(_L8("OMENEWDATASOMENEWDATASOMENEWDATASOMENEWDATA")); // write another 43 bytes
wrStrm.WriteL(_L8("SOMENEWDATASOMENEWDATASOMENEWDATASOMENEWDATASOMENEWDATASOMENEWDATASOMENE")); // write another 72 bytes
wrStrm.WriteL(_L8("WDATASOMENEWDATA")); // write another 16 bytes
size = wrStrm.SizeL(); // check the blob's size
TEST2(size, aBlobSize);
wrStrm.CommitL();
CleanupStack::PopAndDestroy(&wrStrm);
// Read back some of the blob data
CleanupClosePushL(rdStrm);
rdStrm.OpenL(TheDb1, _L("table1"), _L("B"));
size = rdStrm.SizeL(); // check the blob's size
TEST2(size, aBlobSize);
rdStrm.ReadL(data, 1);
TEST(data.Compare(_L8("S")) == 0); // check the first byte
rdStrm.ReadL(data, 136);
TEST(data.Compare(_L8("OMENEWDATASOMENEWDATASOMENEWDATASOMENEWDATASOMENEWDATASOMENEWDATASOMENEWDATASOMENEWDATASOMENEWDATASOMENEWDATASOMENEWDATASOMENEWDATASOMEN")) == 0); // check the next 136 bytes
rdStrm.ReadL(data, 30);
_LIT8(KTrailingZeros, "EWDATASOMENEWDATA\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0");
TEST(data.Compare(KTrailingZeros) == 0); // check the next 30 bytes (which includes some of the original zero bytes)
size = rdStrm.SizeL(); // check the blob's size
TEST2(size, aBlobSize);
CleanupStack::PopAndDestroy(&rdStrm);
}
void StreamBlob3L(TInt aBlobSize)
{
// Blob 3 is a 'real' blob of value "DEDEDEDEDEDEDEDEDEDE"
// Read some of the zero data
RSqlBlobReadStream rdStrm;
CleanupClosePushL(rdStrm);
rdStrm.OpenL(TheDb1, _L("table1"), _L("B"));
TInt size = rdStrm.SizeL(); // check the blob's size
TEST2(size, aBlobSize);
TBuf8<20> data;
rdStrm.ReadL(data, 3);
TEST(data.Compare(_L8("DED")) == 0); // check the first 3 bytes
rdStrm.ReadL(data, 12);
TEST(data.Compare(_L8("EDEDEDEDEDED")) == 0); // check the next 12 bytes
size = rdStrm.SizeL(); // check the blob's size
TEST2(size, aBlobSize);
CleanupStack::PopAndDestroy(&rdStrm);
// Write some new data to the blob
RSqlBlobWriteStream wrStrm;
CleanupClosePushL(wrStrm);
wrStrm.OpenL(TheDb1, _L("table1"), _L("B"));
size = wrStrm.SizeL(); // check the blob's size
TEST2(size, aBlobSize);
wrStrm.WriteL(_L8("ABCDEF")); // write 6 bytes
wrStrm.WriteL(_L8("GHIJKLMNOPQ")); // write another 11 bytes
size = wrStrm.SizeL(); // check the blob's size
TEST2(size, aBlobSize);
wrStrm.CommitL();
CleanupStack::PopAndDestroy(&wrStrm);
// Read back some of the blob data
CleanupClosePushL(rdStrm);
rdStrm.OpenL(TheDb1, _L("table1"), _L("B"));
size = rdStrm.SizeL(); // check the blob's size
TEST2(size, aBlobSize);
rdStrm.ReadL(data, 2);
TEST(data.Compare(_L8("AB")) == 0); // check the first 2 bytes
rdStrm.ReadL(data, 7);
TEST(data.Compare(_L8("CDEFGHI")) == 0); // check the next 7 bytes
rdStrm.ReadL(data, 11);
TEST(data.Compare(_L8("JKLMNOPQEDE")) == 0); // check the next 11 bytes
size = rdStrm.SizeL(); // check the blob's size
TEST2(size, aBlobSize);
CleanupStack::PopAndDestroy(&rdStrm);
// Seek to position - the blob value is now "ABCDEFGHIJKLMNOPQEDE"
CleanupClosePushL(rdStrm);
rdStrm.OpenL(TheDb1, _L("table1"), _L("B"));
TStreamPos pos(9);
rdStrm.Source()->SeekL(MStreamBuf::ERead, pos);
rdStrm.ReadL(data, 2);
TEST(data.Compare(_L8("JK")) == 0);
rdStrm.ReadL(data, 5);
TEST(data.Compare(_L8("LMNOP")) == 0);
TStreamPos pos2(3);
rdStrm.Source()->SeekL(MStreamBuf::ERead, pos2);
rdStrm.ReadL(data, 4);
TEST(data.Compare(_L8("DEFG")) == 0);
TStreamPos pos3(21);
TRAPD(err, rdStrm.Source()->SeekL(MStreamBuf::ERead, pos3));
TEST2(err, KErrEof);
TStreamPos pos4(18);
rdStrm.Source()->SeekL(MStreamBuf::ERead, pos4);
TRAP(err, rdStrm.ReadL(data, 3));
TEST2(err, KErrEof);
CleanupStack::PopAndDestroy(&rdStrm);
CleanupClosePushL(wrStrm);
wrStrm.OpenL(TheDb1, _L("table1"), _L("B"));
TStreamPos pos5(7);
wrStrm.Sink()->SeekL(MStreamBuf::EWrite, pos5);
wrStrm.WriteL(_L8("ZZZZZ"));
wrStrm.WriteL(_L8("YYY"));
TStreamPos pos6(17);
wrStrm.Sink()->SeekL(MStreamBuf::EWrite, pos6);
wrStrm.WriteL(_L8("XXX"));
wrStrm.CommitL();
wrStrm.Close();
CleanupClosePushL(rdStrm);
rdStrm.OpenL(TheDb1, _L("table1"), _L("B"));
rdStrm.ReadL(data, 20);
TEST(data.Compare(_L8("ABCDEFGZZZZZYYYPQXXX")) == 0);
rdStrm.Close();
TStreamPos pos7(21);
wrStrm.OpenL(TheDb1, _L("table1"), _L("B"));
TRAP(err, wrStrm.Sink()->SeekL(MStreamBuf::EWrite, pos7));
TEST2(err, KErrEof);
TStreamPos pos8(18);
wrStrm.Sink()->SeekL(MStreamBuf::EWrite, pos8);
wrStrm.WriteL(_L8("TTT"));
TRAP(err, wrStrm.CommitL());
TEST2(err, KErrEof);
wrStrm.Close();
rdStrm.OpenL(TheDb1, _L("table1"), _L("B"));
rdStrm.ReadL(data, 20);
TEST(data.Compare(_L8("ABCDEFGZZZZZYYYPQXXX")) == 0);
CleanupStack::PopAndDestroy(2);
}
/**
@SYMTestCaseID SYSLIB-SQL-UT-4099
@SYMTestCaseDesc Incremental blob tests on a database using streams.
Insert a zeroblob using RSqlStatement::BindZeroBlob(), read and write to
the blob using streams, also read and write to a text column using streams.
Tests the RSqlBlobReadStream and RSqlBlobWriteStream methods.
@SYMTestPriority Medium
@SYMTestActions Execution of incremental blob stream operations on a database.
@SYMTestExpectedResults Test must not fail
@SYMREQ REQ10411
REQ10418
*/
void StreamBindZeroBlobTestL()
{
const TInt KBlobSize = 300;
InsertBindZeroBlob(KBlobSize);
CheckBlobPropertiesL(KBlobSize);
StreamBlob1L(KBlobSize);
StreamText1L();
CheckBlobPropertiesL(KBlobSize);
}
/**
@SYMTestCaseID SYSLIB-SQL-UT-4100
@SYMTestCaseDesc Incremental blob tests on a database, using streams.
Insert a zeroblob using the SQLite function zeroblob(),
read and write to the blob using streams.
Tests the RSqlBlobReadStream and RSqlBlobWriteStream methods.
@SYMTestPriority Medium
@SYMTestActions Execution of incremental blob stream operations on a database.
@SYMTestExpectedResults Test must not fail
@SYMREQ REQ10411
REQ10418
*/
void StreamSqliteZeroBlobTestL()
{
const TInt KBlobSize = 1500;
InsertSQLiteZeroBlob(KBlobSize);
CheckBlobPropertiesL(KBlobSize);
StreamBlob2L(KBlobSize);
CheckBlobPropertiesL(KBlobSize);
}
/**
@SYMTestCaseID SYSLIB-SQL-UT-4101
@SYMTestCaseDesc Incremental blob tests on a database, using streams.
Insert a real blob, read and write to the blob using streams.
Tests the RSqlBlobReadStream and RSqlBlobWriteStream methods.
@SYMTestPriority Medium
@SYMTestActions Execution of incremental blob stream operations on a database.
@SYMTestExpectedResults Test must not fail
@SYMREQ REQ10411
REQ10418
*/
void StreamRealBlobTestL()
{
const TInt KBlobSize = 20;
InsertBlobValueL(KBlobSize);
CheckBlobPropertiesL(KBlobSize);
StreamBlob3L(KBlobSize);
CheckBlobPropertiesL(KBlobSize);
}
/**
@SYMTestCaseID SYSLIB-SQL-UT-4102
@SYMTestCaseDesc Whole value blob retrieval tests on a database.
Retrieve the whole value of a blob object in one go.
Tests the TSqlBlob 'get' methods.
@SYMTestPriority Medium
@SYMTestActions Execution of whole value blob retrieval operations on a database.
@SYMTestExpectedResults Test must not fail
@SYMREQ REQ10411
REQ10418
*/
void GetWholeBlob3L()
{
// Blob 3 is a 'real' blob of value "ABCDEFGZZZZZYYYPQXXX"
const TInt KBlobSize = 20;
// Get the whole content of Blob 3 in one go, using TSqlBlob::GetLC()
HBufC8* wholeBuf = TSqlBlob::GetLC(TheDb1, _L("table1"), _L("B"));
TInt bufSize = wholeBuf->Size();
TEST2(bufSize, KBlobSize);
TEST(wholeBuf->Des().Compare(_L8("ABCDEFGZZZZZYYYPQXXX")) == 0);
CleanupStack::PopAndDestroy(wholeBuf);
// Get the whole content of Blob 3 in one go, using TSqlBlob::Get()
HBufC8* buf = HBufC8::NewLC(KBlobSize);
TPtr8 bufPtr(buf->Des());
TInt err = TSqlBlob::Get(TheDb1, _L("table1"), _L("B"), bufPtr);
TEST2(err, KErrNone);
TEST(bufPtr.Compare(_L8("ABCDEFGZZZZZYYYPQXXX")) == 0);
CleanupStack::PopAndDestroy(buf);
// Get the whole content of Blob 3 in one go, using TSqlBlob::Get(),
// ensuring that a buffer larger than the blob can be used
HBufC8* largerBuf = HBufC8::NewLC(KBlobSize * 2);
TPtr8 largerBufPtr(largerBuf->Des());
err = TSqlBlob::Get(TheDb1, _L("table1"), _L("B"), largerBufPtr);
TEST2(err, KErrNone);
TEST(largerBufPtr.Compare(_L8("ABCDEFGZZZZZYYYPQXXX")) == 0);
CleanupStack::PopAndDestroy(largerBuf);
// Get the whole content of the blob in 2 chunks of 10 bytes
HBufC8* streamBuf = HBufC8::NewLC(10);
TPtr8 streamBufPtr(streamBuf->Des());
RSqlBlobReadStream rdStrm;
CleanupClosePushL(rdStrm);
rdStrm.OpenL(TheDb1, _L("table1"), _L("B"));
TInt size = rdStrm.SizeL();
TEST2(size, KBlobSize);
HBufC8* combinedData = HBufC8::NewLC(KBlobSize);
TPtr8 combinedDataPtr(combinedData->Des());
for(TInt i = 2; i > 0 ; --i)
{
rdStrm.ReadL(streamBufPtr, 10);
combinedDataPtr.Append(streamBufPtr);
}
TEST(combinedDataPtr.Compare(_L8("ABCDEFGZZZZZYYYPQXXX")) == 0);
CleanupStack::PopAndDestroy(3); // combinedDataRead, rdStrm, streamBuf
}
/**
@SYMTestCaseID SYSLIB-SQL-UT-4104
@SYMTestCaseDesc Whole value blob write tests on a database.
Write the whole value of a blob object in one go.
Tests the TSqlBlob 'set' methods.
@SYMTestPriority Medium
@SYMTestActions Execution of whole value blob write operations on a database.
@SYMTestExpectedResults Test must not fail
@SYMREQ REQ10411
REQ10418
*/
void SetWholeBlob3L()
{
// Blob 3 is a 'real' blob of value "KKKKKKKKKKKKKKKKKEDE"
TInt KBlobSize = 20;
// Set the whole content of Blob 3 in one go
HBufC8* dataBuf = HBufC8::NewLC(KBlobSize);
TPtr8 dataPtr(dataBuf->Des());
dataPtr.Append(_L8("CDCDCDCDCDCDCDCDCDCD"));
TSqlBlob::SetL(TheDb1, _L("table1"), _L("B"), dataPtr);
CleanupStack::PopAndDestroy(dataBuf);
// Check that the new blob data was written
HBufC8* retrievedDataBuf = TSqlBlob::GetLC(TheDb1, _L("table1"), _L("B"));
TInt blobLength = retrievedDataBuf->Size();
TEST2(blobLength, KBlobSize);
TEST(retrievedDataBuf->Des().Compare(_L8("CDCDCDCDCDCDCDCDCDCD")) == 0);
CleanupStack::PopAndDestroy(retrievedDataBuf);
// Set the whole content of the blob in 2 chunks of 10 bytes
RSqlBlobWriteStream wrStrm;
CleanupClosePushL(wrStrm);
wrStrm.OpenL(TheDb1, _L("table1"), _L("B"));
TInt size = wrStrm.SizeL();
TEST2(size, KBlobSize);
for(TInt i = 2; i > 0; --i)
{
wrStrm.WriteL(_L8("ZYZYZYZYZY"));
}
CleanupStack::PopAndDestroy(&wrStrm);
// Check that the new blob data was written
retrievedDataBuf = TSqlBlob::GetLC(TheDb1, _L("table1"), _L("B"));
blobLength = retrievedDataBuf->Size();
TEST2(blobLength, KBlobSize);
TEST(retrievedDataBuf->Des().Compare(_L8("ZYZYZYZYZYZYZYZYZYZY")) == 0);
CleanupStack::PopAndDestroy(retrievedDataBuf);
}
/**
@SYMTestCaseID SYSLIB-SQL-UT-4106
@SYMTestCaseDesc Blob read and write tests on an attached database.
Performs streaming and whole value read and write operations
on a blob in an attached database to ensure that the
RSqlBlobReadStream, RSqlBlobWriteStream and TSqlBlob methods
can be used on an attached database.
Tests the RSqlBlobReadStream, RSqlBlobWriteStream and TSqlBlob methods.
@SYMTestPriority Medium
@SYMTestActions Execution of blob read and write operations on an attached database.
@SYMTestExpectedResults Test must not fail
@SYMREQ REQ10411
REQ10418
*/
void AttachDbTestL()
{
// Attach test db 2 to test db 1
AttachTestDb2();
// Open a read stream on a blob in the attached database -
// the blob in the single record has a value of "FGFGFGFGFG"
const TInt KAttachedBlobSize = 10;
RSqlBlobReadStream rdStrm;
CleanupClosePushL(rdStrm);
rdStrm.OpenL(TheDb1, _L("table2"), _L("blob"), TheDb2.LastInsertedRowId(), KAttachedDbName);
TInt size = rdStrm.SizeL(); // check the blob's size
TEST2(size, KAttachedBlobSize);
TBuf8<20> data;
rdStrm.ReadL(data, 2);
TEST(data.Compare(_L8("FG")) == 0); // check the first 2 bytes
rdStrm.ReadL(data, 8);
TEST(data.Compare(_L8("FGFGFGFG")) == 0); // check the next 8 bytes
size = rdStrm.SizeL(); // check the blob's size
TEST2(size, KAttachedBlobSize);
CleanupStack::PopAndDestroy(&rdStrm);
// Write some new data to the blob
RSqlBlobWriteStream wrStrm;
CleanupClosePushL(wrStrm);
wrStrm.OpenL(TheDb1, _L("table2"), _L("blob"), TheDb2.LastInsertedRowId(), KAttachedDbName);
size = wrStrm.SizeL(); // check the blob's size
TEST2(size, KAttachedBlobSize);
wrStrm.WriteL(_L8("LLLL")); // write 4 bytes
wrStrm.WriteL(_L8("MMMMM")); // write another 5 bytes
size = wrStrm.SizeL(); // check the blob's size
TEST2(size, KAttachedBlobSize);
wrStrm.CommitL();
CleanupStack::PopAndDestroy(&wrStrm);
// Read back some of the blob data
CleanupClosePushL(rdStrm);
rdStrm.OpenL(TheDb1, _L("table2"), _L("blob"), TheDb2.LastInsertedRowId(), KAttachedDbName);
size = rdStrm.SizeL(); // check the blob's size
TEST2(size, KAttachedBlobSize);
rdStrm.ReadL(data, 2);
TEST(data.Compare(_L8("LL")) == 0); // check the first 2 bytes
rdStrm.ReadL(data, 5);
TEST(data.Compare(_L8("LLMMM")) == 0); // check the next 5 bytes
rdStrm.ReadL(data, 3);
TEST(data.Compare(_L8("MMG")) == 0); // check the next 3 bytes
size = rdStrm.SizeL(); // check the blob's size
TEST2(size, KAttachedBlobSize);
CleanupStack::PopAndDestroy(&rdStrm);
// Get the entire blob in the attached database
HBufC8* wholeBuf = TSqlBlob::GetLC(TheDb1, _L("table2"), _L("blob"), TheDb2.LastInsertedRowId(), KAttachedDbName);
TInt blobLength = wholeBuf->Length();
TEST2(blobLength, KAttachedBlobSize);
TEST(wholeBuf->Des().Compare(_L8("LLLLMMMMMG")) == 0);
CleanupStack::PopAndDestroy(wholeBuf);
TSqlBlob::Get(TheDb1, _L("table2"), _L("blob"), data, TheDb2.LastInsertedRowId(), KAttachedDbName);
TEST(data.Compare(_L8("LLLLMMMMMG")) == 0);
// Set the entire blob in the attached database
data.Zero();
data.Append(_L8("STSTSTSTST"));
TSqlBlob::SetL(TheDb1, _L("table2"), _L("blob"), data, TheDb2.LastInsertedRowId(), KAttachedDbName);
wholeBuf = TSqlBlob::GetLC(TheDb1, _L("table2"), _L("blob"), TheDb2.LastInsertedRowId(), KAttachedDbName);
TEST(wholeBuf->Des().Compare(_L8("STSTSTSTST")) == 0);
CleanupStack::PopAndDestroy(wholeBuf);
}
void BadParamReadStreamL()
{
HBufC* tooLongName = HBufC::NewLC(KMaxFileName + 1);
TPtr tooLongNameDes = tooLongName->Des();
tooLongNameDes.Fill('A', KMaxFileName + 1);
// RSqlBlobReadStream::OpenL()
RSqlBlobReadStream rdStrm;
CleanupClosePushL(rdStrm);
TRAPD(err, rdStrm.OpenL(TheDb1, _L("table1"), _L("B"))); // a successful open (on a BLOB column)
TEST2(err, KErrNone);
rdStrm.Close();
TRAP(err, rdStrm.OpenL(TheDb1, _L("table1"), _L("T"))); // a successful open (on a TEXT column)
TEST2(err, KErrNone);
rdStrm.Close();
TRAP(err, rdStrm.OpenL(TheDb2, _L("table1"), _L("B"))); // wrong db connection
TEST2(err, KSqlErrGeneral);
TRAP(err, rdStrm.OpenL(TheDb1, _L(""), _L("B"))); // empty table name
TEST2(err, KErrBadName);
TRAP(err, rdStrm.OpenL(TheDb1, tooLongNameDes, _L("B"))); // too long table name
TEST2(err, KErrBadName);
TRAP(err, rdStrm.OpenL(TheDb1, _L("invalidTableName"), _L("B"))); // invalid table name
TEST2(err, KSqlErrGeneral);
TRAP(err, rdStrm.OpenL(TheDb1, _L("table1"), _L(""))); // empty column name
TEST2(err, KErrBadName);
TRAP(err, rdStrm.OpenL(TheDb1, _L("table1"), tooLongNameDes)); // too long column name
TEST2(err, KErrBadName);
TRAP(err, rdStrm.OpenL(TheDb1, _L("table1"), _L("invalidColumnName"))); // invalid column name
TEST2(err, KSqlErrGeneral);
TRAP(err, rdStrm.OpenL(TheDb1, _L("table1"), _L("I"))); // invalid column type
TEST2(err, KSqlErrGeneral);
TRAP(err, rdStrm.OpenL(TheDb1, _L("table1"), _L("B"), -12)); // illegal ROWID
TEST2(err, KErrArgument);
TRAP(err, rdStrm.OpenL(TheDb1, _L("table1"), _L("B"), 99)); // invalid ROWID
TEST2(err, KSqlErrGeneral);
TRAP(err, rdStrm.OpenL(TheDb1, _L("table1"), _L("B"), KSqlLastInsertedRowId, _L("main"))); // a successful open (on a BLOB column)
TEST2(err, KErrNone);
rdStrm.Close();
TRAP(err, rdStrm.OpenL(TheDb1, _L("table1"), _L("B"), KSqlLastInsertedRowId, _L(""))); // a successful open (on a BLOB column)
TEST2(err, KErrNone);
rdStrm.Close();
TRAP(err, rdStrm.OpenL(TheDb1, _L("table1"), _L("T"), KSqlLastInsertedRowId, _L("main"))); // a successful open (on a TEXT column)
TEST2(err, KErrNone);
rdStrm.Close();
TRAP(err, rdStrm.OpenL(TheDb1, _L("table1"), _L("T"), KSqlLastInsertedRowId, _L(""))); // a successful open (on a TEXT column)
TEST2(err, KErrNone);
rdStrm.Close();
TRAP(err, rdStrm.OpenL(TheDb1, _L("table2"), _L("blob"), TheDb2.LastInsertedRowId(), KAttachedDbName)); // a successful open (on a BLOB column)
TEST2(err, KErrNone);
rdStrm.Close();
TRAP(err, rdStrm.OpenL(TheDb1, _L("table2"), _L("text"), TheDb2.LastInsertedRowId(), KAttachedDbName)); // a successful open (on a TEXT column)
TEST2(err, KErrNone);
rdStrm.Close();
TRAP(err, rdStrm.OpenL(TheDb2, _L("table2"), _L("blob"), TheDb2.LastInsertedRowId(), KAttachedDbName)); // wrong db connection
TEST2(err, KSqlErrGeneral);
TRAP(err, rdStrm.OpenL(TheDb1, _L("table2"), _L("blob"), TheDb2.LastInsertedRowId(), tooLongNameDes)); // too long attached db name
TEST2(err, KErrBadName);
TRAP(err, rdStrm.OpenL(TheDb1, _L("table2"), _L("blob"), TheDb2.LastInsertedRowId(), _L("invalidAttachedDbName"))); // invalid attached db name
TEST2(err, KSqlErrGeneral);
TRAP(err, rdStrm.OpenL(TheDb1, _L("invalidTableName"), _L("blob"), TheDb2.LastInsertedRowId(), KAttachedDbName)); // invalid table name
TEST2(err, KSqlErrGeneral);
TRAP(err, rdStrm.OpenL(TheDb1, _L("table2"), _L("invalidColumnName"), TheDb2.LastInsertedRowId(), KAttachedDbName)); // invalid column name
TEST2(err, KSqlErrGeneral);
TRAP(err, rdStrm.OpenL(TheDb1, _L("table2"), _L("int"), TheDb2.LastInsertedRowId(), KAttachedDbName)); // invalid column type
TEST2(err, KSqlErrGeneral);
TRAP(err, rdStrm.OpenL(TheDb1, _L("table2"), _L("blob"), 64, KAttachedDbName)); // invalid ROWID
TEST2(err, KSqlErrGeneral);
CleanupStack::PopAndDestroy(&rdStrm);
CleanupStack::PopAndDestroy(tooLongName);
// RSqlBlobReadStream::Source()::SeekL()
CleanupClosePushL(rdStrm);
rdStrm.OpenL(TheDb1, _L("table1"), _L("B"));
TInt size = rdStrm.SizeL();
TEST(size > 0);
TStreamPos pos(-1);
TRAP(err, rdStrm.Source()->SeekL(MStreamBuf::ERead, pos));
TEST2(err, KErrEof);
TStreamPos pos2(size - 1);
TRAP(err, rdStrm.Source()->SeekL(MStreamBuf::ERead, pos2));
TEST2(err, KErrNone);
TStreamPos pos3(size + 1);
TRAP(err, rdStrm.Source()->SeekL(MStreamBuf::ERead, pos3));
TEST2(err, KErrEof);
CleanupStack::PopAndDestroy(&rdStrm);
// RSqlBlobReadStream::ReadL()
CleanupClosePushL(rdStrm);
rdStrm.OpenL(TheDb1, _L("table1"), _L("B"));
size = rdStrm.SizeL();
TEST2(size, 20);
TBuf8<20> dataBuf;
TBuf8<50> tooBigDataBuf;
TRAP(err, rdStrm.ReadL(tooBigDataBuf));
TEST2(err, KErrEof);
rdStrm.Close();
rdStrm.OpenL(TheDb1, _L("table1"), _L("B"));
TRAP(err, rdStrm.ReadL(tooBigDataBuf, size + 1));
TEST2(err, KErrEof);
rdStrm.Close();
rdStrm.OpenL(TheDb1, _L("table1"), _L("B"));
TRAP(err, rdStrm.ReadL(tooBigDataBuf, TChar('J'))); // doesn't find 'J' so tries to fill the buffer to its max size
TEST2(err, KErrEof);
CleanupStack::PopAndDestroy(&rdStrm);
}
void BadParamWriteStreamL()
{
HBufC* tooLongName = HBufC::NewLC(KMaxFileName + 1);
TPtr tooLongNameDes = tooLongName->Des();
tooLongNameDes.Fill('A', KMaxFileName + 1);
// RSqlBlobWriteStream::OpenL()
RSqlBlobWriteStream wrStrm;
CleanupClosePushL(wrStrm);
TRAPD(err, wrStrm.OpenL(TheDb1, _L("table1"), _L("B"))); // a successful open (on a BLOB column)
TEST2(err, KErrNone);
wrStrm.Close();
TRAP(err, wrStrm.OpenL(TheDb1, _L("table1"), _L("T"))); // a successful open (on a TEXT column)
TEST2(err, KErrNone);
wrStrm.Close();
TRAP(err, wrStrm.OpenL(TheDb2, _L("table1"), _L("B"))); // wrong db connection
TEST2(err, KSqlErrGeneral);
TRAP(err, wrStrm.OpenL(TheDb1, _L(""), _L("B"))); // empty table name
TEST2(err, KErrBadName);
TRAP(err, wrStrm.OpenL(TheDb1, tooLongNameDes, _L("B"))); // too long table name
TEST2(err, KErrBadName);
TRAP(err, wrStrm.OpenL(TheDb1, _L("invalidTableName"), _L("B"))); // invalid table name
TEST2(err, KSqlErrGeneral);
TRAP(err, wrStrm.OpenL(TheDb1, _L("table1"), _L(""))); // empty column name
TEST2(err, KErrBadName);
TRAP(err, wrStrm.OpenL(TheDb1, _L("table1"), tooLongNameDes)); // too long column name
TEST2(err, KErrBadName);
TRAP(err, wrStrm.OpenL(TheDb1, _L("table1"), _L("invalidColumnName"))); // invalid column name
TEST2(err, KSqlErrGeneral);
TRAP(err, wrStrm.OpenL(TheDb1, _L("table1"), _L("I"))); // invalid column type
TEST2(err, KSqlErrGeneral);
TRAP(err, wrStrm.OpenL(TheDb1, _L("table1"), _L("B"), 0)); // illegal ROWID
TEST2(err, KErrArgument);
TRAP(err, wrStrm.OpenL(TheDb1, _L("table1"), _L("B"), 99)); // invalid ROWID
TEST2(err, KSqlErrGeneral);
TRAP(err, wrStrm.OpenL(TheDb1, _L("table1"), _L("B"), KSqlLastInsertedRowId, _L("main"))); // a successful open (on a BLOB column)
TEST2(err, KErrNone);
wrStrm.Close();
TRAP(err, wrStrm.OpenL(TheDb1, _L("table1"), _L("B"), KSqlLastInsertedRowId, _L(""))); // a successful open (on a BLOB column)
TEST2(err, KErrNone);
wrStrm.Close();
TRAP(err, wrStrm.OpenL(TheDb1, _L("table1"), _L("T"), KSqlLastInsertedRowId, _L("main"))); // a successful open (on a TEXT column)
TEST2(err, KErrNone);
wrStrm.Close();
TRAP(err, wrStrm.OpenL(TheDb1, _L("table1"), _L("T"), KSqlLastInsertedRowId, _L(""))); // a successful open (on a TEXT column)
TEST2(err, KErrNone);
wrStrm.Close();
TRAP(err, wrStrm.OpenL(TheDb1, _L("table2"), _L("blob"), TheDb2.LastInsertedRowId(), KAttachedDbName)); // a successful open (on a BLOB column)
TEST2(err, KErrNone);
wrStrm.Close();
TRAP(err, wrStrm.OpenL(TheDb1, _L("table2"), _L("text"), TheDb2.LastInsertedRowId(), KAttachedDbName)); // a successful open (on a TEXT column)
TEST2(err, KErrNone);
wrStrm.Close();
TRAP(err, wrStrm.OpenL(TheDb2, _L("table2"), _L("blob"), TheDb2.LastInsertedRowId(), KAttachedDbName)); // wrong db connection
TEST2(err, KSqlErrGeneral);
TRAP(err, wrStrm.OpenL(TheDb1, _L("table2"), _L("blob"), TheDb2.LastInsertedRowId(), tooLongNameDes)); // too long attached db name
TEST2(err, KErrBadName);
TRAP(err, wrStrm.OpenL(TheDb1, _L("table2"), _L("blob"), TheDb2.LastInsertedRowId(), _L("invalidAttachedDbName"))); // invalid attached db name
TEST2(err, KSqlErrGeneral);
TRAP(err, wrStrm.OpenL(TheDb1, _L("invalidTableName"), _L("blob"), TheDb2.LastInsertedRowId(), KAttachedDbName)); // invalid table name
TEST2(err, KSqlErrGeneral);
TRAP(err, wrStrm.OpenL(TheDb1, _L("table2"), _L("invalidColumnName"), TheDb2.LastInsertedRowId(), KAttachedDbName)); // invalid column name
TEST2(err, KSqlErrGeneral);
TRAP(err, wrStrm.OpenL(TheDb1, _L("table2"), _L("int"), TheDb2.LastInsertedRowId(), KAttachedDbName)); // invalid column type
TEST2(err, KSqlErrGeneral);
TRAP(err, wrStrm.OpenL(TheDb1, _L("table2"), _L("blob"), 64, KAttachedDbName)); // invalid ROWID
TEST2(err, KSqlErrGeneral);
CleanupStack::PopAndDestroy(&wrStrm);
CleanupStack::PopAndDestroy(tooLongName);
// RSqlBlobWriteStream::Sink()::SeekL()
CleanupClosePushL(wrStrm);
wrStrm.OpenL(TheDb1, _L("table1"), _L("B"));
TInt size = wrStrm.SizeL();
TEST(size > 0);
TStreamPos pos(-1);
TRAP(err, wrStrm.Sink()->SeekL(MStreamBuf::ERead, pos));
TEST2(err, KErrEof);
TStreamPos pos2(size - 1);
TRAP(err, wrStrm.Sink()->SeekL(MStreamBuf::ERead, pos2));
TEST2(err, KErrNone);
TStreamPos pos3(size + 1);
TRAP(err, wrStrm.Sink()->SeekL(MStreamBuf::ERead, pos3));
TEST2(err, KErrEof);
CleanupStack::PopAndDestroy(&wrStrm);
// RSqlBlobWriteStream::WriteL()
CleanupClosePushL(wrStrm);
wrStrm.OpenL(TheDb1, _L("table1"), _L("B"));
size = wrStrm.SizeL();
TEST2(size, 20);
TBuf8<50> tooBigDataBuf;
tooBigDataBuf.Fill('B', 50);
TRAP(err, wrStrm.WriteL(tooBigDataBuf));
#ifdef _DEBUG
TEST2(err, KErrEof);
#else
TEST2(err, KErrNone);
TRAP(err, wrStrm.CommitL());
TEST2(err, KErrEof);
#endif
wrStrm.Close();
wrStrm.OpenL(TheDb1, _L("table1"), _L("B"));
TRAP(err, wrStrm.WriteL(tooBigDataBuf, size + 1));
#ifdef _DEBUG
TEST2(err, KErrEof);
#else
TEST2(err, KErrNone);
TRAP(err, wrStrm.CommitL());
TEST2(err, KErrEof);
#endif
CleanupStack::PopAndDestroy(&wrStrm);
}
void BadParamGetL()
{
HBufC* tooLongName = HBufC::NewLC(KMaxFileName + 1);
TPtr tooLongNameDes = tooLongName->Des();
tooLongNameDes.Fill('A', KMaxFileName + 1);
// TSqlBlob::GetLC()
HBufC8* wholeBuf = TSqlBlob::GetLC(TheDb1, _L("table1"), _L("B")); // a successful get (on a BLOB column)
TInt blobLength = wholeBuf->Length();
TEST(blobLength > 0);
CleanupStack::PopAndDestroy(wholeBuf);
wholeBuf = TSqlBlob::GetLC(TheDb1, _L("table1"), _L("T")); // a successful get (on a TEXT column)
blobLength = wholeBuf->Length();
TEST(blobLength > 0);
CleanupStack::PopAndDestroy(wholeBuf);
TRAPD(err, wholeBuf = TSqlBlob::GetLC(TheDb2, _L("table1"), _L("B"))); // wrong db connection
TEST2(err, KSqlErrGeneral);
TRAP(err, wholeBuf = TSqlBlob::GetLC(TheDb1, _L(""), _L("B"))); // empty table name
TEST2(err, KErrBadName);
TRAP(err, wholeBuf = TSqlBlob::GetLC(TheDb1, tooLongNameDes, _L("B"))); // too long table name
TEST2(err, KErrBadName);
TRAP(err, wholeBuf = TSqlBlob::GetLC(TheDb1, _L("invalidTableName"), _L("B"))); // invalid table name
TEST2(err, KSqlErrGeneral);
TRAP(err, wholeBuf = TSqlBlob::GetLC(TheDb1, _L("table1"), _L(""))); // empty column name
TEST2(err, KErrBadName);
TRAP(err, wholeBuf = TSqlBlob::GetLC(TheDb1, _L("table1"), tooLongNameDes)); // too long column name
TEST2(err, KErrBadName);
TRAP(err, wholeBuf = TSqlBlob::GetLC(TheDb1, _L("table1"), _L("invalidColumnName"))); // invalid column name
TEST2(err, KSqlErrGeneral);
TRAP(err, wholeBuf = TSqlBlob::GetLC(TheDb1, _L("table1"), _L("I"))); // invalid column type
TEST2(err, KSqlErrGeneral);
TRAP(err, wholeBuf = TSqlBlob::GetLC(TheDb1, _L("table1"), _L("B"), -2)); // illegal ROWID
TEST2(err, KErrArgument);
TRAP(err, wholeBuf = TSqlBlob::GetLC(TheDb1, _L("table1"), _L("B"), 3731)); // invalid ROWID
TEST2(err, KSqlErrGeneral);
wholeBuf = TSqlBlob::GetLC(TheDb1, _L("table1"), _L("B"), TheDb1.LastInsertedRowId(), _L("main")); // a successful get (on a BLOB column)
blobLength = wholeBuf->Length();
TEST(blobLength > 0);
CleanupStack::PopAndDestroy(wholeBuf);
wholeBuf = TSqlBlob::GetLC(TheDb1, _L("table1"), _L("B"), TheDb1.LastInsertedRowId(), _L("")); // a successful get (on a BLOB column)
blobLength = wholeBuf->Length();
TEST(blobLength > 0);
CleanupStack::PopAndDestroy(wholeBuf);
wholeBuf = TSqlBlob::GetLC(TheDb1, _L("table1"), _L("T"), TheDb1.LastInsertedRowId(), _L("main")); // a successful get (on a TEXT column)
blobLength = wholeBuf->Length();
TEST(blobLength > 0);
CleanupStack::PopAndDestroy(wholeBuf);
wholeBuf = TSqlBlob::GetLC(TheDb1, _L("table1"), _L("T"), TheDb1.LastInsertedRowId(), _L("")); // a successful get (on a TEXT column)
blobLength = wholeBuf->Length();
TEST(blobLength > 0);
CleanupStack::PopAndDestroy(wholeBuf);
wholeBuf = TSqlBlob::GetLC(TheDb1, _L("table2"), _L("blob"), TheDb2.LastInsertedRowId(), KAttachedDbName); // a successful get (on a BLOB column)
blobLength = wholeBuf->Length();
TEST(blobLength > 0);
CleanupStack::PopAndDestroy(wholeBuf);
wholeBuf = TSqlBlob::GetLC(TheDb1, _L("table2"), _L("text"), TheDb2.LastInsertedRowId(), KAttachedDbName); // a successful get (on a TEXT column)
blobLength = wholeBuf->Length();
TEST(blobLength > 0);
CleanupStack::PopAndDestroy(wholeBuf);
TRAP(err, wholeBuf = TSqlBlob::GetLC(TheDb2, _L("table2"), _L("blob"), TheDb2.LastInsertedRowId(), KAttachedDbName)); // wrong db connection
TEST2(err, KSqlErrGeneral);
TRAP(err, wholeBuf = TSqlBlob::GetLC(TheDb1, _L("invalidTableName"), _L("blob"), TheDb2.LastInsertedRowId(), KAttachedDbName)); // invalid table name
TEST2(err, KSqlErrGeneral);
TRAP(err, wholeBuf = TSqlBlob::GetLC(TheDb1, _L("table2"), _L("invalidColumnName"), TheDb2.LastInsertedRowId(), KAttachedDbName)); // invalid column name
TEST2(err, KSqlErrGeneral);
TRAP(err, wholeBuf = TSqlBlob::GetLC(TheDb1, _L("table2"), _L("int"), TheDb2.LastInsertedRowId(), KAttachedDbName)); // invalid column type
TEST2(err, KSqlErrGeneral);
TRAP(err, wholeBuf = TSqlBlob::GetLC(TheDb1, _L("table2"), _L("blob"), 345, KAttachedDbName)); // invalid ROWID
TEST2(err, KSqlErrGeneral);
TRAP(err, wholeBuf = TSqlBlob::GetLC(TheDb1, _L("table2"), _L("blob"), TheDb2.LastInsertedRowId(), _L("invalidAttachedDbName"))); // invalid attached db name
TEST2(err, KSqlErrGeneral);
TRAP(err, wholeBuf = TSqlBlob::GetLC(TheDb1, _L("table2"), _L("blob"), TheDb2.LastInsertedRowId(), tooLongNameDes)); // too long attached db name
TEST2(err, KErrBadName);
// TSqlBlob::Get()
HBufC8* buf = HBufC8::NewLC(50);
TPtr8 bufPtr(buf->Des());
err = TSqlBlob::Get(TheDb1, _L("table1"), _L("B"), bufPtr); // a successful get (on a BLOB column)
TEST2(err, KErrNone);
err = TSqlBlob::Get(TheDb1, _L("table1"), _L("T"), bufPtr); // a successful get (on a TEXT column)
TEST2(err, KErrNone);
err = TSqlBlob::Get(TheDb2, _L("table1"), _L("B"), bufPtr); // wrong db connection
TEST2(err, KSqlErrGeneral);
err = TSqlBlob::Get(TheDb1, _L(""), _L("B"), bufPtr); // empty table name
TEST2(err, KErrBadName);
err = TSqlBlob::Get(TheDb1, tooLongNameDes, _L("B"), bufPtr); // too long table name
TEST2(err, KErrBadName);
err = TSqlBlob::Get(TheDb1, _L("invalidTableName"), _L("B"), bufPtr); // invalid table name
TEST2(err, KSqlErrGeneral);
err = TSqlBlob::Get(TheDb1, _L("table1"), _L(""), bufPtr); // empty column name
TEST2(err, KErrBadName);
err = TSqlBlob::Get(TheDb1, _L("table1"), tooLongNameDes, bufPtr); // too long column name
TEST2(err, KErrBadName);
err = TSqlBlob::Get(TheDb1, _L("table1"), _L("invalidColumnName"), bufPtr); // invalid column name
TEST2(err, KSqlErrGeneral);
err = TSqlBlob::Get(TheDb1, _L("table1"), _L("I"), bufPtr); // invalid column type
TEST2(err, KSqlErrGeneral);
err = TSqlBlob::Get(TheDb1, _L("table1"), _L("B"), bufPtr, 0); // illegal ROWID
TEST2(err, KErrArgument);
err = TSqlBlob::Get(TheDb1, _L("table1"), _L("B"), bufPtr, 3731); // invalid ROWID
TEST2(err, KSqlErrGeneral);
err = TSqlBlob::Get(TheDb1, _L("table1"), _L("B"), bufPtr, TheDb1.LastInsertedRowId(), _L("main")); // a successful get (on a BLOB column)
TEST2(err, KErrNone);
err = TSqlBlob::Get(TheDb1, _L("table1"), _L("B"), bufPtr, TheDb1.LastInsertedRowId(), _L("")); // a successful get (on a BLOB column)
TEST2(err, KErrNone);
err = TSqlBlob::Get(TheDb1, _L("table1"), _L("T"), bufPtr, TheDb1.LastInsertedRowId(), _L("main")); // a successful get (on a TEXT column)
TEST2(err, KErrNone);
err = TSqlBlob::Get(TheDb1, _L("table1"), _L("T"), bufPtr, TheDb1.LastInsertedRowId(), _L("")); // a successful get (on a TEXT column)
TEST2(err, KErrNone);
err = TSqlBlob::Get(TheDb1, _L("table2"), _L("blob"), bufPtr, TheDb2.LastInsertedRowId(), KAttachedDbName); // a successful get (on a BLOB column)
TEST2(err, KErrNone);
err = TSqlBlob::Get(TheDb1, _L("table2"), _L("text"), bufPtr, TheDb2.LastInsertedRowId(), KAttachedDbName); // a successful get (on a TEXT column)
TEST2(err, KErrNone);
err = TSqlBlob::Get(TheDb2, _L("table2"), _L("blob"), bufPtr, TheDb2.LastInsertedRowId(), KAttachedDbName); // wrong db connection
TEST2(err, KSqlErrGeneral);
err = TSqlBlob::Get(TheDb1, _L("invalidTableName"), _L("blob"), bufPtr, TheDb2.LastInsertedRowId(), KAttachedDbName); // invalid table name
TEST2(err, KSqlErrGeneral);
err = TSqlBlob::Get(TheDb1, _L("table2"), _L("invalidColumnName"), bufPtr, TheDb2.LastInsertedRowId(), KAttachedDbName); // invalid column name
TEST2(err, KSqlErrGeneral);
err = TSqlBlob::Get(TheDb1, _L("table2"), _L("int"), bufPtr, TheDb2.LastInsertedRowId(), KAttachedDbName); // invalid column type
TEST2(err, KSqlErrGeneral);
err = TSqlBlob::Get(TheDb1, _L("table2"), _L("blob"), bufPtr, 345, KAttachedDbName); // invalid ROWID
TEST2(err, KSqlErrGeneral);
err = TSqlBlob::Get(TheDb1, _L("table2"), _L("blob"), bufPtr, TheDb2.LastInsertedRowId(), _L("invalidAttachedDbName")); // invalid attached db name
TEST2(err, KSqlErrGeneral);
err = TSqlBlob::Get(TheDb1, _L("table2"), _L("blob"), bufPtr, TheDb2.LastInsertedRowId(), tooLongNameDes); // too long attached db name
TEST2(err, KErrBadName);
CleanupStack::PopAndDestroy(buf);
CleanupStack::PopAndDestroy(tooLongName);
}
void BadParamSetL()
{
HBufC* tooLongName = HBufC::NewLC(KMaxFileName + 1);
TPtr tooLongNameDes = tooLongName->Des();
tooLongNameDes.Fill('A', KMaxFileName + 1);
// TSqlBlob::SetL()
TRAPD(err, TSqlBlob::SetL(TheDb1, _L("table1"), _L("B"), _L8("twenty characters !!"))); // a successful set (on a BLOB column)
TEST2(err, KErrNone);
TRAP(err, TSqlBlob::SetL(TheDb1, _L("table1"), _L("T"), _L8("twenty characters !!"))); // a successful set (on a TEXT column)
TEST2(err, KErrNone);
TRAP(err, TSqlBlob::SetL(TheDb2, _L("table1"), _L("B"), _L8("twenty characters..."))); // wrong db connection
TEST2(err, KSqlErrGeneral);
TRAP(err, TSqlBlob::SetL(TheDb1, _L(""), _L("B"), _L8("twenty characters..."))); // empty table name
TEST2(err, KErrBadName);
TRAP(err, TSqlBlob::SetL(TheDb1, tooLongNameDes, _L("B"), _L8("twenty characters..."))); // too long table name
TEST2(err, KErrBadName);
TRAP(err, TSqlBlob::SetL(TheDb1, _L("invalidTableName"), _L("B"), _L8("twenty characters..."))); // invalid table name
TEST2(err, KSqlErrGeneral);
TRAP(err, TSqlBlob::SetL(TheDb1, _L("table1"), _L(""), _L8("twenty characters..."))); // empty column name
TEST2(err, KErrBadName);
TRAP(err, TSqlBlob::SetL(TheDb1, _L("table1"), tooLongNameDes, _L8("twenty characters..."))); // too long column name
TEST2(err, KErrBadName);
TRAP(err, TSqlBlob::SetL(TheDb1, _L("table1"), _L("invalidColumnName"), _L8("twenty characters..."))); // invalid column name
TEST2(err, KSqlErrGeneral);
TRAP(err, TSqlBlob::SetL(TheDb1, _L("table1"), _L("I"), _L8("twenty characters..."))); // invalid column type
TEST2(err, KSqlErrGeneral);
TRAP(err, TSqlBlob::SetL(TheDb1, _L("table1"), _L("B"), _L8("twenty characters..."), -3)); // illegal ROWID
TEST2(err, KErrArgument);
TRAP(err, TSqlBlob::SetL(TheDb1, _L("table1"), _L("B"), _L8("twenty characters..."), 1113)); // invalid ROWID
TEST2(err, KSqlErrGeneral);
TRAP(err, TSqlBlob::SetL(TheDb1, _L("table1"), _L("B"), _L8("!!!twenty characters"), TheDb1.LastInsertedRowId(), _L("main"))); // a successful set (on a BLOB column)
TEST2(err, KErrNone);
TRAP(err, TSqlBlob::SetL(TheDb1, _L("table1"), _L("B"), _L8("!!!twenty characters"), TheDb1.LastInsertedRowId(), _L(""))); // a successful set (on a BLOB column)
TEST2(err, KErrNone);
TRAP(err, TSqlBlob::SetL(TheDb1, _L("table1"), _L("T"), _L8("!!!twenty characters"), TheDb1.LastInsertedRowId(), _L("main"))); // a successful set (on a TEXT column)
TEST2(err, KErrNone);
TRAP(err, TSqlBlob::SetL(TheDb1, _L("table1"), _L("T"), _L8("!!!twenty characters"), TheDb1.LastInsertedRowId(), _L(""))); // a successful set (on a TEXT column)
TEST2(err, KErrNone);
TRAP(err, TSqlBlob::SetL(TheDb1, _L("table2"), _L("blob"), _L8("10 chars!!"), TheDb2.LastInsertedRowId(), KAttachedDbName)); // a successful set (on a BLOB column)
TEST2(err, KErrNone);
TRAP(err, TSqlBlob::SetL(TheDb1, _L("table2"), _L("text"), _L8("10 chars!!"), TheDb2.LastInsertedRowId(), KAttachedDbName)); // a successful set (on a TEXT column)
TEST2(err, KErrNone);
TRAP(err, TSqlBlob::SetL(TheDb2, _L("table2"), _L("blob"), _L8("10 chars.."), TheDb2.LastInsertedRowId(), KAttachedDbName)); // wrong db connection
TEST2(err, KSqlErrGeneral);
TRAP(err, TSqlBlob::SetL(TheDb1, _L("invalidTableName"), _L("blob"), _L8("10 chars.."), TheDb2.LastInsertedRowId(), KAttachedDbName)); // invalid table name
TEST2(err, KSqlErrGeneral);
TRAP(err, TSqlBlob::SetL(TheDb1, _L("table2"), _L("invalidColumnName"), _L8("10 chars.."), TheDb2.LastInsertedRowId(), KAttachedDbName)); // invalid column name
TEST2(err, KSqlErrGeneral);
TRAP(err, TSqlBlob::SetL(TheDb1, _L("table2"), _L("int"), _L8("10 chars.."), TheDb2.LastInsertedRowId(), KAttachedDbName)); // invalid column type
TEST2(err, KSqlErrGeneral);
TRAP(err, TSqlBlob::SetL(TheDb1, _L("table2"), _L("blob"), _L8("10 chars.."), 13, KAttachedDbName)); // invalid ROWID
TEST2(err, KSqlErrGeneral);
TRAP(err, TSqlBlob::SetL(TheDb1, _L("table2"), _L("blob"), _L8("10 chars.."), TheDb2.LastInsertedRowId(), _L("invalidAttachedDbName"))); // invalid attached db name
TEST2(err, KSqlErrGeneral);
TRAP(err, TSqlBlob::SetL(TheDb1, _L("table2"), _L("blob"), _L8("10 chars.."), TheDb2.LastInsertedRowId(), tooLongNameDes)); // too long attached db name
TEST2(err, KErrBadName);
CleanupStack::PopAndDestroy(tooLongName);
}
void BadParamBindZeroBlobL()
{
// RSqlStatement::BindZeroBlob()
RSqlBlobReadStream rdStrm;
CleanupClosePushL(rdStrm);
RSqlStatement stmt;
CleanupClosePushL(stmt);
TInt err = stmt.Prepare(TheDb2, _L("INSERT INTO table2 values(1, 'dummy text', :Val)"));
TEST2(err, KErrNone);
TInt paramIndex = stmt.ParameterIndex(_L(":Val"));
TEST(paramIndex >= 0);
err = stmt.BindZeroBlob(paramIndex, -1); // a negative blob size
TEST2(err, KErrNone);
err = stmt.Exec();
TEST2(err, 1);
stmt.Reset();
rdStrm.OpenL(TheDb2, _L("table2"), _L("blob"));
TInt size = rdStrm.SizeL(); // check the blob's size is 0 (0 is used if a negative number was specified)
TEST2(size, 0);
rdStrm.Close();
err = stmt.BindZeroBlob(paramIndex, 0); // a blob size of zero
TEST2(err, KErrNone);
err = stmt.Exec();
TEST2(err, 1);
stmt.Reset();
rdStrm.OpenL(TheDb2, _L("table2"), _L("blob"));
size = rdStrm.SizeL(); // check the blob's size is 0
TEST2(size, 0);
// For subsequent test purposes make the last inserted record have a zeroblob > 0 size
err = stmt.BindZeroBlob(paramIndex, 1);
TEST2(err, KErrNone);
err = stmt.Exec();
TEST2(err, 1);
CleanupStack::PopAndDestroy(&stmt);
CleanupStack::PopAndDestroy(&rdStrm);
}
/**
@SYMTestCaseID SYSLIB-SQL-UT-4107
@SYMTestCaseDesc Bad parameter tests for the methods of RSqlBlobReadStream,
RSqlBlobWriteStream, TSqlBlob and RSqlStatement::BindZeroBlob().
Tests that the correct error code is returned when a bad parameter
is used in a call to one of the methods.
Tests the RSqlBlobReadStream, RSqlBlobWriteStream and TSqlBlob methods
and RSqlStatement::BindZeroBlob().
@SYMTestPriority High
@SYMTestActions Execution of bad parameter tests.
@SYMTestExpectedResults Test must not fail
@SYMREQ REQ10411
REQ10418
*/
void BadParamTestL()
{
BadParamReadStreamL();
BadParamWriteStreamL();
BadParamGetL();
BadParamSetL();
BadParamBindZeroBlobL();
}
/**
@SYMTestCaseID SYSLIB-SQL-UT-4108
@SYMTestCaseDesc Indexed column tests for the methods of RSqlBlobReadStream
and RSqlBlobWriteStream, to ensure that a blob or text column
that is indexed cannot be written to but can be read from
(an SQLite restriction).
@SYMTestPriority Medium
@SYMTestActions Execution of read and write operations on an indexed column in a database.
@SYMTestExpectedResults Test must not fail
@SYMREQ REQ10411
REQ10418
*/
void IndexedColumnTestL()
{
// Create an index on the BLOB column and on the TEXT column in the main and attached databases
CreateIndices();
// Attempt to open a write stream on an indexed BLOB and an indexed TEXT column - this should not be permitted.
// (This is an SQLite restriction, but having an index on a large BLOB or a TEXT column is highly unlikely!)
RSqlBlobWriteStream wrStrm;
CleanupClosePushL(wrStrm);
TRAPD(err, wrStrm.OpenL(TheDb1, _L("table1"), _L("B"))); // indexed BLOB column
TEST2(err, KSqlErrGeneral);
wrStrm.Close();
TRAP(err, wrStrm.OpenL(TheDb1, _L("table1"), _L("T"))); // indexed TEXT column
TEST2(err, KSqlErrGeneral);
wrStrm.Close();
TRAP(err, wrStrm.OpenL(TheDb1, _L("table2"), _L("blob"), TheDb2.LastInsertedRowId(), KAttachedDbName)); // indexed BLOB column
TEST2(err, KSqlErrGeneral);
wrStrm.Close();
TRAP(err, wrStrm.OpenL(TheDb1, _L("table2"), _L("text"), TheDb2.LastInsertedRowId(), KAttachedDbName)); // indexed TEXT column
TEST2(err, KSqlErrGeneral);
CleanupStack::PopAndDestroy(&wrStrm);
TRAP(err, TSqlBlob::SetL(TheDb1, _L("table1"), _L("B"), _L8("twenty characters !!"))); // indexed BLOB column
TEST2(err, KSqlErrGeneral);
TRAP(err, TSqlBlob::SetL(TheDb1, _L("table1"), _L("T"), _L8("twenty characters !!"))); // indexed TEXT column
TEST2(err, KSqlErrGeneral);
TRAP(err, TSqlBlob::SetL(TheDb1, _L("table2"), _L("blob"), _L8("10 chars!!"), TheDb2.LastInsertedRowId(), KAttachedDbName)); // indexed BLOB column
TEST2(err, KSqlErrGeneral);
TRAP(err, TSqlBlob::SetL(TheDb1, _L("table2"), _L("text"), _L8("10 chars!!"), TheDb2.LastInsertedRowId(), KAttachedDbName)); // indexed TEXT column
TEST2(err, KSqlErrGeneral);
// Attempt to open a read stream on an indexed BLOB and an indexed text COLUMN - this should be permitted
RSqlBlobReadStream rdStrm;
CleanupClosePushL(rdStrm);
TRAP(err, rdStrm.OpenL(TheDb1, _L("table1"), _L("B"))); // a successful open (on an indexed BLOB column)
TEST2(err, KErrNone);
rdStrm.Close();
TRAP(err, rdStrm.OpenL(TheDb1, _L("table1"), _L("T"))); // a successful open (on an indexed TEXT column)
TEST2(err, KErrNone);
rdStrm.Close();
TRAP(err, rdStrm.OpenL(TheDb1, _L("table2"), _L("blob"), TheDb2.LastInsertedRowId(), KAttachedDbName)); // a successful open (on an indexed BLOB column)
TEST2(err, KErrNone);
rdStrm.Close();
TRAP(err, rdStrm.OpenL(TheDb1, _L("table2"), _L("text"), TheDb2.LastInsertedRowId(), KAttachedDbName)); // a successful open (on an indexed TEXT column)
TEST2(err, KErrNone);
CleanupStack::PopAndDestroy(&rdStrm);
HBufC8* wholeBuf = TSqlBlob::GetLC(TheDb1, _L("table1"), _L("B")); // a successful get (on an indexed BLOB column)
TInt blobLength = wholeBuf->Length();
TEST(blobLength > 0);
CleanupStack::PopAndDestroy(wholeBuf);
wholeBuf = TSqlBlob::GetLC(TheDb1, _L("table1"), _L("T")); // a successful get (on an indexed TEXT column)
blobLength = wholeBuf->Length();
TEST(blobLength > 0);
CleanupStack::PopAndDestroy(wholeBuf);
wholeBuf = TSqlBlob::GetLC(TheDb1, _L("table2"), _L("blob"), TheDb2.LastInsertedRowId(), KAttachedDbName); // a successful get (on an indexed BLOB column)
blobLength = wholeBuf->Length();
TEST(blobLength > 0);
CleanupStack::PopAndDestroy(wholeBuf);
wholeBuf = TSqlBlob::GetLC(TheDb1, _L("table2"), _L("text"), TheDb2.LastInsertedRowId(), KAttachedDbName); // a successful get (on an indexed TEXT column)
blobLength = wholeBuf->Length();
TEST(blobLength > 0);
CleanupStack::PopAndDestroy(wholeBuf);
HBufC8* buf = HBufC8::NewLC(50);
TPtr8 buffPtr(buf->Des());
err = TSqlBlob::Get(TheDb1, _L("table1"), _L("B"), buffPtr); // a successful get (on an indexed BLOB column)
TEST2(err, KErrNone);
err = TSqlBlob::Get(TheDb1, _L("table1"), _L("T"), buffPtr); // a successful get (on an indexed TEXT column)
TEST2(err, KErrNone);
err = TSqlBlob::Get(TheDb1, _L("table2"), _L("blob"), buffPtr, TheDb2.LastInsertedRowId(), KAttachedDbName); // a successful get (on an indexed BLOB column)
TEST2(err, KErrNone);
err = TSqlBlob::Get(TheDb1, _L("table2"), _L("text"), buffPtr, TheDb2.LastInsertedRowId(), KAttachedDbName); // a successful get (on an indexed TEXT column)
TEST2(err, KErrNone);
CleanupStack::PopAndDestroy(buf);
RemoveIndices();
}
/**
@SYMTestCaseID SYSLIB-SQL-UT-4109
@SYMTestCaseDesc 'End of file' tests for the methods of RSqlBlobReadStream
RSqlBlobWriteStream and TSqlBlob, to ensure that a client cannot
read beyond the end of a blob object or write beyond the end of a
blob object and that an appropriate error code is returned.
@SYMTestPriority High
@SYMTestActions Execution of read and write operations beyond the end of a blob object.
@SYMTestExpectedResults Test must not fail
@SYMREQ REQ10411
REQ10418
*/
void EofTestL()
{
// Use Blob 3 in table1, whose value is "!!!twenty characters"
// Read Eof tests
const TInt KBlobSize = 20;
RSqlBlobReadStream rdStrm;
CleanupClosePushL(rdStrm);
rdStrm.OpenL(TheDb1, _L("table1"), _L("B"));
TInt size = rdStrm.SizeL();
TEST2(size, KBlobSize);
TBuf8<50> data;
TRAPD(err, rdStrm.ReadL(data, KBlobSize));
TEST2(err, KErrNone);
TEST(data.Compare(_L8("!!!twenty characters")) == 0);
TRAP(err, rdStrm.ReadL(data, 1));
TEST2(err, KErrEof);
rdStrm.Close();
rdStrm.OpenL(TheDb1, _L("table1"), _L("B"));
TRAP(err, rdStrm.ReadL(data, 21));
TEST2(err, KErrEof);
rdStrm.Close();
HBufC8* exactSizeBuf = HBufC8::NewLC(KBlobSize);
TPtr8 exactSizeBufPtr(exactSizeBuf->Des());
err = TSqlBlob::Get(TheDb1, _L("table1"), _L("B"), exactSizeBufPtr);
TEST2(err, KErrNone);
TEST(exactSizeBufPtr.Compare(_L8("!!!twenty characters")) == 0);
CleanupStack::PopAndDestroy(exactSizeBuf);
HBufC8* tooSmallBuf = HBufC8::NewLC(KBlobSize/2);
TPtr8 tooSmallBufPtr(tooSmallBuf->Des());
err = TSqlBlob::Get(TheDb1, _L("table1"), _L("B"), tooSmallBufPtr);
TEST2(err, KErrOverflow);
CleanupStack::PopAndDestroy(tooSmallBuf);
// Write Eof tests
RSqlBlobWriteStream wrStrm;
CleanupClosePushL(wrStrm);
wrStrm.OpenL(TheDb1, _L("table1"), _L("B"));
size = wrStrm.SizeL();
TEST2(size, KBlobSize);
// For debug builds: This 20 bytes will be written to the blob straight away
// because 20 bytes is more than the 8 byte buffer
// For release builds: This 20 bytes will NOT be written to the blob straight away
// because there is room for it to be stored in the 1.5K byte buffer
TRAP(err, wrStrm.WriteL(_L8("a twenty char string")));
TEST2(err, KErrNone);
// For debug/release builds: This 1 byte will NOT be written to the blob straight away
// because there is room for it to be stored in the 8 byte/1.5K buffer
TRAP(err, wrStrm.WriteL(_L8("a")));
TEST2(err, KErrNone);
// For debug builds: The CommitL() call will cause an attempt to write the 1 byte
// in the buffer to the blob - however, the stream's write position indicates
// that the write would be beyond the end of the blob and so an error occurs
// For release builds: The CommitL() call will cause an attempt to write the 21 bytes
// in the buffer to the blob - however, 21 bytes is larger than the size of the blob
// and so an error occurs
TRAP(err, wrStrm.CommitL());
TEST2(err, KErrEof);
wrStrm.Close();
// For debug builds: Check that the blob value is now "a twenty char string"
// For release builds: Check that the blob value is still "!!!twenty characters"
rdStrm.OpenL(TheDb1, _L("table1"), _L("B"));
TRAP(err, rdStrm.ReadL(data, KBlobSize));
TEST2(err, KErrNone);
#ifdef _DEBUG
TEST(data.Compare(_L8("a twenty char string")) == 0);
#else
TEST(data.Compare(_L8("!!!twenty characters")) == 0);
#endif
rdStrm.Close();
TheDb1.Exec(_L("BEGIN"));
wrStrm.OpenL(TheDb1, _L("table1"), _L("B"));
// For debug/release builds: These 3 bytes will be stored in the 8 byte/1.5K buffer
TRAP(err, wrStrm.WriteL(_L8("eee")));
TEST2(err, KErrNone);
// For debug builds: These 25 bytes will not fit in the 8 byte buffer and so an attempt
// will be made to write these 25 bytes and the 3 buffered bytes to the blob -
// however, the size of the blob is only 20 and so an error occurs
// For release builds: These 25 bytes will be stored in the 1.5K buffer
TRAP(err, wrStrm.WriteL(_L8("fffffffffffffffffffffffff")));
#ifdef _DEBUG
TEST2(err, KErrEof);
wrStrm.Close();
TheDb1.Exec(_L("ROLLBACK"));
// Check that the blob value is still "a twenty char string"
rdStrm.OpenL(TheDb1, _L("table1"), _L("B"));
TRAP(err, rdStrm.ReadL(data, KBlobSize));
TEST2(err, KErrNone);
TEST(data.Compare(_L8("a twenty char string")) == 0);
rdStrm.Close();
#else
TEST2(err, KErrNone);
// For release builds: The CommitL() call will cause an attempt to write the 28 bytes
// in the buffer to the blob - however, 28 bytes is larger than the size of the blob
// and so an error occurs
TRAP(err, wrStrm.CommitL());
TEST2(err, KErrEof);
wrStrm.Close();
TheDb1.Exec(_L("ROLLBACK"));
// Check that the blob value is still "!!!twenty characters"
rdStrm.OpenL(TheDb1, _L("table1"), _L("B"));
TRAP(err, rdStrm.ReadL(data, KBlobSize));
TEST2(err, KErrNone);
TEST(data.Compare(_L8("!!!twenty characters")) == 0);
rdStrm.Close();
#endif
TheDb1.Exec(_L("BEGIN"));
wrStrm.OpenL(TheDb1, _L("table1"), _L("B"));
TRAP(err, wrStrm.WriteL(_L8("a string that is longer than 20 characters")));
#ifdef _DEBUG
TEST2(err, KErrEof);
wrStrm.Close();
TheDb1.Exec(_L("ROLLBACK"));
wrStrm.OpenL(TheDb1, _L("table1"), _L("B"));
TRAP(err, wrStrm.WriteL(_L8("ggg")));
TEST2(err, KErrNone);
TRAP(err, wrStrm.CommitL());
TEST2(err, KErrNone);
CleanupStack::PopAndDestroy(&wrStrm);
// Check that the blob value is now "gggwenty char string"
rdStrm.OpenL(TheDb1, _L("table1"), _L("B"));
TRAP(err, rdStrm.ReadL(data, KBlobSize));
TEST2(err, KErrNone);
TEST(data.Compare(_L8("gggwenty char string")) == 0);
rdStrm.Close();
#else
TEST2(err, KErrNone);
TRAP(err, wrStrm.CommitL());
TEST2(err, KErrEof);
wrStrm.Close();
TheDb1.Exec(_L("ROLLBACK"));
wrStrm.OpenL(TheDb1, _L("table1"), _L("B"));
TRAP(err, wrStrm.WriteL(_L8("hhh")));
TEST2(err, KErrNone);
TRAP(err, wrStrm.CommitL());
TEST2(err, KErrNone);
CleanupStack::PopAndDestroy(&wrStrm);
// Check that the blob value is now "hhhtwenty characters"
rdStrm.OpenL(TheDb1, _L("table1"), _L("B"));
TRAP(err, rdStrm.ReadL(data, KBlobSize));
TEST2(err, KErrNone);
TEST(data.Compare(_L8("hhhtwenty characters")) == 0);
rdStrm.Close();
#endif
TRAP(err, TSqlBlob::SetL(TheDb1, _L("table1"), _L("B"), _L8("a twenty char string")));
TEST2(err, KErrNone);
rdStrm.OpenL(TheDb1, _L("table1"), _L("B"));
TRAP(err, rdStrm.ReadL(data, KBlobSize));
TEST2(err, KErrNone);
TEST(data.Compare(_L8("a twenty char string")) == 0);
rdStrm.Close();
TheDb1.Exec(_L("BEGIN"));
TRAP(err, TSqlBlob::SetL(TheDb1, _L("table1"), _L("B"), _L8("a string that is longer than 20 characters")));
TEST2(err, KErrEof);
TheDb1.Exec(_L("ROLLBACK"));
rdStrm.OpenL(TheDb1, _L("table1"), _L("B"));
TRAP(err, rdStrm.ReadL(data, KBlobSize));
TEST2(err, KErrNone);
TEST(data.Compare(_L8("a twenty char string")) == 0);
rdStrm.Close();
TRAP(err, TSqlBlob::SetL(TheDb1, _L("table1"), _L("B"), _L8("less than 20")));
TEST2(err, KErrNone);
rdStrm.OpenL(TheDb1, _L("table1"), _L("B"));
TRAP(err, rdStrm.ReadL(data, KBlobSize));
TEST2(err, KErrNone); // changing only part of the blob data is permitted
TEST(data.Compare(_L8("less than 20r string")) == 0);
rdStrm.Close();
CleanupStack::PopAndDestroy(&rdStrm);
}
/**
@SYMTestCaseID SYSLIB-SQL-UT-4110
@SYMTestCaseDesc General blob read and write tests on a private secure database,
to ensure that there are no security issues with the methods of
RSqlBlobReadStream, RSqlBlobWriteStream and TSqlBlob.
@SYMTestPriority High
@SYMTestActions Execution of read and write operations on a private secure database.
@SYMTestExpectedResults Test must not fail
@SYMREQ REQ10411
REQ10418
REQ5794
*/
void PrivateSecureDbTestL()
{
// The blob has the value 'ABABABABABABABA'
// Read data from the blob
const TInt KBlobSize = 15;
RSqlBlobReadStream rdStrm;
CleanupClosePushL(rdStrm);
rdStrm.OpenL(ThePrivateDb, _L("table3"), _L("picture"));
TInt size = rdStrm.SizeL(); // check the blob's size
TEST2(size, KBlobSize);
TBuf8<50> data;
rdStrm.ReadL(data, 5);
TEST(data.Compare(_L8("ABABA")) == 0); // check 5 bytes have been read
rdStrm.ReadL(data, 8);
TEST(data.Compare(_L8("BABABABA")) == 0); // check the next 8 bytes have been read
rdStrm.SizeL(); // check the blob's size
TEST2(size, KBlobSize);
CleanupStack::PopAndDestroy(&rdStrm);
HBufC8* wholeBuf = TSqlBlob::GetLC(ThePrivateDb, _L("table3"), _L("picture"));
TInt blobLength = wholeBuf->Length();
TEST2(blobLength, KBlobSize);
TEST(wholeBuf->Des().Compare(_L8("ABABABABABABABA")) == 0);
CleanupStack::PopAndDestroy(wholeBuf);
HBufC8* buf = HBufC8::NewLC(KBlobSize);
TPtr8 bufPtr(buf->Des());
TInt err = TSqlBlob::Get(ThePrivateDb, _L("table3"), _L("picture"), bufPtr);
TEST2(err, KErrNone);
TEST(bufPtr.Compare(_L8("ABABABABABABABA")) == 0);
CleanupStack::PopAndDestroy(buf);
// Write data to the blob
RSqlBlobWriteStream wrStrm;
CleanupClosePushL(wrStrm);
wrStrm.OpenL(ThePrivateDb, _L("table3"), _L("picture"));
size = wrStrm.SizeL(); // check the blob's size
TEST2(size, KBlobSize);
wrStrm.WriteL(_L8("AABBCC")); // write 6 bytes
wrStrm.WriteL(_L8("DD")); // write another 2 bytes
wrStrm.WriteL(_L8("EEFFG")); // write another 5 bytes
size = wrStrm.SizeL(); // check the blob's size
TEST2(size, KBlobSize);
wrStrm.CommitL();
CleanupStack::PopAndDestroy(&wrStrm);
// Check that the new blob data was written
HBufC8* retrievedDataBuf = TSqlBlob::GetLC(ThePrivateDb, _L("table3"), _L("picture"));
blobLength = retrievedDataBuf->Size();
TEST2(blobLength, KBlobSize);
TEST(retrievedDataBuf->Des().Compare(_L8("AABBCCDDEEFFGBA")) == 0);
CleanupStack::PopAndDestroy(retrievedDataBuf);
HBufC8* dataBuf = HBufC8::NewLC(KBlobSize);
TPtr8 dataPtr(dataBuf->Des());
dataPtr.Append(_L8("CDCDCDCDCDCDCDC"));
TSqlBlob::SetL(ThePrivateDb, _L("table3"), _L("picture"), dataPtr);
CleanupStack::PopAndDestroy(dataBuf);
// Check that the new blob data was written
retrievedDataBuf = TSqlBlob::GetLC(ThePrivateDb, _L("table3"), _L("picture"));
blobLength = retrievedDataBuf->Size();
TEST2(blobLength, KBlobSize);
TEST(retrievedDataBuf->Des().Compare(_L8("CDCDCDCDCDCDCDC")) == 0);
CleanupStack::PopAndDestroy(retrievedDataBuf);
}
/**
@SYMTestCaseID SYSLIB-SQL-UT-4111
@SYMTestCaseDesc Concurrent blob read and write tests using the
methods of RSqlBlobReadStream and RSqlBlobWriteStream.
Tests that read and write operations on different blobs
can happen concurrently and that read operations on the
same blob from different streams can happen concurrently.
@SYMTestPriority Medium
@SYMTestActions Execution of concurrent blob read and write operations on a database.
@SYMTestExpectedResults Test must not fail
@SYMREQ REQ10411
REQ10418
*/
void ConcurrentReadAndWriteTestL()
{
// Insert a zeroblob of size 2Kb
InsertSQLiteZeroBlob(KLargeDataBufLen);
// Insert a zeroblob of size 4Kb
InsertBindZeroBlob(4 * 1024);
// Handles on different blobs
// Write and read from different blobs
RSqlBlobReadStream rdStrm;
CleanupClosePushL(rdStrm);
rdStrm.OpenL(TheDb1, _L("table1"), _L("B"), TheDb1.LastInsertedRowId() - 1);
RSqlBlobWriteStream wrStrm;
CleanupClosePushL(wrStrm);
wrStrm.OpenL(TheDb1, _L("table1"), _L("B"));
wrStrm.WriteL(_L8("GHIJKL")); // blob2 is not updated in cache (as client buffer not full)
TBuf8<100> data;
rdStrm.ReadL(data, 6);
_LIT8(KSixZeros, "\x0\x0\x0\x0\x0\x0");
TEST(data.Compare(KSixZeros) == 0);
wrStrm.CommitL(); // blob2 update is not committed (as the rdStrm handle is open)
wrStrm.Close();
rdStrm.ReadL(data, 6);
TEST(data.Compare(KSixZeros) == 0);
rdStrm.Close(); // the blob2 update is committed
rdStrm.OpenL(TheDb1, _L("table1"), _L("B"), TheDb1.LastInsertedRowId() - 1);
rdStrm.ReadL(data, 2); // read 2 bytes
_LIT8(KTwoZeros, "\x0\x0");
TEST(data.Compare(KTwoZeros) == 0);
wrStrm.OpenL(TheDb1, _L("table1"), _L("B"));
wrStrm.WriteL(TheLargeData); // blob2 is updated in the cache
rdStrm.ReadL(data, 10); // read the next 10 bytes
_LIT8(KTenZeros, "\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0");
TEST(data.Compare(KTenZeros) == 0);
rdStrm.Close();
wrStrm.CommitL(); // the blob2 update is committed
CleanupStack::PopAndDestroy(2);
// Write to different blobs via different streams
CleanupClosePushL(wrStrm);
wrStrm.OpenL(TheDb1, _L("table1"), _L("B"), TheDb1.LastInsertedRowId() - 1);
RSqlBlobWriteStream wrStrm2;
CleanupClosePushL(wrStrm2);
wrStrm2.OpenL(TheDb1, _L("table1"), _L("B"));
wrStrm.WriteL(_L8("ABABABABABABAB"));
wrStrm2.WriteL(_L8("CDCDCD"));
wrStrm.WriteL(_L8("EFEF"));
wrStrm.Close();
wrStrm2.Close(); // the blob1 update is committed and the blob2 update is committed
CleanupClosePushL(rdStrm);
rdStrm.OpenL(TheDb1, _L("table1"), _L("B"), TheDb1.LastInsertedRowId() - 1);
rdStrm.ReadL(data, 18);
TEST(data.Compare(_L8("ABABABABABABABEFEF")) == 0);
rdStrm.Close();
rdStrm.OpenL(TheDb1, _L("table1"), _L("B"));
rdStrm.ReadL(data, 6);
TEST(data.Compare(_L8("CDCDCD")) == 0);
rdStrm.Close();
CleanupStack::PopAndDestroy(3);
// Read from different blobs via different streams
CleanupClosePushL(rdStrm);
rdStrm.OpenL(TheDb1, _L("table1"), _L("B"), TheDb1.LastInsertedRowId() - 1);
RSqlBlobReadStream rdStrm2;
CleanupClosePushL(rdStrm2);
rdStrm2.OpenL(TheDb1, _L("table1"), _L("B"));
rdStrm.ReadL(data, 2);
TEST(data.Compare(_L8("AB")) == 0);
rdStrm2.ReadL(data, 3);
TEST(data.Compare(_L8("CDC")) == 0);
rdStrm.ReadL(data, 15);
TEST(data.Compare(_L8("ABABABABABABEFE")) == 0);
rdStrm2.ReadL(data, 2);
TEST(data.Compare(_L8("DC")) == 0);
CleanupStack::PopAndDestroy(2);
// Handles on the same blob
// NOTE: using different stream objects on the same blob is only
// safe when all of the stream objects are read streams - writing to
// the same blob from different streams or writing and reading from
// the same blob at the same time has undefined behaviour
// Read from the same blob (blob2) via different streams
CleanupClosePushL(wrStrm);
wrStrm.OpenL(TheDb1, _L("table1"), _L("B"));
wrStrm.WriteL(_L8("MNOPQR"));
CleanupStack::PopAndDestroy(); // the blob2 update is committed
CleanupClosePushL(rdStrm);
rdStrm.OpenL(TheDb1, _L("table1"), _L("B"));
CleanupClosePushL(rdStrm2);
rdStrm2.OpenL(TheDb1, _L("table1"), _L("B"));
rdStrm.ReadL(data, 2);
TEST(data.Compare(_L8("MN")) == 0);
rdStrm2.ReadL(data, 3);
TEST(data.Compare(_L8("MNO")) == 0);
rdStrm.ReadL(data, 10);
TEST(data.Compare(_L8("OPQRZZZZZZ")) == 0);
rdStrm2.ReadL(data, 15);
TEST(data.Compare(_L8("PQRZZZZZZZZZZZZ")) == 0);
CleanupStack::PopAndDestroy(2);
}
void UTF16TextL(TInt aTextSize)
{
// The text value is "test", size 8 bytes in UTF-16, aTextSize = 8
// Try to get the whole content of the text as UTF-8, using TSqlBlob::GetLC()
HBufC8* wholeBuf = TSqlBlob::GetLC(TheDb1, _L("table1"), _L("T"));
TInt bufSize = wholeBuf->Size(); // get the number of bytes in the buffer
TEST2(bufSize, aTextSize);
CleanupStack::PopAndDestroy(wholeBuf);
// Try to get the whole content of the text as UTF-8, using TSqlBlob::Get()
HBufC8* buf = HBufC8::NewLC(aTextSize);
TPtr8 bufPtr(buf->Des());
TInt err = TSqlBlob::Get(TheDb1, _L("table1"), _L("T"), bufPtr);
TEST2(err, KErrNone);
bufSize = buf->Size(); // get the number of bytes in the buffer
TEST2(bufSize, aTextSize);
CleanupStack::PopAndDestroy(buf);
// Try to set the whole content of the text as UTF-8, using TSqlBlob::SetL()
HBufC8* dataBuf = HBufC8::NewLC(aTextSize);
TPtr8 dataPtr(dataBuf->Des());
dataPtr.Append(_L8("OPOPOPOP"));
TRAP(err, TSqlBlob::SetL(TheDb1, _L("table1"), _L("T"), dataPtr));
TEST2(err, KErrNone); // can set 8 UTF-8 characters as this is 8 bytes
CleanupStack::PopAndDestroy(dataBuf);
}
/**
@SYMTestCaseID SYSLIB-SQL-UT-4112
@SYMTestCaseDesc UTF-16 text read and write tests using the UTF-8 methods of
TSqlBlob.
@SYMTestPriority Medium
@SYMTestActions Execution of UTF-16 text read and write operations using
UTF-8 descriptors.
@SYMTestExpectedResults Test must not fail
@SYMREQ REQ10411
REQ10418
*/
void UTF16FormatTestL()
{
// Insert a record with a UTF-16 text value (text is encoded in UTF-16 by default)
TInt err = TheDb1.Exec(_L("INSERT INTO table1 VALUES(1, 'test', x'46474647464746474647')"));
TEST2(err, 1);
const TInt KTextSize = 8; // 8 bytes (4 UTF-16 characters)
// Now read and write the UTF-16 text value using UTF-8 methods
UTF16TextL(KTextSize);
}
/**
@SYMTestCaseID SYSLIB-SQL-UT-4114
@SYMTestCaseDesc Storing a big blob test, to ensure that by using the methods
of RSqlBlobReadStream and RSqlBlobWriteStream larger blobs can
be stored in practice than in previous versions of Symbian SQL.
Creates a 18Mb zeroblob and then writes data into it and reads
the data back.
Also tests the TSqlBlob APIs to store and retrieve a large blob.
Note that the test will use 18Mb blob only in WINSCW builds.
Otherwise the used blob size is 3Mb.
@SYMTestPriority Medium
@SYMTestActions Execution of creating a 18Mb zeroblob, writing data to it and
reading it back.
@SYMTestExpectedResults Test must not fail
@SYMREQ REQ10410
*/
void BigBlobTestL()
{
// In this test we create a zeroblob big enough to hold a 18MB blob.
// 18MB is larger than the server could previously read or write,
// due to the server heap limit of 6MB (WINSCW builds).
// This test will prove that a 18MB blob can be written and read
// using the new APIs but not with the old APIs
#if defined __WINS__ || defined __WINSCW__
const TInt KBigBlobSize = 18 * 1024 * 1024;
#else
const TInt KBigBlobSize = 3 * 1024 * 1024;
#endif
// Create a zeroblob big enough to hold a 36MB blob
TInt err = TheDb2.Exec(_L("BEGIN"));
TEST(err >= 0);
RSqlStatement stmt;
err = stmt.Prepare(TheDb2, _L("INSERT INTO table2 values(435, 'big blob test', :Val)"));
TEST2(err, KErrNone);
TInt paramIndex = stmt.ParameterIndex(_L(":Val"));
TEST(paramIndex >= 0);
err = stmt.BindZeroBlob(paramIndex, KBigBlobSize);
TEST2(err, KErrNone);
err = stmt.Exec();
stmt.Close();
if(err == KErrDiskFull)
{
(void)TheDb2.Exec(_L("ROLLBACK"));
TheTest.Printf(_L("==== The disk is full. The test cannot be completed!\r\n"));
RFs fs;
err = fs.Connect();
if(err == KErrNone)
{
TVolumeInfo vinfo;
err = fs.Volume(vinfo, EDriveC);
if(err == KErrNone)
{
TheTest.Printf(_L("==== Free disk space=%d\r\n"), vinfo.iFree);
}
fs.Close();
}
return;
}
TEST2(err, 1);
/////////////////////////////////////////////////////////////////////////////////////////////////////
// Fill a buffer with KBigBlobSize/KBlobPartCnt bytes of data
// (the test application's heap may be too small to allocate a KBigBlobSize bytes buffer)
const TInt KBlobWrPartCnt = 16;// 1/16 part of the blob will be written at once using streaming API
const TInt KBufferSize1 = KBigBlobSize / KBlobWrPartCnt;
HBufC8* blobWrBuf = HBufC8::NewLC(KBufferSize1);
TPtr8 blobWrChunk(blobWrBuf->Des());
blobWrChunk.Fill('Z', KBufferSize1);
// Write KBigBlobSize bytes to the blob in the inserted record
RSqlBlobWriteStream wrStrm;
CleanupClosePushL(wrStrm);
wrStrm.OpenL(TheDb2, _L("table2"), _L("blob"));
TInt size = wrStrm.SizeL(); // check the blob's size
TEST2(size, KBigBlobSize);
for(TInt i1=0;i1<KBlobWrPartCnt;++i1)
{
TRAP(err, wrStrm.WriteL(blobWrChunk)); // write KBufferSize1 bytes of data
TEST2(err, KErrNone);
}
wrStrm.CommitL();
CleanupStack::PopAndDestroy(&wrStrm);
err = TheDb2.Exec(_L("COMMIT"));
TEST2(err, 1);
/////////////////////////////////////////////////////////////////////////////////////////////////////
// Read the big blob value back from the record in KBigBlobSize/6 chunks
const TInt KBlobRdPartCnt = 24;// 1/24 part of the blob will be read at once using streaming API
const TInt KBufferSize2 = KBigBlobSize / KBlobRdPartCnt;
HBufC8* blobRdBuf = HBufC8::NewLC(KBufferSize2);
TPtr8 blobRdBufPtr(blobRdBuf->Des());
RSqlBlobReadStream rdStrm;
CleanupClosePushL(rdStrm);
rdStrm.OpenL(TheDb2, _L("table2"), _L("blob"));
size = rdStrm.SizeL(); // check the blob's size
TEST2(size, KBigBlobSize);
for(TInt i2=0;i2<KBlobRdPartCnt;++i2)
{
rdStrm.ReadL(blobRdBufPtr, KBufferSize2);
TEST(blobRdBufPtr.Compare(blobWrChunk.Left(KBufferSize2)) == 0); // check the first KBigBlobSize/KBlobRdPartCnt bytes
}
TRAP(err, rdStrm.ReadL(blobRdBufPtr, 1));
TEST2(err, KErrEof); // check that there is no more data to be read
CleanupStack::PopAndDestroy(2, blobRdBuf); // rdStrm, blobRdBuf
/////////////////////////////////////////////////////////////////////////////////////////////////////
// Try to read the whole KBigBlobSize blob value using the old API
err = stmt.Prepare(TheDb2, _L("SELECT blob FROM table2 WHERE ROWID == :Val"));
TEST2(err, KErrNone);
paramIndex = stmt.ParameterIndex(_L(":Val"));
TEST(paramIndex >= 0);
err = stmt.BindInt(paramIndex, TheDb2.LastInsertedRowId());
TEST2(err, KErrNone);
// Check that the blob retrieval fails (because there is
// not enough server-side memory to load it into the VDBE)
err = stmt.Next();
#if defined __WINS__ || defined __WINSCW__
TEST2(err, KErrNoMemory);
#else
TEST2(err, KSqlAtRow);
#endif
stmt.Close();
/////////////////////////////////////////////////////////////////////////////////////////////////////
// Try to write another KBigBlobSize bytes big blob value using the old API.
// Check that the at some point the blob write fails (because there is
// not enough server-side memory to store the whole KBigBlobSize bytes).
err = stmt.Prepare(TheDb2, _L("INSERT INTO table2 values(99, 'text', :Val)"));
TEST2(err, KErrNone);
paramIndex = stmt.ParameterIndex(_L(":Val"));
TEST(paramIndex >= 0);
RSqlParamWriteStream strm;
err = strm.BindBinary(stmt, paramIndex);
TEST2(err, KErrNone);
for(TInt i3=0;i3<KBlobWrPartCnt && err==KErrNone;++i3)
{
TRAP(err, strm.WriteL(blobWrChunk, KBufferSize1));
}
#if defined __WINS__ || defined __WINSCW__
TEST2(err, KErrNoMemory);
#else
TEST2(err, KErrNone);
#endif
strm.Close();
stmt.Close();
CleanupStack::PopAndDestroy(blobWrBuf);
blobWrBuf = NULL;
/////////////////////////////////////////////////////////////////////////////////////////////////////
// Use the TSqlBlob APIs to insert another big blob of size 85Kb
// (to test the block algorithm used by TSqlBlob 'set')
const TInt KBigBlobSize2 = 85 * 1024;
err = TheDb2.Exec(_L("BEGIN"));
TEST(err >= 0);
err = stmt.Prepare(TheDb2, _L("INSERT INTO table2 values(189, 'another big blob', :Val)"));
TEST2(err, KErrNone);
paramIndex = stmt.ParameterIndex(_L(":Val"));
TEST(paramIndex >= 0);
err = stmt.BindZeroBlob(paramIndex, KBigBlobSize2);
TEST2(err, KErrNone);
err = stmt.Exec();
TEST2(err, 1);
stmt.Close();
blobWrBuf = HBufC8::NewLC(KBigBlobSize2);
blobWrChunk.Set(blobWrBuf->Des());
blobWrChunk.SetLength(KBigBlobSize2);
blobWrChunk.Fill('F');
TPtr8 p((TUint8*)blobWrChunk.Ptr() + blobWrChunk.Length() / 2, blobWrChunk.Length() / 2);
p.Fill('E');// blobWrBuf now contains 42.5Kb of 'E's followed by 42.5Kb of 'F's
TRAP(err, TSqlBlob::SetL(TheDb2, _L("table2"), _L("blob"), blobWrChunk));
TEST2(err, KErrNone);
err = TheDb2.Exec(_L("COMMIT"));
TEST2(err, 1);
// Read the blob value back from the record
// (to test the block algorithm used by TSqlBlob 'get')
HBufC8* buf = TSqlBlob::GetLC(TheDb2, _L("table2"), _L("blob"));
TEST(buf->Des().Compare(blobWrChunk) == 0);
CleanupStack::PopAndDestroy(buf);
buf = NULL;
buf = HBufC8::NewLC(KBigBlobSize2);
blobRdBufPtr.Set(buf->Des());
err = TSqlBlob::Get(TheDb2, _L("table2"), _L("blob"), blobRdBufPtr);
TEST2(err, KErrNone);
TEST(blobRdBufPtr.Compare(blobWrChunk) == 0);
CleanupStack::PopAndDestroy(2, blobWrBuf); // buf, blobWrBuf
}
void DoTestsL()
{
CreateTestDbs();
// Insert a zeroblob using RSqlStatement::BindZeroBlob() and read and write to it using streams
TheTest.Start(_L(" @SYMTestCaseID:SYSLIB-SQL-UT-4099: Stream BindZeroBlob() test"));
StreamBindZeroBlobTestL();
// Insert a zeroblob using SQLite's zeroblob() function and read and write to it using streams
TheTest.Next(_L(" @SYMTestCaseID:SYSLIB-SQL-UT-4100: Stream zeroblob() test"));
StreamSqliteZeroBlobTestL();
// Insert a record containing a 'real' blob and read and write to it using streams
TheTest.Next(_L(" @SYMTestCaseID:SYSLIB-SQL-UT-4101: Stream real blob test"));
StreamRealBlobTestL();
// Get a whole blob object
TheTest.Next(_L(" @SYMTestCaseID:SYSLIB-SQL-UT-4102: Whole value blob retrieval test"));
GetWholeBlob3L();
// Set a whole blob object
TheTest.Next(_L(" @SYMTestCaseID:SYSLIB-SQL-UT-4104: Whole value blob set test"));
SetWholeBlob3L();
// Attached database test
TheTest.Next(_L(" @SYMTestCaseID:SYSLIB-SQL-UT-4106: Attached database test"));
AttachDbTestL();
// Bad parameter test
TheTest.Next(_L(" @SYMTestCaseID:SYSLIB-SQL-UT-4107: Bad parameter test"));
BadParamTestL();
// Indexed column test
TheTest.Next(_L(" @SYMTestCaseID:SYSLIB-SQL-UT-4108: Indexed column test"));
IndexedColumnTestL();
// End Of File test
TheTest.Next(_L(" @SYMTestCaseID:SYSLIB-SQL-UT-4109: Eof test"));
EofTestL();
// Private secure database test
TheTest.Next(_L(" @SYMTestCaseID:SYSLIB-SQL-UT-4110: Private secure db test"));
PrivateSecureDbTestL();
// Concurrent read and write test
TheTest.Next(_L(" @SYMTestCaseID:SYSLIB-SQL-UT-4111: Concurrent read and write test"));
ConcurrentReadAndWriteTestL();
// UTF-16 read and write test
TheTest.Next(_L(" @SYMTestCaseID:SYSLIB-SQL-UT-4112: UTF-16 format test"));
UTF16FormatTestL();
// Big blob test
TheTest.Next(_L(" @SYMTestCaseID:SYSLIB-SQL-UT-4114: Big blob test"));
BigBlobTestL();
DeleteTestDbs();
}
TInt E32Main()
{
TheTest.Title();
CTrapCleanup* tc = CTrapCleanup::New();
__UHEAP_MARK;
CreateTestDir();
DeleteTestDbs();
FillLargeDataBuf();
TRAPD(err, DoTestsL());
TEST2(err, KErrNone);
__UHEAP_MARKEND;
TheTest.End();
TheTest.Close();
delete tc;
User::Heap().Check();
return KErrNone;
}