From 07f33b729a96f12e5ba9f243add50cb5b751e6a4 Mon Sep 17 00:00:00 2001 From: Cameron Smith Date: Fri, 7 Jun 2013 15:14:18 -0400 Subject: [PATCH 1/2] GH #192: Unsigned integer values not handled properly in result sets --- .../MySQL/include/Poco/Data/MySQL/Extractor.h | 2 +- Data/MySQL/src/Extractor.cpp | 13 ++++++----- Data/MySQL/src/ResultMetadata.cpp | 1 + Data/MySQL/src/StatementExecutor.cpp | 10 ++++---- Data/MySQL/testsuite/src/MySQLTest.cpp | 18 +++++++++++++++ Data/MySQL/testsuite/src/MySQLTest.h | 2 ++ Data/MySQL/testsuite/src/SQLExecutor.cpp | 23 +++++++++++++++++++ Data/MySQL/testsuite/src/SQLExecutor.h | 1 + 8 files changed, 58 insertions(+), 12 deletions(-) diff --git a/Data/MySQL/include/Poco/Data/MySQL/Extractor.h b/Data/MySQL/include/Poco/Data/MySQL/Extractor.h index ea0644b01..0e5be6877 100644 --- a/Data/MySQL/include/Poco/Data/MySQL/Extractor.h +++ b/Data/MySQL/include/Poco/Data/MySQL/Extractor.h @@ -342,7 +342,7 @@ public: private: - bool realExtractFixed(std::size_t pos, enum_field_types type, void* buffer, std::size_t length = 0); + bool realExtractFixed(std::size_t pos, enum_field_types type, void* buffer, std::size_t length = 0, bool isUnsigned = false); // Prevent VC8 warning "operator= could not be generated" Extractor& operator=(const Extractor&); diff --git a/Data/MySQL/src/Extractor.cpp b/Data/MySQL/src/Extractor.cpp index 42e3cb876..4abe9182d 100644 --- a/Data/MySQL/src/Extractor.cpp +++ b/Data/MySQL/src/Extractor.cpp @@ -62,7 +62,7 @@ bool Extractor::extract(std::size_t pos, Poco::Int8& val) bool Extractor::extract(std::size_t pos, Poco::UInt8& val) { - return realExtractFixed(pos, MYSQL_TYPE_TINY, &val); + return realExtractFixed(pos, MYSQL_TYPE_TINY, &val, true); } @@ -74,7 +74,7 @@ bool Extractor::extract(std::size_t pos, Poco::Int16& val) bool Extractor::extract(std::size_t pos, Poco::UInt16& val) { - return realExtractFixed(pos, MYSQL_TYPE_SHORT, &val); + return realExtractFixed(pos, MYSQL_TYPE_SHORT, &val, true); } @@ -86,7 +86,7 @@ bool Extractor::extract(std::size_t pos, Poco::Int32& val) bool Extractor::extract(std::size_t pos, Poco::UInt32& val) { - return realExtractFixed(pos, MYSQL_TYPE_LONG, &val); + return realExtractFixed(pos, MYSQL_TYPE_LONG, &val, true); } @@ -98,7 +98,7 @@ bool Extractor::extract(std::size_t pos, Poco::Int64& val) bool Extractor::extract(std::size_t pos, Poco::UInt64& val) { - return realExtractFixed(pos, MYSQL_TYPE_LONGLONG, &val); + return realExtractFixed(pos, MYSQL_TYPE_LONGLONG, &val, true); } @@ -111,7 +111,7 @@ bool Extractor::extract(std::size_t pos, long& val) bool Extractor::extract(std::size_t pos, unsigned long& val) { - return realExtractFixed(pos, MYSQL_TYPE_LONG, &val); + return realExtractFixed(pos, MYSQL_TYPE_LONG, &val, true); } #endif @@ -255,7 +255,7 @@ void Extractor::reset() } -bool Extractor::realExtractFixed(std::size_t pos, enum_field_types type, void* buffer, std::size_t length) +bool Extractor::realExtractFixed(std::size_t pos, enum_field_types type, void* buffer, std::size_t length, bool isUnsigned) { MYSQL_BIND bind = {0}; my_bool isNull = 0; @@ -264,6 +264,7 @@ bool Extractor::realExtractFixed(std::size_t pos, enum_field_types type, void* b bind.buffer_type = type; bind.buffer = buffer; bind.buffer_length = static_cast(length); + bind.is_unsigned = isUnsigned; if (!_stmt.fetchColumn(pos, &bind)) return false; diff --git a/Data/MySQL/src/ResultMetadata.cpp b/Data/MySQL/src/ResultMetadata.cpp index b018b7d46..ab4a7cb8e 100644 --- a/Data/MySQL/src/ResultMetadata.cpp +++ b/Data/MySQL/src/ResultMetadata.cpp @@ -217,6 +217,7 @@ void ResultMetadata::init(MYSQL_STMT* stmt) _row[i].buffer = &_buffer[0] + offset; _row[i].length = &_lengths[i]; _row[i].is_null = &_isNull[i]; + _row[i].is_unsigned = (fields[i].flags & UNSIGNED_FLAG) > 0; offset += _row[i].buffer_length; }} diff --git a/Data/MySQL/src/StatementExecutor.cpp b/Data/MySQL/src/StatementExecutor.cpp index 3a6ab77d3..944cca4da 100644 --- a/Data/MySQL/src/StatementExecutor.cpp +++ b/Data/MySQL/src/StatementExecutor.cpp @@ -86,7 +86,7 @@ void StatementExecutor::prepare(const std::string& query) void StatementExecutor::bindParams(MYSQL_BIND* params, std::size_t count) { if (_state < STMT_COMPILED) - throw StatementException("Satement is not compiled yet"); + throw StatementException("Statement is not compiled yet"); if (count != mysql_stmt_param_count(_pHandle)) throw StatementException("wrong bind parameters count", 0, _query); @@ -101,7 +101,7 @@ void StatementExecutor::bindParams(MYSQL_BIND* params, std::size_t count) void StatementExecutor::bindResult(MYSQL_BIND* result) { if (_state < STMT_COMPILED) - throw StatementException("Satement is not compiled yet"); + throw StatementException("Statement is not compiled yet"); if (mysql_stmt_bind_result(_pHandle, result) != 0) throw StatementException("mysql_stmt_bind_result error ", _pHandle, _query); @@ -111,7 +111,7 @@ void StatementExecutor::bindResult(MYSQL_BIND* result) void StatementExecutor::execute() { if (_state < STMT_COMPILED) - throw StatementException("Satement is not compiled yet"); + throw StatementException("Statement is not compiled yet"); if (mysql_stmt_execute(_pHandle) != 0) throw StatementException("mysql_stmt_execute error", _pHandle, _query); @@ -127,7 +127,7 @@ void StatementExecutor::execute() bool StatementExecutor::fetch() { if (_state < STMT_EXECUTED) - throw StatementException("Satement is not executed yet"); + throw StatementException("Statement is not executed yet"); int res = mysql_stmt_fetch(_pHandle); @@ -141,7 +141,7 @@ bool StatementExecutor::fetch() bool StatementExecutor::fetchColumn(std::size_t n, MYSQL_BIND *bind) { if (_state < STMT_EXECUTED) - throw StatementException("Satement is not executed yet"); + throw StatementException("Statement is not executed yet"); int res = mysql_stmt_fetch_column(_pHandle, bind, static_cast(n), 0); diff --git a/Data/MySQL/testsuite/src/MySQLTest.cpp b/Data/MySQL/testsuite/src/MySQLTest.cpp index f9e457e0a..352d873cb 100644 --- a/Data/MySQL/testsuite/src/MySQLTest.cpp +++ b/Data/MySQL/testsuite/src/MySQLTest.cpp @@ -471,6 +471,15 @@ void MySQLTest::testBLOBStmt() } +void MySQLTest::testUnsignedInts() +{ + if (!_pSession) fail ("Test not available."); + + recreateUnsignedIntsTable(); + _pExecutor->unsignedInts(); +} + + void MySQLTest::testFloat() { if (!_pSession) fail ("Test not available."); @@ -755,6 +764,15 @@ void MySQLTest::recreateStringsTable() } +void MySQLTest::recreateUnsignedIntsTable() +{ + dropTable("Strings"); + try { *_pSession << "CREATE TABLE Strings (str INTEGER UNSIGNED)", now; } + catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail ("recreateUnsignedIntegersTable()"); } + catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail ("recreateUnsignedIntegersTable()"); } +} + + void MySQLTest::recreateFloatsTable() { dropTable("Strings"); diff --git a/Data/MySQL/testsuite/src/MySQLTest.h b/Data/MySQL/testsuite/src/MySQLTest.h index 887f69af1..038fd7b56 100644 --- a/Data/MySQL/testsuite/src/MySQLTest.h +++ b/Data/MySQL/testsuite/src/MySQLTest.h @@ -99,6 +99,7 @@ public: void testBLOB(); void testBLOBStmt(); + void testUnsignedInts(); void testFloat(); void testDouble(); @@ -134,6 +135,7 @@ private: void recreatePersonTimeTable(); void recreateStringsTable(); void recreateIntsTable(); + void recreateUnsignedIntsTable(); void recreateFloatsTable(); void recreateTuplesTable(); void recreateVectorsTable(); diff --git a/Data/MySQL/testsuite/src/SQLExecutor.cpp b/Data/MySQL/testsuite/src/SQLExecutor.cpp index 52029f589..e8d4be775 100644 --- a/Data/MySQL/testsuite/src/SQLExecutor.cpp +++ b/Data/MySQL/testsuite/src/SQLExecutor.cpp @@ -497,6 +497,29 @@ void SQLExecutor::insertSingleBulk() } +void SQLExecutor::unsignedInts() +{ + std::string funct = "unsignedInts()"; + unsigned int data = UINT32_MAX; + unsigned int ret = 0; + + try { *_pSession << "INSERT INTO Strings VALUES (?)", use(data), now; } + catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } + catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } + + int count = 0; + try { *_pSession << "SELECT COUNT(*) FROM Strings", into(count), now; } + catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } + catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } + assert (count == 1); + + try { *_pSession << "SELECT str FROM Strings", into(ret), now; } + catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } + catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } + assert (ret == data); +} + + void SQLExecutor::floats() { std::string funct = "floats()"; diff --git a/Data/MySQL/testsuite/src/SQLExecutor.h b/Data/MySQL/testsuite/src/SQLExecutor.h index ae6e1f3bd..eb2e23e56 100644 --- a/Data/MySQL/testsuite/src/SQLExecutor.h +++ b/Data/MySQL/testsuite/src/SQLExecutor.h @@ -105,6 +105,7 @@ public: void dateTime(); void date(); void time(); + void unsignedInts(); void floats(); void doubles(); void tuples(); From af84d915d088d3064c44b193c651d3581806c553 Mon Sep 17 00:00:00 2001 From: Cameron Smith Date: Fri, 7 Jun 2013 15:57:22 -0400 Subject: [PATCH 2/2] Added new test to test case list. --- Data/MySQL/testsuite/src/MySQLTest.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Data/MySQL/testsuite/src/MySQLTest.cpp b/Data/MySQL/testsuite/src/MySQLTest.cpp index 352d873cb..cb653302c 100644 --- a/Data/MySQL/testsuite/src/MySQLTest.cpp +++ b/Data/MySQL/testsuite/src/MySQLTest.cpp @@ -894,6 +894,7 @@ CppUnit::Test* MySQLTest::suite() CppUnit_addTest(pSuite, MySQLTest, testDateTime); //CppUnit_addTest(pSuite, MySQLTest, testBLOB); CppUnit_addTest(pSuite, MySQLTest, testBLOBStmt); + CppUnit_addTest(pSuite, MySQLTest, testUnsignedInts); CppUnit_addTest(pSuite, MySQLTest, testFloat); CppUnit_addTest(pSuite, MySQLTest, testDouble); CppUnit_addTest(pSuite, MySQLTest, testTuple);