// Copyright (c) 2005-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 <e32math.h>
#include <bautils.h>
#include <sqldb.h>

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

RTest TheTest(_L("t_sqllang test"));
_LIT(KTestDir, "c:\\test\\");

_LIT(KTestDbName, "c:\\test\\t_sqllang_1.db");
_LIT(KTestDbName2, "c:\\test\\t_sqllang_2.db");

RSqlDatabase TheDb;

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

void DeleteTestFiles()
	{
	RSqlDatabase::Delete(KTestDbName2);
	RSqlDatabase::Delete(KTestDbName);
	}

///////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////
//Test macros and functions
void Check(TInt aValue, TInt aLine)
	{
	if(!aValue)
		{
		DeleteTestFiles();
		TheTest.Printf(_L("*** Expression evaluated to false\r\n"));
		TheTest(EFalse, aLine);
		}
	}
void Check(TInt aValue, TInt aExpected, TInt aLine)
	{
	if(aValue != aExpected)
		{
		DeleteTestFiles();
		TheTest.Printf(_L("*** Expected error: %d, got: %d\r\n"), aExpected, aValue);
		TheTest(EFalse, aLine);
		}
	}
void Check2(TInt64 aValue, TInt64 aExpected, TInt aLine)
	{
	if(aValue != aExpected)
		{
		DeleteTestFiles();
		TheTest.Printf(_L("*** Expected error: %ld, got: %ld\r\n"), aExpected, aValue);
		TheTest(EFalse, aLine);
		}
	}
#define TEST(arg) ::Check((arg), __LINE__)
#define TEST2(aValue, aExpected) ::Check(aValue, aExpected, __LINE__)
#define TEST3(aValue, aExpected) ::Check2(aValue, aExpected, __LINE__)

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

void CreateTestDir()
    {
    RFs fs;
	TInt err = fs.Connect();
	TEST2(err, KErrNone);

	err = fs.MkDir(KTestDir);
	TEST(err == KErrNone || err == KErrAlreadyExists);
	
	fs.Close();
	}
	
///////////////////////////////////////////////////////////////////////////////////////

void PrintLastMsgIfError(TInt aErr)
	{
	if(aErr < 0 && SqlRetCodeClass(aErr) == ESqlDbError)
		{
		const TPtrC& msg = TheDb.LastErrorMessage();
		TheTest.Printf(_L("Last error msg: \"%S\"\r\n"), &msg);	
		}
	}

/**
@SYMTestCaseID			SYSLIB-SQL-CT-1611
@SYMTestCaseDesc		Create a table with INTEGER, SMALLINT, REAl, DOUBLE PRECISION, FLOAT, DECIMAL,...
						columns. Insert some records, retrieve the column values, verify the column values,
						try some mathematical operations with the column values, executed in the SQL
						statement.
@SYMTestPriority		High
@SYMTestActions			Testing SQL engine behaviour with different numerical types. 
						Testing mathematical operations with numeric columns.
@SYMTestExpectedResults Test must not fail
@SYMREQ					REQ5792
                        REQ5793
*/	
void NumericDataTypesTest()
	{
	TEST2(TheDb.Create(KTestDbName), KErrNone);
	
	//Create a table with all possible numeric field types
	_LIT8(KSql1, "CREATE TABLE Tbl(A INTEGER, B SMALLINT, C REAL, D DOUBLE PRECISION, E FLOAT, \
					                    F DECIMAL, G BIGINT, H TINYINT, I BIT, J NUMERIC, K MONEY, \
					                    L SMALLMONEY)");
	TInt err = TheDb.Exec(KSql1);
	PrintLastMsgIfError(err);
	TEST(err >= 0);
	//Insert one record in to the created table
	_LIT8(KSql2, "INSERT INTO Tbl(A,B,C,D,E,F,G,H,I,J,K,L) VALUES(2000000000, 30000, 123.45, 0.912E+55,\
	                                    1.34E-14, 1234.5678, 32000000000, 100, 7, 23.123456, 2123678.56, 11.45)");
	err = TheDb.Exec(KSql2);
	PrintLastMsgIfError(err);
	TEST2(err, 1);
	//Get the inserted record data
	RSqlStatement stmt;
	err = stmt.Prepare(TheDb, _L("SELECT * FROM TBL"));
	PrintLastMsgIfError(err);
	TEST2(err, KErrNone);
	err = stmt.Next();
	PrintLastMsgIfError(err);
	TEST2(err, KSqlAtRow);
	//Check column values
	TEST(stmt.ColumnInt(stmt.ColumnIndex(_L("a"))) == 2000000000);
	TEST(stmt.ColumnInt(stmt.ColumnIndex(_L("b"))) == 30000);
	TEST(Abs(stmt.ColumnReal(stmt.ColumnIndex(_L("c"))) - 123.45) < 0.000001);
	//The next column value test is not working! The extracted column value is 0.9120000000000002E+55
	//I guess the reason is that SQLITE uses manifest typing and "DOUBLE PRECISION" is not in its keyword
	//list. Maybe it is interpreted and stored as 4-byte float value.
	//TEST(Abs(stmt.ColumnReal(stmt.ColumnIndex(_L("d"))) - 0.912E+55) < 0.000001);
	TEST(Abs(stmt.ColumnReal(stmt.ColumnIndex(_L("e"))) - 1.34E-14) < 0.000001);
	TEST(stmt.ColumnReal(stmt.ColumnIndex(_L("f"))) == 1234.5678);
	TEST(stmt.ColumnInt64(stmt.ColumnIndex(_L("g"))) == 32000000000LL);
	TEST(stmt.ColumnInt(stmt.ColumnIndex(_L("h"))) == 100);
	TEST(stmt.ColumnInt(stmt.ColumnIndex(_L("i"))) == 7);
	TEST(Abs(stmt.ColumnReal(stmt.ColumnIndex(_L("j"))) - 23.123456) < 0.000001);
	TEST(Abs(stmt.ColumnReal(stmt.ColumnIndex(_L("k"))) - 2123678.56) < 0.000001);
	TEST(Abs(stmt.ColumnReal(stmt.ColumnIndex(_L("l"))) - 11.45) < 0.000001);
	stmt.Close();
	//The statement object has to be closed before TheDb.Exec() call, 
	//otherwise the reported error is "database table is locked"
	//Insert second record in to the created table but inverse the column types!
	_LIT8(KSql3, "INSERT INTO Tbl(A,   B,  C, D, E, F,  G,  H,  I,  J,K,L) VALUES(\
										-2.5,1.1,12,23,45,111,5.6,7.9,1.1,2,6,7)");
	err = TheDb.Exec(KSql3);
	PrintLastMsgIfError(err);
	TEST2(err, 1);
	//Get the inserted record data
	err = stmt.Prepare(TheDb, _L("SELECT * FROM TBL"));
	PrintLastMsgIfError(err);
	TEST2(err, KErrNone);
	TEST2(stmt.Next(), KSqlAtRow);
	err = stmt.Next();
	PrintLastMsgIfError(err);
	TEST2(err, KSqlAtRow);
	//No column value checking because SQLITE inverted the column types!
	//Check column values
	TEST(Abs(stmt.ColumnReal(stmt.ColumnIndex(_L("a"))) - (-2.5)) < 0.000001);
	TEST(Abs(stmt.ColumnReal(stmt.ColumnIndex(_L("b"))) - 1.1) < 0.000001);
	TEST(stmt.ColumnInt(stmt.ColumnIndex(_L("c"))) == 12);
	TEST(stmt.ColumnInt(stmt.ColumnIndex(_L("d"))) == 23);
	TEST(stmt.ColumnInt(stmt.ColumnIndex(_L("e"))) == 45);
	TEST(stmt.ColumnInt(stmt.ColumnIndex(_L("f"))) == 111);
	TEST(Abs(stmt.ColumnReal(stmt.ColumnIndex(_L("g"))) - 5.6) < 0.000001);
	TEST(Abs(stmt.ColumnReal(stmt.ColumnIndex(_L("h"))) - 7.9) < 0.000001);
	TEST(Abs(stmt.ColumnReal(stmt.ColumnIndex(_L("i"))) - 1.1) < 0.000001);
	TEST(stmt.ColumnInt(stmt.ColumnIndex(_L("j"))) == 2);
	TEST(stmt.ColumnInt(stmt.ColumnIndex(_L("k"))) == 6);
	TEST(stmt.ColumnInt(stmt.ColumnIndex(_L("l"))) == 7);
	
	stmt.Close();
	//Insert third record in to the created table
	_LIT8(KSql4, "INSERT INTO Tbl(A,B,C,     D,  E,  F,   G,  H,  I,J,     K,     L) VALUES(\
	                                    2,3,123.45,1.5,2.5,1.56,320,100,7,23.123,212.56,11.45)");
	err = TheDb.Exec(KSql4);
	PrintLastMsgIfError(err);
	TEST2(err, 1);
	//Issue a "SELECT" statement doing there some arithmetic operations and comparisons on the column values.
	err = stmt.Prepare(TheDb, _L("SELECT A, A-C AS A2, K + L AS A3, H*I AS A4, E/D AS A5 FROM TBL WHERE A > 0 AND A < 10"));
	PrintLastMsgIfError(err);
	TEST2(err, KErrNone);
	TEST2(stmt.Next(), KSqlAtRow);
	//Check column values
	TEST2(stmt.ColumnInt(stmt.ColumnIndex(_L("a"))), 2);
	TEST(Abs(stmt.ColumnReal(stmt.ColumnIndex(_L("a2"))) - (2-123.45)) < 0.000001);
	TEST(Abs(stmt.ColumnReal(stmt.ColumnIndex(_L("a3"))) - (212.56+11.45)) < 0.000001);
	TEST(stmt.ColumnInt(stmt.ColumnIndex(_L("a4"))) == 700);
	TEST(Abs(stmt.ColumnReal(stmt.ColumnIndex(_L("a5"))) - (2.5/1.5)) < 0.000001);
	//There should be no more records
	TEST2(stmt.Next(), KSqlAtEnd);
	stmt.Close();

	TheDb.Close();
	(void)RSqlDatabase::Delete(KTestDbName);
	}

/**
@SYMTestCaseID			SYSLIB-SQL-CT-1630
@SYMTestCaseDesc		Built-in functions test.
						abs(), coalesce(), ifnull(), last_insert_rowid(), length(), like(), lower(),
						max(), min(), nullif(), quote(), random(), round(), sqlite_version(), substr(),
						typeof(), upper(), avg(), count(), sun().
@SYMTestPriority		High
@SYMTestActions			Built-in functions test.
@SYMTestExpectedResults Test must not fail
@SYMREQ					REQ5792
                        REQ5793
*/	
void BuiltInFunctionsTest()
	{
	(void)RSqlDatabase::Delete(KTestDbName);
	TInt err = TheDb.Create(KTestDbName);
	TEST2(err, KErrNone);

	_LIT(KCreateSql, "CREATE TABLE A(Id Integer, \
									 F1 Integer DEFAULT 0, \
									 F2 Integer Default NULL, \
									 F3 TEXT Default Null, \
									 F4 TEXT Default Null)");
	err = TheDb.Exec(KCreateSql);
	TEST(err >= 0);

	_LIT(KInsertSql1, "INSERT INTO A(Id, F1) VALUES(1, 100)");
	err = TheDb.Exec(KInsertSql1);
	TEST2(err, 1);
	
	_LIT(KInsertSql2, "INSERT INTO A(Id, F1) VALUES(2, 1)");
	err = TheDb.Exec(KInsertSql2);
	TEST2(err, 1);

	_LIT(KInsertSql3, "INSERT INTO A(Id, F3) VALUES(3, 'ABCD')");
	err = TheDb.Exec(KInsertSql3);
	TEST2(err, 1);

	_LIT(KInsertSql4, "INSERT INTO A(Id, F4) VALUES(4, 'DCBA')");
	err = TheDb.Exec(KInsertSql4);
	TEST2(err, 1);

	RSqlStatement stmt;
	
	//abs() test --------------------------------------------------------
	err = stmt.Prepare(TheDb, _L("SELECT * FROM A WHERE F1 > ABS(-10)"));
	TEST2(err, KErrNone);
	err = stmt.Next();
	TEST2(err, KSqlAtRow);
	TEST(stmt.ColumnInt(1) == 100);
	stmt.Close();

	//coalesce() test --------------------------------------------------------
	err = stmt.Prepare(TheDb, _L("SELECT COALESCE(F3, F4) AS F FROM A"));
	TEST2(err, KErrNone);
	
	err = stmt.Next();
	TEST2(err, KSqlAtRow);
	TEST(stmt.IsNull(0));
	
	err = stmt.Next();
	TEST2(err, KSqlAtRow);
	TEST(stmt.IsNull(0));
	
	_LIT(KTextVal1, "ABCD");
	err = stmt.Next();
	TEST2(err, KSqlAtRow);
	TPtrC colVal;
	err = stmt.ColumnText(0, colVal);
	TEST2(err, KErrNone);
	TEST(colVal == KTextVal1);
	
	_LIT(KTextVal2, "DCBA");
	err = stmt.Next();
	TEST2(err, KSqlAtRow);
	err = stmt.ColumnText(0, colVal);
	TEST2(err, KErrNone);
	TEST(colVal == KTextVal2);

	stmt.Close();

	//ifnull() test --------------------------------------------------------
	err = stmt.Prepare(TheDb, _L("SELECT IFNULL(F3, F4) AS F FROM A"));
	TEST2(err, KErrNone);
	
	err = stmt.Next();
	TEST2(err, KSqlAtRow);
	TEST(stmt.IsNull(0));
	
	err = stmt.Next();
	TEST2(err, KSqlAtRow);
	TEST(stmt.IsNull(0));
	
	err = stmt.Next();
	TEST2(err, KSqlAtRow);
	err = stmt.ColumnText(0, colVal);
	TEST2(err, KErrNone);
	TEST(colVal == KTextVal1);
	
	err = stmt.Next();
	TEST2(err, KSqlAtRow);
	err = stmt.ColumnText(0, colVal);
	TEST2(err, KErrNone);
	TEST(colVal == KTextVal2);

	stmt.Close();

	//last_insert_rowid() test --------------------------------------------------------
	err = stmt.Prepare(TheDb, _L("SELECT last_insert_rowid() AS F"));
	TEST2(err, KErrNone);
	err = stmt.Next();
	TEST2(err, KSqlAtRow);
	TInt64 colVal64 = stmt.ColumnInt64(0);
	TheTest.Printf(_L("Last insert row id=%d\r\n"), (TInt)colVal64);
	stmt.Close();

	//length() test --------------------------------------------------------
	err = stmt.Prepare(TheDb, _L("SELECT length(F4) AS L FROM A WHERE ID >= 3"));
	TEST2(err, KErrNone);
	
	err = stmt.Next();
	TEST2(err, KSqlAtRow);
	TEST(stmt.ColumnInt(0) == 0);
	
	err = stmt.Next();
	TEST2(err, KSqlAtRow);
	TEST(stmt.ColumnInt(0) == 4);
	
	stmt.Close();

	//like() test --------------------------------------------------------
	err = stmt.Prepare(TheDb, _L("SELECT Id FROM A WHERE F4 LIKE 'DC%'"));
	TEST2(err, KErrNone);
	err = stmt.Next();
	TEST2(err, KSqlAtRow);
	TEST(stmt.ColumnInt(0) == 4);
	stmt.Close();

	_LIT(KInsertSql5, "INSERT INTO A(Id, F4) VALUES(5, 'ab%cd')");
	err = TheDb.Exec(KInsertSql5);
	TEST2(err, 1);
	
	err = stmt.Prepare(TheDb, _L("SELECT Id FROM A WHERE F4 LIKE 'ab/%cd' ESCAPE '/'"));
	TEST2(err, KErrNone);
	err = stmt.Next();
	TEST2(err, KSqlAtRow);
	TEST(stmt.ColumnInt(0) == 5);
	stmt.Close();

	err = stmt.Prepare(TheDb, _L8("SELECT Id FROM A WHERE F4 LIKE 'ab/%cd' ESCAPE '/'"));
	TEST2(err, KErrNone);
	err = stmt.Next();
	TEST2(err, KSqlAtRow);
	TEST(stmt.ColumnInt(0) == 5);
	stmt.Close();

	//lower() test --------------------------------------------------------
	err = stmt.Prepare(TheDb, _L("SELECT LOWER(F3) FROM A WHERE F3 = 'ABCD'"));
	TEST2(err, KErrNone);
	err = stmt.Next();
	TEST2(err, KSqlAtRow);
	err = stmt.ColumnText(0, colVal);
	TEST2(err, KErrNone);
	_LIT(KTextVal3, "abcd");
	TEST(colVal == KTextVal3);
	stmt.Close();

	//max() test --------------------------------------------------------
	err = stmt.Prepare(TheDb, _L("SELECT MAX(F1) AS M FROM A"));
	TEST2(err, KErrNone);
	err = stmt.Next();
	TEST2(err, KSqlAtRow);
	TEST(stmt.ColumnInt(0) == 100);
	stmt.Close();
	
	//min() test --------------------------------------------------------
	err = stmt.Prepare(TheDb, _L("SELECT MIN(F1) AS M FROM A"));
	TEST2(err, KErrNone);
	err = stmt.Next();
	TEST2(err, KSqlAtRow);
	TEST(stmt.ColumnInt(0) == 0);
	stmt.Close();

	//nullif() test --------------------------------------------------------
	err = stmt.Prepare(TheDb, _L("SELECT NULLIF(3, 4) AS M"));
	TEST2(err, KErrNone);
	err = stmt.Next();
	TEST2(err, KSqlAtRow);
	TEST(stmt.ColumnInt(0) == 3);
	stmt.Close();
	
	err = stmt.Prepare(TheDb, _L("SELECT NULLIF(4, 4) AS M"));
	TEST2(err, KErrNone);
	err = stmt.Next();
	TEST2(err, KSqlAtRow);
	TEST(stmt.IsNull(0));
	stmt.Close();
	
	//quote() test --------------------------------------------------------
	err = stmt.Prepare(TheDb, _L("SELECT QUOTE(F4) AS M FROM A WHERE Id = 5"));
	TEST2(err, KErrNone);
	err = stmt.Next();
	TEST2(err, KSqlAtRow);
	err = stmt.ColumnText(0, colVal);
	TEST2(err, KErrNone);
	_LIT(KTextVal4, "'ab%cd'");
	TEST(colVal == KTextVal4);
	stmt.Close();

	//random() test --------------------------------------------------------
	err = stmt.Prepare(TheDb, _L("SELECT * FROM A WHERE Id > RANDOM(*)"));
	TEST2(err, KErrNone);
	stmt.Close();

	//round() test --------------------------------------------------------
	err = stmt.Prepare(TheDb, _L("SELECT ROUND(5.4) AS D"));
	TEST2(err, KErrNone);
	err = stmt.Next();
	TEST2(err, KSqlAtRow);
	TEST(Abs(stmt.ColumnReal(0) - 5.0) < 0.000001);
	stmt.Close();

	err = stmt.Prepare(TheDb, _L("SELECT ROUND(5.4321, 2) AS D"));
	TEST2(err, KErrNone);
	err = stmt.Next();
	TEST2(err, KSqlAtRow);
	TEST(Abs(stmt.ColumnReal(0) - 5.43) < 0.000001);
	stmt.Close();

	//sqlite_version() test --------------------------------------------------------
	err = stmt.Prepare(TheDb, _L("SELECT sqlite_version(*) AS V"));
	TEST2(err, KErrNone);
	err = stmt.Next();
	TEST2(err, KSqlAtRow);
	err = stmt.ColumnText(0, colVal);
	TEST2(err, KErrNone);
	TheTest.Printf(_L("Database engine version: \"%S\"\r\n"), &colVal);
	stmt.Close();

	//substr() test --------------------------------------------------------
	err = stmt.Prepare(TheDb, _L("SELECT SUBSTR('abcd', 2, 2) AS S"));
	TEST2(err, KErrNone);
	err = stmt.Next();
	TEST2(err, KSqlAtRow);
	err = stmt.ColumnText(0, colVal);
	TEST2(err, KErrNone);
	_LIT(KTextVal7, "bc");
	TEST(colVal == KTextVal7);
	stmt.Close();

	err = stmt.Prepare(TheDb, _L("SELECT SUBSTR('abcd', -3, 2) AS S"));
	TEST2(err, KErrNone);
	err = stmt.Next();
	TEST2(err, KSqlAtRow);
	err = stmt.ColumnText(0, colVal);
	TEST2(err, KErrNone);
	TEST(colVal == KTextVal7);
	stmt.Close();

	//typeof() test --------------------------------------------------------
	_LIT(KInsertSql6, "INSERT INTO A(Id, F2) VALUES(6, 2)");
	err = TheDb.Exec(KInsertSql6);
	TEST2(err, 1);

	err = stmt.Prepare(TheDb, _L("SELECT TYPEOF(F1 + F2) AS T FROM A WHERE ID > 4"));
	TEST2(err, KErrNone);

	err = stmt.Next();
	TEST2(err, KSqlAtRow);
	err = stmt.ColumnText(0, colVal);
	TEST2(err, KErrNone);
	_LIT(KTextVal8, "null");
	TEST(colVal == KTextVal8);

	err = stmt.Next();
	TEST2(err, KSqlAtRow);
	err = stmt.ColumnText(0, colVal);
	TEST2(err, KErrNone);
	_LIT(KTextVal9, "integer");
	TEST(colVal == KTextVal9);
	
	stmt.Close();

	//upper() test --------------------------------------------------------
	err = stmt.Prepare(TheDb, _L("SELECT UPPER('ghjk') AS U"));
	TEST2(err, KErrNone);
	err = stmt.Next();
	TEST2(err, KSqlAtRow);
	err = stmt.ColumnText(0, colVal);
	TEST2(err, KErrNone);
	_LIT(KTextVal10, "GHJK");
	TEST(colVal == KTextVal10);
	stmt.Close();

	//avg() test --------------------------------------------------------
	err = stmt.Prepare(TheDb, _L("SELECT AVG(F2) AS F FROM A"));
	TEST2(err, KErrNone);
	err = stmt.Next();
	TEST2(err, KSqlAtRow);
	TEST(Abs(stmt.ColumnReal(0) - 2) < 0.000001);
	stmt.Close();

	//count() test --------------------------------------------------------
	err = stmt.Prepare(TheDb, _L("SELECT COUNT(F2) AS F FROM A"));
	TEST2(err, KErrNone);
	err = stmt.Next();
	TEST2(err, KSqlAtRow);
	TEST(stmt.ColumnInt(0) == 1);
	stmt.Close();

	err = stmt.Prepare(TheDb, _L("SELECT COUNT(*) AS F FROM A"));
	TEST2(err, KErrNone);
	err = stmt.Next();
	TEST2(err, KSqlAtRow);
	TEST(stmt.ColumnInt(0) == 6);
	stmt.Close();

	//sum() test --------------------------------------------------------
	err = stmt.Prepare(TheDb, _L("SELECT SUM(F2) AS S FROM A"));
	TEST2(err, KErrNone);
	err = stmt.Next();
	TEST2(err, KSqlAtRow);
	TEST(Abs(stmt.ColumnReal(0) - 2) < 0.000001);
	stmt.Close();

	// ----------------------------------
	TheDb.Close();
	(void)RSqlDatabase::Delete(KTestDbName);
	}

/**
@SYMTestCaseID			SYSLIB-SQL-CT-1632
@SYMTestCaseDesc		"ATTACH DATABASE" test.
						The test creates two databases. The main database has 
						Account(Id Integer, PersonId Integer, Value Integer) table.
						The attached database has Person(Id Integer, Name TEXT) table.
						The test inserts some records with a valid relation between them in both tables.
						Then the test opens tha main database and attaches the second database to the first one.
						The test prepares and executes SQL statement which retrieves column values from both
						Account and Person tables. The test checks the column values.
@SYMTestPriority		High
@SYMTestActions			"ATTACH DATABASE" test.
@SYMTestExpectedResults Test must not fail
@SYMREQ					REQ5792
                        REQ5793
*/	
void AttachDatabaseTest()
	{
	// ------------------------------------------------------------
	RSqlDatabase db2;
	TInt err = db2.Create(KTestDbName2);
	TEST2(err, KErrNone);
	
	err = db2.Exec(_L("CREATE TABLE Person(Id Integer, Name TEXT)"));
	TEST(err >= 0);

	err = db2.Exec(_L("INSERT INTO Person(Id, Name) VALUES(1, 'A')"));
	TEST2(err, 1);

	err = db2.Exec(_L("INSERT INTO Person(Id, Name) VALUES(2, 'B')"));
	TEST2(err, 1);

	err = db2.Exec(_L("INSERT INTO Person(Id, Name) VALUES(3, 'C')"));
	TEST2(err, 1);
	
	db2.Close();

	// ------------------------------------------------------------
	(void)RSqlDatabase::Delete(KTestDbName);
	err = TheDb.Create(KTestDbName);
	TEST2(err, KErrNone);

	err = TheDb.Exec(_L("CREATE TABLE Account(Id Integer, PersonId Integer, Value Integer)"));
	TEST(err >= 0);

	err = TheDb.Exec(_L("INSERT INTO ACCOUNT(Id, PersonId, Value) VALUES(1, 2, 20)"));
	TEST2(err, 1);

	err = TheDb.Exec(_L("INSERT INTO ACCOUNT(Id, PersonId, Value) VALUES(2, 1, 10)"));
	TEST2(err, 1);

	err = TheDb.Exec(_L("INSERT INTO ACCOUNT(Id, PersonId, Value) VALUES(3, 2, 25)"));
	TEST2(err, 1);

	err = TheDb.Exec(_L("INSERT INTO ACCOUNT(Id, PersonId, Value) VALUES(4, 3, 30)"));
	TEST2(err, 1);

	TheDb.Close();
	
	// ------------------------------------------------------------
	err = TheDb.Open(KTestDbName);	
	TEST2(err, KErrNone);
	
	TBuf<100> sql;
	sql.Copy(_L("ATTACH DATABASE '"));
	sql.Append(KTestDbName2);
	sql.Append(_L("' AS DB2"));
	err = TheDb.Exec(sql);
	TEST(err >= 0);
	
	RSqlStatement stmt;
	err = stmt.Prepare(TheDb, _L("SELECT Account.Value, DB2.Person.Name FROM Account, DB2.Person \
						   		  WHERE Account.PersonId = DB2.Person.Id"));
	TEST2(err, KErrNone);

	TPtrC personName;
	_LIT(KName1, "A");
	_LIT(KName2, "B");
	_LIT(KName3, "C");

	err = stmt.Next();
	TEST2(err, KSqlAtRow);
	err = stmt.ColumnText(1, personName);
	TEST2(err, KErrNone);
	TEST(personName == KName2);
	TEST(stmt.ColumnInt(0) == 20);
	
	err = stmt.Next();
	TEST2(err, KSqlAtRow);
	err = stmt.ColumnText(1, personName);
	TEST2(err, KErrNone);
	TEST(personName == KName1);
	TEST(stmt.ColumnInt(0) == 10);
		
	err = stmt.Next();
	TEST2(err, KSqlAtRow);
	err = stmt.ColumnText(1, personName);
	TEST2(err, KErrNone);
	TEST(personName == KName2);
	TEST(stmt.ColumnInt(0) == 25);

	err = stmt.Next();
	TEST2(err, KSqlAtRow);
	err = stmt.ColumnText(1, personName);
	TEST2(err, KErrNone);
	TEST(personName == KName3);
	TEST(stmt.ColumnInt(0) == 30);
		
	stmt.Close();
	
	err = TheDb.Exec(_L("DETACH DATABASE DB2"));
	TEST(err >= 0);
		
	// ------------------------------------------------------------
	TheDb.Close();
	(void)RSqlDatabase::Delete(KTestDbName2);
	(void)RSqlDatabase::Delete(KTestDbName);
	}
	
/**
@SYMTestCaseID			SYSLIB-SQL-UT-3502
@SYMTestCaseDesc		Test for DEF109100: SQL, code coverage for TSqlBufRIterator is very low.
						The test creates a test table with INT32, INT64, DOUBLE, TEXT, and BINARY columns
						and inserts couple of records there. Then the test prepares a SELECT statement,
						retrieves all table rows, and to retrieve each column value, calls RSqlStatement::ColumnInt().
						The column values are carefully chosen, so some of the ColumnInt() calls have to round
						or clamp the returned value. 
						Summary: the test checks the ColumnInt() behaviour when the column value type is not INT32 and
								 when the column value is too big or too small and cannot fit in 32 bits.
@SYMTestPriority		High
@SYMTestActions			Test for DEF109100: SQL, code coverage for TSqlBufRIterator is very low.
@SYMTestExpectedResults Test must not fail
@SYMDEF					DEF109100
*/	
void ColumnIntTest()
	{
	(void)RSqlDatabase::Delete(KTestDbName);
	TInt err = TheDb.Create(KTestDbName);
	TEST2(err, KErrNone);
	err = TheDb.Exec(_L("CREATE TABLE A(I32 INTEGER,I64 INTEGER,D DOUBLE,T TEXT,B BINARY)"));
	TEST(err >= 0);
	
	err = TheDb.Exec(_L("INSERT INTO A VALUES(-5,-5000000000,-10000000000.0,'AAA',x'1122FF')"));
	TEST2(err, 1);
	err = TheDb.Exec(_L("INSERT INTO A VALUES(5,5000000000,10000000000.0,NULL,NULL)"));
	TEST2(err, 1);
	err = TheDb.Exec(_L("INSERT INTO A VALUES(5,2000000000,1000000000.0,NULL,NULL)"));
	TEST2(err, 1);
	err = TheDb.Exec(_L("INSERT INTO A VALUES(NULL,NULL,1.1234567890123456E+317,NULL,NULL)"));
	TEST2(err, 1);

	RSqlStatement stmt;
	err = stmt.Prepare(TheDb, _L("SELECT I32,I64,D,T,B FROM A"));
	TEST2(err, KErrNone);
	
	err = stmt.Next();
	TEST2(err, KSqlAtRow);
	TInt val = stmt.ColumnInt(0);	
	TEST2(val, -5);					//"-5" is a 32-bit integer value
	val = stmt.ColumnInt(1);
	TEST2(val, KMinTInt);			//"-5000000000" is a 64-bit integer, will be clamped to KMinTInt
	val = stmt.ColumnInt(2);
	TEST2(val, KMinTInt);			//"-10000000000.0" is a 64-bit double, will be rounded to the nearest 32-bit integer
	val = stmt.ColumnInt(3);
	TEST2(val, 0);					//"AAA" is a text string, cannot be converted to a 32-bit integer
	val = stmt.ColumnInt(4);
	TEST2(val, 0);					//"1122FF" is a hex binary, cannot be converted to a 32-bit integer

	err = stmt.Next();
	TEST2(err, KSqlAtRow);
	val = stmt.ColumnInt(0);	
	TEST2(val, 5);					//"5" is a 32-bit integer value
	val = stmt.ColumnInt(1);
	TEST2(val, KMaxTInt);			//"5000000000" is a 64-bit integer, will be clamped to KMaxTInt
	val = stmt.ColumnInt(2);
	TEST2(val, KMaxTInt);			//"10000000000.0" is a 64-bit double, will be rounded to the nearest 32-bit integer
	val = stmt.ColumnInt(3);
	TEST2(val, 0);					//NULL column value
	val = stmt.ColumnInt(4);
	TEST2(val, 0);					//NULL column value

	err = stmt.Next();
	TEST2(err, KSqlAtRow);
	val = stmt.ColumnInt(0);	
	TEST2(val, 5);					
	val = stmt.ColumnInt(1);
	TEST2(val, 2000000000);					
	val = stmt.ColumnInt(2);
	TEST2(val, 1000000000);					
	
	err = stmt.Next();
	TEST2(err, KSqlAtRow);
	val = stmt.ColumnInt(2);
	TEST2(val, KMinTInt);			//"1.1234567890123456E+317" is too big and cannot fit in a 64-bit double
	
	stmt.Close();
	
	TheDb.Close();
	err = RSqlDatabase::Delete(KTestDbName);
	TEST2(err, KErrNone);
	}

/**
@SYMTestCaseID			SYSLIB-SQL-UT-3503
@SYMTestCaseDesc		Test for DEF109100: SQL, code coverage for TSqlBufRIterator is very low.
						The test creates a test table with INT32, INT64, DOUBLE, TEXT, and BINARY columns
						and inserts couple of records there. Then the test prepares a SELECT statement,
						retrieves all table rows, and to retrieve each column value, calls RSqlStatement::ColumnInt64().
						The column values are carefully chosen, so some of the ColumnInt64() calls have to round
						or clamp the returned value. 
						Summary: the test checks the ColumnInt64() behaviour when the column value type is not INT64 and
								 when the column value is too big or too small and cannot be presented as 64-bits integer.
@SYMTestPriority		High
@SYMTestActions			Test for DEF109100: SQL, code coverage for TSqlBufRIterator is very low.
@SYMTestExpectedResults Test must not fail
@SYMDEF					DEF109100
*/	
void ColumnInt64Test()
	{
	(void)RSqlDatabase::Delete(KTestDbName);
	TInt err = TheDb.Create(KTestDbName);
	TEST2(err, KErrNone);
	err = TheDb.Exec(_L("CREATE TABLE A(I32 INTEGER,I64 INTEGER,D DOUBLE,T TEXT,B BINARY)"));
	TEST(err >= 0);
	
	err = TheDb.Exec(_L("INSERT INTO A VALUES(-5,-5000000000,-10000000000.0,'AAA',x'1122FF')"));
	TEST2(err, 1);
	err = TheDb.Exec(_L("INSERT INTO A VALUES(5,5000000000,10000000000.0,NULL,NULL)"));
	TEST2(err, 1);
	err = TheDb.Exec(_L("INSERT INTO A VALUES(5,2000000000,1000000000.0,NULL,NULL)"));
	TEST2(err, 1);
	err = TheDb.Exec(_L("INSERT INTO A VALUES(NULL,NULL,1.1234567890123456E+317,NULL,NULL)"));
	TEST2(err, 1);

	RSqlStatement stmt;
	err = stmt.Prepare(TheDb, _L("SELECT I32,I64,D,T,B FROM A"));
	TEST2(err, KErrNone);
	
	err = stmt.Next();
	TEST2(err, KSqlAtRow);
	TInt64 val = stmt.ColumnInt64(0);	
	TEST3(val, -5);					//"-5" is a 32-bit integer value
	val = stmt.ColumnInt64(1);
	TEST3(val, -5000000000LL);		//"-5000000000" is a 64-bit integer
	val = stmt.ColumnInt64(2);
	TEST3(val, -10000000000LL);		//"-10000000000.0" is a 64-bit double, will be rounded to the nearest 64-bit integer
	val = stmt.ColumnInt64(3);
	TEST3(val, 0);					//"AAA" is a text string, cannot be converted to a 64-bit integer
	val = stmt.ColumnInt64(4);
	TEST3(val, 0);					//"1122FF" is a hex binary, cannot be converted to a 64-bit integer

	err = stmt.Next();
	TEST2(err, KSqlAtRow);
	val = stmt.ColumnInt64(0);	
	TEST3(val, 5);					//"5" is a 32-bit integer value
	val = stmt.ColumnInt64(1);
	TEST3(val, 5000000000LL);		//"5000000000" is a 64-bit integer
	val = stmt.ColumnInt64(2);
	TEST3(val, 10000000000LL);		//"10000000000.0" is a 64-bit double, will be rounded to the nearest 64-bit integer
	val = stmt.ColumnInt64(3);
	TEST3(val, 0);					//NULL column value
	val = stmt.ColumnInt64(4);
	TEST3(val, 0);					//NULL column value

	err = stmt.Next();
	TEST2(err, KSqlAtRow);
	val = stmt.ColumnInt64(0);	
	TEST3(val, 5);					
	val = stmt.ColumnInt64(1);
	TEST3(val, 2000000000);					
	val = stmt.ColumnInt64(2);
	TEST3(val, 1000000000);					
	
	err = stmt.Next();
	TEST2(err, KSqlAtRow);
	val = stmt.ColumnInt64(2);
	TEST3(val, KMinTInt64);			//"1.1234567890123456E+317" is too big and cannot fit in a 64-bit double
	
	stmt.Close();
	
	TheDb.Close();
	err = RSqlDatabase::Delete(KTestDbName);
	TEST2(err, KErrNone);
	}

/**
@SYMTestCaseID			SYSLIB-SQL-UT-3504
@SYMTestCaseDesc		Test for DEF109100: SQL, code coverage for TSqlBufRIterator is very low.
						The test creates a test table with INT32, INT64, DOUBLE, TEXT, and BINARY columns
						and inserts couple of records there. Then the test prepares a SELECT statement,
						retrieves all table rows, and to retrieve each column value, calls RSqlStatement::ColumnReal().
						Summary: the test checks the ColumnReal() behaviour when the column value type is not DOUBLE and
								 when the column value is too big or too small and cannot be presented as 64-bits double.
@SYMTestPriority		High
@SYMTestActions			Test for DEF109100: SQL, code coverage for TSqlBufRIterator is very low.
@SYMTestExpectedResults Test must not fail
@SYMDEF					DEF109100
*/	
void ColumnRealTest()
	{
	(void)RSqlDatabase::Delete(KTestDbName);
	TInt err = TheDb.Create(KTestDbName);
	TEST2(err, KErrNone);
	err = TheDb.Exec(_L("CREATE TABLE A(I32 INTEGER,I64 INTEGER,D DOUBLE,T TEXT,B BINARY)"));
	TEST(err >= 0);
	
	err = TheDb.Exec(_L("INSERT INTO A VALUES(-5,-5000000000,-10000000000.0,'AAA',x'1122FF')"));
	TEST2(err, 1);
	err = TheDb.Exec(_L("INSERT INTO A VALUES(5,5000000000,10000000000.0,NULL,NULL)"));
	TEST2(err, 1);
	err = TheDb.Exec(_L("INSERT INTO A VALUES(5,2000000000,1000000000.0,NULL,NULL)"));
	TEST2(err, 1);
	err = TheDb.Exec(_L("INSERT INTO A VALUES(NULL,NULL,1.1234567890123456E+317,NULL,NULL)"));
	TEST2(err, 1);

	const TReal KEpsilon = 0.000001;

	RSqlStatement stmt;
	err = stmt.Prepare(TheDb, _L("SELECT I32,I64,D,T,B FROM A"));
	TEST2(err, KErrNone);
	
	err = stmt.Next();
	TEST2(err, KSqlAtRow);
	TReal val = stmt.ColumnReal(0);	
	TEST(Abs(val - (-5)) < KEpsilon);		
	val = stmt.ColumnReal(1);
	TEST(Abs(val - (-5000000000LL)) < KEpsilon);
	val = stmt.ColumnReal(2);
	TEST(Abs(val - (-10000000000LL)) < KEpsilon);
	val = stmt.ColumnReal(3);
	TEST(Abs(val) < 0.0001);					//"AAA" is a text string, cannot be converted to a 64-bit double
	val = stmt.ColumnReal(4);
	TEST(Abs(val) < 0.0001);					//"1122FF" is a hex binary, cannot be converted to a 64-bit double

	err = stmt.Next();
	TEST2(err, KSqlAtRow);
	val = stmt.ColumnReal(0);	
	TEST(Abs(val - 5) < KEpsilon);
	val = stmt.ColumnReal(1);
	TEST(Abs(val - 5000000000LL) < KEpsilon);
	val = stmt.ColumnReal(2);
	TEST(Abs(val - 10000000000LL) < KEpsilon);
	val = stmt.ColumnReal(3);
	TEST(Abs(val) < KEpsilon);					//NULL column value
	val = stmt.ColumnReal(4);
	TEST(Abs(val) < KEpsilon);					//NULL column value

	err = stmt.Next();
	TEST2(err, KSqlAtRow);
	val = stmt.ColumnReal(0);	
	TEST(Abs(val - 5) < KEpsilon);		
	val = stmt.ColumnReal(1);
	TEST(Abs(val - 2000000000) < KEpsilon);
	val = stmt.ColumnReal(2);
	TEST(Abs(val - 1000000000) < KEpsilon);
	
	err = stmt.Next();
	TEST2(err, KSqlAtRow);
	val = stmt.ColumnReal(2);
	TEST(Math::IsInfinite(val));				//"1.1234567890123456E+317" is too big and cannot fit in a 64-bit double
	
	stmt.Close();
	
	TheDb.Close();
	err = RSqlDatabase::Delete(KTestDbName);
	TEST2(err, KErrNone);
	}

/**
@SYMTestCaseID			SYSLIB-SQL-UT-3505
@SYMTestCaseDesc		Test for DEF109100: SQL, code coverage for TSqlBufRIterator is very low.
						The test creates a test table with INT32, INT64, DOUBLE, TEXT, and BINARY columns
						and inserts a record there. Then the test prepares a SELECT statement,
						retrieves all table rows, and to retrieve each column value, calls RSqlStatement::ColumnText().
						Summary: the test checks the ColumnText() behaviour when the column value type is not TEXT.
								 (In all non-TEXT cases the ,ethod is expected to return KNullDesC8)
@SYMTestPriority		High
@SYMTestActions			Test for DEF109100: SQL, code coverage for TSqlBufRIterator is very low.
@SYMTestExpectedResults Test must not fail
@SYMDEF					DEF109100
*/	
void ColumnTextTest()
	{
	(void)RSqlDatabase::Delete(KTestDbName);
	TInt err = TheDb.Create(KTestDbName);
	TEST2(err, KErrNone);
	err = TheDb.Exec(_L("CREATE TABLE A(I32 INTEGER,I64 INTEGER,D DOUBLE,T TEXT,B BINARY)"));
	TEST(err >= 0);
	
	err = TheDb.Exec(_L("INSERT INTO A VALUES(-5,-5000000000,-10000000000.0,'AAA',x'1122FF')"));
	TEST2(err, 1);

	RSqlStatement stmt;
	err = stmt.Prepare(TheDb, _L("SELECT I32,I64,D,T,B FROM A"));
	TEST2(err, KErrNone);
	
	err = stmt.Next();
	TEST2(err, KSqlAtRow);
	TPtrC val;
	err = stmt.ColumnText(0, val);	
	TEST2(err, KErrNone);		
	TEST(val == KNullDesC);
	err = stmt.ColumnText(1, val);
	TEST2(err, KErrNone);		
	TEST(val == KNullDesC);
	err = stmt.ColumnText(2, val);
	TEST2(err, KErrNone);		
	TEST(val == KNullDesC);
	err = stmt.ColumnText(3, val);
	TEST2(err, KErrNone);		
	TEST2(val.Length(), 3);
	TEST(val == _L("AAA"));
	err = stmt.ColumnText(4, val);
	TEST2(err, KErrNone);		
	TEST(val == KNullDesC);
	
	stmt.Close();
	
	TheDb.Close();
	err = RSqlDatabase::Delete(KTestDbName);
	TEST2(err, KErrNone);
	}
	
/**
@SYMTestCaseID			SYSLIB-SQL-UT-3506
@SYMTestCaseDesc		Test for DEF109100: SQL, code coverage for TSqlBufRIterator is very low.
						The test creates a test table with INT32, INT64, DOUBLE, TEXT, and BINARY columns
						and inserts a record there. Then the test prepares a SELECT statement,
						retrieves all table rows, and to retrieve each column value, calls RSqlStatement::ColumnBinary().
						Summary: the test checks the ColumnBinary() behaviour when the column value type is not BINARY.
								 (In all non-BINARY cases the method is expected to return KNullDesC8)
@SYMTestPriority		High
@SYMTestActions			Test for DEF109100: SQL, code coverage for TSqlBufRIterator is very low.
@SYMTestExpectedResults Test must not fail
@SYMDEF					DEF109100
*/	
void ColumnBinaryTest()
	{
	(void)RSqlDatabase::Delete(KTestDbName);
	TInt err = TheDb.Create(KTestDbName);
	TEST2(err, KErrNone);
	err = TheDb.Exec(_L("CREATE TABLE A(I32 INTEGER,I64 INTEGER,D DOUBLE,T TEXT,B BINARY)"));
	TEST(err >= 0);
	
	err = TheDb.Exec(_L("INSERT INTO A VALUES(-5,-5000000000,-10000000000.0,'AAA',x'1122FF')"));
	TEST2(err, 1);

	RSqlStatement stmt;
	err = stmt.Prepare(TheDb, _L("SELECT I32,I64,D,T,B FROM A"));
	TEST2(err, KErrNone);
	
	err = stmt.Next();
	TEST2(err, KSqlAtRow);
	TPtrC8 val;
	err = stmt.ColumnBinary(0, val);	
	TEST2(err, KErrNone);		
	TEST(val == KNullDesC8);
	err = stmt.ColumnBinary(1, val);
	TEST2(err, KErrNone);		
	TEST(val == KNullDesC8);
	err = stmt.ColumnBinary(2, val);
	TEST2(err, KErrNone);		
	TEST(val == KNullDesC8);
	err = stmt.ColumnBinary(3, val);
	TEST2(err, KErrNone);		
	TEST(val == KNullDesC8);
	err = stmt.ColumnBinary(4, val);
	TEST2(err, KErrNone);		
	TEST2(val.Length(), 3);
	TEST(val[0] == 0x11);
	TEST(val[1] == 0x22);
	TEST(val[2] == 0xFF);
	
	stmt.Close();
	
	TheDb.Close();
	err = RSqlDatabase::Delete(KTestDbName);
	TEST2(err, KErrNone);
	}
	
void DoTestsL()
	{	
	TheTest.Start(_L(" @SYMTestCaseID:SYSLIB-SQL-CT-1611 E011 numeric data types test "));		
	NumericDataTypesTest();

	TheTest.Next(_L(" @SYMTestCaseID:SYSLIB-SQL-CT-1630 Built-in functions test "));		
	BuiltInFunctionsTest();

	TheTest.Next(_L(" @SYMTestCaseID:SYSLIB-SQL-CT-1632 \"Attach database\" test "));		
	AttachDatabaseTest();

	TheTest.Next(_L(" @SYMTestCaseID:SYSLIB-SQL-UT-3502 \"RSqlStatement::ColumnInt()\" test "));		
	ColumnIntTest();

	TheTest.Next(_L(" @SYMTestCaseID:SYSLIB-SQL-UT-3503 \"RSqlStatement::ColumnInt64()\" test "));		
	ColumnInt64Test();
	
	TheTest.Next(_L(" @SYMTestCaseID:SYSLIB-SQL-UT-3504 \"RSqlStatement::ColumnReal()\" test "));		
	ColumnRealTest();
	
	TheTest.Next(_L(" @SYMTestCaseID:SYSLIB-SQL-UT-3505 \"RSqlStatement::ColumnText()\" test "));		
	ColumnTextTest();

	TheTest.Next(_L(" @SYMTestCaseID:SYSLIB-SQL-UT-3506 \"RSqlStatement::ColumnBinary()\" test "));		
	ColumnBinaryTest();
	}
	
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;
	}
