GH #499: Poco::Data::Statement::execute returns wrong value when zero results (ODBC)

This commit is contained in:
Aleksandar Fabijanic 2014-12-17 23:36:26 -06:00
parent 55dffd864f
commit 86b81bfcbd
24 changed files with 80 additions and 18 deletions

View File

@ -50,7 +50,7 @@ protected:
virtual std::size_t columnsReturned() const; virtual std::size_t columnsReturned() const;
/// Returns number of columns returned by query. /// Returns number of columns returned by query.
virtual std::size_t affectedRowCount() const; virtual int affectedRowCount() const;
/// Returns the number of affected rows. /// Returns the number of affected rows.
/// Used to find out the number of rows affected by insert, delete or update. /// Used to find out the number of rows affected by insert, delete or update.

View File

@ -64,7 +64,7 @@ public:
bool fetchColumn(std::size_t n, MYSQL_BIND *bind); bool fetchColumn(std::size_t n, MYSQL_BIND *bind);
/// Fetches the column. /// Fetches the column.
std::size_t getAffectedRowCount() const; int getAffectedRowCount() const;
operator MYSQL_STMT* (); operator MYSQL_STMT* ();
/// Cast operator to native handle type. /// Cast operator to native handle type.
@ -78,7 +78,7 @@ private:
MYSQL* _pSessionHandle; MYSQL* _pSessionHandle;
MYSQL_STMT* _pHandle; MYSQL_STMT* _pHandle;
int _state; int _state;
std::size_t _affectedRowCount; int _affectedRowCount;
std::string _query; std::string _query;
}; };

View File

@ -42,7 +42,7 @@ std::size_t MySQLStatementImpl::columnsReturned() const
} }
std::size_t MySQLStatementImpl::affectedRowCount() const int MySQLStatementImpl::affectedRowCount() const
{ {
return _stmt.getAffectedRowCount(); return _stmt.getAffectedRowCount();
} }

View File

@ -132,7 +132,7 @@ bool StatementExecutor::fetchColumn(std::size_t n, MYSQL_BIND *bind)
return (res == 0); return (res == 0);
} }
std::size_t StatementExecutor::getAffectedRowCount() const int StatementExecutor::getAffectedRowCount() const
{ {
return _affectedRowCount; return _affectedRowCount;
} }

View File

@ -56,7 +56,7 @@ protected:
std::size_t columnsReturned() const; std::size_t columnsReturned() const;
/// Returns number of columns returned by query. /// Returns number of columns returned by query.
std::size_t affectedRowCount() const; int affectedRowCount() const;
/// Returns the number of affected rows. /// Returns the number of affected rows.
/// Used to find out the number of rows affected by insert or update. /// Used to find out the number of rows affected by insert or update.

View File

@ -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) if (0 == _affectedRowCount)
{ {

View File

@ -596,6 +596,7 @@ CppUnit::Test* ODBCDB2Test::suite()
CppUnit::TestSuite* pSuite = new CppUnit::TestSuite("ODBCDB2Test"); CppUnit::TestSuite* pSuite = new CppUnit::TestSuite("ODBCDB2Test");
CppUnit_addTest(pSuite, ODBCDB2Test, testBareboneODBC); CppUnit_addTest(pSuite, ODBCDB2Test, testBareboneODBC);
CppUnit_addTest(pSuite, ODBCDB2Test, testZeroRows);
CppUnit_addTest(pSuite, ODBCDB2Test, testSimpleAccess); CppUnit_addTest(pSuite, ODBCDB2Test, testSimpleAccess);
CppUnit_addTest(pSuite, ODBCDB2Test, testComplexType); CppUnit_addTest(pSuite, ODBCDB2Test, testComplexType);
CppUnit_addTest(pSuite, ODBCDB2Test, testSimpleAccessVector); CppUnit_addTest(pSuite, ODBCDB2Test, testSimpleAccessVector);

View File

@ -421,6 +421,7 @@ CppUnit::Test* ODBCMySQLTest::suite()
CppUnit::TestSuite* pSuite = new CppUnit::TestSuite("ODBCMySQLTest"); CppUnit::TestSuite* pSuite = new CppUnit::TestSuite("ODBCMySQLTest");
CppUnit_addTest(pSuite, ODBCMySQLTest, testBareboneODBC); CppUnit_addTest(pSuite, ODBCMySQLTest, testBareboneODBC);
CppUnit_addTest(pSuite, ODBCMySQLTest, testZeroRows);
CppUnit_addTest(pSuite, ODBCMySQLTest, testSimpleAccess); CppUnit_addTest(pSuite, ODBCMySQLTest, testSimpleAccess);
CppUnit_addTest(pSuite, ODBCMySQLTest, testComplexType); CppUnit_addTest(pSuite, ODBCMySQLTest, testComplexType);
CppUnit_addTest(pSuite, ODBCMySQLTest, testSimpleAccessVector); CppUnit_addTest(pSuite, ODBCMySQLTest, testSimpleAccessVector);

View File

@ -856,6 +856,7 @@ CppUnit::Test* ODBCOracleTest::suite()
CppUnit::TestSuite* pSuite = new CppUnit::TestSuite("ODBCOracleTest"); CppUnit::TestSuite* pSuite = new CppUnit::TestSuite("ODBCOracleTest");
CppUnit_addTest(pSuite, ODBCOracleTest, testBareboneODBC); CppUnit_addTest(pSuite, ODBCOracleTest, testBareboneODBC);
CppUnit_addTest(pSuite, ODBCOracleTest, testZeroRows);
CppUnit_addTest(pSuite, ODBCOracleTest, testSimpleAccess); CppUnit_addTest(pSuite, ODBCOracleTest, testSimpleAccess);
CppUnit_addTest(pSuite, ODBCOracleTest, testComplexType); CppUnit_addTest(pSuite, ODBCOracleTest, testComplexType);
CppUnit_addTest(pSuite, ODBCOracleTest, testComplexTypeTuple); CppUnit_addTest(pSuite, ODBCOracleTest, testComplexTypeTuple);

View File

@ -585,6 +585,7 @@ CppUnit::Test* ODBCPostgreSQLTest::suite()
CppUnit::TestSuite* pSuite = new CppUnit::TestSuite("ODBCPostgreSQLTest"); CppUnit::TestSuite* pSuite = new CppUnit::TestSuite("ODBCPostgreSQLTest");
CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testBareboneODBC); CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testBareboneODBC);
CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testZeroRows);
CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testSimpleAccess); CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testSimpleAccess);
CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testComplexType); CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testComplexType);
CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testSimpleAccessVector); CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testSimpleAccessVector);

View File

@ -737,6 +737,7 @@ CppUnit::Test* ODBCSQLServerTest::suite()
CppUnit::TestSuite* pSuite = new CppUnit::TestSuite("ODBCSQLServerTest"); CppUnit::TestSuite* pSuite = new CppUnit::TestSuite("ODBCSQLServerTest");
CppUnit_addTest(pSuite, ODBCSQLServerTest, testBareboneODBC); CppUnit_addTest(pSuite, ODBCSQLServerTest, testBareboneODBC);
CppUnit_addTest(pSuite, ODBCSQLServerTest, testZeroRows);
CppUnit_addTest(pSuite, ODBCSQLServerTest, testSimpleAccess); CppUnit_addTest(pSuite, ODBCSQLServerTest, testSimpleAccess);
CppUnit_addTest(pSuite, ODBCSQLServerTest, testComplexType); CppUnit_addTest(pSuite, ODBCSQLServerTest, testComplexType);
CppUnit_addTest(pSuite, ODBCSQLServerTest, testSimpleAccessVector); CppUnit_addTest(pSuite, ODBCSQLServerTest, testSimpleAccessVector);

View File

@ -325,6 +325,7 @@ CppUnit::Test* ODBCSQLiteTest::suite()
CppUnit::TestSuite* pSuite = new CppUnit::TestSuite("ODBCSQLiteTest"); CppUnit::TestSuite* pSuite = new CppUnit::TestSuite("ODBCSQLiteTest");
CppUnit_addTest(pSuite, ODBCSQLiteTest, testBareboneODBC); CppUnit_addTest(pSuite, ODBCSQLiteTest, testBareboneODBC);
CppUnit_addTest(pSuite, ODBCSQLiteTest, testZeroRows);
CppUnit_addTest(pSuite, ODBCSQLiteTest, testSimpleAccess); CppUnit_addTest(pSuite, ODBCSQLiteTest, testSimpleAccess);
CppUnit_addTest(pSuite, ODBCSQLiteTest, testComplexType); CppUnit_addTest(pSuite, ODBCSQLiteTest, testComplexType);
CppUnit_addTest(pSuite, ODBCSQLiteTest, testSimpleAccessVector); CppUnit_addTest(pSuite, ODBCSQLiteTest, testSimpleAccessVector);

View File

@ -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() void ODBCTest::testSimpleAccess()
{ {
if (!_pSession) fail ("Test not available."); if (!_pSession) fail ("Test not available.");

View File

@ -49,6 +49,7 @@ public:
virtual void testBareboneODBC() = 0; virtual void testBareboneODBC() = 0;
virtual void testZeroRows();
virtual void testSimpleAccess(); virtual void testSimpleAccess();
virtual void testComplexType(); virtual void testComplexType();
virtual void testComplexTypeTuple(); virtual void testComplexTypeTuple();

View File

@ -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() void SQLExecutor::simpleAccess()
{ {
std::string funct = "simpleAccess()"; std::string funct = "simpleAccess()";

View File

@ -115,6 +115,7 @@ public:
/// (e.g. SQLGetData() restrictions relaxation policy, if any). /// (e.g. SQLGetData() restrictions relaxation policy, if any).
/// If these test pass, subsequent tests failures are likely ours. /// If these test pass, subsequent tests failures are likely ours.
void zeroRows();
void simpleAccess(); void simpleAccess();
void complexType(); void complexType();
void complexTypeTuple(); void complexTypeTuple();

View File

@ -54,7 +54,7 @@ protected:
std::size_t columnsReturned() const; std::size_t columnsReturned() const;
/// Returns number of columns returned by query. /// Returns number of columns returned by query.
std::size_t affectedRowCount() const; int affectedRowCount() const;
/// Returns the number of affected rows. /// Returns the number of affected rows.
/// Used to find out the number of rows affected by insert, delete or update. /// 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. /// All changes are counted, even if they are later undone by a ROLLBACK or ABORT.
@ -113,14 +113,14 @@ private:
BinderPtr _pBinder; BinderPtr _pBinder;
ExtractorPtr _pExtractor; ExtractorPtr _pExtractor;
MetaColumnVecVec _columns; MetaColumnVecVec _columns;
std::size_t _affectedRowCount; int _affectedRowCount;
StrPtr _pLeftover; StrPtr _pLeftover;
BindIt _bindBegin; BindIt _bindBegin;
bool _canBind; bool _canBind;
bool _isExtracted; bool _isExtracted;
bool _canCompile; bool _canCompile;
static const std::size_t POCO_SQLITE_INV_ROW_CNT; static const int POCO_SQLITE_INV_ROW_CNT;
}; };

View File

@ -32,7 +32,7 @@ namespace Data {
namespace SQLite { namespace SQLite {
const std::size_t SQLiteStatementImpl::POCO_SQLITE_INV_ROW_CNT = std::numeric_limits<std::size_t>::max(); const int SQLiteStatementImpl::POCO_SQLITE_INV_ROW_CNT = std::numeric_limits<std::size_t>::max();
SQLiteStatementImpl::SQLiteStatementImpl(Poco::Data::SessionImpl& rSession, sqlite3* pDB): 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; if (_affectedRowCount != POCO_SQLITE_INV_ROW_CNT) return _affectedRowCount;
return _pStmt == 0 || sqlite3_stmt_readonly(_pStmt) ? 0 : sqlite3_changes(_pDB); return _pStmt == 0 || sqlite3_stmt_readonly(_pStmt) ? 0 : sqlite3_changes(_pDB);

View File

@ -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() void SQLiteTest::testSimpleAccess()
{ {
Session tmp (Poco::Data::SQLite::Connector::KEY, "dummy.db"); 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::TestSuite* pSuite = new CppUnit::TestSuite("SQLiteTest");
CppUnit_addTest(pSuite, SQLiteTest, testBinding); CppUnit_addTest(pSuite, SQLiteTest, testBinding);
CppUnit_addTest(pSuite, SQLiteTest, testZeroRows);
CppUnit_addTest(pSuite, SQLiteTest, testSimpleAccess); CppUnit_addTest(pSuite, SQLiteTest, testSimpleAccess);
CppUnit_addTest(pSuite, SQLiteTest, testInMemory); CppUnit_addTest(pSuite, SQLiteTest, testInMemory);
CppUnit_addTest(pSuite, SQLiteTest, testNullCharPointer); CppUnit_addTest(pSuite, SQLiteTest, testNullCharPointer);

View File

@ -35,6 +35,7 @@ public:
~SQLiteTest(); ~SQLiteTest();
void testBinding(); void testBinding();
void testZeroRows();
void testSimpleAccess(); void testSimpleAccess();
void testInMemory(); void testInMemory();
void testNullCharPointer(); void testNullCharPointer();

View File

@ -416,7 +416,7 @@ private:
Mutex _mutex; Mutex _mutex;
AsyncExecMethodPtr _pAsyncExec; AsyncExecMethodPtr _pAsyncExec;
std::vector<Any> _arguments; std::vector<Any> _arguments;
RowFormatter::Ptr _pRowFormatter; RowFormatter::Ptr _pRowFormatter;
mutable std::string _stmtString; mutable std::string _stmtString;
}; };

View File

@ -161,9 +161,13 @@ protected:
virtual std::size_t columnsReturned() const = 0; virtual std::size_t columnsReturned() const = 0;
/// Returns number of columns returned by query. /// 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. /// Returns the number of affected rows.
/// Used to find out the number of rows affected by insert, delete or update. /// 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; virtual const MetaColumn& metaColumn(std::size_t pos) const = 0;
/// Returns column meta data. /// Returns column meta data.

View File

@ -144,7 +144,14 @@ std::size_t StatementImpl::executeWithLimit()
else else
_state = ST_PAUSED; _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 (hasNext()) count += next();
} while (canBind()); } while (canBind());
return count ? count : affectedRowCount(); int affectedRows = affectedRowCount();
if (count == 0)
{
if (affectedRows > 0)
return affectedRows;
}
return count;
} }

View File

@ -46,7 +46,7 @@ protected:
std::size_t columnsReturned() const; std::size_t columnsReturned() const;
/// Returns number of columns returned by query. /// Returns number of columns returned by query.
std::size_t affectedRowCount() const; int affectedRowCount() const;
/// Returns the number of affected rows. /// Returns the number of affected rows.
/// Used to find out the number of rows affected by insert or update. /// 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; return 0;
} }