From 8efd01e369d9427db38d9f3c524626607f4f114b Mon Sep 17 00:00:00 2001 From: Mark Brand Date: Tue, 30 Oct 2012 10:51:25 +0100 Subject: fix binding of bool type in mysql driver MYSQL_TYPE_TINY should be used for binding bool input value. MYSQL_TYPE_LONG might be too big for bool, resulting in bools being saved in the database as int 127. The problem was not specific to the vendor's BOOL column type. http://dev.mysql.com/doc/refman/5.0/en/numeric-type-overview.html http://dev.mysql.com/doc/refman/5.0/en/c-api-prepared-statement-type-codes.html Added generic autotest to make sure that binding bool works. All drivers should pass this test. Task-number: QTBUG-27763 Change-Id: I4e69f8e3b32fffb702ec9fa8a80ff5c50dea954b Reviewed-by: Andy Shaw Reviewed-by: Bill King (cherry picked from qt5/qtbase commit 593b8f7f0b35ddc424d8ccbd5df11fcf2442858e)) --- src/sql/drivers/mysql/qsql_mysql.cpp | 7 ++++++- tests/auto/qsqlquery/tst_qsqlquery.cpp | 35 ++++++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/src/sql/drivers/mysql/qsql_mysql.cpp b/src/sql/drivers/mysql/qsql_mysql.cpp index 3e00ce2..b820c86 100644 --- a/src/sql/drivers/mysql/qsql_mysql.cpp +++ b/src/sql/drivers/mysql/qsql_mysql.cpp @@ -991,11 +991,16 @@ bool QMYSQLResult::exec() break; } case QVariant::UInt: case QVariant::Int: - case QVariant::Bool: currBind->buffer_type = MYSQL_TYPE_LONG; currBind->buffer = data; currBind->buffer_length = sizeof(int); currBind->is_unsigned = (val.type() != QVariant::Int); + break; + case QVariant::Bool: + currBind->buffer_type = MYSQL_TYPE_TINY; + currBind->buffer = data; + currBind->buffer_length = sizeof(bool); + currBind->is_unsigned = false; break; case QVariant::Double: currBind->buffer_type = MYSQL_TYPE_DOUBLE; diff --git a/tests/auto/qsqlquery/tst_qsqlquery.cpp b/tests/auto/qsqlquery/tst_qsqlquery.cpp index 6923904..bdf7143 100644 --- a/tests/auto/qsqlquery/tst_qsqlquery.cpp +++ b/tests/auto/qsqlquery/tst_qsqlquery.cpp @@ -163,6 +163,8 @@ private slots: void lastInsertId(); void lastQuery_data() { generic_data(); } void lastQuery(); + void bindBool_data() { generic_data(); } + void bindBool(); void bindWithDoubleColonCastOperator_data() { generic_data(); } void bindWithDoubleColonCastOperator(); void queryOnInvalidDatabase_data() { generic_data(); } @@ -572,6 +574,39 @@ void tst_QSqlQuery::mysqlOutValues() QVERIFY_SQL( q, exec( "drop procedure " + qtestproc ) ); } +void tst_QSqlQuery::bindBool() +{ + // QTBUG-27763: bool value got converted to int 127 by mysql driver becuase sizeof(bool) < sizeof(int). + // The problem was the way the bool value from the application was handled. It doesn't matter + // whether the table column type is BOOL or INT. Use INT here because all DBMSs have it and all + // should pass this test. + QFETCH( QString, dbName ); + QSqlDatabase db = QSqlDatabase::database( dbName ); + CHECK_DATABASE( db ); + QSqlQuery q(db); + + const QString tableName(qTableName( "bindBool", __FILE__ )); + q.exec("DROP TABLE " + tableName); + QVERIFY_SQL(q, exec("CREATE TABLE " + tableName + " (id INT, flag INT NOT NULL, PRIMARY KEY(id))")); + + for (int i = 0; i < 2; ++i) { + bool flag = i; + q.prepare("INSERT INTO " + tableName + " (id, flag) VALUES(:id, :flag)"); + q.bindValue(":id", i); + q.bindValue(":flag", flag); + QVERIFY_SQL(q, exec()); + } + + QVERIFY_SQL(q, exec("SELECT id, flag FROM " + tableName)); + for (int i = 0; i < 2; ++i) { + bool flag = i; + QVERIFY_SQL(q, next()); + QCOMPARE(q.value(0).toInt(), i); + QCOMPARE(q.value(1).toBool(), flag); + } + QVERIFY_SQL(q, exec("DROP TABLE " + tableName)); +} + void tst_QSqlQuery::oraOutValues() { QFETCH( QString, dbName ); -- cgit v0.12