SQLite support only one statement at a time
authorHonglei Zhang <honglei.zhang@nokia.com>
Fri, 18 Nov 2011 08:50:07 +0000 (10:50 +0200)
committerQt by Nokia <qt-info@nokia.com>
Wed, 23 Nov 2011 07:36:14 +0000 (08:36 +0100)
SQLite driver support only one statement at a time. This fix makes the
exec and prepare call failed if more than one statements are given.
This is bug fix for QTBUG-21884. Also the behaviour is documented in
the API specification.

Task-number: QTBUG-21884
Change-Id: If1e25a0dd9f9ee38961ef478fc7909f6b05e360a
Reviewed-by: Yunqiao Yin <charles.yin@nokia.com>
src/sql/drivers/sqlite/qsql_sqlite.cpp
src/sql/kernel/qsqlquery.cpp
tests/auto/sql/kernel/qsqlquery/tst_qsqlquery.cpp

index 9fba6d6..8294a55 100644 (file)
@@ -322,12 +322,14 @@ bool QSQLiteResult::prepare(const QString &query)
 
     setSelect(false);
 
+    const void *pzTail = NULL;
+
 #if (SQLITE_VERSION_NUMBER >= 3003011)
     int res = sqlite3_prepare16_v2(d->access, query.constData(), (query.size() + 1) * sizeof(QChar),
-                                   &d->stmt, 0);
+                                   &d->stmt, &pzTail);
 #else
     int res = sqlite3_prepare16(d->access, query.constData(), (query.size() + 1) * sizeof(QChar),
-                                &d->stmt, 0);
+                                &d->stmt, &pzTail);
 #endif
 
     if (res != SQLITE_OK) {
@@ -335,6 +337,11 @@ bool QSQLiteResult::prepare(const QString &query)
                      "Unable to execute statement"), QSqlError::StatementError, res));
         d->finalize();
         return false;
+    } else if (pzTail && !QString(reinterpret_cast<const QChar *>(pzTail)).trimmed().isEmpty()) {
+        setLastError(qMakeError(d->access, QCoreApplication::translate("QSQLiteResult",
+            "Unable to execute multiple statements at a time"), QSqlError::StatementError, SQLITE_MISUSE));
+        d->finalize();
+        return false;
     }
     return true;
 }
index 4eb46f1..fda6301 100644 (file)
@@ -338,6 +338,9 @@ bool QSqlQuery::isNull(int field) const
   Note that the last error for this query is reset when exec() is
   called.
 
+  For SQLite, the query string can contain only one statement at a time.
+  If more than one statements is give, the function returns false.
+
   Example:
 
   \snippet doc/src/snippets/sqldatabase/sqldatabase.cpp 34
@@ -887,6 +890,9 @@ void QSqlQuery::clear()
   syntactically wrong query succeeds, but every consecutive exec()
   will fail.
 
+  For SQLite, the query string can contain only one statement at a time.
+  If more than one statements are give, the function returns false.
+
   Example:
 
   \snippet doc/src/snippets/sqldatabase/sqldatabase.cpp 9
index a88a26d..df3a4dd 100644 (file)
@@ -213,6 +213,8 @@ private slots:
     void QTBUG_5765();
     void QTBUG_14132_data() { generic_data("QOCI"); }
     void QTBUG_14132();
+    void QTBUG_21884_data() { generic_data("QSQLITE"); }
+    void QTBUG_21884();
 
     void sqlite_constraint_data() { generic_data("QSQLITE"); }
     void sqlite_constraint();
@@ -323,6 +325,7 @@ void tst_QSqlQuery::dropTestTables( QSqlDatabase db )
                << qTableName("bug6421", __FILE__).toUpper()
                << qTableName("bug5765", __FILE__)
                << qTableName("bug6852", __FILE__)
+               << qTableName("bug21884", __FILE__)
                << qTableName( "qtest_lockedtable", __FILE__ )
                << qTableName( "Planet", __FILE__ )
                << qTableName( "task_250026", __FILE__ )
@@ -3083,6 +3086,50 @@ void tst_QSqlQuery::QTBUG_5765()
     QCOMPARE(q.value(0).toInt(), 123);
 }
 
+/**
+* This test case tests multiple statements in one execution.
+* Sqlite driver doesn't support multiple statement at one time.
+* If more than one statement is given, the exec or prepare function
+* return failure to the client.
+*/
+void tst_QSqlQuery::QTBUG_21884()
+{
+    QFETCH(QString, dbName);
+    QSqlDatabase db = QSqlDatabase::database(dbName);
+    CHECK_DATABASE(db);
+
+    QSqlQuery q(db);
+
+    QStringList stList;
+    QString tableName(qTableName("bug21884", __FILE__ ));
+    stList << "create table " + tableName + "(id integer primary key, note string)";
+    stList << "select * from " + tableName + ";";
+    stList << "select * from " + tableName + ";  \t\n\r";
+    stList << "drop table " + tableName;
+
+
+    foreach (const QString& st, stList) {
+        QVERIFY_SQL(q, exec(st));
+    }
+
+    foreach (const QString& st, stList) {
+        QVERIFY_SQL(q, prepare(st));
+        QVERIFY_SQL(q, exec());
+    }
+
+    stList.clear();
+    stList << "create table " + tableName + "(id integer primary key); select * from " + tableName;
+    stList << "create table " + tableName + "(id integer primary key); syntax error!;";
+    stList << "create table " + tableName + "(id integer primary key);;";
+    stList << "create table " + tableName + "(id integer primary key);\'\"\a\b\b\v";
+
+    foreach (const QString&st , stList) {
+        QVERIFY2(!q.prepare(st), qPrintable(QString("the statement is expected to fail! ") + st));
+        QVERIFY2(!q.exec(st), qPrintable(QString("the statement is expected to fail! ") + st));
+    }
+}
+
+
 void tst_QSqlQuery::oraOCINumber()
 {
     QFETCH( QString, dbName );