1
0
mirror of https://github.com/pocoproject/poco.git synced 2025-03-31 16:04:27 +02:00

batch statements (multiple results) support

This commit is contained in:
Aleksandar Fabijanic 2007-11-06 02:18:32 +00:00
parent ae34e0ff3b
commit 95c5230389
18 changed files with 284 additions and 195 deletions

@ -126,6 +126,9 @@ private:
void makeInternalExtractors();
/// Creates internal extractors if none were supplied from the user.
bool isStoredProcedure() const;
/// Returns true if SQL is a stored procedure call.
void doPrepare();
/// Prepares placeholders for data returned by statement.
/// It is called during statement compilation for SQL statements

@ -199,6 +199,9 @@ private:
void prepareImpl(std::size_t pos);
/// Utility function to prepare Any and DynamicAny
void resize() const;
/// Resize the values and lengths vectors.
template <typename T>
void preparePOD(std::size_t pos, SQLSMALLINT valueType)
{

@ -284,25 +284,17 @@ bool ODBCStatementImpl::hasNext()
if (!nextRowReady())
{
try
{
activateNextDataSet();
} catch (InvalidAccessException&)
{
return false;
}
try { activateNextDataSet(); }
catch (InvalidAccessException&)
{ return false; }
try { checkError(SQLMoreResults(_stmt)); }
catch (NoDataException&)
{ return false; }
addPreparation();
doPrepare();
fixupExtraction();
try
{
checkError(SQLMoreResults(_stmt));
} catch (NoDataException&)
{
return false;
}
makeStep();
}
else if (Utility::isError(_nextResponse))
@ -408,4 +400,13 @@ void ODBCStatementImpl::fillColumns()
}
bool ODBCStatementImpl::isStoredProcedure() const
{
std::string str = toString();
if (trimInPlace(str).size() < 2) return false;
return ('{' == str[0] && '}' == str[str.size()-1]);
}
} } } // namespace Poco::Data::ODBC

@ -62,6 +62,7 @@ Preparation::Preparation(const Preparation& other):
_maxFieldSize(other._maxFieldSize),
_dataExtraction(other._dataExtraction)
{
resize();
}
@ -79,21 +80,23 @@ Preparation::~Preparation()
std::size_t Preparation::columns() const
{
if (_pValues.empty())
{
SQLSMALLINT nCol = 0;
if (!Utility::isError(SQLNumResultCols(_rStmt, &nCol)) &&
0 != nCol)
{
_pValues.resize(nCol, 0);
_pLengths.resize(nCol, 0);
}
}
if (_pValues.empty()) resize();
return _pValues.size();
}
void Preparation::resize() const
{
SQLSMALLINT nCol = 0;
if (!Utility::isError(SQLNumResultCols(_rStmt, &nCol)) &&
0 != nCol)
{
_pValues.resize(nCol, 0);
_pLengths.resize(nCol, 0);
}
}
Poco::Any& Preparation::operator [] (std::size_t pos)
{
poco_assert (pos >= 0 && pos < _pValues.size());

@ -1201,6 +1201,22 @@ void ODBCDB2Test::testDynamicAny()
}
void ODBCDB2Test::testMultipleResults()
{
if (!_pSession) fail ("Test not available.");
for (int i = 0; i < 8;)
{
recreatePersonTable();
_pSession->setFeature("autoBind", bindValues[i]);
_pSession->setFeature("autoExtract", bindValues[i+1]);
_pExecutor->multipleResults();
i += 2;
}
}
void ODBCDB2Test::dropObject(const std::string& type, const std::string& name)
{
try
@ -1350,7 +1366,11 @@ bool ODBCDB2Test::canConnect(const std::string& driver, const std::string& dsn)
{
std::cout << "DSN found: " << itDSN->first
<< " (" << itDSN->second << ')' << std::endl;
format(_dbConnString, "DSN=%s", dsn);
format(_dbConnString,
"DSN=%s;"
"Uid=db2admin;"
"Pwd=db2admin;",
dsn);
return true;
}
}
@ -1470,6 +1490,7 @@ CppUnit::Test* ODBCDB2Test::suite()
CppUnit_addTest(pSuite, ODBCDB2Test, testAsync);
CppUnit_addTest(pSuite, ODBCDB2Test, testAny);
CppUnit_addTest(pSuite, ODBCDB2Test, testDynamicAny);
CppUnit_addTest(pSuite, ODBCDB2Test, testMultipleResults);
return pSuite;
}

@ -132,6 +132,8 @@ public:
void testAny();
void testDynamicAny();
void testMultipleResults();
void setUp();
void tearDown();

@ -108,6 +108,9 @@ void ODBCMySQLTest::testBareboneODBC()
_pExecutor->bareboneODBCTest(_dbConnString, tableCreateString, SQLExecutor::PB_AT_EXEC, SQLExecutor::DE_MANUAL, false);
_pExecutor->bareboneODBCTest(_dbConnString, tableCreateString, SQLExecutor::PB_AT_EXEC, SQLExecutor::DE_BOUND, false);
/*
MySQL supports batch statements as of 3.51.18
http://bugs.mysql.com/bug.php?id=7445
tableCreateString = "CREATE TABLE Test "
"(First VARCHAR(30),"
@ -118,6 +121,7 @@ void ODBCMySQLTest::testBareboneODBC()
_pExecutor->bareboneODBCMultiResultTest(_dbConnString, tableCreateString, SQLExecutor::PB_IMMEDIATE, SQLExecutor::DE_BOUND);
_pExecutor->bareboneODBCMultiResultTest(_dbConnString, tableCreateString, SQLExecutor::PB_AT_EXEC, SQLExecutor::DE_MANUAL);
_pExecutor->bareboneODBCMultiResultTest(_dbConnString, tableCreateString, SQLExecutor::PB_AT_EXEC, SQLExecutor::DE_BOUND);
*/
}
@ -989,6 +993,27 @@ void ODBCMySQLTest::testDynamicAny()
}
void ODBCMySQLTest::testMultipleResults()
{
/*
MySQL supports batch statements as of 3.51.18
http://bugs.mysql.com/bug.php?id=7445
if (!_pSession) fail ("Test not available.");
for (int i = 0; i < 8;)
{
recreatePersonTable();
_pSession->setFeature("autoBind", bindValues[i]);
_pSession->setFeature("autoExtract", bindValues[i+1]);
_pExecutor->multipleResults();
i += 2;
}
*/
}
void ODBCMySQLTest::dropObject(const std::string& type, const std::string& name)
{
*_pSession << format("DROP %s IF EXISTS %s", type, name), now;
@ -1239,6 +1264,7 @@ CppUnit::Test* ODBCMySQLTest::suite()
CppUnit_addTest(pSuite, ODBCMySQLTest, testAsync);
CppUnit_addTest(pSuite, ODBCMySQLTest, testAny);
CppUnit_addTest(pSuite, ODBCMySQLTest, testDynamicAny);
CppUnit_addTest(pSuite, ODBCMySQLTest, testMultipleResults);
return pSuite;
}

@ -132,6 +132,8 @@ public:
void testAny();
void testDynamicAny();
void testMultipleResults();
void setUp();
void tearDown();

@ -131,17 +131,17 @@ void ODBCOracleTest::testBarebone()
"Third NUMBER)";
*_pSession << "CREATE OR REPLACE "
"PROCEDURE multiResultsProcedure(tmp1 OUT SYS_REFCURSOR, "
"tmp2 OUT SYS_REFCURSOR,"
"tmp3 OUT SYS_REFCURSOR,"
"tmp4 OUT SYS_REFCURSOR,"
"tmp5 OUT SYS_REFCURSOR) IS "
"PROCEDURE multiResultsProcedure(ret1 OUT SYS_REFCURSOR, "
"ret2 OUT SYS_REFCURSOR,"
"ret3 OUT SYS_REFCURSOR,"
"ret4 OUT SYS_REFCURSOR,"
"ret5 OUT SYS_REFCURSOR) IS "
"BEGIN "
"OPEN tmp1 FOR SELECT * FROM Test WHERE First = '1';"
"OPEN tmp2 FOR SELECT * FROM Test WHERE First = '2';"
"OPEN tmp3 FOR SELECT * FROM Test WHERE First = '3';"
"OPEN tmp4 FOR SELECT * FROM Test WHERE First = '4';"
"OPEN tmp5 FOR SELECT * FROM Test WHERE First = '5';"
"OPEN ret1 FOR SELECT * FROM Test WHERE First = '1';"
"OPEN ret2 FOR SELECT * FROM Test WHERE First = '2';"
"OPEN ret3 FOR SELECT * FROM Test WHERE First = '3';"
"OPEN ret4 FOR SELECT * FROM Test WHERE First = '4';"
"OPEN ret5 FOR SELECT * FROM Test WHERE First = '5';"
"END multiResultsProcedure;" , now;
_pExecutor->bareboneODBCMultiResultTest(_dbConnString,
@ -1109,7 +1109,7 @@ void ODBCOracleTest::testStoredProcedureDynamicAny()
}
void ODBCOracleTest::testStoredCursorProcedure()
void ODBCOracleTest::testCursorStoredProcedure()
{
if (!_pSession) fail ("Test not available.");
@ -1251,7 +1251,7 @@ void ODBCOracleTest::testStoredFunction()
}
void ODBCOracleTest::testStoredCursorFunction()
void ODBCOracleTest::testCursorStoredFunction()
{
if (!_pSession) fail ("Test not available.");
@ -1367,6 +1367,39 @@ void ODBCOracleTest::testDynamicAny()
}
void ODBCOracleTest::testMultipleResults()
{
if (!_pSession) fail ("Test not available.");
std::string sql = "CREATE OR REPLACE "
"PROCEDURE multiResultsProcedure(paramAge1 IN NUMBER,"
" paramAge2 IN NUMBER,"
" ret1 OUT SYS_REFCURSOR, "
" ret2 OUT SYS_REFCURSOR,"
" ret3 OUT SYS_REFCURSOR) IS "
"BEGIN "
" OPEN ret1 FOR SELECT * FROM Person WHERE Age = paramAge1;"
" OPEN ret2 FOR SELECT Age FROM Person WHERE FirstName = 'Bart';"
" OPEN ret3 FOR SELECT * FROM Person WHERE Age = paramAge2;"
"END multiResultsProcedure;";
for (int i = 0; i < 8;)
{
recreatePersonTable();
*_pSession << sql, now;
_pSession->setFeature("autoBind", bindValues[i]);
_pSession->setFeature("autoExtract", bindValues[i+1]);
_pExecutor->multipleResults("{call multiResultsProcedure(?, ?)}");
i += 2;
}
}
void ODBCOracleTest::dropObject(const std::string& type, const std::string& name)
{
try
@ -1593,14 +1626,16 @@ bool ODBCOracleTest::init(const std::string& driver, const std::string& dsn)
_pExecutor = new SQLExecutor(driver + " SQL Executor", _pSession);
#ifdef POCO_OS_FAMILY_WINDOWS
// Workaround:
//
// Barebone ODBC test is called initially for Oracle only.
// Barebone ODBC test is called automatically on startup for Oracle.
// The test framework does not exit cleanly if
// Oracle tests are enabled (i.e. Oracle driver is found)
// but no tests are executed.
// The exact reason for this behavior is unknown at this time.
testBarebone();
#endif
return true;
}
@ -1661,11 +1696,11 @@ CppUnit::Test* ODBCOracleTest::suite()
CppUnit_addTest(pSuite, ODBCOracleTest, testTuple);
CppUnit_addTest(pSuite, ODBCOracleTest, testTupleVector);
CppUnit_addTest(pSuite, ODBCOracleTest, testStoredProcedure);
CppUnit_addTest(pSuite, ODBCOracleTest, testStoredCursorProcedure);
CppUnit_addTest(pSuite, ODBCOracleTest, testCursorStoredProcedure);
CppUnit_addTest(pSuite, ODBCOracleTest, testStoredProcedureAny);
CppUnit_addTest(pSuite, ODBCOracleTest, testStoredProcedureDynamicAny);
CppUnit_addTest(pSuite, ODBCOracleTest, testStoredFunction);
CppUnit_addTest(pSuite, ODBCOracleTest, testStoredCursorFunction);
CppUnit_addTest(pSuite, ODBCOracleTest, testCursorStoredFunction);
CppUnit_addTest(pSuite, ODBCOracleTest, testInternalExtraction);
CppUnit_addTest(pSuite, ODBCOracleTest, testInternalStorageType);
CppUnit_addTest(pSuite, ODBCOracleTest, testNull);
@ -1673,6 +1708,7 @@ CppUnit::Test* ODBCOracleTest::suite()
CppUnit_addTest(pSuite, ODBCOracleTest, testAsync);
CppUnit_addTest(pSuite, ODBCOracleTest, testAny);
CppUnit_addTest(pSuite, ODBCOracleTest, testDynamicAny);
CppUnit_addTest(pSuite, ODBCOracleTest, testMultipleResults);
return pSuite;
}

@ -120,9 +120,9 @@ public:
void testInternalStorageType();
void testStoredProcedure();
void testStoredCursorProcedure();
void testCursorStoredProcedure();
void testStoredFunction();
void testStoredCursorFunction();
void testCursorStoredFunction();
void testStoredProcedureAny();
void testStoredProcedureDynamicAny();
@ -134,6 +134,8 @@ public:
void testAny();
void testDynamicAny();
void testMultipleResults();
void setUp();
void tearDown();

@ -123,7 +123,8 @@ void ODBCPostgreSQLTest::testBareboneODBC()
_pExecutor->bareboneODBCTest(_dbConnString, tableCreateString, SQLExecutor::PB_AT_EXEC, SQLExecutor::DE_MANUAL, false);
_pExecutor->bareboneODBCTest(_dbConnString, tableCreateString, SQLExecutor::PB_AT_EXEC, SQLExecutor::DE_BOUND, false);
//neither pSQL ODBC nor Mammoth drivers support multiple results properly
/*
tableCreateString = "CREATE TABLE Test "
"(First VARCHAR(30),"
"Second INTEGER,"
@ -133,6 +134,7 @@ void ODBCPostgreSQLTest::testBareboneODBC()
_pExecutor->bareboneODBCMultiResultTest(_dbConnString, tableCreateString, SQLExecutor::PB_IMMEDIATE, SQLExecutor::DE_BOUND);
_pExecutor->bareboneODBCMultiResultTest(_dbConnString, tableCreateString, SQLExecutor::PB_AT_EXEC, SQLExecutor::DE_MANUAL);
_pExecutor->bareboneODBCMultiResultTest(_dbConnString, tableCreateString, SQLExecutor::PB_AT_EXEC, SQLExecutor::DE_BOUND);
*/
}
@ -1113,6 +1115,8 @@ void ODBCPostgreSQLTest::testDynamicAny()
void ODBCPostgreSQLTest::testMultipleResults()
{
//neither pSQL ODBC nor Mammoth drivers support multiple results properly
/*
if (!_pSession) fail ("Test not available.");
for (int i = 0; i < 8;)
@ -1124,6 +1128,7 @@ void ODBCPostgreSQLTest::testMultipleResults()
i += 2;
}
*/
}

@ -45,7 +45,7 @@
// uncomment to use Mammoth ODBCng driver
//#define POCO_ODBC_USE_MAMMOTH_NG
#define POCO_ODBC_USE_MAMMOTH_NG
class ODBCPostgreSQLTest: public CppUnit::TestCase

@ -987,14 +987,8 @@ Deprecated types are not supported as output parameters. Use current large obje
}
void ODBCSQLServerTest::testStoredCursorProcedure()
void ODBCSQLServerTest::testCursorStoredProcedure()
{
/*TODO: Support for returning recordsets from MS SQL Server is currently limited.
In order for it to work, nothing else but the recordset (not even output parameters)
can be returned.
To achieve full functionality, SQLMoreResults functionality probably must be incorporated
into the framework.
*/
if (!_pSession) fail ("Test not available.");
for (int k = 0; k < 8;)
@ -1204,63 +1198,6 @@ void ODBCSQLServerTest::testStoredFunction()
}
void ODBCSQLServerTest::testStoredCursorFunction()
{
/* TODO (see comments about errors below - probably needs SQLMoreResults to function properly)
if (!_pSession) fail ("Test not available.");
for (int k = 0; k < 8;)
{
_pSession->setFeature("autoBind", bindValues[k]);
_pSession->setFeature("autoExtract", bindValues[k+1]);
recreatePersonTable();
typedef Tuple<std::string, std::string, std::string, int> Person;
std::vector<Person> people;
people.push_back(Person("Simpson", "Homer", "Springfield", 42));
people.push_back(Person("Simpson", "Bart", "Springfield", 12));
people.push_back(Person("Simpson", "Lisa", "Springfield", 10));
*_pSession << "INSERT INTO Person VALUES (?, ?, ?, ?)", use(people), now;
dropObject("PROCEDURE", "storedCursorFunction");
*_pSession << "CREATE PROCEDURE storedCursorFunction(@ageLimit int) AS "
"BEGIN "
" SELECT * "
" FROM Person "
" WHERE Age < @ageLimit "
" ORDER BY Age DESC; "
" RETURN @ageLimit; "
"END;"
, now;
people.clear();
int age = 13;
int result = 0;
*_pSession << "{? = call storedCursorFunction(?)}", out(result), in(age), into(people), now;
//assert (result == age); //fails (result == 0)
assert (2 == people.size());
assert (Person("Simpson", "Bart", "Springfield", 12) == people[0]);
assert (Person("Simpson", "Lisa", "Springfield", 10) == people[1]);
result = 0;
Statement stmt = ((*_pSession << "{? = call storedCursorFunction(?)}", out(result), in(age), now));
RecordSet rs(stmt);
assert (rs["LastName"] == "Simpson");
assert (rs["FirstName"] == "Bart");
assert (rs["Address"] == "Springfield");
assert (rs["Age"] == 12);
dropObject("TABLE", "Person");//fails ([Microsoft][ODBC SQL Server Driver]Connection is busy with results for another hstmt")
dropObject("PROCEDURE", "storedCursorFunction");
k += 2;
}
*/
}
void ODBCSQLServerTest::testRowIterator()
{
if (!_pSession) fail ("Test not available.");
@ -1638,11 +1575,10 @@ CppUnit::Test* ODBCSQLServerTest::suite()
CppUnit_addTest(pSuite, ODBCSQLServerTest, testTuple);
CppUnit_addTest(pSuite, ODBCSQLServerTest, testTupleVector);
CppUnit_addTest(pSuite, ODBCSQLServerTest, testStoredProcedure);
CppUnit_addTest(pSuite, ODBCSQLServerTest, testStoredCursorProcedure);
CppUnit_addTest(pSuite, ODBCSQLServerTest, testCursorStoredProcedure);
CppUnit_addTest(pSuite, ODBCSQLServerTest, testStoredProcedureAny);
CppUnit_addTest(pSuite, ODBCSQLServerTest, testStoredProcedureDynamicAny);
CppUnit_addTest(pSuite, ODBCSQLServerTest, testStoredFunction);
CppUnit_addTest(pSuite, ODBCSQLServerTest, testStoredCursorFunction);
CppUnit_addTest(pSuite, ODBCSQLServerTest, testInternalExtraction);
CppUnit_addTest(pSuite, ODBCSQLServerTest, testInternalStorageType);
CppUnit_addTest(pSuite, ODBCSQLServerTest, testNull);

@ -120,11 +120,10 @@ public:
void testTupleVector();
void testStoredProcedure();
void testStoredCursorProcedure();
void testCursorStoredProcedure();
void testStoredProcedureAny();
void testStoredProcedureDynamicAny();
void testStoredFunction();
void testStoredCursorFunction();
void testInternalExtraction();
void testInternalStorageType();

@ -56,12 +56,13 @@
#include <iterator>
#define print_odbc_error(r, h) \
#define poco_odbc_check(r, h) \
if (!SQL_SUCCEEDED(r)) \
{ \
StatementException se(h); \
std::cout << se.toString() << std::endl; \
}
} \
assert (SQL_SUCCEEDED(r));
using namespace Poco::Data;
@ -218,13 +219,13 @@ void SQLExecutor::bareboneODBCTest(const std::string& dbConnString,
// Environment begin
rc = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);
assert (SQL_SUCCEEDED(rc));
poco_odbc_check (rc, hstmt);
rc = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER) SQL_OV_ODBC3, 0);
assert (SQL_SUCCEEDED(rc));
poco_odbc_check (rc, hstmt);
// Connection begin
rc = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);
assert (SQL_SUCCEEDED(rc));
poco_odbc_check (rc, hstmt);
POCO_SQLCHAR connectOutput[512] = {0};
SQLSMALLINT result;
@ -236,14 +237,14 @@ void SQLExecutor::bareboneODBCTest(const std::string& dbConnString,
, sizeof(connectOutput)
, &result
, SQL_DRIVER_NOPROMPT);
assert (SQL_SUCCEEDED(rc));
poco_odbc_check (rc, hstmt);
// retrieve datetime type information for this DBMS
rc = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);
assert (SQL_SUCCEEDED(rc));
poco_odbc_check (rc, hstmt);
rc = SQLGetTypeInfo(hstmt, SQL_TIMESTAMP);
assert (SQL_SUCCEEDED(rc));
poco_odbc_check (rc, hstmt);
SQLINTEGER dateTimeColSize = 0;
SQLSMALLINT dateTimeDecDigits = 0;
@ -252,19 +253,19 @@ void SQLExecutor::bareboneODBCTest(const std::string& dbConnString,
if (SQL_SUCCEEDED(rc))
{
rc = SQLGetData(hstmt, 3, SQL_C_SLONG, &dateTimeColSize, sizeof(SQLINTEGER), 0);
assert (SQL_SUCCEEDED(rc));
poco_odbc_check (rc, hstmt);
rc = SQLGetData(hstmt, 14, SQL_C_SSHORT, &dateTimeDecDigits, sizeof(SQLSMALLINT), 0);
assert (SQL_SUCCEEDED(rc));
poco_odbc_check (rc, hstmt);
}
else if (SQL_NO_DATA == rc)
std::cerr << "Warning: no data type info returned by driver." << std::endl;
rc = SQLFreeHandle(SQL_HANDLE_STMT, hstmt);
assert (SQL_SUCCEEDED(rc));
poco_odbc_check (rc, hstmt);
// Statement begin
rc = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);
assert (SQL_SUCCEEDED(rc));
poco_odbc_check (rc, hstmt);
std::string sql = "DROP TABLE Test";
POCO_SQLCHAR* pStr = (POCO_SQLCHAR*) sql.c_str();
@ -275,15 +276,15 @@ void SQLExecutor::bareboneODBCTest(const std::string& dbConnString,
sql = tableCreateString;
pStr = (POCO_SQLCHAR*) sql.c_str();
rc = SQLPrepare(hstmt, pStr, (SQLINTEGER) sql.length());
assert (SQL_SUCCEEDED(rc));
poco_odbc_check (rc, hstmt);
rc = SQLExecute(hstmt);
assert (SQL_SUCCEEDED(rc));
poco_odbc_check (rc, hstmt);
sql = "INSERT INTO Test VALUES (?,?,?,?,?,?)";
pStr = (POCO_SQLCHAR*) sql.c_str();
rc = SQLPrepare(hstmt, pStr, (SQLINTEGER) sql.length());
assert (SQL_SUCCEEDED(rc));
poco_odbc_check (rc, hstmt);
std::string str[3] = { "111", "222", "333" };
int fourth = 4;
@ -314,7 +315,7 @@ void SQLExecutor::bareboneODBCTest(const std::string& dbConnString,
(SQLPOINTER) str[0].c_str(),
size,
&li);
assert (SQL_SUCCEEDED(rc));
poco_odbc_check (rc, hstmt);
size = (SQLINTEGER) str[1].size();
if (SQLExecutor::PB_AT_EXEC == bindMode)
@ -330,7 +331,7 @@ void SQLExecutor::bareboneODBCTest(const std::string& dbConnString,
(SQLPOINTER) str[1].c_str(),
size,
&li);
assert (SQL_SUCCEEDED(rc));
poco_odbc_check (rc, hstmt);
size = (SQLINTEGER) str[2].size();
if (SQLExecutor::PB_AT_EXEC == bindMode)
@ -347,7 +348,7 @@ void SQLExecutor::bareboneODBCTest(const std::string& dbConnString,
(SQLPOINTER) str[2].data(),
size,
&li);
assert (SQL_SUCCEEDED(rc));
poco_odbc_check (rc, hstmt);
rc = SQLBindParameter(hstmt,
(SQLUSMALLINT) 4,
@ -359,7 +360,7 @@ void SQLExecutor::bareboneODBCTest(const std::string& dbConnString,
(SQLPOINTER) &fourth,
0,
0);
assert (SQL_SUCCEEDED(rc));
poco_odbc_check (rc, hstmt);
rc = SQLBindParameter(hstmt,
(SQLUSMALLINT) 5,
@ -371,7 +372,7 @@ void SQLExecutor::bareboneODBCTest(const std::string& dbConnString,
(SQLPOINTER) &fifth,
0,
0);
assert (SQL_SUCCEEDED(rc));
poco_odbc_check (rc, hstmt);
rc = SQLBindParameter(hstmt,
(SQLUSMALLINT) 6,
@ -383,7 +384,7 @@ void SQLExecutor::bareboneODBCTest(const std::string& dbConnString,
(SQLPOINTER) &sixth,
0,
0);
assert (SQL_SUCCEEDED(rc));
poco_odbc_check (rc, hstmt);
size = 0;
if (SQLExecutor::PB_AT_EXEC == bindMode)
@ -414,12 +415,12 @@ void SQLExecutor::bareboneODBCTest(const std::string& dbConnString,
++i;
}while (SQL_NEED_DATA == (rc = SQLParamData(hstmt, &pParam)));
}
assert (SQL_SUCCEEDED(rc));
poco_odbc_check (rc, hstmt);
sql = "SELECT * FROM Test";
pStr = (POCO_SQLCHAR*) sql.c_str();
rc = SQLPrepare(hstmt, pStr, (SQLINTEGER) sql.length());
assert (SQL_SUCCEEDED(rc));
poco_odbc_check (rc, hstmt);
char chr[3][5] = {{ 0 }};
SQLLEN lengths[6] = { 0 };
@ -435,7 +436,7 @@ void SQLExecutor::bareboneODBCTest(const std::string& dbConnString,
(SQLPOINTER) chr[0],
(SQLINTEGER) 4,
&lengths[0]);
assert (SQL_SUCCEEDED(rc));
poco_odbc_check (rc, hstmt);
rc = SQLBindCol(hstmt,
(SQLUSMALLINT) 2,
@ -443,7 +444,7 @@ void SQLExecutor::bareboneODBCTest(const std::string& dbConnString,
(SQLPOINTER) chr[1],
(SQLINTEGER) 4,
&lengths[1]);
assert (SQL_SUCCEEDED(rc));
poco_odbc_check (rc, hstmt);
rc = SQLBindCol(hstmt,
(SQLUSMALLINT) 3,
@ -451,7 +452,7 @@ void SQLExecutor::bareboneODBCTest(const std::string& dbConnString,
(SQLPOINTER) chr[2],
(SQLINTEGER) 4,
&lengths[2]);
assert (SQL_SUCCEEDED(rc));
poco_odbc_check (rc, hstmt);
rc = SQLBindCol(hstmt,
(SQLUSMALLINT) 4,
@ -459,7 +460,7 @@ void SQLExecutor::bareboneODBCTest(const std::string& dbConnString,
(SQLPOINTER) &fourth,
(SQLINTEGER) 0,
&lengths[3]);
assert (SQL_SUCCEEDED(rc));
poco_odbc_check (rc, hstmt);
rc = SQLBindCol(hstmt,
(SQLUSMALLINT) 5,
@ -467,7 +468,7 @@ void SQLExecutor::bareboneODBCTest(const std::string& dbConnString,
(SQLPOINTER) &fifth,
(SQLINTEGER) 0,
&lengths[4]);
assert (SQL_SUCCEEDED(rc));
poco_odbc_check (rc, hstmt);
rc = SQLBindCol(hstmt,
(SQLUSMALLINT) 6,
@ -475,13 +476,13 @@ void SQLExecutor::bareboneODBCTest(const std::string& dbConnString,
(SQLPOINTER) &sixth,
(SQLINTEGER) 0,
&lengths[5]);
assert (SQL_SUCCEEDED(rc));
poco_odbc_check (rc, hstmt);
}
rc = SQLExecute(hstmt);
assert (SQL_SUCCEEDED(rc));
poco_odbc_check (rc, hstmt);
rc = SQLFetch(hstmt);
assert (SQL_SUCCEEDED(rc));
poco_odbc_check (rc, hstmt);
if (SQLExecutor::DE_MANUAL == extractMode)
{
@ -491,7 +492,7 @@ void SQLExecutor::bareboneODBCTest(const std::string& dbConnString,
chr[0],
4,
&lengths[0]);
assert (SQL_SUCCEEDED(rc));
poco_odbc_check (rc, hstmt);
rc = SQLGetData(hstmt,
(SQLUSMALLINT) 2,
@ -499,7 +500,7 @@ void SQLExecutor::bareboneODBCTest(const std::string& dbConnString,
chr[1],
4,
&lengths[1]);
assert (SQL_SUCCEEDED(rc));
poco_odbc_check (rc, hstmt);
rc = SQLGetData(hstmt,
(SQLUSMALLINT) 3,
@ -507,7 +508,7 @@ void SQLExecutor::bareboneODBCTest(const std::string& dbConnString,
chr[2],
3,
&lengths[2]);
assert (SQL_SUCCEEDED(rc));
poco_odbc_check (rc, hstmt);
rc = SQLGetData(hstmt,
(SQLUSMALLINT) 4,
@ -515,7 +516,7 @@ void SQLExecutor::bareboneODBCTest(const std::string& dbConnString,
&fourth,
0,
&lengths[3]);
assert (SQL_SUCCEEDED(rc));
poco_odbc_check (rc, hstmt);
rc = SQLGetData(hstmt,
(SQLUSMALLINT) 5,
@ -523,7 +524,7 @@ void SQLExecutor::bareboneODBCTest(const std::string& dbConnString,
&fifth,
0,
&lengths[4]);
assert (SQL_SUCCEEDED(rc));
poco_odbc_check (rc, hstmt);
rc = SQLGetData(hstmt,
(SQLUSMALLINT) 6,
@ -531,7 +532,7 @@ void SQLExecutor::bareboneODBCTest(const std::string& dbConnString,
&sixth,
0,
&lengths[5]);
assert (SQL_SUCCEEDED(rc));
poco_odbc_check (rc, hstmt);
}
assert (0 == strncmp("111", chr[0], 3));
@ -550,25 +551,25 @@ void SQLExecutor::bareboneODBCTest(const std::string& dbConnString,
}
rc = SQLCloseCursor(hstmt);
assert (SQL_SUCCEEDED(rc));
poco_odbc_check (rc, hstmt);
sql = "DROP TABLE Test";
pStr = (POCO_SQLCHAR*) sql.c_str();
rc = SQLExecDirect(hstmt, pStr, (SQLINTEGER) sql.length());
assert (SQL_SUCCEEDED(rc));
poco_odbc_check (rc, hstmt);
rc = SQLFreeHandle(SQL_HANDLE_STMT, hstmt);
assert (SQL_SUCCEEDED(rc));
poco_odbc_check (rc, hstmt);
// Connection end
rc = SQLDisconnect(hdbc);
assert (SQL_SUCCEEDED(rc));
poco_odbc_check (rc, hstmt);
rc = SQLFreeHandle(SQL_HANDLE_DBC, hdbc);
assert (SQL_SUCCEEDED(rc));
poco_odbc_check (rc, hstmt);
// Environment end
rc = SQLFreeHandle(SQL_HANDLE_ENV, henv);
assert (SQL_SUCCEEDED(rc));
poco_odbc_check (rc, hstmt);
}
@ -586,13 +587,13 @@ void SQLExecutor::bareboneODBCMultiResultTest(const std::string& dbConnString,
// Environment begin
rc = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);
assert (SQL_SUCCEEDED(rc));
poco_odbc_check (rc, hstmt);
rc = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER) SQL_OV_ODBC3, 0);
assert (SQL_SUCCEEDED(rc));
poco_odbc_check (rc, hstmt);
// Connection begin
rc = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);
assert (SQL_SUCCEEDED(rc));
poco_odbc_check (rc, hstmt);
POCO_SQLCHAR connectOutput[512] = {0};
SQLSMALLINT result;
@ -604,11 +605,11 @@ void SQLExecutor::bareboneODBCMultiResultTest(const std::string& dbConnString,
, sizeof(connectOutput)
, &result
, SQL_DRIVER_NOPROMPT);
assert (SQL_SUCCEEDED(rc));
poco_odbc_check (rc, hstmt);
// Statement begin
rc = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);
assert (SQL_SUCCEEDED(rc));
poco_odbc_check (rc, hstmt);
std::string sql = "DROP TABLE Test";
POCO_SQLCHAR* pStr = (POCO_SQLCHAR*) sql.c_str();
@ -619,17 +620,17 @@ void SQLExecutor::bareboneODBCMultiResultTest(const std::string& dbConnString,
sql = tableCreateString;
pStr = (POCO_SQLCHAR*) sql.c_str();
rc = SQLPrepare(hstmt, pStr, (SQLINTEGER) sql.length());
assert (SQL_SUCCEEDED(rc));
poco_odbc_check (rc, hstmt);
rc = SQLExecute(hstmt);
assert (SQL_SUCCEEDED(rc));
poco_odbc_check (rc, hstmt);
// insert multiple rows
pStr = (POCO_SQLCHAR*) insert.c_str();
rc = SQLPrepare(hstmt, pStr, (SQLINTEGER) insert.length());
assert (SQL_SUCCEEDED(rc));
poco_odbc_check (rc, hstmt);
rc = SQLExecute(hstmt);
assert (SQL_SUCCEEDED(rc));
poco_odbc_check (rc, hstmt);
do
{
SQLINTEGER rowCount = 0;
@ -638,10 +639,49 @@ void SQLExecutor::bareboneODBCMultiResultTest(const std::string& dbConnString,
} while (SQL_NO_DATA != SQLMoreResults(hstmt));
// make sure all five rows made it in
sql = "select count(*) from Test";
int count = 0;
SQLLEN length = 0;
pStr = (POCO_SQLCHAR*) sql.c_str();
rc = SQLPrepare(hstmt, pStr, (SQLINTEGER) sql.length());
poco_odbc_check (rc, hstmt);
if (SQLExecutor::DE_BOUND == extractMode)
{
rc = SQLBindCol(hstmt,
(SQLUSMALLINT) 1,
SQL_C_SLONG,
(SQLPOINTER) &count,
(SQLINTEGER) 0,
&length);
poco_odbc_check (rc, hstmt);
}
rc = SQLExecute(hstmt);
poco_odbc_check (rc, hstmt);
rc = SQLFetch(hstmt);
poco_odbc_check (rc, hstmt);
if (SQLExecutor::DE_MANUAL == extractMode)
{
rc = SQLGetData(hstmt,
(SQLUSMALLINT) 1,
SQL_C_SLONG,
&count,
0,
&length);
poco_odbc_check (rc, hstmt);
}
assert (5 == count);
rc = SQLCloseCursor(hstmt);
poco_odbc_check (rc, hstmt);
// select multiple rows
pStr = (POCO_SQLCHAR*) select.c_str();
rc = SQLPrepare(hstmt, pStr, (SQLINTEGER) select.length());
assert (SQL_SUCCEEDED(rc));
poco_odbc_check (rc, hstmt);
char chr[5] = { 0 };
SQLLEN lengths[3] = { 0 };
@ -656,7 +696,7 @@ void SQLExecutor::bareboneODBCMultiResultTest(const std::string& dbConnString,
(SQLPOINTER) chr,
(SQLINTEGER) 4,
&lengths[0]);
assert (SQL_SUCCEEDED(rc));
poco_odbc_check (rc, hstmt);
rc = SQLBindCol(hstmt,
(SQLUSMALLINT) 2,
@ -664,7 +704,7 @@ void SQLExecutor::bareboneODBCMultiResultTest(const std::string& dbConnString,
(SQLPOINTER) &second,
(SQLINTEGER) 0,
&lengths[1]);
assert (SQL_SUCCEEDED(rc));
poco_odbc_check (rc, hstmt);
rc = SQLBindCol(hstmt,
(SQLUSMALLINT) 3,
@ -672,22 +712,21 @@ void SQLExecutor::bareboneODBCMultiResultTest(const std::string& dbConnString,
(SQLPOINTER) &third,
(SQLINTEGER) 0,
&lengths[2]);
assert (SQL_SUCCEEDED(rc));
poco_odbc_check (rc, hstmt);
}
rc = SQLExecute(hstmt);
print_odbc_error (rc, hstmt);
assert (SQL_SUCCEEDED(rc));
poco_odbc_check (rc, hstmt);
char one = 0x31;
int two = 2;
float three = 3.5;
count = 0;
do
{
rc = SQLFetch(hstmt);
print_odbc_error (rc, hstmt);
assert (SQL_SUCCEEDED(rc));
poco_odbc_check (rc, hstmt);
if (SQLExecutor::DE_MANUAL == extractMode)
{
@ -697,7 +736,7 @@ void SQLExecutor::bareboneODBCMultiResultTest(const std::string& dbConnString,
chr,
4,
&lengths[0]);
assert (SQL_SUCCEEDED(rc));
poco_odbc_check (rc, hstmt);
rc = SQLGetData(hstmt,
(SQLUSMALLINT) 2,
@ -705,7 +744,7 @@ void SQLExecutor::bareboneODBCMultiResultTest(const std::string& dbConnString,
&second,
0,
&lengths[1]);
assert (SQL_SUCCEEDED(rc));
poco_odbc_check (rc, hstmt);
rc = SQLGetData(hstmt,
(SQLUSMALLINT) 3,
@ -713,7 +752,7 @@ void SQLExecutor::bareboneODBCMultiResultTest(const std::string& dbConnString,
&third,
0,
&lengths[2]);
assert (SQL_SUCCEEDED(rc));
poco_odbc_check (rc, hstmt);
}
assert (one++ == chr[0]);
@ -721,25 +760,28 @@ void SQLExecutor::bareboneODBCMultiResultTest(const std::string& dbConnString,
assert (three == third);
three += 1.0;
++count;
} while (SQL_NO_DATA != SQLMoreResults(hstmt));
assert (5 == count);
sql = "DROP TABLE Test";
pStr = (POCO_SQLCHAR*) sql.c_str();
rc = SQLExecDirect(hstmt, pStr, (SQLINTEGER) sql.length());
assert (SQL_SUCCEEDED(rc));
poco_odbc_check (rc, hstmt);
rc = SQLFreeHandle(SQL_HANDLE_STMT, hstmt);
assert (SQL_SUCCEEDED(rc));
poco_odbc_check (rc, hstmt);
// Connection end
rc = SQLDisconnect(hdbc);
assert (SQL_SUCCEEDED(rc));
poco_odbc_check (rc, hstmt);
rc = SQLFreeHandle(SQL_HANDLE_DBC, hdbc);
assert (SQL_SUCCEEDED(rc));
poco_odbc_check (rc, hstmt);
// Environment end
rc = SQLFreeHandle(SQL_HANDLE_ENV, henv);
assert (SQL_SUCCEEDED(rc));
poco_odbc_check (rc, hstmt);
}
@ -2569,7 +2611,7 @@ void SQLExecutor::dynamicAny()
}
void SQLExecutor::multipleResults()
void SQLExecutor::multipleResults(const std::string& sql)
{
typedef Tuple<std::string, std::string, std::string, int> Person;
std::vector<Person> people;
@ -2578,16 +2620,22 @@ void SQLExecutor::multipleResults()
people.push_back(Person("Simpson", "Lisa", "Springfield", 10));
*_pSession << "INSERT INTO Person VALUES (?, ?, ?, ?)", use(people), now;
Person Homer, Lisa, Bart;
Person pHomer, pLisa;
int aHomer(42), aLisa(10), aBart(0);
*_pSession << "SELECT * FROM Person WHERE FirstName = 'Homer'; "
"SELECT * FROM Person WHERE FirstName = 'Bart'; "
"SELECT * FROM Person WHERE FirstName = 'Lisa'; "
, into(Homer, 0), into(Bart, 1), into(Lisa, 2)
try {
*_pSession << sql
, into(pHomer), use(aHomer)
, into(aBart, 1)
, into(pLisa, 2), use(aLisa)
, now;
} catch (StatementException& ex)
{
std::cout << ex.toString() << std::endl;
}
assert (Person("Simpson", "Homer", "Springfield", 42) == Homer);
assert (Person("Simpson", "Bart", "Springfield", 12) == Bart);
assert (Person("Simpson", "Lisa", "Springfield", 10) == Lisa);
assert (Person("Simpson", "Homer", "Springfield", 42) == pHomer);
assert (12 == aBart);
assert (Person("Simpson", "Lisa", "Springfield", 10) == pLisa);
}

@ -146,7 +146,10 @@ public:
void any();
void dynamicAny();
void multipleResults();
void multipleResults(const std::string& sql =
"SELECT * FROM Person WHERE Age = ?; "
"SELECT Age FROM Person WHERE FirstName = 'Bart'; "
"SELECT * FROM Person WHERE Age = ?; ");
private:
static const std::string MULTI_INSERT;

@ -600,7 +600,7 @@ Binding<T>* in(const T& t, const std::string& name = "")
template <typename T>
Binding<T>* out(const T& t, const std::string& name = "")
Binding<T>* out(T& t, const std::string& name = "")
/// Convenience function for a more compact Binding creation.
{
Binding<T>* pB = new Binding<T>(t, name, AbstractBinding::PD_OUT);
@ -610,7 +610,7 @@ Binding<T>* out(const T& t, const std::string& name = "")
template <typename T>
Binding<T>* io(const T& t, const std::string& name = "")
Binding<T>* io(T& t, const std::string& name = "")
/// Convenience function for a more compact Binding creation.
{
Binding<T>* pB = new Binding<T>(t, name, AbstractBinding::PD_IN_OUT);

@ -346,7 +346,6 @@ Poco::UInt32 StatementImpl::activateNextDataSet()
void StatementImpl::addExtract(AbstractExtraction* pExtraction)
{
poco_check_ptr (pExtraction);
Poco::UInt32 pos = pExtraction->position();
if (pos >= _extractors.size())
_extractors.resize(pos + 1);