// Copyright (c) 2005-2010 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 <s32buf.h>				//MStreamBuf
#include <sqldb.h>

///////////////////////////////////////////////////////////////////////////////////////

RTest TheTest(_L("t_sqlapi test"));
_LIT(KTestDir, "c:\\test\\");
_LIT(KTestDbName1, "c:\\test\\t_sqlapi1.db");
_LIT(KTestDbName2, "c:[1111CCCC]t_sqlapi2.db");
_LIT(KTestDbName3, "C:\\TEST\\t_sqlapi3.db");
_LIT(KTestDbName4, "C:[1111CCCC]D012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789.db");
_LIT(KTestDbName5, "C:\\TEST\\D012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789.db");
_LIT(KTestDbName6, "C:[1111CCCC]t_sqlapi6.db");
_LIT(KTestDbName7, "C:[1111CCCC]t_sqlapi7.db");
_LIT(KTestDbName8, "c:\\test\\t_sqlapi8.db");
_LIT(KTestDbName9, "c:\\private\\1111CCCC\\t_sqlapi9.db");
_LIT(KTestCfgDbName, "c:\\test\\t_sqlapi_cfg.db");
_LIT(KTestCfgDbName2, "c:[1111CCCC]t_sqlapi_cfg.db");
_LIT(KServerPrivateDir, "\\private\\10281e17\\");

_LIT(KDbName7, "C:\\TEST\\t_sqlapi7_2.db");

// used for the config test
_LIT8(KServerConfigString1, "   ;  cache_size =  1024 ; page_size =1024 ;encoding =  \"UTF-8\"   ");
_LIT8(KServerConfigString2, " badconfigstring ");
_LIT8(KServerConfigString3, " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
_LIT8(KServerConfigString4, "");
_LIT8(KServerConfigString5, "dfgdfrgdkfjgjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjj43w3wk4jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn");

const TUid KSecureUid = {0x1111CCCC};//The same as the UID in the MMP file

_LIT(KCreateDbScript, "z:\\test\\contacts_schema_to_vendors.sql");
_LIT(KFillDbScript, "z:\\test\\add_simple_contacts.sql");
_LIT8(KCommitStr8, "COMMIT;");
_LIT16(KCommitStr16, "COMMIT;");

///////////////////////////////////////////////////////////////////////////////////////

void DeleteTestFiles()
	{
	RSqlDatabase::Delete(KTestDbName1);
	RSqlDatabase::Delete(KTestDbName2);
	RSqlDatabase::Delete(KTestDbName3);
	RSqlDatabase::Delete(KTestDbName4);
	RSqlDatabase::Delete(KTestDbName5);
	RSqlDatabase::Delete(KTestDbName6);
	RSqlDatabase::Delete(KTestDbName7);
	RSqlDatabase::Delete(KTestDbName8);
	RSqlDatabase::Delete(KTestDbName9);
	RSqlDatabase::Delete(KTestCfgDbName);
	RSqlDatabase::Delete(KTestCfgDbName2);
	RSqlDatabase::Delete(KDbName7);
	}

///////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////
//Test macros and functions
void Check(TInt aValue, TInt aLine)
	{
	if(!aValue)
		{
		DeleteTestFiles();
		TheTest(EFalse, aLine);
		}
	}
void Check(TInt aValue, TInt aExpected, TInt aLine)
	{
	if(aValue != aExpected)
		{
		DeleteTestFiles();
		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__)

///////////////////////////////////////////////////////////////////////////////////////

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();
	}

///////////////////////////////////////////////////////////////////////////////////////

template <class DES, class BUF> void ExecSqlStmtOnDb(RSqlDatabase& aDb, const TDesC8& aSqlString, 
												     TInt aExpectedError)
	{
	BUF sqlBuf;
	sqlBuf.Copy(aSqlString);
	
	TInt rc = aDb.Exec(sqlBuf);
	if(rc < 0 && SqlRetCodeClass(rc) == ESqlDbError)
		{
		TPtrC msg = aDb.LastErrorMessage();
		RDebug::Print(_L("Execute SQL error - '%S'\r\n"), &msg);
		}
	if(aExpectedError < 0)
		{
		TEST2(rc, aExpectedError);
		}
	else
		{
		TEST(rc >= 0);
		}
	}

template <class DES, class BUF>  RSqlStatement PrepareSqlStmt(RSqlDatabase& aDb, const TDesC8& aSqlString,
															  TInt aExpectedError)
	{
	BUF sqlBuf;
	sqlBuf.Copy(aSqlString);
	
	RSqlStatement stmt;
	TInt rc = stmt.Prepare(aDb, sqlBuf);
	if(rc != KErrNone && SqlRetCodeClass(rc) == ESqlDbError)
		{
		TPtrC msg = aDb.LastErrorMessage();
		RDebug::Print(_L("Execute SQL error - '%S'\r\n"), &msg);
		}
	TEST2(rc, aExpectedError);
	return stmt;
	}

void ExecSqlStmt(RSqlDatabase& aDb, RSqlStatement& aStmt, TInt aExpectedError)
	{
	TInt rc = aStmt.Exec();
	if(rc < 0 && SqlRetCodeClass(rc) == ESqlDbError)
		{
		TPtrC msg = aDb.LastErrorMessage();
		RDebug::Print(_L("Execute SQL error - '%S'\r\n"), &msg);
		}
	if(aExpectedError < 0)
		{
		TEST2(rc, aExpectedError);
		}
	else
		{
		TEST(rc >= 0);
		}
	}
		
///////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////

/**
@SYMTestCaseID			SYSLIB-SQL-CT-1601
@SYMTestCaseDesc		Create/Open/Close database tests. Invalid database names, very long database names,
						private databases, public databases, open twice database, create already
						existing database, open non-exisitng database, open corrupted database.
@SYMTestPriority		High
@SYMTestActions			Tests for RSqlDatabase::Create(), RSqlDatabase::Open() methods.
@SYMTestExpectedResults Test must not fail
@SYMREQ					REQ5792
                        REQ5793
*/	
void OpenCloseDatabaseTest()
	{
	RSqlDatabase db;
	TSecurityPolicy defaultPolicy(TSecurityPolicy::EAlwaysPass);
	RSqlSecurityPolicy securityPolicy;
	TInt rc = securityPolicy.Create(defaultPolicy);
	TEST2(rc, KErrNone);
	
	//Secure shared database file on a non-existing drive (A:)
	_LIT(KDbPath1, "A:[1111CCCC]db1.db");
	rc = db.Create(KDbPath1, securityPolicy);
	TEST2(rc, KErrNotReady);
	db.Close();

	//Attempt to open a non-existing file.
	_LIT(KDbFName, "c:\\test\\nofile.db");
	rc = db.Open(KDbFName);
	TEST2(rc, KErrNotFound);
		
	//Zero length database file name.
	rc = db.Create(_L(""));
	TEST2(rc,  KErrBadName);
	db.Close();
	
	//Database file name containing only the drive name
	rc = db.Create(_L("C:"));
	TEST2(rc, KErrBadName);
	db.Close();
	
	//Database file name containing only the path, without the file name
	rc = db.Create(_L("C:\\TEST\\"));
	TEST2(rc, KErrBadName);
	db.Close();
	
	//Public shared database file on a non-existing drive (A:)	
	_LIT(KDbPath2, "A:\\test\\db1.db");
	rc = db.Create(KDbPath2);
	TEST2(rc, KErrNotReady);
	db.Close();

	// create database with good config specified
	rc = db.Create(KTestCfgDbName,&KServerConfigString1);
	TEST2(rc, KErrNone);
	db.Close();
	TInt rc2 = RSqlDatabase::Delete(KTestCfgDbName);
	TEST2(rc2, KErrNone);
	
	// create database with bad config specified
	rc = db.Create(KTestCfgDbName,&KServerConfigString2);
	TEST2(rc, KErrArgument);
	db.Close();

	// create database with long config specified
	rc = db.Create(KTestCfgDbName,&KServerConfigString3);
	TEST2(rc, KErrArgument);
	db.Close();

	// create database with empty config specified - not an error
	rc = db.Create(KTestCfgDbName,&KServerConfigString4);
	TEST2(rc, KErrNone);
	db.Close();
	rc2 = RSqlDatabase::Delete(KTestCfgDbName);
	TEST2(rc2, KErrNone);

    // create database with very long config specified
    rc = db.Create(KTestCfgDbName, &KServerConfigString5);
    TEST2(rc, KErrArgument);
    db.Close();
	
	//Secure shared database file on an existing drive (C:). 
	//Very long database file name (> 90 characters) but still a valid name.
	rc = db.Create(KTestDbName4, securityPolicy);
	db.Close();
	rc2 = RSqlDatabase::Delete(KTestDbName4);
	TEST2(rc, KErrNone);
	TEST2(rc2, KErrNone);

	//Secure shared database file on an existing drive (C:). 
	//Very long database file name (> 90 characters) but still a valid name.
	//With config
	rc = db.Create(KTestCfgDbName2, securityPolicy, &KServerConfigString1);
	db.Close();
	rc2 = RSqlDatabase::Delete(KTestCfgDbName2);
	TEST2(rc, KErrNone);
	TEST2(rc2, KErrNone);
	
	//Public shared database file on an existing drive (C:). 
	//Very long database file name (> 90 characters) but still a valid name.
	rc = db.Create(KTestDbName5);
	db.Close();
	rc2 = RSqlDatabase::Delete(KTestDbName5);
	TEST2(rc, KErrNone);
	TEST2(rc2, KErrNone);
	
	RFs fs;
	TEST2(fs.Connect(), KErrNone);
	TFileName privatePath;
	TEST2(fs.PrivatePath(privatePath), KErrNone);
	fs.Close();
	
	//Private shared database file on an existing drive (C:). 
	//Very long database file name.
	const TInt KMaxFileName2 = KMaxFileName - 40;//"-40" because the SQLITE engine creates a journal file if begins
	                                             //a transaction. The name of the journal file is 
	                                             //"<dbFileName>-journal.<ext>". It is obvious that if the 
	                                             //database file name is too long but still valid and its creation
	                                             //succeeds, the journal file creation may fail because the journal
	                                             //file name becomes too long
	TBuf<KMaxFileName2> dbPath;
	_LIT(KExt, ".DB");
	dbPath.Copy(_L("C:"));
	dbPath.Append(KSecureUid.Name());
	TInt len = KMaxFileName2 + 1 - (dbPath.Length() + KExt().Length() + privatePath.Length());
	while(--len)
		{
		dbPath.Append(TChar('A'));	
		}
	dbPath.Append(KExt);	
	TEST(dbPath.Length() == (KMaxFileName2 - privatePath.Length()));
	rc = db.Create(dbPath, securityPolicy);
	db.Close();
	rc2 = RSqlDatabase::Delete(dbPath);
	TEST2(rc, KErrNone);
	TEST2(rc2, KErrNone);
	
	// Private database with config
	TBuf<KMaxFileName> cfgPath;
	cfgPath.Copy(_L("C:"));
	cfgPath.Append(KSecureUid.Name());
	cfgPath.Append(KExt);
	rc = db.Create(cfgPath,securityPolicy,&KServerConfigString1);
	db.Close();
	rc2 = RSqlDatabase::Delete(cfgPath);
	TEST2(rc, KErrNone);
	TEST2(rc2, KErrNone);
	
	//Public shared database file on an existing drive (C:). 
	//Very long database file name.
	dbPath.Copy(_L("C:\\TEST\\D"));
	len = KMaxFileName2 + 1 - (dbPath.Length() + KExt().Length());
	while(--len)
		{
		dbPath.Append(TChar('A'));	
		}
	dbPath.Append(KExt);	
	TEST(dbPath.Length() == KMaxFileName2);
	rc = db.Create(dbPath);
	db.Close();
	rc2 = RSqlDatabase::Delete(dbPath);
	TEST2(rc, KErrNone);
	TEST2(rc2, KErrNone);

	//Create/Close/Open/Close secure shared database test
	rc = db.Create(KTestDbName6, securityPolicy);
	db.Close();
	rc2 = db.Open(KTestDbName6);
	db.Close();
	TInt rc3 = RSqlDatabase::Delete(KTestDbName6);
	TEST2(rc, KErrNone);
	TEST2(rc2, KErrNone);
	TEST2(rc3, KErrNone);
	
	//An attempt to create already existing secure shared file.	
	rc = db.Create(KTestDbName6, securityPolicy);
	db.Close();
	rc2 = db.Create(KTestDbName6, securityPolicy);
	db.Close();
	rc3 = RSqlDatabase::Delete(KTestDbName6);
	TEST2(rc, KErrNone);
	TEST2(rc2, KErrAlreadyExists);
	TEST2(rc3, KErrNone);
	
	//An attempt to open twice the same database file using different RSqlDatabase objects
	rc = db.Create(KTestDbName6, securityPolicy);
	RSqlDatabase db2;	
	rc2 = db2.Open(KTestDbName6);
	db2.Close();
	db.Close();
	rc3 = RSqlDatabase::Delete(KTestDbName6);
	TEST2(rc, KErrNone);
	TEST2(rc2, KErrNone);//-- KErrInUse -- in case EFileRead | EFileWrite file open mode!
	TEST2(rc3, KErrNone);

	//An attempt to create secure shared database file on a read-only drive (Z:)
	_LIT(KDbPath8, "Z:[1111CCCC]db1.db");
	rc = db.Create(KDbPath8, securityPolicy);
	TEST2(rc, KErrAccessDenied);
	db.Close();

	//An attempt to create non-secure shared database file on a read-only drive (Z:)
	_LIT(KDbPath8a, "Z:\\db1.db");
	rc = db.Create(KDbPath8a);
	TEST2(rc, KErrAccessDenied);
	db.Close();

	//An attempt to open non-existing secure shared database file on a read-only drive (Z:)
	rc = db.Open(KDbPath8);
	TEST(rc == KErrNotFound || rc == KErrPathNotFound);
	db.Close();

	//An attempt to open existing public shared database file on a read-only drive (Z:)
	_LIT(KDbPath9, "Z:\\TEST\\TestDb1.db");
	rc = db.Open(KDbPath9);
	TEST2(rc, KErrNone);
	db.Close();
	
	//An attempt to open corrupted public shared database file on a read-only drive (Z:)
	_LIT(KDbPath10, "Z:\\TEST\\CorruptDb.db");
	rc = db.Open(KDbPath10);
	// it will be KErrNotDb if SqlServer.cfg exists, else KErrNone if it doesn't
	// this is because we can detect a corrupt database when we attempt to
	// set the configuration. If there is no cfg file, then there will be no
	// attempt to set the pragmas and so the corrupt file is undetected
	TEST(rc==KSqlErrNotDb || rc==KErrNone);
	db.Close();

	//Copy the corrupted database file on drive C:
	TEST2(fs.Connect(), KErrNone);
	rc = BaflUtils::CopyFile(fs, KDbPath10, KTestDbName3);
	TEST2(rc, KErrNone);
	(void)fs.SetAtt(KTestDbName3, 0, KEntryAttReadOnly);
	fs.Close();

	//An attempt to open corrupted public shared database file on a drive (C:)
	rc = db.Open(KTestDbName3);
	TEST(rc == KSqlErrNotDb || rc == KErrNone);//Note: but it may be a different error code as well
	db.Close();
	(void)RSqlDatabase::Delete(KTestDbName3);
	
	//Create, Close, Open, Close and again Open database test
	rc = db.Create(KTestDbName2, securityPolicy);
	TEST2(rc, KErrNone);
	db.Close();
	rc = db.Open(KTestDbName2);
	TEST2(rc, KErrNone);
	db.Close();
	rc = db.Open(KTestDbName2);
	TEST2(rc, KErrNone);
	db.Close();

	//Open two connections to the same database.
	rc = db.Open(KTestDbName2);
	TEST2(rc, KErrNone);
	rc = db2.Open(KTestDbName2);
	TEST2(rc, KErrNone);
	db2.Close();
	db.Close();
	
	rc = RSqlDatabase::Delete(KTestDbName2);
	TEST2(rc, KErrNone);
	
	securityPolicy.Close();
	}

///////////////////////////////////////////////////////////////////////////////////////

/**
@SYMTestCaseID			SYSLIB-SQL-CT-1602
@SYMTestCaseDesc		Setting database isolation level tests.
@SYMTestPriority		High
@SYMTestActions			Tests for RSqlDatabase::SetIsolationLevel() method.
@SYMTestExpectedResults Test must not fail
@SYMREQ					REQ5792
                        REQ5793
*/	
void SetIsolationLevelTest()
	{
	(void)RSqlDatabase::Delete(KTestDbName1);

	RSqlDatabase db;		
	TInt err = db.Create(KTestDbName1);
	TEST2(err, KErrNone);

	err = db.SetIsolationLevel(RSqlDatabase::EReadCommitted);
	TEST2(err, KErrNotSupported);
	
	err = db.SetIsolationLevel(RSqlDatabase::ERepeatableRead);
	TEST2(err, KErrNotSupported);
	
	err = db.SetIsolationLevel(RSqlDatabase::EReadUncommitted);
	TEST2(err, KErrNone);
	
	err = db.SetIsolationLevel(RSqlDatabase::ESerializable);
	TEST2(err, KErrNone);
	
	db.Close();
	
	(void)RSqlDatabase::Delete(KTestDbName1);
	}

///////////////////////////////////////////////////////////////////////////////////////

/**
@SYMTestCaseID			SYSLIB-SQL-CT-1603
@SYMTestCaseDesc		Deleting database tests. Deleting non-existing database, opened database, 
						database on non-existing drive, zero-length database name, only path (no file name),
						rom drive based database.
@SYMTestPriority		High
@SYMTestActions			Tests for RSqlDatabase::Delete() method.
@SYMTestExpectedResults Test must not fail
@SYMREQ					REQ5792
                        REQ5793
*/	
void DeleteDatabaseTest()
	{
	//An attempt to delete non-existing secure shared database
	_LIT(KDbName1, "C:[1111CCCC]EE__900000.adb");
	TInt err = RSqlDatabase::Delete(KDbName1);
	TEST2(err, KErrNotFound);

	//An attempt to delete non-existing public database
	_LIT(KDbName2, "C:\\TEST\\__900000.adb");
	err = RSqlDatabase::Delete(KDbName2);
	TEST2(err, KErrNotFound);
	
	//Zero length database file name.
	_LIT(KDbName3, "");
	err = RSqlDatabase::Delete(KDbName3);
	TEST2(err,  KErrBadName);
	
	//Database file name containing only the drive name
	_LIT(KDbName4, "C:");
	err = RSqlDatabase::Delete(KDbName4);
	TEST2(err, KErrBadName);
	
	//Database file name containing only the path, without the file name
	_LIT(KDbName5, "C:");
	err = RSqlDatabase::Delete(KDbName5);
	TEST2(err, KErrBadName);
	
	//Public shared database file on a non-existing drive (A:)	
	_LIT(KDbName6, "A:\\test\\db1.db");
	err = RSqlDatabase::Delete(KDbName6);
	TEST2(err, KErrNotReady);

	//An attempt to delete opened database.
	RSqlDatabase db;	
	err = db.Create(KDbName7);
	TEST2(err, KErrNone);
	err = RSqlDatabase::Delete(KDbName7);
	TEST2(err, KErrInUse);
	db.Close();
	err = RSqlDatabase::Delete(KDbName7);
	TEST2(err, KErrNone);

	//An attempt to delete existing public shared database file on a read-only drive (Z:)
	_LIT(KDbName8, "Z:\\TEST\\TestDb1.db");
	err = RSqlDatabase::Delete(KDbName8);
	TEST2(err, KErrAccessDenied);
	
	//Create secure database
	TSecurityPolicy defaultPolicy(TSecurityPolicy::EAlwaysPass);
	RSqlSecurityPolicy securityPolicy;
	err = securityPolicy.Create(defaultPolicy);
	TEST2(err, KErrNone);
	err = db.Create(KTestDbName7, securityPolicy);
	TEST2(err, KErrNone);
	db.Close();
	securityPolicy.Close();
	
	//Attempt to delete a secure public database.
	//The calling application has no rights to delete a file with that name from the server's 
	//private data cage.
   	err = RSqlDatabase::Delete(_L("C:[45454545]qq.db"));
	TEST2(err, KErrPermissionDenied);

	//Attempt to delete a secure public database. No drive specified.
	//The calling application has no rights to delete a file with that name from the server's 
	//private data cage.
	err = RSqlDatabase::Delete(_L("[45454545]qq.db"));
	TEST2(err, KErrPermissionDenied);

	//Attempt to delete secure database specifying the full database path
	TParse parse;
	parse.Set(KTestDbName7, &KServerPrivateDir(), 0);
	err = RSqlDatabase::Delete(parse.FullName());
	TEST2(err, KErrArgument);

	//Attempt to delete secure database specifying only the database name
	err = RSqlDatabase::Delete(parse.NameAndExt());
	//If C: is the system drive then the operation must pass.
	TEST2(err, KErrNone);
	}

///////////////////////////////////////////////////////////////////////////////////////

/**
@SYMTestCaseID			SYSLIB-SQL-CT-1640
@SYMTestCaseDesc		Copying database tests. Copying:
						- non-secure to non-secure database;
						- non-secure to secure database;
						- secure to non-secure database;
						- secure to secure database;
						- secure database, when the application is not the database creator (owner);
@SYMTestPriority		High
@SYMTestActions			Tests for RSqlDatabase::Copy() method.
@SYMTestExpectedResults Test must not fail
@SYMREQ					REQ5792
                        REQ5793
*/	
void CopyDatabaseTest()
	{
	RSqlDatabase db;	

	//Create secure database
	TSecurityPolicy defaultPolicy(TSecurityPolicy::EAlwaysPass);
	RSqlSecurityPolicy securityPolicy;
	TInt err = securityPolicy.Create(defaultPolicy);
	TEST2(err, KErrNone);
	err = db.Create(KTestDbName7, securityPolicy);
	TEST2(err, KErrNone);
	db.Close();
	securityPolicy.Close();
	
	//Create non-secure database
	err = db.Create(KTestDbName1);
	TEST2(err, KErrNone);
	db.Close();

	//Copy non-secure to non-secure database	
	err = RSqlDatabase::Copy(KTestDbName1, KTestDbName8);
	TEST2(err, KErrNone);

	//Attempt to copy non-secure to secure database	
	err = RSqlDatabase::Copy(KTestDbName1, _L("C:[99999999]pkk.db"));
	TEST2(err, KErrPermissionDenied);

	//Attempt to copy secure to non-secure database	
	err = RSqlDatabase::Copy(KTestDbName7, _L("C:\\test\\asdf.db"));
	TEST2(err, KErrPermissionDenied);

	//Copy secure to secure database. The test application is the database owner.
	err = RSqlDatabase::Copy(KTestDbName7, KTestDbName4);
	TEST2(err, KErrNone);
	err = RSqlDatabase::Delete(KTestDbName4);
	TEST2(err, KErrNone);

	//Attempt to copy secure to secure database. The test application is not the database owner.
	err = RSqlDatabase::Copy(KTestDbName7, _L("C:[11111111]ff.db"));
	TEST2(err, KErrPermissionDenied);
	err = RSqlDatabase::Copy(_L("C:[11111111]ff.db"), _L("C:[22222222]ff.db"));
	TEST2(err, KErrPermissionDenied);
	err = RSqlDatabase::Copy(_L("C:[11111111]ff.db"), KTestDbName7);
	TEST2(err, KErrPermissionDenied);
	
	(void)RSqlDatabase::Delete(KTestDbName8);
	(void)RSqlDatabase::Delete(KTestDbName7);
	(void)RSqlDatabase::Delete(KTestDbName4);
	(void)RSqlDatabase::Delete(KTestDbName1);
	}

///////////////////////////////////////////////////////////////////////////////////////

/**
@SYMTestCaseID			SYSLIB-SQL-CT-1604
@SYMTestCaseDesc		Create a table with two integer columns. The second column has a default value NULL.
						Check what will be the result of "column1 + column2" operation, if "column2" 
						value is NULL.
@SYMTestPriority		High
@SYMTestActions			Tests mathematical operations with ESqlNull column values.
@SYMTestExpectedResults Test must not fail
@SYMREQ					REQ5792
                        REQ5793
*/	
void NullColumnValues()
	{
	(void)RSqlDatabase::Delete(KTestDbName1);
	
	RSqlDatabase db;		
	TInt err = db.Create(KTestDbName1);
	TEST2(err, KErrNone);

	err = db.Exec(_L8("CREATE TABLE test(int_fld integer, null_int_fld integer default null)"));
	TEST(err >= 0);

	err = db.Exec(_L8("INSERT INTO test(int_fld) values(200)"));
	TEST2(err, 1);

	RSqlStatement stmt;
	
	err = stmt.Prepare(db, _L8("SELECT * from test"));
	TEST2(err, KErrNone);
	
	err = stmt.Next();
	TEST2(err, KSqlAtRow);

	TSqlColumnType colType = stmt.ColumnType(0);
	TEST(colType == ESqlInt);
	
	colType = stmt.ColumnType(1);
	TEST(colType == ESqlNull);
	
	TInt val = stmt.ColumnInt(0);
	TEST(val == 200);
	
	val = stmt.ColumnInt(1);
	TEST(val == 0);

	stmt.Close();
	
	err = stmt.Prepare(db, _L8("SELECT (int_fld + null_int_fld) as res from test"));
	TEST2(err, KErrNone);
	
	err = stmt.Next();
	TEST2(err, KSqlAtRow);
	
	colType = stmt.ColumnType(0);
	TEST(colType == ESqlNull);
	
	val = stmt.ColumnInt(0);
	TEST(val == 0);
	
	stmt.Close();
	db.Close();

	(void)RSqlDatabase::Delete(KTestDbName1);
	}

///////////////////////////////////////////////////////////////////////////////////////

_LIT8(KStmt1, "CREATE TABLE A1(Fld1 INTEGER, Fld2 DOUBLE);\
									   CREATE TABLE A2(Fld1 INTEGER, Fld2 DOUBLE);\
									   CREATE TRIGGER TrgA1Ins BEFORE Insert ON A1\
									   BEGIN\
									      INSERT INTO A2(Fld1, Fld2) VALUES(new.Fld1, new.Fld2);\
									   END;");
_LIT8(KStmt2, "INSERT INTO A1(Fld1, Fld2) VALUES(1, 2.0)");
_LIT8(KStmt3, "SELECT * FROM A2");
_LIT8(KStmt4, "INSERT INTO A1(Fld1, Fld2) VALUES(2, 4.0); UPDATE A2 SET Fld2 = 11.3 WHERE Fld1 = 2");
_LIT8(KStmt5, "");
_LIT8(KStmt6, "INSERT INTO A1(Fld1, Fld2) VALUESa(6, 234.0);");
_LIT8(KStmt7, "");
_LIT8(KStmt8, ";;;;;");
_LIT8(KStmt9, "INSERT INTO A1(Fld1, Fld2) VALUES(:v1, :v2)");

/**
@SYMTestCaseID			SYSLIB-SQL-CT-1605
@SYMTestCaseDesc		SQL statements execution. Valid SQL statements. Empty SQL statement. 
						More than one SQL statements, separated with ";". SQL statement which syntax is
						incorrect. SQL statement with parameters. INSERT/SELECT/CREATE TABLE SQL statements.
@SYMTestPriority		High
@SYMTestActions			RSqlDatabase::Exec() tests, 16-bit and 8-bit SQL statements
@SYMTestExpectedResults Test must not fail
@SYMREQ					REQ5792
                        REQ5793
*/	
template <class DES, class BUF> void ExecOnDbTest()
	{
	RSqlDatabase db;
	TInt rc = db.Create(KTestDbName1);
	TEST2(rc, KErrNone);

	//Create two tables and a trigger	              	  
	ExecSqlStmtOnDb<DES, BUF>(db, KStmt1, KErrNone); 

	//INSERT sql statement execution
	ExecSqlStmtOnDb<DES, BUF>(db, KStmt2, KErrNone); 

	//SELECT sql statement execution
	ExecSqlStmtOnDb<DES, BUF>(db, KStmt3, KErrNone); 

	//Executing more than one SQL statement in a single Exec() call.
	ExecSqlStmtOnDb<DES, BUF>(db, KStmt4, KErrNone); 

	//Executing zero length SQL statement.
	ExecSqlStmtOnDb<DES, BUF>(db, KStmt5, KErrNone); 
	
	//Executing a SQL statement with syntax errors.
	ExecSqlStmtOnDb<DES, BUF>(db, KStmt6, KSqlErrGeneral); 

	//Executing an empty SQL statement.
	ExecSqlStmtOnDb<DES, BUF>(db, KStmt7, KErrNone); 
	
	//Executing a SQL string, which does not have any SQL statements inside, but has valid syntax.
	ExecSqlStmtOnDb<DES, BUF>(db, KStmt8, KErrNone); 
	
	//Executing SQL statement with parameters. They will be set with NULL values, if not set explicitly.
	ExecSqlStmtOnDb<DES, BUF>(db, KStmt9, KErrNone); 
	
	db.Close();

	rc = RSqlDatabase::Delete(KTestDbName1);
	TEST2(rc, KErrNone);
	}

_LIT8(KStmt10, "");
_LIT8(KStmt11, ";   ;  ;;;");
_LIT8(KStmt12, "CREATE TABLE AAA(Fld1 INTEGER, Fld2 VARCHAR(100))");
_LIT8(KStmt13, "INSERT INTO AAA(Fld1, Fld2) VALUES(5, 'FldVal1-1234567890')");
_LIT8(KStmt14, "SELECT fld1, fld2 FROM AAA");
_LIT8(KStmt15, "SELECT fld2, fld1 FROM AAA");
_LIT8(KStmt16, "SELECT fld2, fld1 FROM AAA WHERE Fld1 > :Prm1 AND fld2 = :PRM2");
_LIT8(KStmt17, "INSERT INTO AAA(Fld1, Fld2) VALUES(:b, :a);");
_LIT8(KStmt18, "CREATE TABLE BBB(Fld1 INTEGER, Fld2 BIGINT, Fld3 DOUBLE, \
					                       Fld4 TEXT, Fld5 LONGBLOB, Fld6 TEXT NULL)");
_LIT8(KStmt19, "INSERT INTO BBB(Fld1, Fld2, Fld3, Fld4, Fld5, Fld6)\
	                                       VALUES(:V1, :V2, :V3, :V4, :V5, :V6)");
_LIT8(KStmt20, "SELECT * FROM BBB");

/**
@SYMTestCaseID			SYSLIB-SQL-CT-1606
@SYMTestCaseDesc		Preparing SQL statements. Moving to the next record. Retrieving and verifying 
						the column types and values. Binding parameter values.
@SYMTestPriority		High
@SYMTestActions			RSqlStatement::Prepare(), RSqlStatement::Next() tests, 16-bit and 8-bit SQL statements.
						RSqlStatement::ColumnIndex(), RSqlStatement::Column<DataType>(), RSqlStatement::Bind<DataType>(),
						RSqlStatement::Column<DataType>().				
@SYMTestExpectedResults Test must not fail
@SYMREQ					REQ5792
                        REQ5793
*/	
template <class DES, class BUF> void StatementTest()
	{
	RSqlDatabase db;	
	TInt rc = db.Create(KTestDbName1);
	TEST2(rc, KErrNone);

	//Executing an empty SQL statement.
	RSqlStatement stmt = PrepareSqlStmt<DES, BUF>(db, KStmt10, KErrArgument);
	stmt.Close();

	//Executing a SQL string, which does not have any SQL statements inside, but has valid syntax.
	stmt = PrepareSqlStmt<DES, BUF>(db, KStmt11, KErrArgument); 
	stmt.Close();
	
	//SQL statement without parameters. Create a table.
	stmt = PrepareSqlStmt<DES, BUF>(db, KStmt12, KErrNone);
	ExecSqlStmt(db, stmt, KErrNone);
	stmt.Close();

	//SQL statement without parameters. Insert a record into the table.
	stmt = PrepareSqlStmt<DES, BUF>(db, KStmt13, KErrNone);
	ExecSqlStmt(db, stmt, KErrNone);
	stmt.Close();
		
	//Test RSqlStatement::ColumnIndex().
	stmt = PrepareSqlStmt<DES, BUF>(db, KStmt14, KErrNone);
	TInt idx1 = stmt.ColumnIndex(_L("FLD1"));
	TEST(idx1 == 0);
	TInt idx2 = stmt.ColumnIndex(_L("FlD2"));
	TEST(idx2 == 1);
	TInt idx3 = stmt.ColumnIndex(_L("fld3"));
	TEST(idx3 < 0);
	stmt.Close();
	
	stmt = PrepareSqlStmt<DES, BUF>(db, KStmt15, KErrNone);
	idx1 = stmt.ColumnIndex(_L("FLD1"));
	TEST(idx1 == 1);
	idx2 = stmt.ColumnIndex(_L("FlD2"));
	TEST(idx2 == 0);
	idx3 = stmt.ColumnIndex(_L("fld3"));
	TEST(idx3 < 0);
	
	//Test RSqlStatement::Column<DataType>() methods.
	TInt recCnt = 0;
	while((rc = stmt.Next()) == KSqlAtRow)
		{
		++recCnt;
		
		TInt intVal = stmt.ColumnInt(idx1);
		TEST(intVal == 5);
		
		//Integer column value retrieved as a text.
		TPtrC strVal1;
		TInt err = stmt.ColumnText(idx1, strVal1);
		TEST2(err, KErrNone);
		TEST(strVal1 == KNullDesC);
		
		//Text column value retrieved as a binary
		TBuf8<50> strVal3;
		err = stmt.ColumnBinary(idx2, strVal3);
		TEST2(err, KErrNone);
		TEST(strVal3 == KNullDesC8);
		
		TPtrC strVal2;
		err = stmt.ColumnText(idx2, strVal2);
		TEST2(err, KErrNone);
		TEST(strVal2 == _L("FldVal1-1234567890"));
				
		//Invalid column index. Panic: "SqlDb 5"
		//intVal = stmt.ColumnInt(1002);
		//intVal = stmt.ColumnInt(-24);
		}
	stmt.Close();
	TEST2(rc, KSqlAtEnd);
	TEST2(SqlRetCodeClass(rc), ESqlInformation);
	TEST(recCnt == 1);
	
	//Test RSqlStatement::Bind<DataType>() methods.
	stmt = PrepareSqlStmt<DES, BUF>(db, KStmt16, KErrNone);
	idx1 = stmt.ColumnIndex(_L("FLD1"));
	TEST(idx1 == 1);
	idx2 = stmt.ColumnIndex(_L("FlD2"));
	TEST(idx2 == 0);
	TInt prmIdx1 = stmt.ParameterIndex(_L(":prm1"));
	TEST(prmIdx1 == 0);
	TInt prmIdx2 = stmt.ParameterIndex(_L(":prm2"));
	TEST(prmIdx2 == 1);
	rc = stmt.BindInt(prmIdx1, -4);
	//No problem to bind whatever value type we like
	//rc = stmt.BindBinary(prmIdx1, KSqlStmt4());
	TEST2(rc, KErrNone);
	rc = stmt.BindText(prmIdx2, _L("FldVal1-1234567890"));
	TEST2(rc, KErrNone);
	//Test RSqlStatement::Column<DataType>() methods.
	recCnt = 0;
	while((rc = stmt.Next()) == KSqlAtRow)
		{
		++recCnt;
		TInt intVal = stmt.ColumnInt(idx1);
		TEST(intVal == 5);
		TPtrC strVal;
		TInt err = stmt.ColumnText(idx2, strVal);
		TEST2(err, KErrNone);
		TEST(strVal == _L("FldVal1-1234567890"));
		}
	stmt.Close();
	TEST2(rc, KSqlAtEnd);
	TEST2(SqlRetCodeClass(rc), ESqlInformation);
	TEST(recCnt == 1);
	
	//Test an INSERT SQL - prepare, bind, exec.
	stmt = PrepareSqlStmt<DES, BUF>(db, KStmt17, KErrNone);
	prmIdx1 = stmt.ParameterIndex(_L(":A"));
	TEST(prmIdx1 == 1);
	prmIdx2 = stmt.ParameterIndex(_L(":B"));
	TEST(prmIdx2 == 0);
	rc = stmt.BindInt(prmIdx1, 20);
	TEST2(rc, KErrNone);
	rc = stmt.BindText(prmIdx2, _L("FldVal2"));
	TEST2(rc, KErrNone);
	rc = stmt.Exec();
	TEST2(rc, 1);
	
	stmt.Close();
	
	//Create a table with INTEGER, INT64, REAL, TEXT, BINARY, NULL, field types
	stmt = PrepareSqlStmt<DES, BUF>(db, KStmt18, KErrNone);
	ExecSqlStmt(db, stmt, KErrNone);
	stmt.Close();
	
	enum {KLow = 1, KHigh = 2};
	//Insert (KHigh - KLow + 1) records
	stmt = PrepareSqlStmt<DES, BUF>(db, KStmt19, KErrNone);
	TInt v32 = 1024;
	TInt64 v64 = MAKE_TINT64(0x00FF00FF, 0x12345678);
	TReal vReal = 234.75;
	TBuf<10> vText;
	TBuf8<10> vBinary;
	for(TInt i=KLow;i<=KHigh;++i)
		{
		rc = stmt.BindInt(0, v32 * i);
		TEST2(rc, KErrNone);
		
		rc = stmt.BindInt64(1, v64 * i);
		TEST2(rc, KErrNone);
		
		rc = stmt.BindReal(2, vReal * i);
		TEST2(rc, KErrNone);
		
		vText.Copy(_L("TEXT"));
		vText.Append(TChar(i + '0'));
		rc = stmt.BindText(3, vText);
		TEST2(rc, KErrNone);

		vBinary.Copy(_L("BINARY"));
		vBinary.Append(TChar(i + '0'));
		rc = stmt.BindBinary(4, vBinary);
		TEST2(rc, KErrNone);

		rc = stmt.BindNull(5);
		TEST2(rc, KErrNone);

		rc = stmt.Exec();
		TEST2(rc, 1);

		rc = stmt.Reset();
		TEST2(rc, KErrNone);
		}
	stmt.Close();

	//Read and test (KHigh - KLow + 1) records
	stmt = PrepareSqlStmt<DES, BUF>(db, KStmt20, KErrNone);
	recCnt = 0;
	while((rc = stmt.Next()) == KSqlAtRow)
		{
		++recCnt;
		TInt v1 = stmt.ColumnInt(0);
		TEST(v1 == v32 * recCnt);

		TInt64 v2 = stmt.ColumnInt64(1);
		TEST(v2 == v64 * recCnt);

		TReal v3 = stmt.ColumnReal(2);
		TEST(Abs(v3 - vReal * recCnt) < 0.000001);
		
		vText.Copy(_L("TEXT"));
		vText.Append(TChar(recCnt + '0'));
		TPtrC v4;
		TInt err = stmt.ColumnText(3, v4);
		TEST2(err, KErrNone);
		TEST(v4 == vText);
		
		vBinary.Copy(_L("BINARY"));
		vBinary.Append(TChar(recCnt + '0'));
		TPtrC8 v5;
		err = stmt.ColumnBinary(4, v5);
		TEST2(err, KErrNone);
		TEST(v5 == vBinary);
		
		TBool b = stmt.IsNull(5);
		TEST(b != 0);
		}
	stmt.Close();
	TEST2(rc, KSqlAtEnd);
	TEST2(SqlRetCodeClass(rc), ESqlInformation);
	TEST(recCnt == (KHigh - KLow + 1));
	
	db.Close();

	rc = RSqlDatabase::Delete(KTestDbName1);
	TEST2(rc, KErrNone);
	}

/**
@SYMTestCaseID			SYSLIB-SQL-CT-1607
@SYMTestCaseDesc		Retrieving long text column values test.
						Retrieving long column values using RSqlStatement::ColumnText() when the recipient buffer
						is not big enough.
@SYMTestPriority		High
@SYMTestActions			RSqlColumnReadStream::ColumnText() test.
@SYMTestExpectedResults Test must not fail
@SYMREQ					REQ5792
                        REQ5793
*/	
void ColumnTextStreamTest()
	{
	RSqlDatabase db;	
	TInt rc = db.Create(KTestDbName1);
	TEST2(rc, KErrNone);

	enum {KSqlBufSize = 64};
	
	//Create a table
	_LIT8(KSqlStmt1, "CREATE TABLE A(Fld1 INTEGER, Fld2 TEXT);");
	ExecSqlStmtOnDb<TDesC8, TBuf8<KSqlBufSize> >(db, KSqlStmt1(), KErrNone); 
	
	const TInt KTextLen = 3101;

	_LIT(KSqlStmt2, "INSERT INTO A(Fld1, Fld2) VALUES(");
	
	//Allocate a buffer for the SQL statement.
	HBufC* buf = HBufC::New(KSqlStmt2().Length() + KTextLen + 10);
	TEST(buf != NULL);

	TPtr sql = buf->Des();
	
	//Insert row 1
	
	const TChar KChar1('A');
	sql.Copy(KSqlStmt2);
	sql.Append(_L("1, '"));
	TInt i;
	for(i=0;i<KTextLen;++i)
		{
		sql.Append(KChar1);
		}
	sql.Append(_L("')"));

	rc = db.Exec(sql);
	TEST2(rc, 1);

	//Insert row 2
	
	const TChar KChar2('B');
	sql.Copy(KSqlStmt2);
	sql.Append(_L("2, '"));
	for(i=0;i<KTextLen;++i)
		{
		sql.Append(KChar2);
		}
	sql.Append(_L("')"));

	rc = db.Exec(sql);
	TEST2(rc, 1);

	//Prepare SELECT SQL statement
	_LIT8(KSqlStmt3, "SELECT * FROM A");
	RSqlStatement stmt = PrepareSqlStmt<TDesC, TBuf<KSqlBufSize> >(db, KSqlStmt3, KErrNone);

	//Move on row 1
	rc = stmt.Next();
	TEST2(rc, KSqlAtRow);

	//Read the long text column using a stream
	RSqlColumnReadStream columnStream;
	rc = columnStream.ColumnText(stmt, 1);
	columnStream.Close();
	TEST2(rc, KErrNone);

	//...and the leaving version of ColumnText() 
	TRAP(rc, columnStream.ColumnTextL(stmt, 1));
	TEST2(rc, KErrNone);
	
	TInt size = stmt.ColumnSize(1);
	TPtr colData = buf->Des();
	TRAP(rc, columnStream.ReadL(colData, size));
	columnStream.Close();
	TEST2(rc, KErrNone);
	
	//Check the column value
	for(i=0;i<KTextLen;++i)
		{
		TEST(colData[i] == (TUint8)KChar1);	
		}

	//Move on row 2
	rc = stmt.Next();
	TEST2(rc, KSqlAtRow);

	//Read row 2 using ColumnText(TInt aColumnIndex, TPtrC& aPtr).
	TPtrC colDataPtr;
	rc = stmt.ColumnText(1, colDataPtr);
	TEST2(rc, KErrNone);
	
	//Check the column value
	for(i=0;i<KTextLen;++i)
		{
		TEST(colDataPtr[i] == (TUint8)KChar2);	
		}

	//Read row 2 using ColumnText(TInt aColumnIndex, TDes& aDest).
	rc = stmt.ColumnText(1, colData);
	TEST2(rc, KErrNone);
	//Too small target buffer
	TBuf<3> buf1;
    rc = stmt.ColumnText(1, buf1);
    TEST2(rc, KErrOverflow);
	
	//Check the column value
	for(i=0;i<KTextLen;++i)
		{
		TEST(colData[i] == (TUint8)KChar2);	
		}
	
	//Read row 2 using a stream
	colData.Zero();
	rc = columnStream.ColumnText(stmt, 1);
	TEST2(rc, KErrNone);
	size = stmt.ColumnSize(1);
	TRAP(rc, columnStream.ReadL(colData, size));
	columnStream.Close();
	TEST2(rc, KErrNone);
	
	//Check the column value
	for(i=0;i<KTextLen;++i)
		{
		TEST(colData[i] == (TUint8)KChar2);	
		}
	
	//Read the column value using RSqlStatement::ColumnText(). 
	//The recipient buffer max length is smaller than the column value length.
	rc = stmt.Reset();
	TEST2(rc, KErrNone);
	rc = stmt.Next();
	TEST2(rc, KSqlAtRow);
	const TInt KBufMaxLen = 100;
	TBuf<KBufMaxLen> colBuf;
	rc = stmt.ColumnText(1, colBuf);
	TEST2(rc, KErrOverflow);
	//Check the column value
	for(i=0;i<KBufMaxLen;++i)
		{
		TEST(colBuf[i] == (TUint8)KChar1);	
		}
		
	stmt.Close();
	
	//Deallocate buf
	delete buf; 
	buf = NULL;
	
	db.Close();

	rc = RSqlDatabase::Delete(KTestDbName1);
	TEST2(rc, KErrNone);
	}

/**
@SYMTestCaseID			SYSLIB-SQL-CT-1621
@SYMTestCaseDesc		Retrieving long binary column values test.
						Retrieving long column values using RSqlStatement::ColumnBinary() when the recipient buffer
						is not big enough.
@SYMTestPriority		High
@SYMTestActions			RSqlColumnReadStream::ColumnBinary() test.
@SYMTestExpectedResults Test must not fail
@SYMREQ					REQ5792
                        REQ5793
*/	
void ColumnBinaryStreamTest()
	{
	RSqlDatabase db;	
	TInt rc = db.Create(KTestDbName1);
	TEST2(rc, KErrNone);

	enum {KSqlBufSize = 64};
	
	//Create a table
	_LIT8(KSqlStmt1, "CREATE TABLE A(Fld1 INTEGER, Fld2 BLOB);");
	ExecSqlStmtOnDb<TDesC8, TBuf8<KSqlBufSize> >(db, KSqlStmt1(), KErrNone); 
	
	const TInt KDataLen = 3311;

	_LIT8(KSqlStmt2, "INSERT INTO A(Fld1, Fld2) VALUES(");
	
	//Allocate a buffer for the SQL statement.
	HBufC8* buf = HBufC8::New(KSqlStmt2().Length() + KDataLen * 2 + 10);//"* 2" - SQL statement with HEX values
	TEST(buf != NULL);

	TPtr8 sql = buf->Des();
	
	//Insert row 1

	const TUint8 KHexVal1 = 0x7E;
	_LIT8(KHexValStr1, "7E");
	sql.Copy(KSqlStmt2);
	sql.Append(_L8("1, x'"));
	TInt i;
	for(i=0;i<KDataLen;++i)
		{
		sql.Append(KHexValStr1);
		}
	sql.Append(_L8("')"));

	rc = db.Exec(sql);
	TEST2(rc, 1);

	//Insert row 2
	
	const TUint8 KHexVal2 = 0xA3;
	_LIT8(KHexValStr2, "A3");
	sql.Copy(KSqlStmt2);
	sql.Append(_L8("2, x'"));
	for(i=0;i<KDataLen;++i)
		{
		sql.Append(KHexValStr2);
		}
	sql.Append(_L8("')"));

	rc = db.Exec(sql);
	TEST2(rc, 1);

    //Insert row 3: the binary column length is just 2 bytes
    rc = db.Exec(_L("INSERT INTO A VALUES(3, x'A5D3')"));
    TEST2(rc, 1);
	
	//Prepare SELECT SQL statement
	_LIT8(KSqlStmt3, "SELECT * FROM A");
	RSqlStatement stmt = PrepareSqlStmt<TDesC8, TBuf8<KSqlBufSize> >(db, KSqlStmt3, KErrNone);

	//Move on row 1
	rc = stmt.Next();
	TEST2(rc, KSqlAtRow);

	//Read the long binary column using a stream
	RSqlColumnReadStream columnStream;
	rc = columnStream.ColumnBinary(stmt, 1);
	columnStream.Close();
	TEST2(rc, KErrNone);
	
	//...and the leaving version of ColumnBinary() 
	TRAP(rc, columnStream.ColumnBinaryL(stmt, 1));
	TEST2(rc, KErrNone);
	
	TInt size = stmt.ColumnSize(1);
	TPtr8 colData = buf->Des();
	TRAP(rc, columnStream.ReadL(colData, size));
	columnStream.Close();
	TEST2(rc, KErrNone);
	
	//Check the column value
	for(i=0;i<KDataLen;++i)
		{
		TUint8 val = colData[i];
		TEST(val = KHexVal1);	
		}

	//Move on row 2
	rc = stmt.Next();
	TEST2(rc, KSqlAtRow);

	//Read row 2 using ColumnBinary(TInt aColumnIndex, TPtrC8& aPtr).
	TPtrC8 colDataPtr;
	rc = stmt.ColumnBinary(1, colDataPtr);
	TEST2(rc, KErrNone);
	
	//Check the column value
	for(i=0;i<KDataLen;++i)
		{
		TUint8 val = colDataPtr[i];
		TEST(val = KHexVal2);	
		}

	//Read row 2 using ColumnBinary(TInt aColumnIndex, TDes8& aDest).
	rc = stmt.ColumnBinary(1, colData);
	TEST2(rc, KErrNone);
	
	//Check the column value
	for(i=0;i<KDataLen;++i)
		{
		TUint8 val = colData[i];
		TEST(val = KHexVal2);	
		}
	
	//Read row 2 using a stream
	colData.Zero();
	rc = columnStream.ColumnBinary(stmt, 1);
	TEST2(rc, KErrNone);
	size = stmt.ColumnSize(1);
	TRAP(rc, columnStream.ReadL(colData, size));
	columnStream.Close();
	TEST2(rc, KErrNone);
	
	//Check the column value
	for(i=0;i<KDataLen;++i)
		{
		TUint8 val = colData[i];
		TEST(val = KHexVal2);	
		}
		
	//Read the column value using RSqlStatement::ColumnBinary(). 
	//The recipient buffer max length is smaller than the column value length.
	rc = stmt.Reset();
	TEST2(rc, KErrNone);
	rc = stmt.Next();
	TEST2(rc, KSqlAtRow);
	const TInt KBufMaxLen = 100;
	TBuf8<KBufMaxLen> colBuf;
	rc = stmt.ColumnBinary(1, colBuf);
	TEST2(rc, KErrOverflow);
	//Check the column value
	for(i=0;i<KBufMaxLen;++i)
		{
		TUint8 val = colBuf[i];
		TEST(val = KHexVal2);	
		}
	
    //Move on row 3. The binary column value length is just 2 bytes.
    rc = stmt.Next();
    TEST2(rc, KSqlAtRow);
    rc = stmt.Next();
    TEST2(rc, KSqlAtRow);
    TBuf8<2> buf1;
    rc = stmt.ColumnBinary(1, buf1); 
    TEST2(rc, KErrNone);
    TEST2(buf1.Length(), 2);
    TBuf8<1> buf2;
    rc = stmt.ColumnBinary(1, buf2); 
    TEST2(rc, KErrOverflow);
	
	stmt.Close();
	
	//Deallocate buf
	delete buf; 
	buf = NULL;
	
	db.Close();

	rc = RSqlDatabase::Delete(KTestDbName1);
	TEST2(rc, KErrNone);
	}

/**
@SYMTestCaseID			SYSLIB-SQL-CT-1608
@SYMTestCaseDesc		Setting long text parameter values test.
@SYMTestPriority		High
@SYMTestActions			RSqlParamWriteStream::BindText() test.
@SYMTestExpectedResults Test must not fail
@SYMREQ					REQ5792
                        REQ5793
*/	
void TextParameterStreamTest()
	{
	RSqlDatabase db;	
	TInt rc = db.Create(KTestDbName1);
	TEST2(rc, KErrNone);

	enum {KSqlBufSize = 64};
	
	//Create a table
	_LIT8(KSqlStmt1, "CREATE TABLE A(Fld1 INTEGER, Fld2 TEXT);");
	ExecSqlStmtOnDb<TDesC8, TBuf8<KSqlBufSize> >(db, KSqlStmt1(), KErrNone); 

	const TInt KTextLen = 3001;

	_LIT(KSqlStmt2, "INSERT INTO A(Fld1, Fld2) VALUES(");
	
	//Allocate a buffer for the SQL statement.
	HBufC* buf = HBufC::New(KSqlStmt2().Length() + KTextLen + 10);
	TEST(buf != NULL);

	TPtr sql = buf->Des();
	
	//Insert a row

	const TChar KChar('g');
	sql.Copy(KSqlStmt2);
	sql.Append(_L("1, '"));
	TInt i;
	for(i=0;i<KTextLen;++i)
		{
		sql.Append(KChar);
		}
	sql.Append(_L("')"));

	rc = db.Exec(sql);
	TEST2(rc, 1);

	//Prepare parametrized SQL statement
	_LIT8(KSqlStmt3, "SELECT * FROM A WHERE Fld2 = :Val");
	RSqlStatement stmt = PrepareSqlStmt<TDesC, TBuf<KSqlBufSize> >(db, KSqlStmt3, KErrNone);

	//Open the parameter stream
	RSqlParamWriteStream paramStream;
	rc = paramStream.BindText(stmt, 0);
	paramStream.Close();
	TEST2(rc, KErrNone);

	//...and the leaving version of BindText()
	TRAP(rc, paramStream.BindTextL(stmt, 0));
	TEST2(rc, KErrNone);
	
	//Prepare and set the parameter value
	TPtr val = buf->Des();
	val.Zero();
	for(i=0;i<KTextLen;++i)
		{
		val.Append(KChar);
		}
	TRAP(rc, (paramStream.WriteL(val), paramStream.CommitL()));
	TEST2(rc, KErrNone);

	//Move on row 1
	rc = stmt.Next();
	TEST2(rc, KSqlAtRow);

	paramStream.Close();

	//Read the row using ColumnText(TInt aColumnIndex, TPtrC& aPtr).
	TPtrC colDataPtr;
	rc = stmt.ColumnText(1, colDataPtr);
	TEST2(rc, KErrNone);
	
	//Check the column value
	for(i=0;i<KTextLen;++i)
		{
		TEST(colDataPtr[i] == (TUint8)KChar);	
		}
	
	stmt.Close();

	//Deallocate buf
	delete buf; 
	buf = NULL;

	///////////////////////////////////////////////////////////////////////////////////////////////	
	//Open a "short" text parameter. The streaming API should work with "short" text parameters too.
	_LIT(KTextVal, "U012");

	//Delete all records
	_LIT8(KSqlStmt4, "DELETE FROM A");
	ExecSqlStmtOnDb<TDesC8, TBuf8<KSqlBufSize> >(db, KSqlStmt4(), KErrNone); 

	//Prepare INSERT SQL statement.	
	_LIT8(KSqlStmt5, "INSERT INTO A(Fld1, Fld2) VALUES(1, :Val)");
	stmt = PrepareSqlStmt<TDesC, TBuf<KSqlBufSize> >(db, KSqlStmt5, KErrNone);

	//Open the parameter stream
	rc = paramStream.BindText(stmt, 0);
	TEST2(rc, KErrNone);

	//Prepare and set the parameter value
	TRAP(rc, (paramStream.WriteL(KTextVal), paramStream.CommitL()));
	TEST2(rc, KErrNone);

	//Execute the prepared SQL statement
	rc = stmt.Exec();
	TEST2(rc, 1);

	paramStream.Close();
	stmt.Close();
	
	//Prepare SELECT SQL statement
	_LIT8(KSqlStmt6, "SELECT * FROM A WHERE Fld1 = 1");
	stmt = PrepareSqlStmt<TDesC, TBuf<KSqlBufSize> >(db, KSqlStmt6, KErrNone);

	//Move on row 1
	rc = stmt.Next();
	TEST2(rc, KSqlAtRow);

	///////////////////////////////////////////////////////////////////////////////////////////////	
	//Open a stream for a "short" text column. The streaming API should work with "short" text columns too.

	TBuf<20> columnVal;
	RSqlColumnReadStream columnStream;
	rc = columnStream.ColumnText(stmt, 1);
	TEST2(rc, KErrNone);
	TInt size = stmt.ColumnSize(1);
	TRAP(rc, columnStream.ReadL(columnVal, size));
	columnStream.Close();
	TEST2(rc, KErrNone);
	
	//Check the column value
	TEST(columnVal == KTextVal);
	
	stmt.Close();
	
	db.Close();

	rc = RSqlDatabase::Delete(KTestDbName1);
	TEST2(rc, KErrNone);
	}

/**
@SYMTestCaseID			SYSLIB-SQL-CT-1622
@SYMTestCaseDesc		Setting long binary parameter values test.
@SYMTestPriority		High
@SYMTestActions			RSqlParamWriteStream::BindBinary() test.
@SYMTestExpectedResults Test must not fail
@SYMREQ					REQ5792
                        REQ5793
*/	
void BinaryParameterStreamTest()
	{
	//Create a test database
	RSqlDatabase db;	
	TInt rc = db.Create(KTestDbName1);
	TEST2(rc, KErrNone);

	enum {KSqlBufSize = 64};
	
	//Create a table
	_LIT8(KSqlStmt1, "CREATE TABLE A(Fld1 INTEGER, Fld2 BLOB);");
	ExecSqlStmtOnDb<TDesC8, TBuf8<KSqlBufSize> >(db, KSqlStmt1(), KErrNone); 

	const TInt KDataLen = 3731;

	_LIT8(KSqlStmt2, "INSERT INTO A(Fld1, Fld2) VALUES(");
	
	//Allocate a buffer for the SQL statement.
	HBufC8* buf = HBufC8::New(KSqlStmt2().Length() + KDataLen * 2 + 10);//"* 2" - SQL statement with HEX values
	TEST(buf != NULL);

	TPtr8 sql = buf->Des();
	
	//Insert a row

	const TUint8 KHexVal = 0xD3;
	_LIT8(KHexValStr, "D3");
	sql.Copy(KSqlStmt2);
	sql.Append(_L8("1, x'"));
	TInt i;
	for(i=0;i<KDataLen;++i)
		{
		sql.Append(KHexValStr);
		}
	sql.Append(_L8("')"));

	rc = db.Exec(sql);
	TEST2(rc, 1);

	//Prepare parametrized SQL statement
	_LIT8(KSqlStmt3, "SELECT * FROM A WHERE Fld2 = :Val");
	RSqlStatement stmt = PrepareSqlStmt<TDesC8, TBuf8<KSqlBufSize> >(db, KSqlStmt3, KErrNone);

	//Open the parameter stream
	RSqlParamWriteStream paramStream;
	rc = paramStream.BindBinary(stmt, 0);
	TEST2(rc, KErrNone);
	paramStream.Close();
    //Open the parameter stream with BindBinaryL()
    TRAP(rc, paramStream.BindBinaryL(stmt, 0));
    TEST2(rc, KErrNone);

	//Prepare and set the parameter value (NULL parameter value)
	TPtr8 prmVal = buf->Des();
	prmVal.SetLength(0);
	
	TRAP(rc, (paramStream.WriteL(prmVal), paramStream.CommitL()));
	TEST2(rc, KErrNone);

	rc = stmt.Next();
	TEST2(rc, KSqlAtEnd);
	
	paramStream.Close();
	stmt.Reset();
	
	//Prepare and set the parameter value (non-NULL binary value)
	rc = paramStream.BindBinary(stmt, 0);
	TEST2(rc, KErrNone);
	
	prmVal.SetLength(KDataLen);
	for(i=0;i<KDataLen;++i)
		{
		prmVal[i] = KHexVal;
		}
	TRAP(rc, (paramStream.WriteL(prmVal), paramStream.CommitL()));
	TEST2(rc, KErrNone);

	//Move on row 1
	rc = stmt.Next();
	TEST2(rc, KSqlAtRow);

	paramStream.Close();

	//Read the row using ColumnBinary(TInt aColumnIndex, TPtrC8& aPtr).
	TPtrC8 colDataPtr;
	rc = stmt.ColumnBinary(1, colDataPtr);
	TEST2(rc, KErrNone);
	
	//Check the column value
	for(i=0;i<KDataLen;++i)
		{
		TUint8 byte = colDataPtr[i];
		TEST(byte == KHexVal);	
		}
	
	stmt.Close();

	//Deallocate buf
	delete buf; 
	buf = NULL;


	///////////////////////////////////////////////////////////////////////////////////////////////	
	//Open a "short" binary parameter. The streaming API should work with "short" binary parameters too.
	_LIT8(KBinVal, "\x1\x2\x3\x4");

	//Delete all records
	_LIT8(KSqlStmt4, "DELETE FROM A");
	ExecSqlStmtOnDb<TDesC8, TBuf8<KSqlBufSize> >(db, KSqlStmt4(), KErrNone); 

	//Prepare INSERT SQL statement.	
	_LIT8(KSqlStmt5, "INSERT INTO A(Fld1, Fld2) VALUES(1, :Val)");
	stmt = PrepareSqlStmt<TDesC, TBuf<KSqlBufSize> >(db, KSqlStmt5, KErrNone);

	//Open the parameter stream
	rc = paramStream.BindBinary(stmt, 0);
	TEST2(rc, KErrNone);

	//Prepare and set the parameter value
	TRAP(rc, (paramStream.WriteL(KBinVal), paramStream.CommitL()));
	TEST2(rc, KErrNone);

	//Execute the prepared SQL statement
	rc = stmt.Exec();
	TEST2(rc, 1);

	paramStream.Close();
	stmt.Close();
	
	//Prepare SELECT SQL statement
	_LIT8(KSqlStmt6, "SELECT * FROM A WHERE Fld1 = 1");
	stmt = PrepareSqlStmt<TDesC, TBuf<KSqlBufSize> >(db, KSqlStmt6, KErrNone);

	//Move on row 1
	rc = stmt.Next();
	TEST2(rc, KSqlAtRow);

	///////////////////////////////////////////////////////////////////////////////////////////////	
	//Open a stream for a "short" binary column. The streaming API should work with "short" binary columns too.

	TBuf8<20> columnVal;
	RSqlColumnReadStream columnStream;
	rc = columnStream.ColumnBinary(stmt, 1);
	TEST2(rc, KErrNone);
	TInt size = stmt.ColumnSize(1);
	TRAP(rc, columnStream.ReadL(columnVal, size));
	columnStream.Close();
	TEST2(rc, KErrNone);
	
	//Check the column value
	TEST(columnVal == KBinVal);
	
	stmt.Close();
		
	db.Close();

	rc = RSqlDatabase::Delete(KTestDbName1);
	TEST2(rc, KErrNone);
	}

/**
@SYMTestCaseID			SYSLIB-SQL-CT-1634
@SYMTestCaseDesc		RSqlStatement test - nameless parameter.
						Tests RSqlStatement behaviour if the prepared statement has nameless parameters.
@SYMTestPriority		High
@SYMTestActions			RSqlStatement test - nameless parameter.
@SYMTestExpectedResults Test must not fail
@SYMREQ					REQ5792
                        REQ5793
*/	
void NamelessParameterTest()
	{
	//Create a test database
	RSqlDatabase db;	
	TInt rc = db.Create(KTestDbName1);
	TEST2(rc, KErrNone);

	rc = db.Exec(_L("CREATE TABLE A(F1 INTEGER, F2 INTEGER, F3 INTEGER)"));
	TEST(rc >= 0);

	RSqlStatement stmt;
	rc = stmt.Prepare(db, _L("SELECT * FROM A WHERE F1 = ? AND F2 = ? AND F3 = :Val"));
	TEST2(rc, KErrNone);

	TEST(stmt.ParameterIndex(_L("?0")) == 0);
	TEST(stmt.ParameterIndex(_L("?1")) == 1);
	TEST(stmt.ParameterIndex(_L(":VAL")) == 2);
		
	stmt.Close();

	db.Close();
	rc = RSqlDatabase::Delete(KTestDbName1);
	TEST2(rc, KErrNone);
	}

//Reads a SQL file and returns the file content as HBUFC string.
//The caller is responsible for destroying the returned HBUFC object.
template <class HBUFC> HBUFC* ReadSqlScript(const TDesC& aSqlFileName)
	{
	RFs fs;
	TEST2(fs.Connect(), KErrNone);
	
	RFile file;
	TEST2(file.Open(fs, aSqlFileName, EFileRead), KErrNone);
	
	TInt size = 0;
	TEST2(file.Size(size), KErrNone);
	
	HBufC8* sql = HBufC8::New(size);
	TEST(sql != NULL);
	
	TPtr8 ptr = sql->Des();
	TEST2(file.Read(ptr, size), KErrNone);

	file.Close();
	fs.Close();
	
	HBUFC* sql2 = HBUFC::New(size);
	TEST(sql2 != NULL);
	sql2->Des().Copy(sql->Des());
	delete sql;
	
	return sql2;
	}
//Explicit ReadSqlScript() template instantiations.
template HBufC8* ReadSqlScript<HBufC8>(const TDesC&);
template HBufC16* ReadSqlScript<HBufC16>(const TDesC&);

//Searches for the next aCommitStr appearance in aSqlScript string and returns a PTRC object holding
//the SQL strings from the beginning of aSqlScript till the aCommitStr (including it).
template <class PTRC, class DESC> PTRC GetNextTrans(PTRC& aSqlScript, const DESC& aCommitStr)
	{
	PTRC res(NULL, 0);
	TInt pos = aSqlScript.FindF(aCommitStr);
	if(pos >= 0)
		{
		pos += aCommitStr.Length();
		res.Set(aSqlScript.Left(pos));
		aSqlScript.Set(aSqlScript.Mid(pos));
		}
	return res;
	}
//Explicit GetNextTrans() template instantiations.
template TPtrC8 GetNextTrans<TPtrC8, TDesC8>(TPtrC8&, const TDesC8&);
template TPtrC16 GetNextTrans<TPtrC16, TDesC16>(TPtrC16&, const TDesC16&);

//Creates aDb database schema.
void CreateDbSchema(RSqlDatabase& aDb)
	{
	HBufC8* createDbScript = ReadSqlScript<HBufC8>(KCreateDbScript());
	TInt err = aDb.Exec(createDbScript->Des());
	TEST(err >= 0);	
	delete createDbScript;
	}

/**
@SYMTestCaseID			SYSLIB-SQL-CT-1768
@SYMTestCaseDesc		The test creates a database.
						Then the test executes 8-bit and 16-bit sql statements asynchronously
						(using asynchronous versions of RSqlDatabase::Exec() and RSqlStatement::Exec())
@SYMTestPriority		High
@SYMTestActions			SQL, Asynchronous sql statements execution.
@SYMTestExpectedResults Test must not fail
@SYMREQ					REQ5792
                        REQ5793
*/	
void AsyncTest()
	{
	//////////////////////////////////////////////////////////////////////////
	//Asynchronous execution, 8-bit sql statements
	//Create the database
	RSqlDatabase db;
	TInt err = db.Create(KTestDbName1);
	TEST2(err, KErrNone);
	CreateDbSchema(db);
	//Read the sql script file and execute the statements 
	HBufC8* fillDbScript1 = ReadSqlScript<HBufC8>(KFillDbScript());
	TPtrC8 ptr1(fillDbScript1->Des());
	TPtrC8 sql1(GetNextTrans<TPtrC8, TDesC8>(ptr1, KCommitStr8()));
	TRequestStatus status;
	db.Exec(sql1, status);
    TEST2(status.Int(), KRequestPending);
    User::WaitForRequest(status); 
    TEST(status.Int() >= 0);
	delete fillDbScript1;
	//////////////////////////////////////////////////////////////////////////
	//Asynchronous execution, RSqlStatement::Exec().
	RSqlStatement stmt;
	
	err = stmt.Prepare(db, _L("UPDATE IDENTITYTABLE SET CM_FIRSTNAME=:V1"));
    TEST2(err, KErrNone);
    err = stmt.BindText(0, _L("+++first+++"));
    TEST2(err, KErrNone);
	stmt.Exec(status);
    TEST2(status.Int(), KRequestPending);
    User::WaitForRequest(status); 
    TEST(status.Int() >= 0);
	stmt.Close();
	
	err = stmt.Prepare(db, _L("UPDATE IDENTITYTABLE SET CM_FIRSTNAME='+++first+++'"));
    TEST2(err, KErrNone);
	stmt.Exec(status);
    TEST2(status.Int(), KRequestPending);
    User::WaitForRequest(status); 
    TEST(status.Int() >= 0);
	stmt.Close();
	
	//Verify the UPDATE operation
	err = stmt.Prepare(db, _L("SELECT COUNT(*) FROM identitytable WHERE cm_firstname = '+++first+++'"));
    TEST2(err, KErrNone);
    err = stmt.Next();
    TEST2(err, KSqlAtRow);
    TInt cnt = stmt.ColumnInt(0);
    TEST2(cnt, 64);
    stmt.Close();
	//Close and delete the database
	db.Close();
	err = RSqlDatabase::Delete(KTestDbName1);
	TEST2(err, KErrNone);
	//////////////////////////////////////////////////////////////////////////
	//Asynchronous execution, 16-bit sql statements
	//Create the database
	err = db.Create(KTestDbName1);
	TEST2(err, KErrNone);
	CreateDbSchema(db);
	//Read the sql script file and execute the statements 
	HBufC16* fillDbScript2 = ReadSqlScript<HBufC16>(KFillDbScript());
	TPtrC16 ptr2(fillDbScript2->Des());
	TPtrC16 sql2(GetNextTrans<TPtrC16, TDesC16>(ptr2, KCommitStr16()));
	db.Exec(sql2, status);
    TEST2(status.Int(), KRequestPending);
    User::WaitForRequest(status); 
    TEST(status.Int() >= 0);
	delete fillDbScript2;
	//Close and delete the database
	db.Close();
	err = RSqlDatabase::Delete(KTestDbName1);
	TEST2(err, KErrNone);
	}

/**
@SYMTestCaseID			SYSLIB-SQL-CT-1816
@SYMTestCaseDesc		RSqlDatabase::Size() test.
						Call RSqlDatabase::Size() in various situations and check that the call does not fail.
@SYMTestPriority		High
@SYMTestActions			Call RSqlDatabase::Size() in various situations and check that the call does not fail.
@SYMTestExpectedResults Test must not fail
@SYMREQ					REQ7141
*/
void SizeTest()
	{
	const TInt KTestDbCnt = 3;
	TPtrC dbNames[KTestDbCnt];
	dbNames[0].Set(KTestDbName1); //Non-secure shared database
	dbNames[1].Set(KTestDbName9); //Private database
	dbNames[2].Set(KTestDbName7); //Secure shared database
	
	TSecurityPolicy defaultPolicy(TSecurityPolicy::EAlwaysPass);
	RSqlSecurityPolicy securityPolicy;
	TInt rc = securityPolicy.Create(defaultPolicy);
	TEST2(rc, KErrNone);
	
	for(TInt i=0;i<KTestDbCnt;++i)
		{
		(void)RSqlDatabase::Delete(dbNames[i]);
		RSqlDatabase db;
		TInt rc = i == 2 ? db.Create(dbNames[i], securityPolicy) : db.Create(dbNames[i]);
		TEST2(rc, KErrNone);
		//Check database size
		TInt size1 = db.Size();
		TEST(size1 >= 0);
		//Insert some data and check the size again
		rc = db.Exec(_L("CREATE TABLE A(Id INTEGER, T TEXT)"));
		TEST(rc >= 0);
		rc = db.Exec(_L("INSERT INTO A VALUES(1, '1111111')"));
		TEST(rc >= 0);
		rc = db.Exec(_L("INSERT INTO A VALUES(2, '22222222222222')"));
		TEST(rc >= 0);
		TInt size2 = db.Size();
		TEST(size2 > size1);
		//Check the database size in a transaction
		rc = db.Exec(_L("BEGIN"));
		TEST(rc >= 0);
		TInt size3 = db.Size();
		TEST(size3 == size2);
		rc = db.Exec(_L("INSERT INTO A VALUES(3, '3333333333333333333333333333333333333333333333333333333333333')"));
		TEST(rc >= 0);
		rc = db.Exec(_L("INSERT INTO A VALUES(4, '4444444444444444444444444444444444444444444444444444444444444')"));
		TEST(rc >= 0);
		rc = db.Exec(_L("INSERT INTO A VALUES(5, '5555555555555555555555555555555555555555555555555555555555555')"));
		TEST(rc >= 0);
		TInt size4 = db.Size();
		TEST(size4 == size2);
		rc = db.Exec(_L("COMMIT"));
		TEST(rc >= 0);
		TInt size5 = db.Size();
		TEST(size5 == size2);
		//Cleanup
		db.Close();
		rc = RSqlDatabase::Delete(dbNames[i]);
		TEST2(rc, KErrNone);
		}
	securityPolicy.Close();
	}

/**
@SYMTestCaseID			SYSLIB-SQL-CT-1817
@SYMTestCaseDesc		RSqlDatabase::InTransaction() test.
						Call RSqlDatabase::InTransaction() in various situations and check that the method reports 
						database's transaction state correctly.
@SYMTestPriority		High
@SYMTestActions			Call RSqlDatabase::InTransaction() in various situations and check that the method reports 
						database's transaction state correctly.
@SYMTestExpectedResults Test must not fail
@SYMREQ					REQ7141
*/
void InTransactionTest()
	{
	(void)RSqlDatabase::Delete(KTestDbName1);
	RSqlDatabase db;
	TInt rc = db.Create(KTestDbName1);
	TEST2(rc, KErrNone);
	//
	TBool state = db.InTransaction();
	TEST(!state);
	rc = db.Exec(_L("BEGIN"));
	TEST(rc >= 0);
	state = db.InTransaction();
	TEST(!!state);
	rc = db.Exec(_L("ROLLBACK"));
	TEST(rc >= 0);
	state = db.InTransaction();
	TEST(!state);
	//Cleanup
	db.Close();
	rc = RSqlDatabase::Delete(KTestDbName1);
	TEST2(rc, KErrNone);
	}

/**
@SYMTestCaseID			SYSLIB-SQL-UT-4039
@SYMTestCaseDesc		RSqlDatabase::Size(TSize&) functional test.
						The test creates a non-secure shared database, private database, secure shared database
						and tests that the new RSqlDatabase::Size(TSize&) can be used on the created databases.
@SYMTestPriority		High
@SYMTestActions			RSqlDatabase::Size(TSize&) functional test.
@SYMTestExpectedResults Test must not fail
@SYMREQ					REQ10407
*/
void SizeTest2()
	{
	const TInt KTestDbCnt = 3;
	TPtrC dbNames[KTestDbCnt];
	dbNames[0].Set(KTestDbName1); //Non-secure shared database
	dbNames[1].Set(KTestDbName9); //Private database
	dbNames[2].Set(KTestDbName7); //Secure shared database
	
	TSecurityPolicy defaultPolicy(TSecurityPolicy::EAlwaysPass);
	RSqlSecurityPolicy securityPolicy;
	TInt rc = securityPolicy.Create(defaultPolicy);
	TEST2(rc, KErrNone);
	
	_LIT8(KConfig, "compaction=background");
	
	for(TInt i=0;i<KTestDbCnt;++i)
		{
		(void)RSqlDatabase::Delete(dbNames[i]);
		RSqlDatabase db;
		TInt rc = i == 2 ? db.Create(dbNames[i], securityPolicy, &KConfig) : db.Create(dbNames[i], &KConfig);
		TEST2(rc, KErrNone);
		//Check database size
		RSqlDatabase::TSize size;
		rc = db.Size(size);
		TEST2(rc, KErrNone);
		TEST(size.iSize > 0);
		TEST2(size.iFree, 0);
		//Insert some data and check the size again
		rc = db.Exec(_L("CREATE TABLE A(Id INTEGER, T TEXT)"));
		TEST(rc >= 0);
		const TInt KTestRecCnt = 50;
		rc = db.Exec(_L("BEGIN"));
		TEST(rc >= 0);
		for(TInt k=0;k<KTestRecCnt;++k)
			{
			TBuf<100> sql;
			sql.Format(_L("INSERT INTO A VALUES(%d, 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA')"), k + 1);
			rc = db.Exec(sql);
			TEST2(rc, 1);
			}
		rc = db.Exec(_L("COMMIT"));
		TEST(rc >= 0);
		rc = db.Size(size);
		TEST2(rc, KErrNone);
		TEST(size.iSize > 0);
		TEST2(size.iFree, 0);
		//Delete the records and check the size again.
		rc = db.Exec(_L("DELETE FROM A"));
		rc = db.Size(size);
		TEST2(rc, KErrNone);
		TEST(size.iSize > 0);
		TEST(size.iFree > 0);
		//Cleanup
		db.Close();
		rc = RSqlDatabase::Delete(dbNames[i]);
		TEST2(rc, KErrNone);
		}
	securityPolicy.Close();
	}

/**
@SYMTestCaseID			SYSLIB-SQL-UT-4040
@SYMTestCaseDesc		RSqlDatabase::Size(TSize&) on an attached database - functional test.
						The test creates a database and attaches another database. Then the test
						verifies that the new RSqlDatabase::Size(TSize&) method can be used on the attached 
						database. The test also calls the new method with an invalid attached database
						name and check that an appropriate error is reported.
@SYMTestPriority		High
@SYMTestActions			RSqlDatabase::Size(TSize&) on an attached database - functional test.
@SYMTestExpectedResults Test must not fail
@SYMREQ					REQ10407
*/
void AttachedSizeTest2()
	{
	RSqlDatabase db;
	
	TInt err = db.Create(KTestDbName1);
	TEST2(err, KErrNone);
	err = db.Exec(_L("CREATE TABLE A(I INTEGER)"));
	TEST(err >= 0);
	db.Close();
	err = db.Create(KTestDbName8);
	TEST2(err, KErrNone);
	err = db.Exec(_L("CREATE TABLE B(J INTEGER)"));
	TEST(err >= 0);
	err = db.Exec(_L("BEGIN"));
	TEST(err >= 0);
	for(TInt i=0;i<1000;++i)
		{
		err = db.Exec(_L("INSERT INTO B(J) VALUES(1)"));
		TEST2(err, 1);
		}
	err = db.Exec(_L("COMMIT"));
	TEST(err >= 0);
	db.Close();
	
	err = db.Open(KTestDbName1);
	TEST2(err, KErrNone);
	_LIT(KAttachDbName, "B");
	err = db.Attach(KTestDbName8, KAttachDbName);
	TEST2(err, KErrNone);
	
	//Size(TSize&) - main and the attached databse
	RSqlDatabase::TSize	size1;
	err = db.Size(size1);
	TEST2(err, KErrNone);
	TEST(size1.iSize > 0);
	TEST(size1.iFree >= 0);
	RSqlDatabase::TSize	size2;
	err = db.Size(size2, KAttachDbName);
	TEST2(err, KErrNone);
	TEST(size2.iSize > 0);
	TEST(size2.iFree >= 0);
	TEST(size2.iSize > size1.iSize);

	//Very long attached database name
	TBuf<KMaxFileName + 10> longDbName;
	longDbName.SetLength(longDbName.MaxLength());
	err = db.Size(size1, longDbName);
	TEST2(err, KErrBadName);
	
	//An attempt to get the size of a non-existing attached database
	err = db.Size(size1, _L("TheDbDoesNotExist"));
	TEST2(err, KSqlErrGeneral);
	TPtrC msg = db.LastErrorMessage();
	TheTest.Printf(_L("Non-existing attached database, error message: %S\r\n"), &msg);
	
    //An attempt to get the size when the attached database name contains "bad" unicode characters (cannot be converted to UTF8)
    TBuf<2> dbName3;
    dbName3.SetLength(2);
    dbName3[0] = TChar(0xD800); 
    dbName3[1] = TChar(0xFC00); 
    err = db.Size(size1, dbName3);
    TEST2(err, KErrGeneral);
	
	err = db.Detach(KAttachDbName);
	TEST2(err, KErrNone);
	db.Close();
	(void)RSqlDatabase::Delete(KTestDbName8);
	(void)RSqlDatabase::Delete(KTestDbName1);
	}

/**
@SYMTestCaseID			SYSLIB-SQL-UT-4041
@SYMTestCaseDesc		RSqlDatabase::Size(TSize&) and different compaction modes - functional test.
						The test creates databases using all possible compaction modes and
						verifies that the new RSqlDatabase::Size(TSize&) method can be used on these 
						databases without any problems.
@SYMTestPriority		High
@SYMTestActions			RSqlDatabase::Size(TSize&) and different compaction modes - functional test.
@SYMTestExpectedResults Test must not fail
@SYMREQ					REQ10407
*/
void DiffCompactModeSize2Test()
	{
	_LIT8(KAutoCompaction, "compaction = auto");
	RSqlDatabase db;
	TInt err = db.Create(KTestDbName1, &KAutoCompaction);
	TEST2(err, KErrNone);
	err = db.Exec(_L("CREATE TABLE A(I INTEGER)"));
	TEST(err >= 0);
	RSqlDatabase::TSize	size;
	err = db.Size(size);
	TEST2(err, KErrNone);
	TEST(size.iSize > 0);
	TEST(size.iFree >= 0);
	db.Close();
	(void)RSqlDatabase::Delete(KTestDbName1);
	
	_LIT8(KManualCompaction, "compaction = manual");
	err = db.Create(KTestDbName1, &KManualCompaction);
	TEST2(err, KErrNone);
	err = db.Exec(_L("CREATE TABLE A(I INTEGER)"));
	TEST(err >= 0);
	err = db.Size(size);
	TEST2(err, KErrNone);
	TEST(size.iSize > 0);
	TEST(size.iFree >= 0);
	db.Close();
	(void)RSqlDatabase::Delete(KTestDbName1);
	
	_LIT8(KBackgroundCompaction, "compaction = background");
	err = db.Create(KTestDbName1, &KBackgroundCompaction);
	TEST2(err, KErrNone);
	err = db.Exec(_L("CREATE TABLE A(I INTEGER)"));
	TEST(err >= 0);
	err = db.Size(size);
	TEST2(err, KErrNone);
	TEST(size.iSize > 0);
	TEST(size.iFree >= 0);
	db.Close();
	(void)RSqlDatabase::Delete(KTestDbName1);
	}

void DoTestsL()
	{
	TheTest.Start(_L(" @SYMTestCaseID:SYSLIB-SQL-CT-1601 Create/Open/Close database tests "));	
	OpenCloseDatabaseTest();

	TheTest.Next(_L(" @SYMTestCaseID:SYSLIB-SQL-CT-1602 SetIsolationLevel() database tests "));	
	SetIsolationLevelTest();
	
	TheTest.Next(_L(" @SYMTestCaseID:SYSLIB-SQL-CT-1603 Delete database tests "));	
	DeleteDatabaseTest();
	
	TheTest.Next(_L(" @SYMTestCaseID:SYSLIB-SQL-CT-1640 Copy database tests "));	
	CopyDatabaseTest();
	
	TheTest.Next(_L(" @SYMTestCaseID:SYSLIB-SQL-CT-1604 Operations with NULL column values "));
	NullColumnValues();
	
	enum {KSqlBufSize = 1024};
	
	TheTest.Next(_L(" @SYMTestCaseID:SYSLIB-SQL-CT-1605 RSqlDatabase::Exec() test. 16-bit SQL strings. "));	
	ExecOnDbTest<TDesC, TBuf<KSqlBufSize> >();
	
	TheTest.Next(_L(" @SYMTestCaseID:SYSLIB-SQL-CT-1605 RSqlDatabase::Exec() test. 8-bit SQL strings. "));	
	ExecOnDbTest<TDesC8, TBuf8<KSqlBufSize> >();
	
	TheTest.Next(_L(" @SYMTestCaseID:SYSLIB-SQL-CT-1606 RSqlStatement test. 16-bit SQL strings. "));	
	StatementTest<TDesC, TBuf<KSqlBufSize> >();
	
	TheTest.Next(_L(" @SYMTestCaseID:SYSLIB-SQL-CT-1606 RSqlStatement test. 8-bit SQL strings. "));
	StatementTest<TDesC8, TBuf8<KSqlBufSize> >();
	
	TheTest.Next(_L(" @SYMTestCaseID:SYSLIB-SQL-CT-1607 RSqlColumnReadStream test. Long text column "));
	ColumnTextStreamTest();

	TheTest.Next(_L(" @SYMTestCaseID:SYSLIB-SQL-CT-1621 RSqlColumnReadStream test. Long binary column "));
	ColumnBinaryStreamTest();

	TheTest.Next(_L(" @SYMTestCaseID:SYSLIB-SQL-CT-1608 RSqlParamWriteStream test. Long text parameter "));
	TextParameterStreamTest();

	TheTest.Next(_L(" @SYMTestCaseID:SYSLIB-SQL-CT-1622 RSqlParamWriteStream test. Long binary parameter "));
	BinaryParameterStreamTest();

	TheTest.Next(_L(" @SYMTestCaseID:SYSLIB-SQL-CT-1634 RSqlStatement test. Nameless parameter "));
	NamelessParameterTest();

	TheTest.Next(_L(" @SYMTestCaseID:SYSLIB-SQL-CT-1768 Asynchronous execution tests "));
	AsyncTest();	
	
	TheTest.Next(_L(" @SYMTestCaseID:SYSLIB-SQL-CT-1816 RSqlDatabase::Size() tests "));
	SizeTest();
	
	TheTest.Next(_L(" @SYMTestCaseID:SYSLIB-SQL-CT-1817 RSqlDatabase::InTransaction() tests "));
	InTransactionTest();

	TheTest.Next(_L(" @SYMTestCaseID:SYSLIB-SQL-UT-4039 RSqlDatabase::Size(RSqlDatabase::TSize&) tests"));
	SizeTest2();

	TheTest.Next(_L(" @SYMTestCaseID:SYSLIB-SQL-UT-4040 RSqlDatabase::Size(RSqlDatabase::TSize&) - attached database tests"));
	AttachedSizeTest2();
	
	TheTest.Next(_L(" @SYMTestCaseID:SYSLIB-SQL-UT-4041 RSqlDatabase::Size(RSqlDatabase::TSize&) - different compaction modes tests"));
	DiffCompactModeSize2Test();
	}

TInt E32Main()
	{
	TheTest.Title();
	
	CTrapCleanup* tc = CTrapCleanup::New();
	
	__UHEAP_MARK;
	
	CreateTestDir();
	DeleteTestFiles();
	TRAPD(err, DoTestsL());
	DeleteTestFiles();
	TEST2(err, KErrNone);
	
	__UHEAP_MARKEND;
	
	TheTest.End();
	TheTest.Close();
	
	delete tc;
	
	User::Heap().Check();
	return KErrNone;
	}
