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;
/// 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.

View File

@ -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;
};

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();
}

View File

@ -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;
}

View File

@ -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.

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)
{

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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);

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

View File

@ -49,6 +49,7 @@ public:
virtual void testBareboneODBC() = 0;
virtual void testZeroRows();
virtual void testSimpleAccess();
virtual void testComplexType();
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()
{
std::string funct = "simpleAccess()";

View File

@ -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();

View File

@ -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;
};

View File

@ -32,7 +32,7 @@ namespace Data {
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):
@ -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);

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()
{
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);

View File

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

View File

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

View File

@ -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.

View File

@ -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;
}

View File

@ -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;
}