/*
Boost Software License - Version 1.0 - August 17th, 2003

Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:

The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/
#include "ODBCSybaseTest.h"
#include "Poco/CppUnit/TestCaller.h"
#include "Poco/CppUnit/TestSuite.h"
#include "Poco/String.h"
#include "Poco/Format.h"
#include "Poco/Any.h"
#include "Poco/DynamicAny.h"
#include "Poco/Tuple.h"
#include "Poco/Exception.h"
#include "Poco/Data/LOB.h"
#include "Poco/Data/RecordSet.h"
#include "Poco/Data/StatementImpl.h"
#include "Poco/Data/ODBC/Connector.h"
#include "Poco/Data/ODBC/Utility.h"
#include "Poco/Data/ODBC/Diagnostics.h"
#include "Poco/Data/ODBC/ODBCException.h"
#include "Poco/Data/ODBC/ODBCStatementImpl.h"
#include <sqltypes.h>
#include <iostream>


using namespace Poco::Data::Keywords;
using Poco::Data::DataException;
using Poco::Data::ODBC::Utility;
using Poco::Data::ODBC::ConnectionException;
using Poco::Data::ODBC::StatementException;
using Poco::Data::ODBC::StatementDiagnostics;
using Poco::format;
using Poco::Tuple;
using Poco::Any;
using Poco::AnyCast;
using Poco::DynamicAny;
using Poco::NotFoundException;

#include "Poco/CppUnit/TestCaller.h"
#include "Poco/CppUnit/TestSuite.h"

#define SYBASE_DSN "" 
#define SYBASE_UID ""
#define SYBASE_PWD ""
#define SYBASE_DB "mstk"


static std::string sybaseDriver()
{
	return Poco::Environment::get("POCO_TEST_SYBASE_DRIVER",
#if defined(POCO_OS_FAMILY_WINDOWS)
	"{Adaptive Server Enterprise}"
#else
	"libsybdrvodb-sqllen8.so"
#endif
	);
}


static std::string sybaseExtra()
{
	std::string e = Poco::Environment::get("POCO_TEST_SYBASE_EXTRA", "");
	return (e.empty() ? "" : e + ";");
}


std::string SybaseODBC::_connectString =
	"driver=" + sybaseDriver() + ";" +
	sybaseExtra() +
	"db=" SYBASE_DB ";"
	"uid=" SYBASE_UID ";"
	"pwd=" SYBASE_PWD ";"
	"DynamicPrepare=1;"
#if !defined(POCO_OS_FAMILY_WINDOWS)
	"CS=iso_1;"
#endif
;



ODBCTest::SessionPtr SybaseODBC::_pSession;
ODBCTest::ExecPtr    SybaseODBC::_pExecutor;
std::string          SybaseODBC::_driver = "";
std::string          SybaseODBC::_dsn = SYBASE_DSN;
std::string          SybaseODBC::_uid = SYBASE_UID;
std::string          SybaseODBC::_pwd = SYBASE_PWD;


SybaseODBC::SybaseODBC(const std::string& name) :
ODBCTest(name, _pSession, _pExecutor, _dsn, _uid, _pwd, _connectString)
{

}

void SybaseODBC::testBareboneODBC()
{
	if (!&session()) fail("Test not available.");
}


void SybaseODBC::dropObject(const std::string& type, const std::string& name)
{
	try
	{
		session() << format("DROP %s %s", type, name), now;
	}
	catch (StatementException& ex)
	{
		bool ignoreError = false;
		const StatementDiagnostics::FieldVec& flds = ex.diagnostics().fields();
		StatementDiagnostics::Iterator it = flds.begin();
		for (; it != flds.end(); ++it)
		{
			if ((-204 == it->_nativeError) || (3701 /* Sybase */ == it->_nativeError))//(table does not exist)
			{
				ignoreError = true;
				break;
			}
		}

		if (!ignoreError) throw;
	}
}


void SybaseODBC::recreateNullableTable()
{
	dropObject("TABLE", ExecUtil::nullabletest());
	try { session() << "CREATE TABLE " << ExecUtil::nullabletest() << " (EmptyString VARCHAR(30) NULL, EmptyInteger INTEGER NULL, EmptyFloat FLOAT NULL , EmptyDateTime DATETIME NULL)", now; }
	catch (ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail("recreateNullableTable()"); }
	catch (StatementException& se){ std::cout << se.toString() << std::endl; fail("recreateNullableTable()"); }
}


void SybaseODBC::recreateNumericTable()
{
	dropObject("TABLE", ExecUtil::numeric_tbl());
	try {
		session() << "CREATE TABLE " << ExecUtil::numeric_tbl() <<
			" (id integer, num8 NUMERIC(8), num16_3 NUMERIC(16,3), num18 NUMERIC(18), num18_8 NUMERIC(18,8), num22 NUMERIC(22))", now;
	}
	catch (ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail("recreateNumericTable()"); }
	catch (StatementException& se){ std::cout << se.toString() << std::endl; fail("recreateNumericTable()"); }
}

void SybaseODBC::recreatePersonTable()
{
	doPersonTable();
}

void SybaseODBC::doPersonTable(const std::string& lnAttr)
{
	dropObject("TABLE", ExecUtil::person());
	try { session() << "CREATE TABLE " << ExecUtil::person() << " (LastName VARCHAR(30)" << lnAttr << ", FirstName VARCHAR(30), Address VARCHAR(30), Age INTEGER)", now; }
	catch (ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail("recreatePersonTable()"); }
	catch (StatementException& se){ std::cout << se.toString() << std::endl; fail("recreatePersonTable()"); }
}


void SybaseODBC::recreatePersonBLOBTable()
{
	dropObject("TABLE", ExecUtil::person());
	try { session() << "CREATE TABLE " << ExecUtil::person() << " (LastName VARCHAR(30), FirstName VARCHAR(30), Address VARCHAR(30), Image VARBINARY(10240))", now; }
	catch (ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail("recreatePersonBLOBTable()"); }
	catch (StatementException& se){ std::cout << se.toString() << std::endl; fail("recreatePersonBLOBTable()"); }
}


void SybaseODBC::recreatePersonDateTable()
{
	dropObject("TABLE", ExecUtil::person());
	try { session() << "CREATE TABLE " << ExecUtil::person() << " (LastName VARCHAR(30), FirstName VARCHAR(30), Address VARCHAR(30), BornDate DATE)", now; }
	catch (ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail("recreatePersonDateTable()"); }
	catch (StatementException& se){ std::cout << se.toString() << std::endl; fail("recreatePersonDateTable()"); }
}


void SybaseODBC::recreatePersonTimeTable()
{
	dropObject("TABLE", ExecUtil::person());
	try { session() << "CREATE TABLE " << ExecUtil::person() << " (LastName VARCHAR(30), FirstName VARCHAR(30), Address VARCHAR(30), BornTime TIME)", now; }
	catch (ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail("recreatePersonTimeTable()"); }
	catch (StatementException& se){ std::cout << se.toString() << std::endl; fail("recreatePersonTimeTable()"); }
}


void SybaseODBC::recreatePersonDateTimeTable()
{
	dropObject("TABLE", ExecUtil::person());
	try { session() << "CREATE TABLE " << ExecUtil::person() << " (LastName VARCHAR(30), FirstName VARCHAR(30), Address VARCHAR(30), Born DATETIME)", now; }
	catch (ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail("recreatePersonDateTimeTable()"); }
	catch (StatementException& se){ std::cout << se.toString() << std::endl; fail("recreatePersonDateTimeTable()"); }
}


void SybaseODBC::recreateIntsTable()
{
	dropObject("TABLE", ExecUtil::strings());
	try { session() << "CREATE TABLE " << ExecUtil::strings() << " (str INTEGER)", now; }
	catch (ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail("recreateIntsTable()"); }
	catch (StatementException& se){ std::cout << se.toString() << std::endl; fail("recreateIntsTable()"); }
}


void SybaseODBC::recreateStringsTable()
{
	dropObject("TABLE", ExecUtil::strings());
	try { session() << "CREATE TABLE " << ExecUtil::strings() << " (str VARCHAR(30))", now; }
	catch (ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail("recreateStringsTable()"); }
	catch (StatementException& se){ std::cout << se.toString() << std::endl; fail("recreateStringsTable()"); }
}


void SybaseODBC::recreateFloatsTable()
{
	dropObject("TABLE", ExecUtil::strings());
	try { session() << "CREATE TABLE " << ExecUtil::strings() << " (str FLOAT)", now; }
	catch (ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail("recreateFloatsTable()"); }
	catch (StatementException& se){ std::cout << se.toString() << std::endl; fail("recreateFloatsTable()"); }
}


void SybaseODBC::recreateTuplesTable()
{
	dropObject("TABLE", ExecUtil::tuples());
	try {
		session() << "CREATE TABLE " << ExecUtil::tuples() <<
			"(int0 INTEGER, int1 INTEGER, int2 INTEGER, int3 INTEGER, int4 INTEGER, int5 INTEGER, int6 INTEGER, "
			"int7 INTEGER, int8 INTEGER, int9 INTEGER, int10 INTEGER, int11 INTEGER, int12 INTEGER, int13 INTEGER,"
			"int14 INTEGER, int15 INTEGER, int16 INTEGER, int17 INTEGER, int18 INTEGER, int19 INTEGER)", now;
	}
	catch (ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail("recreateTuplesTable()"); }
	catch (StatementException& se){ std::cout << se.toString() << std::endl; fail("recreateTuplesTable()"); }
}


void SybaseODBC::recreateVectorsTable()
{
	dropObject("TABLE", ExecUtil::vectors());
	try { session() << "CREATE TABLE " << ExecUtil::vectors() << " (i0 INTEGER, flt0 FLOAT, str0 VARCHAR(30))", now; }
	catch (ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail("recreateVectorsTable()"); }
	catch (StatementException& se){ std::cout << se.toString() << std::endl; fail("recreateVectorsTable()"); }
}


void SybaseODBC::recreateAnysTable()
{
	dropObject("TABLE", ExecUtil::anys());
	try { session() << "CREATE TABLE " << ExecUtil::anys() << " (i0 INTEGER, flt0 FLOAT, str0 VARCHAR(30))", now; }
	catch (ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail("recreateAnysTable()"); }
	catch (StatementException& se){ std::cout << se.toString() << std::endl; fail("recreateAnysTable()"); }
}


void SybaseODBC::recreateNullsTable(const std::string& notNull)
{
	dropObject("TABLE", ExecUtil::nulltest());
	std::string nl = (notNull.empty() ? " NULL " : notNull);
	try {
		session() << format("CREATE TABLE %s (i INTEGER %s, r FLOAT %s, v VARCHAR(30) %s)", ExecUtil::nulltest(),
			nl,
			nl,
			nl), now;
	}
	catch (ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail("recreateNullsTable()"); }
	catch (StatementException& se){ std::cout << se.toString() << std::endl; fail("recreateNullsTable()"); }
}

void SybaseODBC::doMiscTable(bool haveSecCol)
{
	dropObject("TABLE", ExecUtil::misctest());
	try
	{
		session() << "CREATE TABLE " << ExecUtil::misctest() <<
			"(First VARCHAR(30),"
			<< (haveSecCol ? "Second VARBINARY(10240)," : "") <<
			"Third INTEGER,"
			"Fourth FLOAT,"
			"Fifth DATETIME)", now;
	}
	catch (ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail("recreateMiscTable()"); }
	catch (StatementException& se){ std::cout << se.toString() << std::endl; fail("recreateMiscTable()"); }
}

void SybaseODBC::testBulkPerformance()
{
	session().setFeature("autoBind", true);
	session().setFeature("autoExtract", true);

	doMiscTable(false);
	executor().doBulkPerformance(1000);
}


void SybaseODBC::recreateMiscTable()
{
	doMiscTable(true);
}

void SybaseODBC::recreateLogTable()
{
	dropObject("TABLE", ExecUtil::pocolog());
	dropObject("TABLE", ExecUtil::pocolog_a());;

	try
	{
		std::string sql = "CREATE TABLE %s "
			"(Source VARCHAR(100),"
			"Name VARCHAR(100),"
			"ProcessId INTEGER,"
			"Thread VARCHAR(100), "
			"ThreadId INTEGER,"
			"Priority INTEGER,"
			"Text VARCHAR(100),"
			"DateTime DATETIME)";

		session() << sql, ExecUtil::pocolog(), now;
		session() << sql, ExecUtil::pocolog_a(), now;

	}
	catch (ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail("recreateLogTable()"); }
	catch (StatementException& se){ std::cout << se.toString() << std::endl; fail("recreateLogTable()"); }
}

void SybaseODBC::testStoredProcedure()
{
	const std::string nm(ExecUtil::stored_proc());
	dropObject("procedure", nm);

	for (int k = 0; k < 8;)
	{
		session().setFeature("autoBind", bindValue(k));
		session().setFeature("autoExtract", bindValue(k + 1));

		{
			session() << "create procedure " + nm + " "
				"as "
				"select -1 where 1 = 2 ", now;
			Poco::Data::Statement stat(session());
			stat << "{ call " << nm << "() }", now;
			Poco::Data::RecordSet rs(stat);
			dropObject("procedure", nm);
			assert(0 == rs.rowCount());
		}
		{
			Poco::Nullable<std::string> ins;
			Poco::Nullable<std::string> os = Poco::Nullable<std::string>("ab");
			Poco::Nullable<int> oi(12);
			Poco::Nullable<Poco::Data::Date> od = Poco::Nullable<Poco::Data::Date>(Poco::Data::Date());
			Poco::Nullable<Poco::DateTime> odtm = Poco::Nullable<Poco::DateTime>(Poco::DateTime());
			session() << "create procedure " + nm + " @ins varchar(40), @oi integer output, @os varchar(10) output, @od date output, @dtm datetime output "
				"as "
				"begin "
				"select @oi = null;"
				"select @os = @ins;"
				"select @od = null;"
				"select @dtm = null;"
					" end" 
				, now;
			session() << "{ call " << nm << "(?, ?, ?, ?, ?) }", in(ins), out(oi), out(os), out(od), out(odtm), now;
			dropObject("procedure", nm);
			assert(oi.isNull());
			assert(os.isNull());
			assert(od.isNull());
			assert(odtm.isNull());
		}
		{
			session() << "create procedure " << nm << " @c char(8) AS select @c", now;
			Poco::Nullable<std::string> ns;
			Poco::Data::Statement stat(session());
			stat << "{ call " << nm << "(?) }", use(ns), now;
			dropObject("procedure", nm);
			Poco::Data::RecordSet rs(stat);
			assert(1 == rs.rowCount());
			bool nl = rs.isNull(size_t(0), 0);
			assert( nl );
		}
		{
			Poco::Data::Statement stat(session());
			stat << "{ exec  -- @exType='mdExch', @exList='TRAD' }", Poco::Data::Keywords::limit(1);
			while (!stat.done())
			{
				stat.execute();
				Poco::Data::RecordSet rs(stat);
				assert(0 == rs.rowCount());
			}
		}

		session() << "create procedure " + nm + " "
			"@outParam int output "
			"as "
			"select @outParam = -1", now;

		int i = 0;
		session() << "{ call " << nm << "(?) }", out(i), now;
		dropObject("procedure", nm);
		assert(-1 == i);

		session() << "create procedure " + nm + " "
			"@inParam int, @outParam int output "
			"as "
			"select @outParam = @inParam * @inParam"
			, now;

		i = 2;
		int j = 0;
		session() << "{ call " << nm << "(?, ?)} ", in(i), out(j), now;
		dropObject("procedure", nm);
		assert(4 == j);

		session() << "create procedure " + nm + " "
			"@ioParam int output "
			"as "
			"select @ioParam = @ioParam * @ioParam"
			, now;

		i = 2;
		session() << "{ call " << nm << "(?) }", io(i), now;
		dropObject("procedure", nm);
		assert(4 == i);

		session() << "create procedure " + nm + " "
			"@inParam varchar(1000), @outParam varchar(1000) output "
			"as "
			"select @outParam = @inParam"
			, now;

		std::string inParam =
			"1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890"
			"1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890"
			"1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890"
			"1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890"
			"1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890"
			"1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890"
			"1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890"
			"1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890"
			"1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890";
		std::string outParam;
		session() << "{ call " << nm << "(?,?) }", in(inParam), out(outParam), now;
		dropObject("procedure", nm);
		assert(inParam == outParam);

		k += 2;
	}
}

void SybaseODBC::testStoredProcedureDynamicAny()
{
	const std::string nm(ExecUtil::stored_proc());
	dropObject("procedure", nm);

	for (int k = 0; k < 8;)
	{
		session().setFeature("autoBind", bindValue(k));

		DynamicAny i = 2;
		DynamicAny j = 0;

		session() << "create procedure " << nm << " "
			"@inParam int, @outParam int output "
			"as "
			"select @outParam = @inParam * @inParam"
			, now;

		session() << "{ call " << nm << "(?, ?) }", in(i), out(j), now;
		dropObject("procedure", nm);
		assert(4 == j);

		session() << "create procedure " << nm << " @outParam int output "
			"as "
			"select @outParam = @outParam * @outParam"
			, now;

		i = 2;
		session() << "{ call " << nm << "(?) }", io(i), now;
		dropObject("procedure", nm);
		assert(4 == i);

		k += 2;
	}
}

void SybaseODBC::testStoredProcedureAny()
{
	const std::string nm(ExecUtil::stored_proc());
	dropObject("procedure", nm);

	for (int k = 0; k < 8;)
	{
		session().setFeature("autoBind", bindValue(k));
		session().setFeature("autoExtract", bindValue(k + 1));

		Any i = 2;
		Any j = 0;

		session() << "create procedure " << nm << " "
			"@inParam int, @outParam int output "
			"as "
			"select @outParam = @inParam * @inParam"
			, now;

		session() << "{ call " << nm << "(?, ?) }", in(i), out(j), now;

		dropObject("procedure", nm);
		assert(4 == AnyCast<int>(j));

		session() << "create procedure " << nm << " @outParam int output "
			"as "
			"select @outParam = @outParam * @outParam"
			, now;

		i = 2;
		session() << "{ call " << nm << "(?) }", io(i), now;
		dropObject("procedure", nm);
		assert(4 == AnyCast<int>(i));

		session() << "create procedure " << nm << " "
			"@i int , @f float , @s1 varchar(10) , @d date , @t time , @dt datetime , @bin binary , @res int output"
			" as "
			"select @res = 11 where (@i is null) and (@f is null) and (@s1 is null) and (@d is null) and (@t is null) and (@dt is null) and (@bin is null)"
			, now;
		Poco::Dynamic::Var res(0);
		Poco::Dynamic::Var null;
		Poco::Data::Statement stat(session());
		stat << "{ call " << nm << "(?,?,?,?,?,?,?  ?) }";
		stat.addBind(Poco::Data::Keywords::bind(Poco::Data::DATA_NULL_INTEGER));
		stat.addBind(Poco::Data::Keywords::bind(Poco::Data::DATA_NULL_FLOAT));
		stat.addBind(Poco::Data::Keywords::bind(Poco::Data::DATA_NULL_STRING));
		stat.addBind(Poco::Data::Keywords::bind(Poco::Data::DATA_NULL_DATE));
		stat.addBind(Poco::Data::Keywords::bind(Poco::Dynamic::Var(Poco::Data::DATA_NULL_TIME)));
		stat.addBind(Poco::Data::Keywords::bind(Poco::Data::DATA_NULL_DATETIME));
		stat.addBind(Poco::Data::Keywords::bind(Poco::Dynamic::Var(Poco::Data::DATA_NULL_BLOB)));
			
		stat.addBind(Poco::Data::Keywords::out(res));
		stat.execute();
		dropObject("procedure", nm);
		assert(11 == res.extract<int>());

		k += 2;
	}
}


void SybaseODBC::testTransaction()
{
	if (!&session())fail("Test not available.");

	for (int i = 0; i < 8;)
	{
		doPersonTable(" UNIQUE ");
		session().setFeature("autoBind", bindValue(i));
		session().setFeature("autoExtract", bindValue(i + 1));
		executor().transaction(dbConnString());
		i += 2;
	}
}

/*static*/
CppUnit::Test* SybaseODBC::suite()
{
	if ((_pSession = init(_driver, _dsn, _uid, _pwd, _connectString)))
	{
		std::cout << "*** Connected to [" << _driver << "] test database." << std::endl;

		_pExecutor = new SQLExecutor(_driver + " SQL Executor", _pSession);

		CppUnit::TestSuite* pSuite = new CppUnit::TestSuite("SybaseODBC");

		CppUnit_addTest(pSuite, SybaseODBC, testBareboneODBC);
		CppUnit_addTest(pSuite, SybaseODBC, testSyntaxError);
		CppUnit_addTest(pSuite, SybaseODBC, testSimpleAccess);
		CppUnit_addTest(pSuite, SybaseODBC, testComplexType);
		CppUnit_addTest(pSuite, SybaseODBC, testSimpleAccessVector);
		CppUnit_addTest(pSuite, SybaseODBC, testComplexTypeVector);
		CppUnit_addTest(pSuite, SybaseODBC, testSharedPtrComplexTypeVector);
		CppUnit_addTest(pSuite, SybaseODBC, testAutoPtrComplexTypeVector);
		CppUnit_addTest(pSuite, SybaseODBC, testInsertVector);
		CppUnit_addTest(pSuite, SybaseODBC, testInsertEmptyVector);
		CppUnit_addTest(pSuite, SybaseODBC, testSimpleAccessList);
		CppUnit_addTest(pSuite, SybaseODBC, testComplexTypeList);
		CppUnit_addTest(pSuite, SybaseODBC, testInsertList);
		CppUnit_addTest(pSuite, SybaseODBC, testInsertEmptyList);
		CppUnit_addTest(pSuite, SybaseODBC, testSimpleAccessDeque);
		CppUnit_addTest(pSuite, SybaseODBC, testComplexTypeDeque);
		CppUnit_addTest(pSuite, SybaseODBC, testInsertDeque);
		CppUnit_addTest(pSuite, SybaseODBC, testInsertEmptyDeque);
		CppUnit_addTest(pSuite, SybaseODBC, testAffectedRows);
		CppUnit_addTest(pSuite, SybaseODBC, testInsertSingleBulk);
		CppUnit_addTest(pSuite, SybaseODBC, testInsertSingleBulkVec);
		CppUnit_addTest(pSuite, SybaseODBC, testLimit);
		CppUnit_addTest(pSuite, SybaseODBC, testLimitOnce);
		CppUnit_addTest(pSuite, SybaseODBC, testLimitPrepare);
		CppUnit_addTest(pSuite, SybaseODBC, testLimitZero);
		CppUnit_addTest(pSuite, SybaseODBC, testPrepare);
		CppUnit_addTest(pSuite, SybaseODBC, testBulk);
		CppUnit_addTest(pSuite, SybaseODBC, testBulkPerformance);
		CppUnit_addTest(pSuite, SybaseODBC, testSetSimple);
		CppUnit_addTest(pSuite, SybaseODBC, testSetComplex);
		CppUnit_addTest(pSuite, SybaseODBC, testSetComplexUnique);
		CppUnit_addTest(pSuite, SybaseODBC, testMultiSetSimple);
		CppUnit_addTest(pSuite, SybaseODBC, testMultiSetComplex);
		CppUnit_addTest(pSuite, SybaseODBC, testMapComplex);
		CppUnit_addTest(pSuite, SybaseODBC, testMapComplexUnique);
		CppUnit_addTest(pSuite, SybaseODBC, testMultiMapComplex);
		CppUnit_addTest(pSuite, SybaseODBC, testSelectIntoSingle);
		CppUnit_addTest(pSuite, SybaseODBC, testSelectIntoSingleStep);
		CppUnit_addTest(pSuite, SybaseODBC, testSelectIntoSingleFail);
		CppUnit_addTest(pSuite, SybaseODBC, testLowerLimitOk);
		CppUnit_addTest(pSuite, SybaseODBC, testLowerLimitFail);
		CppUnit_addTest(pSuite, SybaseODBC, testCombinedLimits);
		CppUnit_addTest(pSuite, SybaseODBC, testCombinedIllegalLimits);
		CppUnit_addTest(pSuite, SybaseODBC, testRange);
		CppUnit_addTest(pSuite, SybaseODBC, testIllegalRange);
		CppUnit_addTest(pSuite, SybaseODBC, testSingleSelect);
		CppUnit_addTest(pSuite, SybaseODBC, testEmptyDB);
		CppUnit_addTest(pSuite, SybaseODBC, testBLOB);
		CppUnit_addTest(pSuite, SybaseODBC, testBLOBContainer);
		CppUnit_addTest(pSuite, SybaseODBC, testBLOBStmt);
		CppUnit_addTest(pSuite, SybaseODBC, testDate);
		CppUnit_addTest(pSuite, SybaseODBC, testTime);
		CppUnit_addTest(pSuite, SybaseODBC, testDateTime);
		CppUnit_addTest(pSuite, SybaseODBC, testFloat);
		CppUnit_addTest(pSuite, SybaseODBC, testDouble);
		CppUnit_addTest(pSuite, SybaseODBC, testTuple);
		CppUnit_addTest(pSuite, SybaseODBC, testTupleVector);
		CppUnit_addTest(pSuite, SybaseODBC, testInternalExtraction);
		CppUnit_addTest(pSuite, SybaseODBC, testFilter);
		CppUnit_addTest(pSuite, SybaseODBC, testInternalBulkExtraction);
		CppUnit_addTest(pSuite, SybaseODBC, testInternalStorageType);
		CppUnit_addTest(pSuite, SybaseODBC, testStoredProcedure);
		CppUnit_addTest(pSuite, SybaseODBC, testStoredProcedureAny);
		CppUnit_addTest(pSuite, SybaseODBC, testStoredProcedureDynamicAny);
		CppUnit_addTest(pSuite, SybaseODBC, testNull);
		CppUnit_addTest(pSuite, SybaseODBC, testRowIterator);
		CppUnit_addTest(pSuite, SybaseODBC, testAsync);
		CppUnit_addTest(pSuite, SybaseODBC, testAny);
		CppUnit_addTest(pSuite, SybaseODBC, testDynamicAny);
		CppUnit_addTest(pSuite, SybaseODBC, testMultipleResults);
		CppUnit_addTest(pSuite, SybaseODBC, testMultipleResultsNoProj);
		CppUnit_addTest(pSuite, SybaseODBC, testSQLChannel); // this test may suffer from race conditions
		CppUnit_addTest(pSuite, SybaseODBC, testSQLLogger);
		//CppUnit_addTest(pSuite, SybaseODBC, testSessionTransaction); // this test fails when connection is fast
		CppUnit_addTest(pSuite, SybaseODBC, testTransaction);
		CppUnit_addTest(pSuite, SybaseODBC, testTransactor);
		CppUnit_addTest(pSuite, SybaseODBC, testNullable);
		CppUnit_addTest(pSuite, SybaseODBC, testReconnect);
		CppUnit_addTest(pSuite, SybaseODBC, testNumeric);
		CppUnit_addTest(pSuite, SybaseODBC, testInsertStatReuse);

		_pExecutor = 0;
		_pSession = 0;

		return pSuite;
	}

	return 0;
}
