Merge pull request #214 from cksmith/fix-192

Fixed GH #192: MySQL: Unsigned integer values not handled properly in result sets
This commit is contained in:
Aleksandar Fabijanic 2013-06-07 13:34:04 -07:00
commit 1d2a95e110
8 changed files with 59 additions and 12 deletions

View File

@ -342,7 +342,7 @@ public:
private: 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" // Prevent VC8 warning "operator= could not be generated"
Extractor& operator=(const Extractor&); Extractor& operator=(const Extractor&);

View File

@ -62,7 +62,7 @@ bool Extractor::extract(std::size_t pos, Poco::Int8& val)
bool Extractor::extract(std::size_t pos, Poco::UInt8& 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) 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) 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) 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) 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 #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}; MYSQL_BIND bind = {0};
my_bool isNull = 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_type = type;
bind.buffer = buffer; bind.buffer = buffer;
bind.buffer_length = static_cast<unsigned long>(length); bind.buffer_length = static_cast<unsigned long>(length);
bind.is_unsigned = isUnsigned;
if (!_stmt.fetchColumn(pos, &bind)) if (!_stmt.fetchColumn(pos, &bind))
return false; return false;

View File

@ -217,6 +217,7 @@ void ResultMetadata::init(MYSQL_STMT* stmt)
_row[i].buffer = &_buffer[0] + offset; _row[i].buffer = &_buffer[0] + offset;
_row[i].length = &_lengths[i]; _row[i].length = &_lengths[i];
_row[i].is_null = &_isNull[i]; _row[i].is_null = &_isNull[i];
_row[i].is_unsigned = (fields[i].flags & UNSIGNED_FLAG) > 0;
offset += _row[i].buffer_length; offset += _row[i].buffer_length;
}} }}

View File

@ -86,7 +86,7 @@ void StatementExecutor::prepare(const std::string& query)
void StatementExecutor::bindParams(MYSQL_BIND* params, std::size_t count) void StatementExecutor::bindParams(MYSQL_BIND* params, std::size_t count)
{ {
if (_state < STMT_COMPILED) 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)) if (count != mysql_stmt_param_count(_pHandle))
throw StatementException("wrong bind parameters count", 0, _query); 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) void StatementExecutor::bindResult(MYSQL_BIND* result)
{ {
if (_state < STMT_COMPILED) 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) if (mysql_stmt_bind_result(_pHandle, result) != 0)
throw StatementException("mysql_stmt_bind_result error ", _pHandle, _query); throw StatementException("mysql_stmt_bind_result error ", _pHandle, _query);
@ -111,7 +111,7 @@ void StatementExecutor::bindResult(MYSQL_BIND* result)
void StatementExecutor::execute() void StatementExecutor::execute()
{ {
if (_state < STMT_COMPILED) if (_state < STMT_COMPILED)
throw StatementException("Satement is not compiled yet"); throw StatementException("Statement is not compiled yet");
if (mysql_stmt_execute(_pHandle) != 0) if (mysql_stmt_execute(_pHandle) != 0)
throw StatementException("mysql_stmt_execute error", _pHandle, _query); throw StatementException("mysql_stmt_execute error", _pHandle, _query);
@ -127,7 +127,7 @@ void StatementExecutor::execute()
bool StatementExecutor::fetch() bool StatementExecutor::fetch()
{ {
if (_state < STMT_EXECUTED) if (_state < STMT_EXECUTED)
throw StatementException("Satement is not executed yet"); throw StatementException("Statement is not executed yet");
int res = mysql_stmt_fetch(_pHandle); int res = mysql_stmt_fetch(_pHandle);
@ -141,7 +141,7 @@ bool StatementExecutor::fetch()
bool StatementExecutor::fetchColumn(std::size_t n, MYSQL_BIND *bind) bool StatementExecutor::fetchColumn(std::size_t n, MYSQL_BIND *bind)
{ {
if (_state < STMT_EXECUTED) 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<unsigned int>(n), 0); int res = mysql_stmt_fetch_column(_pHandle, bind, static_cast<unsigned int>(n), 0);

View File

@ -471,6 +471,15 @@ void MySQLTest::testBLOBStmt()
} }
void MySQLTest::testUnsignedInts()
{
if (!_pSession) fail ("Test not available.");
recreateUnsignedIntsTable();
_pExecutor->unsignedInts();
}
void MySQLTest::testFloat() void MySQLTest::testFloat()
{ {
if (!_pSession) fail ("Test not available."); 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() void MySQLTest::recreateFloatsTable()
{ {
dropTable("Strings"); dropTable("Strings");
@ -876,6 +894,7 @@ CppUnit::Test* MySQLTest::suite()
CppUnit_addTest(pSuite, MySQLTest, testDateTime); CppUnit_addTest(pSuite, MySQLTest, testDateTime);
//CppUnit_addTest(pSuite, MySQLTest, testBLOB); //CppUnit_addTest(pSuite, MySQLTest, testBLOB);
CppUnit_addTest(pSuite, MySQLTest, testBLOBStmt); CppUnit_addTest(pSuite, MySQLTest, testBLOBStmt);
CppUnit_addTest(pSuite, MySQLTest, testUnsignedInts);
CppUnit_addTest(pSuite, MySQLTest, testFloat); CppUnit_addTest(pSuite, MySQLTest, testFloat);
CppUnit_addTest(pSuite, MySQLTest, testDouble); CppUnit_addTest(pSuite, MySQLTest, testDouble);
CppUnit_addTest(pSuite, MySQLTest, testTuple); CppUnit_addTest(pSuite, MySQLTest, testTuple);

View File

@ -99,6 +99,7 @@ public:
void testBLOB(); void testBLOB();
void testBLOBStmt(); void testBLOBStmt();
void testUnsignedInts();
void testFloat(); void testFloat();
void testDouble(); void testDouble();
@ -134,6 +135,7 @@ private:
void recreatePersonTimeTable(); void recreatePersonTimeTable();
void recreateStringsTable(); void recreateStringsTable();
void recreateIntsTable(); void recreateIntsTable();
void recreateUnsignedIntsTable();
void recreateFloatsTable(); void recreateFloatsTable();
void recreateTuplesTable(); void recreateTuplesTable();
void recreateVectorsTable(); void recreateVectorsTable();

View File

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

View File

@ -105,6 +105,7 @@ public:
void dateTime(); void dateTime();
void date(); void date();
void time(); void time();
void unsignedInts();
void floats(); void floats();
void doubles(); void doubles();
void tuples(); void tuples();