diff --git a/Data/MySQL/include/Poco/Data/MySQL/MySQLStatementImpl.h b/Data/MySQL/include/Poco/Data/MySQL/MySQLStatementImpl.h index d178ae666..1aedb9bf6 100644 --- a/Data/MySQL/include/Poco/Data/MySQL/MySQLStatementImpl.h +++ b/Data/MySQL/include/Poco/Data/MySQL/MySQLStatementImpl.h @@ -50,7 +50,7 @@ protected: virtual std::size_t columnsReturned() const; /// Returns number of columns returned by query. - virtual std::size_t affectedRowCount() const; + virtual int affectedRowCount() const; /// Returns the number of affected rows. /// Used to find out the number of rows affected by insert, delete or update. diff --git a/Data/MySQL/include/Poco/Data/MySQL/StatementExecutor.h b/Data/MySQL/include/Poco/Data/MySQL/StatementExecutor.h index 4aa05c725..6a57e6989 100644 --- a/Data/MySQL/include/Poco/Data/MySQL/StatementExecutor.h +++ b/Data/MySQL/include/Poco/Data/MySQL/StatementExecutor.h @@ -64,7 +64,7 @@ public: bool fetchColumn(std::size_t n, MYSQL_BIND *bind); /// Fetches the column. - std::size_t getAffectedRowCount() const; + int getAffectedRowCount() const; operator MYSQL_STMT* (); /// Cast operator to native handle type. @@ -78,7 +78,7 @@ private: MYSQL* _pSessionHandle; MYSQL_STMT* _pHandle; int _state; - std::size_t _affectedRowCount; + int _affectedRowCount; std::string _query; }; diff --git a/Data/MySQL/src/MySQLStatementImpl.cpp b/Data/MySQL/src/MySQLStatementImpl.cpp index c3325ce53..c96896f4f 100644 --- a/Data/MySQL/src/MySQLStatementImpl.cpp +++ b/Data/MySQL/src/MySQLStatementImpl.cpp @@ -42,7 +42,7 @@ std::size_t MySQLStatementImpl::columnsReturned() const } -std::size_t MySQLStatementImpl::affectedRowCount() const +int MySQLStatementImpl::affectedRowCount() const { return _stmt.getAffectedRowCount(); } diff --git a/Data/MySQL/src/StatementExecutor.cpp b/Data/MySQL/src/StatementExecutor.cpp index a63ff3142..ad8290797 100644 --- a/Data/MySQL/src/StatementExecutor.cpp +++ b/Data/MySQL/src/StatementExecutor.cpp @@ -132,7 +132,7 @@ bool StatementExecutor::fetchColumn(std::size_t n, MYSQL_BIND *bind) return (res == 0); } -std::size_t StatementExecutor::getAffectedRowCount() const +int StatementExecutor::getAffectedRowCount() const { return _affectedRowCount; } diff --git a/Data/ODBC/include/Poco/Data/ODBC/ODBCStatementImpl.h b/Data/ODBC/include/Poco/Data/ODBC/ODBCStatementImpl.h index 1d01c8296..89c74b359 100644 --- a/Data/ODBC/include/Poco/Data/ODBC/ODBCStatementImpl.h +++ b/Data/ODBC/include/Poco/Data/ODBC/ODBCStatementImpl.h @@ -56,7 +56,7 @@ protected: std::size_t columnsReturned() const; /// Returns number of columns returned by query. - std::size_t affectedRowCount() const; + int affectedRowCount() const; /// Returns the number of affected rows. /// Used to find out the number of rows affected by insert or update. diff --git a/Data/ODBC/src/ODBCStatementImpl.cpp b/Data/ODBC/src/ODBCStatementImpl.cpp index c48343362..2aee16db3 100644 --- a/Data/ODBC/src/ODBCStatementImpl.cpp +++ b/Data/ODBC/src/ODBCStatementImpl.cpp @@ -440,7 +440,7 @@ const MetaColumn& ODBCStatementImpl::metaColumn(std::size_t pos) const } -std::size_t ODBCStatementImpl::affectedRowCount() const +int ODBCStatementImpl::affectedRowCount() const { if (0 == _affectedRowCount) { diff --git a/Data/ODBC/testsuite/src/ODBCDB2Test.cpp b/Data/ODBC/testsuite/src/ODBCDB2Test.cpp index 296f58e31..dc4078eb4 100644 --- a/Data/ODBC/testsuite/src/ODBCDB2Test.cpp +++ b/Data/ODBC/testsuite/src/ODBCDB2Test.cpp @@ -596,6 +596,7 @@ CppUnit::Test* ODBCDB2Test::suite() CppUnit::TestSuite* pSuite = new CppUnit::TestSuite("ODBCDB2Test"); CppUnit_addTest(pSuite, ODBCDB2Test, testBareboneODBC); + CppUnit_addTest(pSuite, ODBCDB2Test, testZeroRows); CppUnit_addTest(pSuite, ODBCDB2Test, testSimpleAccess); CppUnit_addTest(pSuite, ODBCDB2Test, testComplexType); CppUnit_addTest(pSuite, ODBCDB2Test, testSimpleAccessVector); diff --git a/Data/ODBC/testsuite/src/ODBCMySQLTest.cpp b/Data/ODBC/testsuite/src/ODBCMySQLTest.cpp index 023477041..ba1aedf30 100644 --- a/Data/ODBC/testsuite/src/ODBCMySQLTest.cpp +++ b/Data/ODBC/testsuite/src/ODBCMySQLTest.cpp @@ -421,6 +421,7 @@ CppUnit::Test* ODBCMySQLTest::suite() CppUnit::TestSuite* pSuite = new CppUnit::TestSuite("ODBCMySQLTest"); CppUnit_addTest(pSuite, ODBCMySQLTest, testBareboneODBC); + CppUnit_addTest(pSuite, ODBCMySQLTest, testZeroRows); CppUnit_addTest(pSuite, ODBCMySQLTest, testSimpleAccess); CppUnit_addTest(pSuite, ODBCMySQLTest, testComplexType); CppUnit_addTest(pSuite, ODBCMySQLTest, testSimpleAccessVector); diff --git a/Data/ODBC/testsuite/src/ODBCOracleTest.cpp b/Data/ODBC/testsuite/src/ODBCOracleTest.cpp index b0f353825..75ecd7c2c 100644 --- a/Data/ODBC/testsuite/src/ODBCOracleTest.cpp +++ b/Data/ODBC/testsuite/src/ODBCOracleTest.cpp @@ -856,6 +856,7 @@ CppUnit::Test* ODBCOracleTest::suite() CppUnit::TestSuite* pSuite = new CppUnit::TestSuite("ODBCOracleTest"); CppUnit_addTest(pSuite, ODBCOracleTest, testBareboneODBC); + CppUnit_addTest(pSuite, ODBCOracleTest, testZeroRows); CppUnit_addTest(pSuite, ODBCOracleTest, testSimpleAccess); CppUnit_addTest(pSuite, ODBCOracleTest, testComplexType); CppUnit_addTest(pSuite, ODBCOracleTest, testComplexTypeTuple); diff --git a/Data/ODBC/testsuite/src/ODBCPostgreSQLTest.cpp b/Data/ODBC/testsuite/src/ODBCPostgreSQLTest.cpp index 00a1ef98c..a4f9b95d6 100644 --- a/Data/ODBC/testsuite/src/ODBCPostgreSQLTest.cpp +++ b/Data/ODBC/testsuite/src/ODBCPostgreSQLTest.cpp @@ -585,6 +585,7 @@ CppUnit::Test* ODBCPostgreSQLTest::suite() CppUnit::TestSuite* pSuite = new CppUnit::TestSuite("ODBCPostgreSQLTest"); CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testBareboneODBC); + CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testZeroRows); CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testSimpleAccess); CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testComplexType); CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testSimpleAccessVector); diff --git a/Data/ODBC/testsuite/src/ODBCSQLServerTest.cpp b/Data/ODBC/testsuite/src/ODBCSQLServerTest.cpp index cc7d73130..3ba078628 100644 --- a/Data/ODBC/testsuite/src/ODBCSQLServerTest.cpp +++ b/Data/ODBC/testsuite/src/ODBCSQLServerTest.cpp @@ -737,6 +737,7 @@ CppUnit::Test* ODBCSQLServerTest::suite() CppUnit::TestSuite* pSuite = new CppUnit::TestSuite("ODBCSQLServerTest"); CppUnit_addTest(pSuite, ODBCSQLServerTest, testBareboneODBC); + CppUnit_addTest(pSuite, ODBCSQLServerTest, testZeroRows); CppUnit_addTest(pSuite, ODBCSQLServerTest, testSimpleAccess); CppUnit_addTest(pSuite, ODBCSQLServerTest, testComplexType); CppUnit_addTest(pSuite, ODBCSQLServerTest, testSimpleAccessVector); diff --git a/Data/ODBC/testsuite/src/ODBCSQLiteTest.cpp b/Data/ODBC/testsuite/src/ODBCSQLiteTest.cpp index 73a3e29d9..9c47b5c16 100644 --- a/Data/ODBC/testsuite/src/ODBCSQLiteTest.cpp +++ b/Data/ODBC/testsuite/src/ODBCSQLiteTest.cpp @@ -325,6 +325,7 @@ CppUnit::Test* ODBCSQLiteTest::suite() CppUnit::TestSuite* pSuite = new CppUnit::TestSuite("ODBCSQLiteTest"); CppUnit_addTest(pSuite, ODBCSQLiteTest, testBareboneODBC); + CppUnit_addTest(pSuite, ODBCSQLiteTest, testZeroRows); CppUnit_addTest(pSuite, ODBCSQLiteTest, testSimpleAccess); CppUnit_addTest(pSuite, ODBCSQLiteTest, testComplexType); CppUnit_addTest(pSuite, ODBCSQLiteTest, testSimpleAccessVector); diff --git a/Data/ODBC/testsuite/src/ODBCTest.cpp b/Data/ODBC/testsuite/src/ODBCTest.cpp index a1ca123b3..fe1323f5d 100644 --- a/Data/ODBC/testsuite/src/ODBCTest.cpp +++ b/Data/ODBC/testsuite/src/ODBCTest.cpp @@ -79,6 +79,23 @@ ODBCTest::~ODBCTest() } +void ODBCTest::testZeroRows() +{ + if (!_pSession) fail ("Test not available."); + + std::string tableName("Person"); + + for (int i = 0; i < 8;) + { + recreatePersonTable(); + _pSession->setFeature("autoBind", bindValue(i)); + _pSession->setFeature("autoExtract", bindValue(i+1)); + _pExecutor->zeroRows(); + i += 2; + } +} + + void ODBCTest::testSimpleAccess() { if (!_pSession) fail ("Test not available."); diff --git a/Data/ODBC/testsuite/src/ODBCTest.h b/Data/ODBC/testsuite/src/ODBCTest.h index ce076de55..a0a09c01d 100644 --- a/Data/ODBC/testsuite/src/ODBCTest.h +++ b/Data/ODBC/testsuite/src/ODBCTest.h @@ -49,6 +49,7 @@ public: virtual void testBareboneODBC() = 0; + virtual void testZeroRows(); virtual void testSimpleAccess(); virtual void testComplexType(); virtual void testComplexTypeTuple(); diff --git a/Data/ODBC/testsuite/src/SQLExecutor.cpp b/Data/ODBC/testsuite/src/SQLExecutor.cpp index 8f817892b..9baf6d7f4 100644 --- a/Data/ODBC/testsuite/src/SQLExecutor.cpp +++ b/Data/ODBC/testsuite/src/SQLExecutor.cpp @@ -942,6 +942,13 @@ void SQLExecutor::execute(const std::string& sql) } +void SQLExecutor::zeroRows() +{ + Statement stmt = (session() << "SELECT * FROM Person WHERE 0 = 1"); + assert(0 == stmt.execute()); +} + + void SQLExecutor::simpleAccess() { std::string funct = "simpleAccess()"; diff --git a/Data/ODBC/testsuite/src/SQLExecutor.h b/Data/ODBC/testsuite/src/SQLExecutor.h index 40975088d..259b39f9d 100644 --- a/Data/ODBC/testsuite/src/SQLExecutor.h +++ b/Data/ODBC/testsuite/src/SQLExecutor.h @@ -115,6 +115,7 @@ public: /// (e.g. SQLGetData() restrictions relaxation policy, if any). /// If these test pass, subsequent tests failures are likely ours. + void zeroRows(); void simpleAccess(); void complexType(); void complexTypeTuple(); diff --git a/Data/SQLite/include/Poco/Data/SQLite/SQLiteStatementImpl.h b/Data/SQLite/include/Poco/Data/SQLite/SQLiteStatementImpl.h index ac521e403..7a6531c8b 100644 --- a/Data/SQLite/include/Poco/Data/SQLite/SQLiteStatementImpl.h +++ b/Data/SQLite/include/Poco/Data/SQLite/SQLiteStatementImpl.h @@ -54,7 +54,7 @@ protected: std::size_t columnsReturned() const; /// Returns number of columns returned by query. - std::size_t affectedRowCount() const; + int affectedRowCount() const; /// Returns the number of affected rows. /// Used to find out the number of rows affected by insert, delete or update. /// All changes are counted, even if they are later undone by a ROLLBACK or ABORT. @@ -113,14 +113,14 @@ private: BinderPtr _pBinder; ExtractorPtr _pExtractor; MetaColumnVecVec _columns; - std::size_t _affectedRowCount; + int _affectedRowCount; StrPtr _pLeftover; BindIt _bindBegin; bool _canBind; bool _isExtracted; bool _canCompile; - static const std::size_t POCO_SQLITE_INV_ROW_CNT; + static const int POCO_SQLITE_INV_ROW_CNT; }; diff --git a/Data/SQLite/src/SQLiteStatementImpl.cpp b/Data/SQLite/src/SQLiteStatementImpl.cpp index d27a5f46c..3ec987d96 100644 --- a/Data/SQLite/src/SQLiteStatementImpl.cpp +++ b/Data/SQLite/src/SQLiteStatementImpl.cpp @@ -32,7 +32,7 @@ namespace Data { namespace SQLite { -const std::size_t SQLiteStatementImpl::POCO_SQLITE_INV_ROW_CNT = std::numeric_limits::max(); +const int SQLiteStatementImpl::POCO_SQLITE_INV_ROW_CNT = std::numeric_limits::max(); SQLiteStatementImpl::SQLiteStatementImpl(Poco::Data::SessionImpl& rSession, sqlite3* pDB): @@ -302,7 +302,7 @@ const MetaColumn& SQLiteStatementImpl::metaColumn(std::size_t pos) const } -std::size_t SQLiteStatementImpl::affectedRowCount() const +int SQLiteStatementImpl::affectedRowCount() const { if (_affectedRowCount != POCO_SQLITE_INV_ROW_CNT) return _affectedRowCount; return _pStmt == 0 || sqlite3_stmt_readonly(_pStmt) ? 0 : sqlite3_changes(_pDB); diff --git a/Data/SQLite/testsuite/src/SQLiteTest.cpp b/Data/SQLite/testsuite/src/SQLiteTest.cpp index cf61b0d3a..25107f130 100644 --- a/Data/SQLite/testsuite/src/SQLiteTest.cpp +++ b/Data/SQLite/testsuite/src/SQLiteTest.cpp @@ -295,6 +295,16 @@ void SQLiteTest::testBinding() } +void SQLiteTest::testZeroRows() +{ + Session tmp (Poco::Data::SQLite::Connector::KEY, "dummy.db"); + tmp << "DROP TABLE IF EXISTS ZeroTest", now; + tmp << "CREATE TABLE IF NOT EXISTS ZeroTest (zt INTEGER(3))", now; + Statement stmt = (tmp << "SELECT * FROM ZeroTest"); + assert(0 == stmt.execute()); +} + + void SQLiteTest::testSimpleAccess() { Session tmp (Poco::Data::SQLite::Connector::KEY, "dummy.db"); @@ -3361,6 +3371,7 @@ CppUnit::Test* SQLiteTest::suite() CppUnit::TestSuite* pSuite = new CppUnit::TestSuite("SQLiteTest"); CppUnit_addTest(pSuite, SQLiteTest, testBinding); + CppUnit_addTest(pSuite, SQLiteTest, testZeroRows); CppUnit_addTest(pSuite, SQLiteTest, testSimpleAccess); CppUnit_addTest(pSuite, SQLiteTest, testInMemory); CppUnit_addTest(pSuite, SQLiteTest, testNullCharPointer); diff --git a/Data/SQLite/testsuite/src/SQLiteTest.h b/Data/SQLite/testsuite/src/SQLiteTest.h index 00b787823..cb7b273e0 100644 --- a/Data/SQLite/testsuite/src/SQLiteTest.h +++ b/Data/SQLite/testsuite/src/SQLiteTest.h @@ -35,6 +35,7 @@ public: ~SQLiteTest(); void testBinding(); + void testZeroRows(); void testSimpleAccess(); void testInMemory(); void testNullCharPointer(); diff --git a/Data/include/Poco/Data/Statement.h b/Data/include/Poco/Data/Statement.h index acbf89a10..3ec465292 100644 --- a/Data/include/Poco/Data/Statement.h +++ b/Data/include/Poco/Data/Statement.h @@ -416,7 +416,7 @@ private: Mutex _mutex; AsyncExecMethodPtr _pAsyncExec; std::vector _arguments; - RowFormatter::Ptr _pRowFormatter; + RowFormatter::Ptr _pRowFormatter; mutable std::string _stmtString; }; diff --git a/Data/include/Poco/Data/StatementImpl.h b/Data/include/Poco/Data/StatementImpl.h index 06306e455..37b63b2c1 100644 --- a/Data/include/Poco/Data/StatementImpl.h +++ b/Data/include/Poco/Data/StatementImpl.h @@ -161,9 +161,13 @@ protected: virtual std::size_t columnsReturned() const = 0; /// Returns number of columns returned by query. - virtual std::size_t affectedRowCount() const = 0; + virtual int affectedRowCount() const = 0; /// Returns the number of affected rows. /// Used to find out the number of rows affected by insert, delete or update. + /// + /// Some back-ends may return a negative number in certain circumstances (e.g. + /// some ODBC drivers when this function is called after a select statement + /// execution). virtual const MetaColumn& metaColumn(std::size_t pos) const = 0; /// Returns column meta data. diff --git a/Data/src/StatementImpl.cpp b/Data/src/StatementImpl.cpp index 37e3d2db6..8ad14f187 100644 --- a/Data/src/StatementImpl.cpp +++ b/Data/src/StatementImpl.cpp @@ -144,7 +144,14 @@ std::size_t StatementImpl::executeWithLimit() else _state = ST_PAUSED; - return count ? count : affectedRowCount(); + int affectedRows = affectedRowCount(); + if (count == 0) + { + if (affectedRows > 0) + return affectedRows; + } + + return count; } @@ -159,7 +166,14 @@ std::size_t StatementImpl::executeWithoutLimit() while (hasNext()) count += next(); } while (canBind()); - return count ? count : affectedRowCount(); + int affectedRows = affectedRowCount(); + if (count == 0) + { + if (affectedRows > 0) + return affectedRows; + } + + return count; } diff --git a/Data/testsuite/src/TestStatementImpl.h b/Data/testsuite/src/TestStatementImpl.h index 818b6d9f7..ae60bcbb3 100644 --- a/Data/testsuite/src/TestStatementImpl.h +++ b/Data/testsuite/src/TestStatementImpl.h @@ -46,7 +46,7 @@ protected: std::size_t columnsReturned() const; /// Returns number of columns returned by query. - std::size_t affectedRowCount() const; + int affectedRowCount() const; /// Returns the number of affected rows. /// Used to find out the number of rows affected by insert or update. @@ -101,7 +101,7 @@ inline AbstractBinding::BinderPtr TestStatementImpl::binder() } -inline std::size_t TestStatementImpl::affectedRowCount() const +inline int TestStatementImpl::affectedRowCount() const { return 0; }