Aleksandar Fabijanic 19 лет назад
Родитель
Сommit
c1ecb3ee05
30 измененных файлов с 1145 добавлено и 207 удалено
  1. 1 1
      Data/ODBC/include/Poco/Data/ODBC/ODBCStatementImpl.h
  2. 10 9
      Data/ODBC/src/ODBCStatementImpl.cpp
  3. 16 0
      Data/ODBC/testsuite/src/ODBCDB2Test.cpp
  4. 1 0
      Data/ODBC/testsuite/src/ODBCDB2Test.h
  5. 45 28
      Data/ODBC/testsuite/src/ODBCMySQLTest.cpp
  6. 5 1
      Data/ODBC/testsuite/src/ODBCMySQLTest.h
  7. 117 84
      Data/ODBC/testsuite/src/ODBCOracleTest.cpp
  8. 2 0
      Data/ODBC/testsuite/src/ODBCOracleTest.h
  9. 18 0
      Data/ODBC/testsuite/src/ODBCPostgreSQLTest.cpp
  10. 1 0
      Data/ODBC/testsuite/src/ODBCPostgreSQLTest.h
  11. 154 13
      Data/ODBC/testsuite/src/ODBCSQLServerTest.cpp
  12. 5 1
      Data/ODBC/testsuite/src/ODBCSQLServerTest.h
  13. 16 0
      Data/ODBC/testsuite/src/ODBCSQLiteTest.cpp
  14. 1 0
      Data/ODBC/testsuite/src/ODBCSQLiteTest.h
  15. 73 3
      Data/ODBC/testsuite/src/SQLExecutor.cpp
  16. 1 0
      Data/ODBC/testsuite/src/SQLExecutor.h
  17. 31 0
      Data/include/Poco/Data/AbstractSessionImpl.h
  18. 136 9
      Data/include/Poco/Data/Column.h
  19. 3 3
      Data/include/Poco/Data/Extraction.h
  20. 33 11
      Data/include/Poco/Data/RecordSet.h
  21. 49 1
      Data/include/Poco/Data/Statement.h
  22. 82 6
      Data/include/Poco/Data/StatementImpl.h
  23. 13 13
      Data/src/RecordSet.cpp
  24. 53 0
      Data/src/Statement.cpp
  25. 115 14
      Data/src/StatementImpl.cpp
  26. 153 2
      Data/testsuite/src/DataTest.cpp
  27. 3 1
      Data/testsuite/src/DataTest.h
  28. 1 1
      Data/testsuite/src/SessionImpl.cpp
  29. 3 1
      Data/testsuite/src/TestStatementImpl.cpp
  30. 4 5
      Data/testsuite/src/TestStatementImpl.h

+ 1 - 1
Data/ODBC/include/Poco/Data/ODBC/ODBCStatementImpl.h

@@ -128,7 +128,7 @@ private:
 	void fillColumns();
 	void checkError(SQLRETURN rc, const std::string& msg="");
 
-	SessionImpl&                 _rSession;
+	const SQLHDBC&               _rConnection;
 	const StatementHandle        _stmt;
 	Poco::SharedPtr<Preparation> _pPreparation;
 	Poco::SharedPtr<Binder>      _pBinder;

+ 10 - 9
Data/ODBC/src/ODBCStatementImpl.cpp

@@ -35,7 +35,7 @@
 
 
 #include "Poco/Data/ODBC/ODBCStatementImpl.h"
-#include "Poco/Data/ODBC/Handle.h"
+#include "Poco/Data/ODBC/ConnectionHandle.h"
 #include "Poco/Data/ODBC/Utility.h"
 #include "Poco/Data/ODBC/ODBCException.h"
 #include "Poco/Data/AbstractPrepare.h"
@@ -51,8 +51,9 @@ const std::string ODBCStatementImpl::INVALID_CURSOR_STATE = "24000";
 
 
 ODBCStatementImpl::ODBCStatementImpl(SessionImpl& rSession):
-	_rSession(rSession),
-	_stmt(_rSession.dbc()),
+	Poco::Data::StatementImpl(rSession),
+	_rConnection(rSession.dbc()),
+	_stmt(rSession.dbc()),
 	_stepCalled(false),
 	_nextResponse(0)
 {
@@ -62,7 +63,7 @@ ODBCStatementImpl::ODBCStatementImpl(SessionImpl& rSession):
 		0),
 			"SQLSetStmtAttr(SQL_CURSOR_TYPE, SQL_CURSOR_FORWARD_ONLY)");
 
-	if (_rSession.getFeature("autoBind"))
+	if (session().getFeature("autoBind"))
 	{
 		SQLSetStmtAttr(_stmt, 
 			SQL_ATTR_PARAM_BIND_TYPE, 
@@ -96,16 +97,16 @@ void ODBCStatementImpl::compileImpl()
 	if (statement.empty())
 		throw ODBCException("Empty statements are illegal");
 
-	Preparation::DataExtraction ext = _rSession.getFeature("autoExtract") ? 
+	Preparation::DataExtraction ext = session().getFeature("autoExtract") ? 
 		Preparation::DE_BOUND : Preparation::DE_MANUAL;
 	
-	std::size_t maxFieldSize = AnyCast<std::size_t>(_rSession.getProperty("maxFieldSize"));
+	std::size_t maxFieldSize = AnyCast<std::size_t>(session().getProperty("maxFieldSize"));
 	_pPreparation = new Preparation(_stmt, 
 		statement, 
 		maxFieldSize,
 		ext);
 
-	Binder::ParameterBinding bind = _rSession.getFeature("autoBind") ? 
+	Binder::ParameterBinding bind = session().getFeature("autoBind") ? 
 		Binder::PB_IMMEDIATE : Binder::PB_AT_EXEC;
 
 	_pBinder = new Binder(_stmt, bind);
@@ -274,7 +275,7 @@ std::string ODBCStatementImpl::nativeSQL()
 		pNative = new char[retlen];
 		memset(pNative, 0, retlen);
 		length = retlen;
-		if (Utility::isError(SQLNativeSql(_rSession.dbc(),
+		if (Utility::isError(SQLNativeSql(_rConnection,
 			(POCO_SQLCHAR*) statement.c_str(),
 			(SQLINTEGER) statement.size(),
 			(POCO_SQLCHAR*) pNative,
@@ -282,7 +283,7 @@ std::string ODBCStatementImpl::nativeSQL()
 			&retlen)))
 		{
 			delete [] pNative;
-			throw ConnectionException(_rSession.dbc(), "SQLNativeSql()");
+			throw ConnectionException(_rConnection, "SQLNativeSql()");
 		}
 		++retlen;//accomodate for terminating '\0'
 	}while (retlen > length);

+ 16 - 0
Data/ODBC/testsuite/src/ODBCDB2Test.cpp

@@ -828,6 +828,21 @@ void ODBCDB2Test::testInternalExtraction()
 }
 
 
+void ODBCDB2Test::testInternalStorageType()
+{
+	if (!_pSession) fail ("Test not available.");
+
+	for (int i = 0; i < 8;)
+	{
+		recreateVectorsTable();
+		_pSession->setFeature("autoBind", bindValues[i]);
+		_pSession->setFeature("autoExtract", bindValues[i+1]);
+		_pExecutor->internalStorageType();
+		i += 2;
+	}
+}
+
+
 void ODBCDB2Test::dropTable(const std::string& tableName)
 {
 	try
@@ -1056,6 +1071,7 @@ CppUnit::Test* ODBCDB2Test::suite()
 		CppUnit_addTest(pSuite, ODBCDB2Test, testTuple);
 		CppUnit_addTest(pSuite, ODBCDB2Test, testTupleVector);
 		CppUnit_addTest(pSuite, ODBCDB2Test, testInternalExtraction);
+		CppUnit_addTest(pSuite, ODBCDB2Test, testInternalStorageType);
 
 		return pSuite;
 	}

+ 1 - 0
Data/ODBC/testsuite/src/ODBCDB2Test.h

@@ -115,6 +115,7 @@ public:
 	void testTupleVector();
 
 	void testInternalExtraction();
+	void testInternalStorageType();
 
 	void setUp();
 	void tearDown();

+ 45 - 28
Data/ODBC/testsuite/src/ODBCMySQLTest.cpp

@@ -35,6 +35,7 @@
 #include "CppUnit/TestSuite.h"
 #include "Poco/String.h"
 #include "Poco/Format.h"
+#include "Poco/Tuple.h"
 #include "Poco/Exception.h"
 #include "Poco/Data/Common.h"
 #include "Poco/Data/BLOB.h"
@@ -54,6 +55,7 @@ using Poco::Data::ODBC::ConnectionException;
 using Poco::Data::ODBC::StatementException;
 using Poco::Data::ODBC::StatementDiagnostics;
 using Poco::format;
+using Poco::Tuple;
 using Poco::NotFoundException;
 
 
@@ -817,34 +819,46 @@ void ODBCMySQLTest::testInternalExtraction()
 }
 
 
-void ODBCMySQLTest::dropTable(const std::string& tableName)
+void ODBCMySQLTest::testInternalStorageType()
 {
-	try
+	if (!_pSession) fail ("Test not available.");
+
+	for (int i = 0; i < 8;)
 	{
-		*_pSession << format("DROP TABLE %s", tableName), now;
+		recreateVectorsTable();
+		_pSession->setFeature("autoBind", bindValues[i]);
+		_pSession->setFeature("autoExtract", bindValues[i+1]);
+		_pExecutor->internalStorageType();
+		i += 2;
 	}
-	catch (StatementException& ex)
-	{
-		bool ignoreError = false;
-		const StatementDiagnostics::FieldVec& flds = ex.diagnostics().fields();
-		StatementDiagnostics::Iterator it = flds.begin();
-		for (; it != flds.end(); ++it)
-		{
-			if (1051 == it->_nativeError)//(table does not exist)
-			{
-				ignoreError = true;
-				break;
-			}
-		}
+}
 
-		if (!ignoreError) throw;
-	}
+
+void ODBCMySQLTest::testStoredProcedure()
+{
+	//MySQL is currently buggy in this area: 
+	// http://bugs.mysql.com/bug.php?id=17898
+	// http://bugs.mysql.com/bug.php?id=27632
+}
+
+
+void ODBCMySQLTest::testStoredFunction()
+{
+	//MySQL is currently buggy in this area: 
+	// http://bugs.mysql.com/bug.php?id=17898
+	// http://bugs.mysql.com/bug.php?id=27632
+}
+
+
+void ODBCMySQLTest::dropObject(const std::string& type, const std::string& name)
+{
+	*_pSession << format("DROP %s IF EXISTS %s", type, name), now;
 }
 
 
 void ODBCMySQLTest::recreatePersonTable()
 {
-	dropTable("Person");
+	dropObject("TABLE", "Person");
 	try { *_pSession << "CREATE TABLE Person (LastName VARCHAR(30), 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()"); }
@@ -853,7 +867,7 @@ void ODBCMySQLTest::recreatePersonTable()
 
 void ODBCMySQLTest::recreatePersonBLOBTable()
 {
-	dropTable("Person");
+	dropObject("TABLE", "Person");
 	try { *_pSession << "CREATE TABLE Person (LastName VARCHAR(30), FirstName VARCHAR(30), Address VARCHAR(30), Image BLOB)", now; }
 	catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail ("recreatePersonBLOBTable()"); }
 	catch(StatementException& se){ std::cout << se.toString() << std::endl; fail ("recreatePersonBLOBTable()"); }
@@ -862,7 +876,7 @@ void ODBCMySQLTest::recreatePersonBLOBTable()
 
 void ODBCMySQLTest::recreateIntsTable()
 {
-	dropTable("Strings");
+	dropObject("TABLE", "Strings");
 	try { *_pSession << "CREATE TABLE 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()"); }
@@ -871,7 +885,7 @@ void ODBCMySQLTest::recreateIntsTable()
 
 void ODBCMySQLTest::recreateStringsTable()
 {
-	dropTable("Strings");
+	dropObject("TABLE", "Strings");
 	try { *_pSession << "CREATE TABLE 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()"); }
@@ -880,7 +894,7 @@ void ODBCMySQLTest::recreateStringsTable()
 
 void ODBCMySQLTest::recreateFloatsTable()
 {
-	dropTable("Strings");
+	dropObject("TABLE", "Strings");
 	try { *_pSession << "CREATE TABLE 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()"); }
@@ -889,7 +903,7 @@ void ODBCMySQLTest::recreateFloatsTable()
 
 void ODBCMySQLTest::recreateTuplesTable()
 {
-	dropTable("Tuples");
+	dropObject("TABLE", "Tuples");
 	try { *_pSession << "CREATE TABLE Tuples "
 		"(i0 INTEGER, i1 INTEGER, i2 INTEGER, i3 INTEGER, i4 INTEGER, i5 INTEGER, i6 INTEGER, "
 		"i7 INTEGER, i8 INTEGER, i9 INTEGER, i10 INTEGER, i11 INTEGER, i12 INTEGER, i13 INTEGER,"
@@ -901,7 +915,7 @@ void ODBCMySQLTest::recreateTuplesTable()
 
 void ODBCMySQLTest::recreateVectorsTable()
 {
-	dropTable("Vectors");
+	dropObject("TABLE", "Vectors");
 	try { *_pSession << "CREATE TABLE 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()"); }
@@ -959,9 +973,9 @@ void ODBCMySQLTest::setUp()
 
 void ODBCMySQLTest::tearDown()
 {
-	dropTable("Person");
-	dropTable("Strings");
-	dropTable("Tuples");
+	dropObject("TABLE", "Person");
+	dropObject("TABLE", "Strings");
+	dropObject("TABLE", "Tuples");
 }
 
 
@@ -1046,7 +1060,10 @@ CppUnit::Test* ODBCMySQLTest::suite()
 		CppUnit_addTest(pSuite, ODBCMySQLTest, testDouble);
 		CppUnit_addTest(pSuite, ODBCMySQLTest, testTuple);
 		CppUnit_addTest(pSuite, ODBCMySQLTest, testTupleVector);
+		CppUnit_addTest(pSuite, ODBCMySQLTest, testStoredProcedure);
+		CppUnit_addTest(pSuite, ODBCMySQLTest, testStoredFunction);
 		CppUnit_addTest(pSuite, ODBCMySQLTest, testInternalExtraction);
+		CppUnit_addTest(pSuite, ODBCMySQLTest, testInternalStorageType);
 
 		return pSuite;
 	}

+ 5 - 1
Data/ODBC/testsuite/src/ODBCMySQLTest.h

@@ -118,6 +118,10 @@ public:
 	void testTupleVector();
 
 	void testInternalExtraction();
+	void testInternalStorageType();
+
+	void testStoredProcedure();
+	void testStoredFunction();
 
 	void setUp();
 	void tearDown();
@@ -125,7 +129,7 @@ public:
 	static CppUnit::Test* suite();
 
 private:
-	void dropTable(const std::string& tableName);
+	void dropObject(const std::string& type, const std::string& name);
 	void recreatePersonTable();
 	void recreatePersonBLOBTable();
 	void recreateStringsTable();

+ 117 - 84
Data/ODBC/testsuite/src/ODBCOracleTest.cpp

@@ -827,100 +827,132 @@ void ODBCOracleTest::testInternalExtraction()
 }
 
 
-void ODBCOracleTest::testStoredProcedure()
+void ODBCOracleTest::testInternalStorageType()
 {
-	*_pSession << "CREATE OR REPLACE "
-		"PROCEDURE storedProcedure(outParam OUT NUMBER) IS "
-		" BEGIN outParam := -1; "
-		"END storedProcedure;" , now;
-
-	int i = 0;
-	*_pSession << "{call storedProcedure(?)}", out(i), now;
-	assert(-1 == i);
-	*_pSession << "DROP PROCEDURE storedProcedure;", now;
+	if (!_pSession) fail ("Test not available.");
 
-	*_pSession << "CREATE OR REPLACE "
-		"PROCEDURE storedProcedure(inParam IN NUMBER, outParam OUT NUMBER) IS "
-		" BEGIN outParam := inParam*inParam; "
-		"END storedProcedure;" , now;
+	for (int i = 0; i < 8;)
+	{
+		recreateVectorsTable();
+		_pSession->setFeature("autoBind", bindValues[i]);
+		_pSession->setFeature("autoExtract", bindValues[i+1]);
+		_pExecutor->internalStorageType();
+		i += 2;
+	}
+}
 
-	i = 2;
-	int j = 0;
-	*_pSession << "{call storedProcedure(?, ?)}", in(i), out(j), now;
-	assert(4 == j);
-	*_pSession << "DROP PROCEDURE storedProcedure;", now;
 
-	*_pSession << "CREATE OR REPLACE "
-		"PROCEDURE storedProcedure(ioParam IN OUT NUMBER) IS "
-		" BEGIN ioParam := ioParam*ioParam; "
-		" END storedProcedure;" , now;
+void ODBCOracleTest::testStoredProcedure()
+{
+	if (!_pSession) fail ("Test not available.");
 
-	i = 2;
-	*_pSession << "{call storedProcedure(?)}", io(i), now;
-	assert(4 == i);
-	*_pSession << "DROP PROCEDURE storedProcedure;", now;
+	for (int k = 0; k < 8;)
+	{
+		_pSession->setFeature("autoBind", bindValues[k]);
+		_pSession->setFeature("autoExtract", bindValues[k+1]);
+
+		*_pSession << "CREATE OR REPLACE "
+			"PROCEDURE storedProcedure(outParam OUT NUMBER) IS "
+			" BEGIN outParam := -1; "
+			"END storedProcedure;" , now;
+
+		int i = 0;
+		*_pSession << "{call storedProcedure(?)}", out(i), now;
+		assert(-1 == i);
+		*_pSession << "DROP PROCEDURE storedProcedure;", now;
+
+		*_pSession << "CREATE OR REPLACE "
+			"PROCEDURE storedProcedure(inParam IN NUMBER, outParam OUT NUMBER) IS "
+			" BEGIN outParam := inParam*inParam; "
+			"END storedProcedure;" , now;
+
+		i = 2;
+		int j = 0;
+		*_pSession << "{call storedProcedure(?, ?)}", in(i), out(j), now;
+		assert(4 == j);
+		*_pSession << "DROP PROCEDURE storedProcedure;", now;
+
+		*_pSession << "CREATE OR REPLACE "
+			"PROCEDURE storedProcedure(ioParam IN OUT NUMBER) IS "
+			" BEGIN ioParam := ioParam*ioParam; "
+			" END storedProcedure;" , now;
+
+		i = 2;
+		*_pSession << "{call storedProcedure(?)}", io(i), now;
+		assert(4 == i);
+		*_pSession << "DROP PROCEDURE storedProcedure;", now;
+
+		k += 2;
+	}
 }
 
 
 void ODBCOracleTest::testStoredFunction()
 {
-	*_pSession << "CREATE OR REPLACE "
-		"FUNCTION storedFunction RETURN NUMBER IS "
-		" BEGIN return(-1); "
-		" END storedFunction;" , now;
-
-	int i = 0;
-	*_pSession << "{? = call storedFunction()}", out(i), now;
-	assert(-1 == i);
-	*_pSession << "DROP FUNCTION storedFunction;", now;
-
-	*_pSession << "CREATE OR REPLACE "
-		"FUNCTION storedFunction(inParam IN NUMBER) RETURN NUMBER IS "
-		" BEGIN RETURN(inParam*inParam); "
-		" END storedFunction;" , now;
-
-	i = 2;
-	int result = 0;
-	*_pSession << "{? = call storedFunction(?)}", out(result), in(i), now;
-	assert(4 == result);
-	*_pSession << "DROP FUNCTION storedFunction;", now;
-
-	*_pSession << "CREATE OR REPLACE "
-		"FUNCTION storedFunction(inParam IN NUMBER, outParam OUT NUMBER) RETURN NUMBER IS "
-		" BEGIN outParam := inParam*inParam; RETURN(outParam); "
-		" END storedFunction;" , now;
-
-	i = 2;
-	int j = 0;
-	result = 0;
-	*_pSession << "{? = call storedFunction(?, ?)}", out(result), in(i), out(j), now;
-	assert(4 == j);
-	assert(j == result); 
-	*_pSession << "DROP FUNCTION storedFunction;", now;
-
-	*_pSession << "CREATE OR REPLACE "
-		"FUNCTION storedFunction(param1 IN OUT NUMBER, param2 IN OUT NUMBER) RETURN NUMBER IS "
-		" temp NUMBER := param1; "
-		" BEGIN param1 := param2; param2 := temp; RETURN(param1+param2); "
-		" END storedFunction;" , now;
-
-	i = 1;
-	j = 2;
-	result = 0;
-	*_pSession << "{? = call storedFunction(?, ?)}", out(result), io(i), io(j), now;
-	assert(1 == j);
-	assert(2 == i);
-	assert(3 == result); 
-	
-	Tuple<int, int> params(1, 2);
-	assert(1 == params.get<0>());
-	assert(2 == params.get<1>());
-	result = 0;
-	*_pSession << "{? = call storedFunction(?, ?)}", out(result), io(params), now;
-	assert(1 == params.get<1>());
-	assert(2 == params.get<0>());
-	assert(3 == result); 
-	*_pSession << "DROP FUNCTION storedFunction;", now;
+	if (!_pSession) fail ("Test not available.");
+
+	for (int k = 0; k < 8;)
+	{
+		*_pSession << "CREATE OR REPLACE "
+			"FUNCTION storedFunction RETURN NUMBER IS "
+			" BEGIN return(-1); "
+			" END storedFunction;" , now;
+
+		int i = 0;
+		*_pSession << "{? = call storedFunction()}", out(i), now;
+		assert(-1 == i);
+		*_pSession << "DROP FUNCTION storedFunction;", now;
+
+		*_pSession << "CREATE OR REPLACE "
+			"FUNCTION storedFunction(inParam IN NUMBER) RETURN NUMBER IS "
+			" BEGIN RETURN(inParam*inParam); "
+			" END storedFunction;" , now;
+
+		i = 2;
+		int result = 0;
+		*_pSession << "{? = call storedFunction(?)}", out(result), in(i), now;
+		assert(4 == result);
+		*_pSession << "DROP FUNCTION storedFunction;", now;
+
+		*_pSession << "CREATE OR REPLACE "
+			"FUNCTION storedFunction(inParam IN NUMBER, outParam OUT NUMBER) RETURN NUMBER IS "
+			" BEGIN outParam := inParam*inParam; RETURN(outParam); "
+			" END storedFunction;" , now;
+
+		i = 2;
+		int j = 0;
+		result = 0;
+		*_pSession << "{? = call storedFunction(?, ?)}", out(result), in(i), out(j), now;
+		assert(4 == j);
+		assert(j == result); 
+		*_pSession << "DROP FUNCTION storedFunction;", now;
+
+		*_pSession << "CREATE OR REPLACE "
+			"FUNCTION storedFunction(param1 IN OUT NUMBER, param2 IN OUT NUMBER) RETURN NUMBER IS "
+			" temp NUMBER := param1; "
+			" BEGIN param1 := param2; param2 := temp; RETURN(param1+param2); "
+			" END storedFunction;" , now;
+
+		i = 1;
+		j = 2;
+		result = 0;
+		*_pSession << "{? = call storedFunction(?, ?)}", out(result), io(i), io(j), now;
+		assert(1 == j);
+		assert(2 == i);
+		assert(3 == result); 
+		
+		Tuple<int, int> params(1, 2);
+		assert(1 == params.get<0>());
+		assert(2 == params.get<1>());
+		result = 0;
+		*_pSession << "{? = call storedFunction(?, ?)}", out(result), io(params), now;
+		assert(1 == params.get<1>());
+		assert(2 == params.get<0>());
+		assert(3 == result); 
+		*_pSession << "DROP FUNCTION storedFunction;", now;
+
+		k = k + 2;
+	}
 }
 
 
@@ -1176,6 +1208,7 @@ CppUnit::Test* ODBCOracleTest::suite()
 		CppUnit_addTest(pSuite, ODBCOracleTest, testStoredProcedure);
 		CppUnit_addTest(pSuite, ODBCOracleTest, testStoredFunction);
 		CppUnit_addTest(pSuite, ODBCOracleTest, testInternalExtraction);
+		CppUnit_addTest(pSuite, ODBCOracleTest, testInternalStorageType);
 
 		return pSuite;
 	}

+ 2 - 0
Data/ODBC/testsuite/src/ODBCOracleTest.h

@@ -116,6 +116,8 @@ public:
 	void testTupleVector();
 
 	void testInternalExtraction();
+	void testInternalStorageType();
+
 	void testStoredProcedure();
 	void testStoredFunction();
 

+ 18 - 0
Data/ODBC/testsuite/src/ODBCPostgreSQLTest.cpp

@@ -35,6 +35,7 @@
 #include "CppUnit/TestSuite.h"
 #include "Poco/String.h"
 #include "Poco/Format.h"
+#include "Poco/Tuple.h"
 #include "Poco/Exception.h"
 #include "Poco/Data/Common.h"
 #include "Poco/Data/BLOB.h"
@@ -54,6 +55,7 @@ using Poco::Data::ODBC::ConnectionException;
 using Poco::Data::ODBC::StatementException;
 using Poco::Data::ODBC::StatementDiagnostics;
 using Poco::format;
+using Poco::Tuple;
 using Poco::NotFoundException;
 
 
@@ -811,6 +813,21 @@ void ODBCPostgreSQLTest::testInternalExtraction()
 }
 
 
+void ODBCPostgreSQLTest::testInternalStorageType()
+{
+	if (!_pSession) fail ("Test not available.");
+
+	for (int i = 0; i < 8;)
+	{
+		recreateVectorsTable();
+		_pSession->setFeature("autoBind", bindValues[i]);
+		_pSession->setFeature("autoExtract", bindValues[i+1]);
+		_pExecutor->internalStorageType();
+		i += 2;
+	}
+}
+
+
 void ODBCPostgreSQLTest::dropTable(const std::string& tableName)
 {
 	try
@@ -1068,6 +1085,7 @@ CppUnit::Test* ODBCPostgreSQLTest::suite()
 		CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testTuple);
 		CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testTupleVector);
 		CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testInternalExtraction);
+		CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testInternalStorageType);
 
 		return pSuite;
 	}

+ 1 - 0
Data/ODBC/testsuite/src/ODBCPostgreSQLTest.h

@@ -118,6 +118,7 @@ public:
 	void testTupleVector();
 
 	void testInternalExtraction();
+	void testInternalStorageType();
 
 	void setUp();
 	void tearDown();

+ 154 - 13
Data/ODBC/testsuite/src/ODBCSQLServerTest.cpp

@@ -35,6 +35,7 @@
 #include "CppUnit/TestSuite.h"
 #include "Poco/String.h"
 #include "Poco/Format.h"
+#include "Poco/Tuple.h"
 #include "Poco/Exception.h"
 #include "Poco/Data/Common.h"
 #include "Poco/Data/BLOB.h"
@@ -54,6 +55,7 @@ using Poco::Data::ODBC::ConnectionException;
 using Poco::Data::ODBC::StatementException;
 using Poco::Data::ODBC::StatementDiagnostics;
 using Poco::format;
+using Poco::Tuple;
 using Poco::NotFoundException;
 
 
@@ -829,11 +831,147 @@ void ODBCSQLServerTest::testInternalExtraction()
 }
 
 
-void ODBCSQLServerTest::dropTable(const std::string& tableName)
+void ODBCSQLServerTest::testInternalStorageType()
+{
+	if (!_pSession) fail ("Test not available.");
+
+	for (int i = 0; i < 8;)
+	{
+		recreateVectorsTable();
+		_pSession->setFeature("autoBind", bindValues[i]);
+		_pSession->setFeature("autoExtract", bindValues[i+1]);
+		_pExecutor->internalStorageType();
+		i += 2;
+	}
+}
+
+
+void ODBCSQLServerTest::testStoredProcedure()
+{
+	dropObject("PROCEDURE", "storedProcedure");
+
+	*_pSession << "CREATE PROCEDURE storedProcedure "
+	"@outParam int = 0 OUTPUT "
+	"AS "
+	"SET @outParam = -1 "
+	, now;
+	
+	int i = 0;
+	*_pSession << "{call storedProcedure(?)}", out(i), now;
+	assert(-1 == i);
+	dropObject("PROCEDURE", "storedProcedure");
+
+	*_pSession << "CREATE PROCEDURE storedProcedure "
+	"@inParam int, "
+	"@outParam int = 0 OUTPUT "
+	"AS "
+	"SET @outParam = @inParam*@inParam "
+	, now;
+
+	i = 2;
+	int j = 0;
+	/*not working */
+	try{
+		*_pSession << "{call storedProcedure(2, ?)}", out(j), now;
+	}catch(StatementException& ex)
+	{
+		std::cout << ex.toString();
+	}
+	//assert(4 == j);
+	dropObject("PROCEDURE", "storedProcedure");
+
+	*_pSession << "CREATE PROCEDURE storedProcedure "
+	"@ioParam int "
+	"AS "
+	"SET @ioParam = @ioParam*@ioParam "
+	, now;
+
+	i = 2;
+	/*not working*/
+	try{
+		*_pSession << "{call storedProcedure(?)}", io(i), now;
+	}catch(StatementException& ex)
+	{
+		std::cout << ex.toString();
+	}
+	//assert(4 == i);
+	dropObject("PROCEDURE", "storedProcedure");
+}
+
+
+void ODBCSQLServerTest::testStoredFunction()
+{
+	dropObject("PROCEDURE", "storedFunction");
+	*_pSession << "CREATE PROCEDURE storedFunction "
+	"AS "
+	"DECLARE @retVal int "
+	"SET @retVal = -1 "
+	"RETURN @retVal"
+	, now;
+
+	int i = 0;
+	*_pSession << "{? = call storedFunction}", out(i), now;
+
+	assert(-1 == i);
+	dropObject("PROCEDURE", "storedFunction");
+
+	/*TODO
+	*_pSession << "CREATE OR REPLACE "
+		"FUNCTION storedFunction(inParam IN NUMBER) RETURN NUMBER IS "
+		" BEGIN RETURN(inParam*inParam); "
+		" END storedFunction;" , now;
+
+	i = 2;
+	int result = 0;
+	*_pSession << "{? = call storedFunction(?)}", out(result), in(i), now;
+	assert(4 == result);
+	*_pSession << "DROP FUNCTION storedFunction;", now;
+
+	*_pSession << "CREATE OR REPLACE "
+		"FUNCTION storedFunction(inParam IN NUMBER, outParam OUT NUMBER) RETURN NUMBER IS "
+		" BEGIN outParam := inParam*inParam; RETURN(outParam); "
+		" END storedFunction;" , now;
+
+	i = 2;
+	int j = 0;
+	result = 0;
+	*_pSession << "{? = call storedFunction(?, ?)}", out(result), in(i), out(j), now;
+	assert(4 == j);
+	assert(j == result); 
+	*_pSession << "DROP FUNCTION storedFunction;", now;
+
+	*_pSession << "CREATE OR REPLACE "
+		"FUNCTION storedFunction(param1 IN OUT NUMBER, param2 IN OUT NUMBER) RETURN NUMBER IS "
+		" temp NUMBER := param1; "
+		" BEGIN param1 := param2; param2 := temp; RETURN(param1+param2); "
+		" END storedFunction;" , now;
+
+	i = 1;
+	j = 2;
+	result = 0;
+	*_pSession << "{? = call storedFunction(?, ?)}", out(result), io(i), io(j), now;
+	assert(1 == j);
+	assert(2 == i);
+	assert(3 == result); 
+	
+	Tuple<int, int> params(1, 2);
+	assert(1 == params.get<0>());
+	assert(2 == params.get<1>());
+	result = 0;
+	*_pSession << "{? = call storedFunction(?, ?)}", out(result), io(params), now;
+	assert(1 == params.get<1>());
+	assert(2 == params.get<0>());
+	assert(3 == result); 
+	*_pSession << "DROP FUNCTION storedFunction;", now;
+	*/
+}
+
+
+void ODBCSQLServerTest::dropObject(const std::string& type, const std::string& name)
 {
 	try
 	{
-		*_pSession << format("DROP TABLE %s", tableName), now;
+		*_pSession << format("DROP %s %s", type, name), now;
 	}
 	catch (StatementException& ex)
 	{
@@ -856,7 +994,7 @@ void ODBCSQLServerTest::dropTable(const std::string& tableName)
 
 void ODBCSQLServerTest::recreatePersonTable()
 {
-	dropTable("Person");
+	dropObject("TABLE", "Person");
 	try { *_pSession << "CREATE TABLE Person (LastName VARCHAR(30), 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()"); }
@@ -865,7 +1003,7 @@ void ODBCSQLServerTest::recreatePersonTable()
 
 void ODBCSQLServerTest::recreatePersonBLOBTable()
 {
-	dropTable("Person");
+	dropObject("TABLE", "Person");
 	try { *_pSession << "CREATE TABLE Person (LastName VARCHAR(30), FirstName VARCHAR(30), Address VARCHAR(30), Image VARBINARY(MAX))", now; }
 	catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail ("recreatePersonBLOBTable()"); }
 	catch(StatementException& se){ std::cout << se.toString() << std::endl; fail ("recreatePersonBLOBTable()"); }
@@ -874,7 +1012,7 @@ void ODBCSQLServerTest::recreatePersonBLOBTable()
 
 void ODBCSQLServerTest::recreateIntsTable()
 {
-	dropTable("Strings");
+	dropObject("TABLE", "Strings");
 	try { *_pSession << "CREATE TABLE 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()"); }
@@ -883,7 +1021,7 @@ void ODBCSQLServerTest::recreateIntsTable()
 
 void ODBCSQLServerTest::recreateStringsTable()
 {
-	dropTable("Strings");
+	dropObject("TABLE", "Strings");
 	try { *_pSession << "CREATE TABLE 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()"); }
@@ -892,7 +1030,7 @@ void ODBCSQLServerTest::recreateStringsTable()
 
 void ODBCSQLServerTest::recreateFloatsTable()
 {
-	dropTable("Strings");
+	dropObject("TABLE", "Strings");
 	try { *_pSession << "CREATE TABLE 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()"); }
@@ -901,7 +1039,7 @@ void ODBCSQLServerTest::recreateFloatsTable()
 
 void ODBCSQLServerTest::recreateTuplesTable()
 {
-	dropTable("Tuples");
+	dropObject("TABLE", "Tuples");
 	try { *_pSession << "CREATE TABLE 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,"
@@ -913,7 +1051,7 @@ void ODBCSQLServerTest::recreateTuplesTable()
 
 void ODBCSQLServerTest::recreateVectorTable()
 {
-	dropTable("Vector");
+	dropObject("TABLE", "Vector");
 	try { *_pSession << "CREATE TABLE Vector (i0 INTEGER)", now; }
 	catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail ("recreateVectorTable()"); }
 	catch(StatementException& se){ std::cout << se.toString() << std::endl; fail ("recreateVectorTable()"); }
@@ -922,7 +1060,7 @@ void ODBCSQLServerTest::recreateVectorTable()
 
 void ODBCSQLServerTest::recreateVectorsTable()
 {
-	dropTable("Vectors");
+	dropObject("TABLE", "Vectors");
 	try { *_pSession << "CREATE TABLE Vectors (int0 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()"); }
@@ -981,9 +1119,9 @@ void ODBCSQLServerTest::setUp()
 
 void ODBCSQLServerTest::tearDown()
 {
-	dropTable("Person");
-	dropTable("Strings");
-	dropTable("Tuples");
+	dropObject("TABLE", "Person");
+	dropObject("TABLE", "Strings");
+	dropObject("TABLE", "Tuples");
 }
 
 
@@ -1068,7 +1206,10 @@ CppUnit::Test* ODBCSQLServerTest::suite()
 		CppUnit_addTest(pSuite, ODBCSQLServerTest, testDouble);
 		CppUnit_addTest(pSuite, ODBCSQLServerTest, testTuple);
 		CppUnit_addTest(pSuite, ODBCSQLServerTest, testTupleVector);
+		CppUnit_addTest(pSuite, ODBCSQLServerTest, testStoredProcedure);
+		CppUnit_addTest(pSuite, ODBCSQLServerTest, testStoredFunction);
 		CppUnit_addTest(pSuite, ODBCSQLServerTest, testInternalExtraction);
+		CppUnit_addTest(pSuite, ODBCSQLServerTest, testInternalStorageType);
 
 		return pSuite;
 	}

+ 5 - 1
Data/ODBC/testsuite/src/ODBCSQLServerTest.h

@@ -117,7 +117,11 @@ public:
 	void testTuple();
 	void testTupleVector();
 
+	void testStoredProcedure();
+	void testStoredFunction();
+
 	void testInternalExtraction();
+	void testInternalStorageType();
 
 	void setUp();
 	void tearDown();
@@ -125,7 +129,7 @@ public:
 	static CppUnit::Test* suite();
 
 private:
-	void dropTable(const std::string& tableName);
+	void dropObject(const std::string& type, const std::string& name);
 	void recreatePersonTable();
 	void recreatePersonBLOBTable();
 	void recreateStringsTable();

+ 16 - 0
Data/ODBC/testsuite/src/ODBCSQLiteTest.cpp

@@ -807,6 +807,21 @@ void ODBCSQLiteTest::testInternalExtraction()
 }
 
 
+void ODBCSQLiteTest::testInternalStorageType()
+{
+	if (!_pSession) fail ("Test not available.");
+
+	for (int i = 0; i < 8;)
+	{
+		recreateVectorsTable();
+		_pSession->setFeature("autoBind", bindValues[i]);
+		_pSession->setFeature("autoExtract", bindValues[i+1]);
+		_pExecutor->internalStorageType();
+		i += 2;
+	}
+}
+
+
 void ODBCSQLiteTest::dropTable(const std::string& tableName)
 {
 	try
@@ -1029,6 +1044,7 @@ CppUnit::Test* ODBCSQLiteTest::suite()
 		CppUnit_addTest(pSuite, ODBCSQLiteTest, testTuple);
 		CppUnit_addTest(pSuite, ODBCSQLiteTest, testTupleVector);
 		CppUnit_addTest(pSuite, ODBCSQLiteTest, testInternalExtraction);
+		CppUnit_addTest(pSuite, ODBCSQLiteTest, testInternalStorageType);
 
 		return pSuite;
 	}

+ 1 - 0
Data/ODBC/testsuite/src/ODBCSQLiteTest.h

@@ -115,6 +115,7 @@ public:
 	void testTupleVector();
 
 	void testInternalExtraction();
+	void testInternalStorageType();
 
 	void setUp();
 	void tearDown();

+ 73 - 3
Data/ODBC/testsuite/src/SQLExecutor.cpp

@@ -1836,7 +1836,7 @@ void SQLExecutor::internalExtraction()
 		i = rset.value("str0", 2);
 		assert (5 == i);
 		
-		const Column<int>& col = rset.column<int>(0);
+		const Column<int>& col = rset.column<int, std::vector<int> >(0);
 		Column<int>::Iterator it = col.begin();
 		Column<int>::Iterator end = col.end();
 		for (int i = 1; it != end; ++it, ++i)
@@ -1870,7 +1870,7 @@ void SQLExecutor::internalExtraction()
 		s = rset.value("cnt", 0).convert<std::string>();
 		assert ("4" == s);
 
-		try { rset.column<int>(100); fail ("must fail"); }
+		try { rset.column<int, std::vector<int> >(100); fail ("must fail"); }
 		catch (RangeException&) { }
 
 		try	{ rset.value<std::string>(0,0); fail ("must fail"); }
@@ -1879,9 +1879,79 @@ void SQLExecutor::internalExtraction()
 		stmt = (*_pSession << "DELETE FROM Vectors", now);
 		rset = stmt;
 
-		try { rset.column<int>(0); fail ("must fail"); }
+		try { rset.column<int, std::vector<int> >(0); fail ("must fail"); }
 		catch (RangeException&) { }
 	}
 	catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); }
 	catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); }
 }
+
+
+void SQLExecutor::internalStorageType()
+{
+	std::string funct = "internalStorageType()";
+	std::vector<Statement::Manipulator> manips;
+	manips.push_back(list);
+	manips.push_back(deque);
+	manips.push_back(vector);
+
+	std::vector<Tuple<int, double, std::string> > v;
+	v.push_back(Tuple<int, double, std::string>(1, 1.5f, "3"));
+	v.push_back(Tuple<int, double, std::string>(2, 2.5f, "4"));
+	v.push_back(Tuple<int, double, std::string>(3, 3.5f, "5"));
+	v.push_back(Tuple<int, double, std::string>(4, 4.5f, "6"));
+
+	try { *_pSession << "INSERT INTO Vectors VALUES (?,?,?)", use(v), now; }
+	catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); }
+	catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); }
+
+	try 
+	{ 
+		std::vector<Statement::Manipulator>::iterator it = manips.begin();
+		std::vector<Statement::Manipulator>::iterator end = manips.end();
+
+		for (; it != end; ++it)
+		{
+			Statement stmt = (*_pSession << "SELECT * FROM Vectors", *it, now);
+			RecordSet rset(stmt);
+
+			assert (3 == rset.columnCount());
+			assert (4 == rset.rowCount());
+
+			int curVal = 3;
+			do
+			{
+				assert (rset["str0"] == curVal);
+				++curVal;
+			} while (rset.moveNext());
+
+			rset.moveFirst();
+			assert (rset["str0"] == "3");
+			rset.moveLast();
+			assert (rset["str0"] == "6");
+
+			try
+			{
+				stmt = (*_pSession << "SELECT * FROM Vectors", now, *it);
+				fail ("must fail");
+			}
+			catch(InvalidAccessException&){}
+
+			try
+			{
+				stmt = (*_pSession << "SELECT * FROM Vectors", into(v), now, *it);
+				fail ("must fail");
+			}
+			catch(InvalidAccessException&){}
+
+			try
+			{
+				stmt = (*_pSession << "SELECT * FROM Vectors", into(v), *it, now);
+				fail ("must fail");
+			}
+			catch(InvalidAccessException&){}
+		}
+	}
+	catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); }
+	catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); }
+}

+ 1 - 0
Data/ODBC/testsuite/src/SQLExecutor.h

@@ -126,6 +126,7 @@ public:
 	void tupleVector();
 
 	void internalExtraction();
+	void internalStorageType();
 
 private:
 	Poco::Data::Session* _pSession;

+ 31 - 0
Data/include/Poco/Data/AbstractSessionImpl.h

@@ -74,7 +74,19 @@ public:
 
 	AbstractSessionImpl()
 		/// Creates the AbstractSessionImpl.
+		/// Adds "storage" property and sets the default internal storage container 
+		/// type to std::vector.
+		/// The storage is created by statements automatically whenever a query 
+		/// returning results is executed but external storage is provided by the user.
+		/// Storage type can be reconfigured at runtime both globally (for the
+		/// duration of the session) and locally (for a single statement execution only). 
+		/// See StatementImpl for details on how this property is used at runtime.
 	{
+		addProperty("storage", 
+			&AbstractSessionImpl<C>::setStorage, 
+			&AbstractSessionImpl<C>::getStorage);
+
+		setProperty("storage", std::string("vector"));
 	}
 
 	~AbstractSessionImpl()
@@ -142,6 +154,24 @@ public:
 		else throw NotSupportedException(name);
 	}
 	
+	void setStorage(const std::string& value)
+		/// Sets the storage type.
+	{
+		_storage = value;
+	}
+
+	void setStorage(const std::string& name, const Poco::Any& value)
+		/// Sets the storage type.
+	{
+		_storage = Poco::RefAnyCast<std::string>(value);
+	}
+		
+	Poco::Any getStorage(const std::string& name="")
+		/// Returns the storage type
+	{
+		return _storage;
+	}
+
 protected:
 	void addFeature(const std::string& name, FeatureSetter setter, FeatureGetter getter)
 		/// Adds a feature to the map of supported features.
@@ -185,6 +215,7 @@ private:
 	
 	FeatureMap  _features;
 	PropertyMap _properties;
+	std::string _storage;
 };
 
 

+ 136 - 9
Data/include/Poco/Data/Column.h

@@ -44,13 +44,14 @@
 #include "Poco/Data/MetaColumn.h"
 #include "Poco/SharedPtr.h"
 #include <vector>
+#include <list>
 
 
 namespace Poco {
 namespace Data {
 
 
-template <class T>
+template <class T, class C = std::vector<T> >
 class Column
 	/// Column class is column data container.
 	/// Data (a pointer to vector of contained values) is assigned to the class 
@@ -59,11 +60,11 @@ class Column
 	/// This class owns the data assigned to it and deletes the storage on destruction.
 {
 public:
-	typedef std::vector<T> DataVec;
-	typedef typename DataVec::const_iterator Iterator;
-	typedef typename DataVec::size_type Size;
+	typedef C Container;
+	typedef typename Container::const_iterator Iterator;
+	typedef typename Container::size_type Size;
 
-	Column(const MetaColumn& metaColumn, std::vector<T>* pData): _metaColumn(metaColumn), _pData(pData)
+	Column(const MetaColumn& metaColumn, C* pData): _metaColumn(metaColumn), _pData(pData)
 		/// Creates the Column.
 	{
 		poco_check_ptr (_pData);
@@ -94,7 +95,7 @@ public:
 		std::swap(_pData, other._pData);
 	}
 
-	DataVec& data()
+	Container& data()
 		/// Returns reference to contained data.
 	{
 		return *_pData;
@@ -128,7 +129,133 @@ public:
 	void reset()
 		/// Clears and shrinks the storage.
 	{
-		std::vector<T>().swap(*_pData);
+		C().swap(*_pData);
+	}
+
+	const std::string& name() const
+		/// Returns column name.
+	{
+		return _metaColumn.name();
+	}
+
+	std::size_t length() const
+		/// Returns column maximum length.
+	{
+		return _metaColumn.length();
+	}
+
+	std::size_t precision() const
+		/// Returns column precision.
+		/// Valid for floating point fields only (zero for other data types).
+	{
+		return _metaColumn.precision();
+	}
+
+	std::size_t position() const
+		/// Returns column position.
+	{
+		return _metaColumn.position();
+	}
+
+	MetaColumn::ColumnDataType type() const
+		/// Returns column type.
+	{
+		return _metaColumn.type();
+	}
+
+	Iterator begin() const
+		/// Returns iterator pointing to the beginning of data storage vector.
+	{
+		return _pData->begin();
+	}
+
+	Iterator end() const
+		/// Returns iterator pointing to the end of data storage vector.
+	{
+		return _pData->end();
+	}
+
+private:
+	Column();
+
+	MetaColumn _metaColumn;
+	Poco::SharedPtr<Container> _pData;
+};
+
+
+template <class T>
+class Column<T, std::list<T> >
+	/// Column specialization for std::list
+{
+public:
+	typedef std::list<T> List;
+	typedef typename List::const_iterator Iterator;
+	typedef typename List::size_type Size;
+
+	Column(const MetaColumn& metaColumn, std::list<T>* pData): _metaColumn(metaColumn), _pData(pData)
+		/// Creates the Column.
+	{
+		poco_check_ptr (_pData);
+	}
+
+	Column(const Column& col): _metaColumn(col._metaColumn), _pData(col._pData)
+		/// Creates the Column.
+	{
+	}
+
+	~Column()
+		/// Destroys the Column.
+	{
+	}
+
+	Column& operator = (const Column& col)
+		/// Assignment operator.
+	{
+		Column tmp(col);
+		swap(tmp);
+		return *this;
+	}
+
+	void swap(Column& other)
+		/// Swaps the column with another one.
+	{
+		std::swap(_metaColumn, other._metaColumn);
+		std::swap(_pData, other._pData);
+	}
+
+	List& data()
+		/// Returns reference to contained data.
+	{
+		return *_pData;
+	}
+
+	const T& value(std::size_t row) const
+		/// Returns the field value in specified row.
+	{
+		List::const_iterator it = _pData->begin();
+		List::const_iterator end = _pData->end();
+		for (int i = 0; it != end; ++it, ++i)
+			if (i == row) return *it;
+
+		throw RangeException("Invalid row number."); 
+	}
+
+	const T& operator [] (std::size_t row) const
+		/// Returns the field value in specified row.
+	{
+		return value(row);
+	}
+
+	Size rowCount() const
+		/// Returns number of rows.
+	{
+		return _pData->size();
+	}
+
+	void reset()
+		/// Clears the storage.
+	{
+		_pData->clear();
 	}
 
 	const std::string& name() const
@@ -177,8 +304,8 @@ public:
 private:
 	Column();
 
-	MetaColumn               _metaColumn;
-	Poco::SharedPtr<DataVec> _pData;
+	MetaColumn _metaColumn;
+	Poco::SharedPtr<List> _pData;
 };
 
 

+ 3 - 3
Data/include/Poco/Data/Extraction.h

@@ -310,7 +310,7 @@ class InternalExtraction: public Extraction<C>
 	/// InternalExtraction objects can not be copied or assigned.
 {
 public:
-	explicit InternalExtraction(C& result, Column<T>* pColumn): 
+	explicit InternalExtraction(C& result, Column<T,C>* pColumn): 
 		Extraction<C>(result), 
 		_pColumn(pColumn)
 		/// Creates InternalExtraction.
@@ -341,7 +341,7 @@ public:
 		}
 	}
 
-	const Column<T>& column() const
+	const Column<T,C>& column() const
 	{
 		return *_pColumn;
 	}
@@ -351,7 +351,7 @@ private:
 	InternalExtraction(const InternalExtraction&);
 	InternalExtraction& operator = (const InternalExtraction&);
 
-	Column<T>* _pColumn;
+	Column<T,C>* _pColumn;
 };
 
 

+ 33 - 11
Data/include/Poco/Data/RecordSet.h

@@ -88,18 +88,18 @@ public:
 	std::size_t columnCount() const;
 		/// Returns the number of rows in the recordset.
 
-	template<class T>
-	const Column<T>& column(const std::string& name) const
+	template<class T, class C>
+	const Column<T,C>& column(const std::string& name) const
 		/// Returns the reference to the first Column with the specified name.
 	{
-		return column<T>(columnPosition<T>(name));
+		return column<T,C>(columnPosition<T,C>(name));
 	}
 
-	template<class T>
-	const Column<T>& column(std::size_t pos) const
+	template<class T, class C>
+	const Column<T,C>& column(std::size_t pos) const
 		/// Returns the reference to column at specified location.
 	{
-		typedef const InternalExtraction<T>* ExtractionVecPtr;
+		typedef const InternalExtraction<T,C>* ExtractionVecPtr;
 
 		const AbstractExtractionVec& rExtractions = extractions();
 
@@ -125,14 +125,36 @@ public:
 	const T& value(std::size_t col, std::size_t row) const
 		/// Returns the reference to data value at [col, row] location.
 	{
-		return column<T>(col).value(row);
+		switch (storage())
+		{
+		case STORAGE_VECTOR:
+		case STORAGE_UNKNOWN:
+			return column<T, std::vector<T> >(col).value(row);
+		case STORAGE_LIST:
+			return column<T, std::list<T> >(col).value(row);
+		case STORAGE_DEQUE:
+			return column<T, std::deque<T> >(col).value(row);
+		default:
+			throw IllegalStateException("Invalid storage setting.");
+		}
 	}
 
 	template<class T>
 	const T& value(const std::string& name, std::size_t row) const
 		/// Returns the reference to data value at named column, row location.
 	{
-		return column<T>(name).value(row);
+		switch (storage())
+		{
+		case STORAGE_VECTOR:
+		case STORAGE_UNKNOWN:
+			return column<T, std::vector<T> >(name).value(row);
+		case STORAGE_LIST:
+			return column<T, std::list<T> >(name).value(row);
+		case STORAGE_DEQUE:
+			return column<T, std::deque<T> >(name).value(row);
+		default:
+			throw IllegalStateException("Invalid storage setting.");
+		}
 	}
 
 	DynamicAny value(std::size_t col, std::size_t row) const;
@@ -204,11 +226,11 @@ public:
 private:
 	RecordSet();
 
-	template<class T>
+	template<class T, class C>
 	std::size_t columnPosition(const std::string& name) const
 		/// Returns the position of the column with specified name.
 	{
-		typedef const InternalExtraction<T>* ExtractionVecPtr;
+		typedef const InternalExtraction<T,C>* ExtractionVecPtr;
 
 		const AbstractExtractionVec& rExtractions = extractions();
 		AbstractExtractionVec::const_iterator it = rExtractions.begin();
@@ -220,7 +242,7 @@ private:
 
 			if (pExtraction)
 			{
-				const Column<T>& col = pExtraction->column();
+				const Column<T,C>& col = pExtraction->column();
 				if (0 == Poco::icompare(name, col.name()))
 					return col.position();
 			}

+ 49 - 1
Data/include/Poco/Data/Statement.h

@@ -63,7 +63,15 @@ class Data_API Statement
 {
 public:
 	typedef void (*Manipulator)(Statement&);
-	
+
+	enum Storage
+	{
+		STORAGE_VECTOR = StatementImpl::STORAGE_VECTOR_IMPL,
+		STORAGE_LIST = StatementImpl::STORAGE_LIST_IMPL,
+		STORAGE_DEQUE = StatementImpl::STORAGE_DEQUE_IMPL,
+		STORAGE_UNKNOWN = StatementImpl::STORAGE_UNKNOWN_IMPL
+	};
+
 	Statement(StatementImpl* pImpl);
 		/// Creates the Statement.
 
@@ -134,6 +142,22 @@ public:
 	Statement& reset(Session& session);
 		/// Resets the Statement so that it can be filled with a new SQL command.
 
+	bool canModifyStorage();
+		/// Returns true if statement is in a state that allows the internal storage to be modified.
+
+	Storage storage() const;
+		/// Returns the internal storage type for the stamement.
+
+	void setStorage(const std::string& storage);
+		/// Sets the internal storage type for the stamement.
+
+	const std::string& getStorage() const;
+		/// Returns the internal storage type for the stamement.
+
+	std::size_t extractionCount() const;
+		/// Returns the number of extraction storage buffers associated
+		/// with the statement.
+
 protected:
 	const AbstractExtractionVec& extractions() const;
 		/// Returns the extractions vector.
@@ -157,6 +181,12 @@ private:
 //
 void Data_API now(Statement& statement);
 
+void Data_API vector(Statement& statement);
+
+void Data_API list(Statement& statement);
+
+void Data_API deque(Statement& statement);
+
 
 //
 // inlines
@@ -221,6 +251,24 @@ inline const MetaColumn& Statement::metaColumn(const std::string& name) const
 }
 
 
+inline void Statement::setStorage(const std::string& storage)
+{
+	_ptr->setStorage(storage);
+}
+
+
+inline std::size_t Statement::extractionCount() const
+{
+	return _ptr->extractionCount();
+}
+
+
+inline Statement::Storage Statement::storage() const
+{
+	return static_cast<Storage>(_ptr->getStorage());
+}
+
+
 } } // namespace Poco::Data
 
 

+ 82 - 6
Data/include/Poco/Data/StatementImpl.h

@@ -59,6 +59,9 @@ namespace Poco {
 namespace Data {
 
 
+class SessionImpl;
+
+
 class Data_API StatementImpl: public Poco::RefCountedObject
 	/// StatementImpl interface that subclasses must implement to define database dependent query execution.
 	///
@@ -74,7 +77,20 @@ public:
 		ST_RESET
 	};
 
-	StatementImpl();
+	enum Storage
+	{
+		STORAGE_VECTOR_IMPL,
+		STORAGE_LIST_IMPL,
+		STORAGE_DEQUE_IMPL,
+		STORAGE_UNKNOWN_IMPL
+	};
+
+	static const std::string VECTOR;
+	static const std::string LIST;
+	static const std::string DEQUE;
+	static const std::string UNKNOWN;
+
+	StatementImpl(SessionImpl& rSession);
 		/// Creates the StatementImpl.
 
 	virtual ~StatementImpl();
@@ -107,6 +123,19 @@ public:
 	State getState() const;
 		/// Returns the state of the Statement.
 
+	void setStorage(Storage storage);
+		/// Sets the storage type for this statement;
+
+	void setStorage(const std::string& storage);
+		/// Sets the storage type for this statement;
+
+	Storage getStorage() const;
+		/// Returns the storage type for this statement.
+
+	std::size_t extractionCount() const;
+		/// Returns the number of extraction storage buffers associated
+		/// with the statement.
+
 protected:
 	virtual Poco::UInt32 columnsReturned() const = 0;
 		/// Returns number of columns returned by query. 
@@ -161,8 +190,29 @@ protected:
 		/// Returns the extractions vector.
 
 	void makeExtractors(Poco::UInt32 count);
-		/// Creates extraction vector. Used in case when there is
-		/// data returned, but no extraction supplied externally.
+		/// Determines the type of the internal extraction container and
+		/// calls the extraction creation function (addInternalExtract)
+		/// with appropriate data type and container type arguments.
+		/// 
+		/// This function is only called in cases when there is data 
+		/// returned by query, but no data storage supplied by user.
+		///
+		/// The type of the internal container is determined in the
+		/// following order:
+		/// 1. If statement has the container type set, the type is used.
+		/// 2. If statement does not have the container type set,
+		///    session is queried for container type setting. If the
+		///    session container type setting is found, it is used.
+		/// 3. If neither session nor statement have the internal
+		///    container type set, std::vector is used.
+		///
+		/// Supported internal extraction container types are:
+		/// - std::vector (default)
+		/// - std::deque
+		/// - std::list
+
+	SessionImpl& session();
+		/// Rteurns session associated with this statement.
 
 private:
 	void compile();
@@ -193,9 +243,9 @@ private:
 	void addInternalExtract(const MetaColumn& mc)
 		/// Utility function to create and add an internal extraction.
 	{
-		std::vector<T>* pData = new C;
-		Column<T>* pCol = new Column<T>(mc, pData);
-		addExtract(new InternalExtraction<T>(*pData, pCol));
+		C* pData = new C;
+		Column<T,C>* pCol = new Column<T,C>(mc, pData);
+		addExtract(new InternalExtraction<T,C>(*pData, pCol));
 	}
 
 	StatementImpl(const StatementImpl& stmt);
@@ -208,6 +258,8 @@ private:
 	std::ostringstream    _ostr;
 	AbstractBindingVec    _bindings;
 	AbstractExtractionVec _extractors;
+	SessionImpl&          _rSession;
+	Storage               _storage;
 
 	friend class Statement; 
 };
@@ -270,6 +322,30 @@ inline StatementImpl::State StatementImpl::getState() const
 }
 
 
+inline SessionImpl& StatementImpl::session()
+{
+	return _rSession;
+}
+
+
+inline void StatementImpl::setStorage(Storage storage)
+{
+	_storage = storage;
+}
+
+
+inline StatementImpl::Storage StatementImpl::getStorage() const
+{
+	return _storage;
+}
+
+
+inline std::size_t StatementImpl::extractionCount() const
+{
+	return extractions().size();
+}
+
+
 } } // namespace Poco::Data
 
 

+ 13 - 13
Data/src/RecordSet.cpp

@@ -62,7 +62,7 @@ DynamicAny RecordSet::value(std::size_t col, std::size_t row) const
 		case MetaColumn::FDT_UINT8:  return value<UInt8>(col, row);
 		case MetaColumn::FDT_INT16:  return value<Int16>(col, row);
 		case MetaColumn::FDT_UINT16: return value<UInt16>(col, row);
-		case MetaColumn::FDT_INT32:  return value<Int32>(col, row);
+		case MetaColumn::FDT_INT32:	 return value<Int32>(col, row);
 		case MetaColumn::FDT_UINT32: return value<UInt32>(col, row);
 		case MetaColumn::FDT_INT64:  return value<Int64>(col, row);
 		case MetaColumn::FDT_UINT64: return value<UInt64>(col, row);
@@ -81,18 +81,18 @@ DynamicAny RecordSet::value(const std::string& name, std::size_t row) const
 	switch (columnType(name))
 	{
 		case MetaColumn::FDT_BOOL:
-		case MetaColumn::FDT_INT8:   return value<Int8>(name, row);        
-		case MetaColumn::FDT_UINT8:  return value<UInt8>(name, row);       
-		case MetaColumn::FDT_INT16:  return value<Int16>(name, row);       
-		case MetaColumn::FDT_UINT16: return value<UInt16>(name, row);      
-		case MetaColumn::FDT_INT32:  return value<Int32>(name, row);       
-		case MetaColumn::FDT_UINT32: return value<UInt32>(name, row);      
-		case MetaColumn::FDT_INT64:  return value<Int64>(name, row);       
-		case MetaColumn::FDT_UINT64: return value<UInt64>(name, row);      
-		case MetaColumn::FDT_FLOAT:  return value<float>(name, row);       
-		case MetaColumn::FDT_DOUBLE: return value<double>(name, row);      
-		case MetaColumn::FDT_STRING: return value<std::string>(name, row); 
-		case MetaColumn::FDT_BLOB:   return value<BLOB>(name, row);        
+		case MetaColumn::FDT_INT8:   return value<Int8>(name, row);
+		case MetaColumn::FDT_UINT8:  return value<UInt8>(name, row);
+		case MetaColumn::FDT_INT16:  return value<Int16>(name, row);
+		case MetaColumn::FDT_UINT16: return value<UInt16>(name, row);
+		case MetaColumn::FDT_INT32:	 return value<Int32>(name, row);
+		case MetaColumn::FDT_UINT32: return value<UInt32>(name, row);
+		case MetaColumn::FDT_INT64:  return value<Int64>(name, row);
+		case MetaColumn::FDT_UINT64: return value<UInt64>(name, row);
+		case MetaColumn::FDT_FLOAT:  return value<float>(name, row);
+		case MetaColumn::FDT_DOUBLE: return value<double>(name, row);
+		case MetaColumn::FDT_STRING: return value<std::string>(name, row);
+		case MetaColumn::FDT_BLOB:   return value<BLOB>(name, row);
 		default:
 			throw Poco::InvalidArgumentException("Data type not supported.");
 	}

+ 53 - 0
Data/src/Statement.cpp

@@ -106,6 +106,14 @@ bool Statement::done()
 }
 
 
+bool Statement::canModifyStorage()
+{
+	return 0 == extractionCount() &&
+		(_ptr->getState() == StatementImpl::ST_INITIALIZED ||
+		_ptr->getState() == StatementImpl::ST_RESET);
+}
+
+
 Statement& Statement::reset(Session& session)
 {
 	Statement stmt(session.createStatementImpl());
@@ -114,10 +122,55 @@ Statement& Statement::reset(Session& session)
 }
 
 
+const std::string& Statement::getStorage() const
+{
+	switch (storage())
+	{
+	case STORAGE_VECTOR:
+		return StatementImpl::VECTOR;
+	case STORAGE_LIST:
+		return StatementImpl::LIST;
+	case STORAGE_DEQUE:
+		return StatementImpl::DEQUE;
+	case STORAGE_UNKNOWN:
+		return StatementImpl::UNKNOWN;
+	}
+
+	throw IllegalStateException("Invalid storage setting.");
+}
+
+
 void now(Statement& statement)
 {
 	statement.execute();
 }
 
 
+void vector(Statement& statement)
+{
+	if (!statement.canModifyStorage())
+		throw InvalidAccessException("Storage not modifiable.");
+
+	statement.setStorage("vector");
+}
+
+
+void list(Statement& statement)
+{
+	if (!statement.canModifyStorage())
+		throw InvalidAccessException("Storage not modifiable.");
+
+	statement.setStorage("list");
+}
+
+
+void deque(Statement& statement)
+{
+	if (!statement.canModifyStorage())
+		throw InvalidAccessException("Storage not modifiable.");
+
+	statement.setStorage("deque");
+}
+
+
 } } // namespace Poco::Data

+ 115 - 14
Data/src/StatementImpl.cpp

@@ -35,6 +35,7 @@
 
 
 #include "Poco/Data/StatementImpl.h"
+#include "Poco/Data/SessionImpl.h"
 #include "Poco/Data/DataException.h"
 #include "Poco/Data/AbstractBinder.h"
 #include "Poco/Data/Extraction.h"
@@ -44,15 +45,26 @@
 #include "Poco/Exception.h"
 
 
+using Poco::icompare;
+
+
 namespace Poco {
 namespace Data {
 
 
-StatementImpl::StatementImpl():
+const std::string StatementImpl::VECTOR = "vector";
+const std::string StatementImpl::LIST = "list";
+const std::string StatementImpl::DEQUE = "deque";
+const std::string StatementImpl::UNKNOWN = "unknown";
+
+
+StatementImpl::StatementImpl(SessionImpl& rSession):
 	_state(ST_INITIALIZED),
 	_extrLimit(upperLimit((Poco::UInt32) Limit::LIMIT_UNLIMITED, false)),
 	_lowerLimit(0),
 	_columnsExtracted(0),
+	_rSession(rSession),
+	_storage(STORAGE_UNKNOWN_IMPL),
 	_ostr(),
 	_bindings()
 {
@@ -254,49 +266,138 @@ void StatementImpl::resetExtraction()
 }
 
 
+void StatementImpl::setStorage(const std::string& storage)
+{
+	if (0 == icompare(VECTOR, storage))
+		_storage = STORAGE_VECTOR_IMPL; 
+	else if (0 == icompare(LIST, storage))
+		_storage = STORAGE_LIST_IMPL;
+	else if (0 == icompare(DEQUE, storage))
+		_storage = STORAGE_DEQUE_IMPL;
+	else if (0 == icompare(UNKNOWN, storage))
+		_storage = STORAGE_UNKNOWN_IMPL;
+	else
+		throw NotFoundException();
+}
+
+
 void StatementImpl::makeExtractors(Poco::UInt32 count)
 {
+	std::string storage;
+	
+	switch (_storage)
+	{
+	case STORAGE_VECTOR_IMPL: storage = VECTOR; break;
+	case STORAGE_LIST_IMPL:   storage = LIST; break;
+	case STORAGE_DEQUE_IMPL:  storage = DEQUE; break;
+	case STORAGE_UNKNOWN_IMPL:
+		storage = AnyCast<std::string>(session().getProperty("storage")); 
+		break;
+	}
+
+	if ("" == storage) storage = VECTOR;
+
 	for (int i = 0; i < count; ++i)
 	{
 		const MetaColumn& mc = metaColumn(i);
 		switch (mc.type())
 		{
 			case MetaColumn::FDT_BOOL:
-			case MetaColumn::FDT_INT8:   
-				addInternalExtract<Int8, std::vector<Int8> >(mc); 
+			case MetaColumn::FDT_INT8:  
+				if (0 == icompare(VECTOR, storage))
+					addInternalExtract<Int8, std::vector<Int8> >(mc); 
+				else if (0 == icompare(LIST, storage))
+					addInternalExtract<Int8, std::list<Int8> >(mc);
+				else if (0 == icompare(DEQUE, storage))
+					addInternalExtract<Int8, std::deque<Int8> >(mc);
 				break;
 			case MetaColumn::FDT_UINT8:  
-				addInternalExtract<UInt8, std::vector<UInt8> >(mc); 
+				if (0 == icompare(VECTOR, storage))
+					addInternalExtract<UInt8, std::vector<UInt8> >(mc); 
+				else if (0 == icompare(LIST, storage))
+					addInternalExtract<UInt8, std::list<UInt8> >(mc);
+				else if (0 == icompare(DEQUE, storage))
+					addInternalExtract<UInt8, std::deque<UInt8> >(mc);
 				break;
 			case MetaColumn::FDT_INT16:  
-				addInternalExtract<Int16, std::vector<Int16> >(mc); 
+				if (0 == icompare(VECTOR, storage))
+					addInternalExtract<Int16, std::vector<Int16> >(mc); 
+				else if (0 == icompare(LIST, storage))
+					addInternalExtract<Int16, std::list<Int16> >(mc);
+				else if (0 == icompare(DEQUE, storage))
+					addInternalExtract<Int16, std::deque<Int16> >(mc);
 				break;
 			case MetaColumn::FDT_UINT16: 
-				addInternalExtract<UInt16, std::vector<UInt16> >(mc); 
+				if (0 == icompare(VECTOR, storage))
+					addInternalExtract<UInt16, std::vector<UInt16> >(mc); 
+				else if (0 == icompare(LIST, storage))
+					addInternalExtract<UInt16, std::list<UInt16> >(mc);
+				else if (0 == icompare(DEQUE, storage))
+					addInternalExtract<UInt16, std::deque<UInt16> >(mc);
 				break;
 			case MetaColumn::FDT_INT32:  
-				addInternalExtract<Int32, std::vector<Int32> >(mc); 
+				if (0 == icompare(VECTOR, storage))
+					addInternalExtract<Int32, std::vector<Int32> >(mc); 
+				else if (0 == icompare(LIST, storage))
+					addInternalExtract<Int32, std::list<Int32> >(mc);
+				else if (0 == icompare(DEQUE, storage))
+					addInternalExtract<Int32, std::deque<Int32> >(mc);
 				break;
 			case MetaColumn::FDT_UINT32: 
-				addInternalExtract<UInt32, std::vector<UInt32> >(mc); 
+				if (0 == icompare(VECTOR, storage))
+					addInternalExtract<UInt32, std::vector<UInt32> >(mc); 
+				else if (0 == icompare(LIST, storage))
+					addInternalExtract<UInt32, std::list<UInt32> >(mc);
+				else if (0 == icompare(DEQUE, storage))
+					addInternalExtract<UInt32, std::deque<UInt32> >(mc);
 				break;
 			case MetaColumn::FDT_INT64:  
-				addInternalExtract<Int64, std::vector<Int64> >(mc); 
+				if (0 == icompare(VECTOR, storage))
+					addInternalExtract<Int64, std::vector<Int64> >(mc); 
+				else if (0 == icompare(LIST, storage))
+					addInternalExtract<Int64, std::list<Int64> >(mc);
+				else if (0 == icompare(DEQUE, storage))
+					addInternalExtract<Int64, std::deque<Int64> >(mc); 
 				break;
 			case MetaColumn::FDT_UINT64: 
-				addInternalExtract<UInt64, std::vector<UInt64> >(mc); 
+				if (0 == icompare(VECTOR, storage))
+					addInternalExtract<UInt64, std::vector<UInt64> >(mc); 
+				else if (0 == icompare(LIST, storage))
+					addInternalExtract<UInt64, std::list<UInt64> >(mc);
+				else if (0 == icompare(DEQUE, storage))
+					addInternalExtract<UInt64, std::deque<UInt64> >(mc);
 				break;
 			case MetaColumn::FDT_FLOAT:  
-				addInternalExtract<float, std::vector<float> >(mc); 
+				if (0 == icompare(VECTOR, storage))
+					addInternalExtract<float, std::vector<float> >(mc); 
+				else if (0 == icompare(LIST, storage))
+					addInternalExtract<float, std::list<float> >(mc);
+				else if (0 == icompare(DEQUE, storage))
+					addInternalExtract<float, std::deque<float> >(mc);
 				break;
 			case MetaColumn::FDT_DOUBLE: 
-				addInternalExtract<double, std::vector<double> >(mc); 
+				if (0 == icompare(VECTOR, storage))
+					addInternalExtract<double, std::vector<double> >(mc); 
+				else if (0 == icompare(LIST, storage))
+					addInternalExtract<double, std::list<double> >(mc);
+				else if (0 == icompare(DEQUE, storage))
+					addInternalExtract<double, std::deque<double> >(mc); 
 				break;
 			case MetaColumn::FDT_STRING: 
-				addInternalExtract<std::string, std::vector<std::string> >(mc); 
+				if (0 == icompare(VECTOR, storage))
+					addInternalExtract<std::string, std::vector<std::string> >(mc); 
+				else if (0 == icompare(LIST, storage))
+					addInternalExtract<std::string, std::list<std::string> >(mc);
+				else if (0 == icompare(DEQUE, storage))
+					addInternalExtract<std::string, std::deque<std::string> >(mc);
 				break;
 			case MetaColumn::FDT_BLOB:   
-				addInternalExtract<BLOB, std::vector<BLOB> >(mc); 
+				if (0 == icompare(VECTOR, storage))
+					addInternalExtract<BLOB, std::vector<BLOB> >(mc); 
+				else if (0 == icompare(LIST, storage))
+					addInternalExtract<BLOB, std::list<BLOB> >(mc);
+				else if (0 == icompare(DEQUE, storage))
+					addInternalExtract<BLOB, std::deque<BLOB> >(mc);
 				break;
 			default:
 				throw Poco::InvalidArgumentException("Data type not supported.");

+ 153 - 2
Data/testsuite/src/DataTest.cpp

@@ -347,7 +347,7 @@ void DataTest::readFromBLOB(BinaryReader& reader)
 }
 
 
-void DataTest::testColumn()
+void DataTest::testColumnVector()
 {
 	MetaColumn mc(0, "mc", MetaColumn::FDT_DOUBLE, 2, 3, true);
 
@@ -417,7 +417,156 @@ void DataTest::testColumn()
 	assert (c.rowCount() == 0);
 	assert (c1.rowCount() == 0);
 	assert (c2.rowCount() == 0);
+}
+
 
+void DataTest::testColumnDeque()
+{
+	typedef std::deque<int> ContainerType;
+	typedef Column<int, ContainerType> ColumnType;
+
+	MetaColumn mc(0, "mc", MetaColumn::FDT_DOUBLE, 2, 3, true);
+
+	assert (mc.name() == "mc");
+	assert (mc.position() == 0);
+	assert (mc.length() == 2);
+	assert (mc.precision() == 3);
+	assert (mc.type() == MetaColumn::FDT_DOUBLE);
+	assert (mc.isNullable());
+
+	ContainerType* pData = new ContainerType;
+	pData->push_back(1);
+	pData->push_back(2);
+	pData->push_back(3);
+	pData->push_back(4);
+	pData->push_back(5);
+	
+	ColumnType c(mc, pData);
+
+	assert (c.rowCount() == 5);
+	assert (c[0] == 1);
+	assert (c[1] == 2);
+	assert (c[2] == 3);
+	assert (c[3] == 4);
+	assert (c[4] == 5);
+	assert (c.name() == "mc");
+	assert (c.position() == 0);
+	assert (c.length() == 2);
+	assert (c.precision() == 3);
+	assert (c.type() == MetaColumn::FDT_DOUBLE);
+
+	try
+	{
+		int i = c[100];
+		fail ("must fail");
+	}
+	catch (RangeException&) { }
+
+	ColumnType c1 = c;
+
+	assert (c1.rowCount() == 5);
+	assert (c1[0] == 1);
+	assert (c1[1] == 2);
+	assert (c1[2] == 3);
+	assert (c1[3] == 4);
+	assert (c1[4] == 5);
+
+	ColumnType c2(c1);
+
+	assert (c2.rowCount() == 5);
+	assert (c2[0] == 1);
+	assert (c2[1] == 2);
+	assert (c2[2] == 3);
+	assert (c2[3] == 4);
+	assert (c2[4] == 5);
+
+	ContainerType vi;
+	vi.assign(c.begin(), c.end());
+	assert (vi.size() == 5);
+	assert (vi[0] == 1);
+	assert (vi[1] == 2);
+	assert (vi[2] == 3);
+	assert (vi[3] == 4);
+	assert (vi[4] == 5);
+
+	c.reset();
+	assert (c.rowCount() == 0);
+	assert (c1.rowCount() == 0);
+	assert (c2.rowCount() == 0);
+}
+
+
+void DataTest::testColumnList()
+{
+	typedef std::list<int> ContainerType;
+	typedef Column<int, ContainerType> ColumnType;
+
+	MetaColumn mc(0, "mc", MetaColumn::FDT_DOUBLE, 2, 3, true);
+
+	assert (mc.name() == "mc");
+	assert (mc.position() == 0);
+	assert (mc.length() == 2);
+	assert (mc.precision() == 3);
+	assert (mc.type() == MetaColumn::FDT_DOUBLE);
+	assert (mc.isNullable());
+
+	ContainerType* pData = new ContainerType;
+	pData->push_back(1);
+	pData->push_back(2);
+	pData->push_back(3);
+	pData->push_back(4);
+	pData->push_back(5);
+	
+	ColumnType c(mc, pData);
+
+	assert (c.rowCount() == 5);
+	assert (c[0] == 1);
+	assert (c[1] == 2);
+	assert (c[2] == 3);
+	assert (c[3] == 4);
+	assert (c[4] == 5);
+	assert (c.name() == "mc");
+	assert (c.position() == 0);
+	assert (c.length() == 2);
+	assert (c.precision() == 3);
+	assert (c.type() == MetaColumn::FDT_DOUBLE);
+
+	try
+	{
+		int i = c[100];
+		fail ("must fail");
+	}
+	catch (RangeException&) { }
+
+	ColumnType c1 = c;
+
+	assert (c1.rowCount() == 5);
+	assert (c1[0] == 1);
+	assert (c1[1] == 2);
+	assert (c1[2] == 3);
+	assert (c1[3] == 4);
+	assert (c1[4] == 5);
+
+	ColumnType c2(c1);
+	assert (c2.rowCount() == 5);
+	assert (c2[0] == 1);
+	assert (c2[1] == 2);
+	assert (c2[2] == 3);
+	assert (c2[3] == 4);
+	assert (c2[4] == 5);
+
+	ContainerType vi;
+	vi.assign(c.begin(), c.end());
+	assert (vi.size() == 5);
+	ContainerType::const_iterator it = vi.begin();
+	ContainerType::const_iterator end = vi.end();
+	for (int i = 1; it != end; ++it, ++i)
+		assert (*it == i);
+
+	c.reset();
+	assert (c.rowCount() == 0);
+	assert (c1.rowCount() == 0);
+	assert (c2.rowCount() == 0);
 }
 
 
@@ -440,7 +589,9 @@ CppUnit::Test* DataTest::suite()
 	CppUnit_addTest(pSuite, DataTest, testProperties);
 	CppUnit_addTest(pSuite, DataTest, testBLOB);
 	CppUnit_addTest(pSuite, DataTest, testBLOBStreams);
-	CppUnit_addTest(pSuite, DataTest, testColumn);
+	CppUnit_addTest(pSuite, DataTest, testColumnVector);
+	CppUnit_addTest(pSuite, DataTest, testColumnDeque);
+	CppUnit_addTest(pSuite, DataTest, testColumnList);
 
 	return pSuite;
 }

+ 3 - 1
Data/testsuite/src/DataTest.h

@@ -53,7 +53,9 @@ public:
 	void testProperties();
 	void testBLOB();
 	void testBLOBStreams();
-	void testColumn();
+	void testColumnVector();
+	void testColumnDeque();
+	void testColumnList();
 
 	void setUp();
 	void tearDown();

+ 1 - 1
Data/testsuite/src/SessionImpl.cpp

@@ -61,7 +61,7 @@ SessionImpl::~SessionImpl()
 
 Poco::Data::StatementImpl* SessionImpl::createStatementImpl()
 {
-	return new TestStatementImpl;
+	return new TestStatementImpl(*this);
 }
 
 

+ 3 - 1
Data/testsuite/src/TestStatementImpl.cpp

@@ -31,6 +31,7 @@
 
 
 #include "TestStatementImpl.h"
+#include "SessionImpl.h"
 
 
 namespace Poco {
@@ -38,7 +39,8 @@ namespace Data {
 namespace Test {
 
 
-TestStatementImpl::TestStatementImpl()
+TestStatementImpl::TestStatementImpl(SessionImpl& rSession):
+	Poco::Data::StatementImpl(rSession)
 {
 }
 

+ 4 - 5
Data/testsuite/src/TestStatementImpl.h

@@ -44,20 +44,19 @@
 #include "Preparation.h"
 
 
-struct sqlite3;
-struct sqlite3_stmt;
-
-
 namespace Poco {
 namespace Data {
 namespace Test {
 
 
+class SessionImpl;
+
+
 class TestStatementImpl: public Poco::Data::StatementImpl
 	/// A no-op implementation of TestStatementImpl for testing.
 {
 public:
-	TestStatementImpl();
+	TestStatementImpl(SessionImpl& rSession);
 		/// Creates the TestStatementImpl.
 
 	~TestStatementImpl();