fix parsing of bound SQL statements for PostgreSQL

PostgreSQL allows bound variables inside square braces.

Task-number: QTBUG-34541

Change-Id: I4f069b3f1078d4cdf172fbac9e0d7d23d20d167a
Reviewed-by: Mark Brand <mabrand@mabrand.nl>
This commit is contained in:
Israel Lins Albuquerque 2013-11-04 19:45:28 -02:00 committed by The Qt Project
parent b3b689edcb
commit 5193c14536
5 changed files with 32 additions and 7 deletions

View File

@ -62,6 +62,7 @@ class QVariant;
class Q_SQL_EXPORT QSqlDriver : public QObject class Q_SQL_EXPORT QSqlDriver : public QObject
{ {
friend class QSqlDatabase; friend class QSqlDatabase;
friend class QSqlResultPrivate;
Q_OBJECT Q_OBJECT
Q_DECLARE_PRIVATE(QSqlDriver) Q_DECLARE_PRIVATE(QSqlDriver)

View File

@ -51,6 +51,7 @@
#include "qsqldriver.h" #include "qsqldriver.h"
#include "qpointer.h" #include "qpointer.h"
#include "qsqlresult_p.h" #include "qsqlresult_p.h"
#include "private/qsqldriver_p.h"
#include <QDebug> #include <QDebug>
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
@ -89,6 +90,7 @@ QString QSqlResultPrivate::positionalToNamedBinding(const QString &query) const
result.reserve(n * 5 / 4); result.reserve(n * 5 / 4);
QChar closingQuote; QChar closingQuote;
int count = 0; int count = 0;
bool ignoreBraces = (sqldriver->d_func()->dbmsType == QSqlDriverPrivate::PostgreSQL);
for (int i = 0; i < n; ++i) { for (int i = 0; i < n; ++i) {
QChar ch = query.at(i); QChar ch = query.at(i);
@ -110,7 +112,7 @@ QString QSqlResultPrivate::positionalToNamedBinding(const QString &query) const
} else { } else {
if (ch == QLatin1Char('\'') || ch == QLatin1Char('"') || ch == QLatin1Char('`')) if (ch == QLatin1Char('\'') || ch == QLatin1Char('"') || ch == QLatin1Char('`'))
closingQuote = ch; closingQuote = ch;
else if (ch == QLatin1Char('[')) else if (!ignoreBraces && ch == QLatin1Char('['))
closingQuote = QLatin1Char(']'); closingQuote = QLatin1Char(']');
result += ch; result += ch;
} }
@ -129,6 +131,7 @@ QString QSqlResultPrivate::namedToPositionalBinding(const QString &query)
QChar closingQuote; QChar closingQuote;
int count = 0; int count = 0;
int i = 0; int i = 0;
bool ignoreBraces = (sqldriver->d_func()->dbmsType == QSqlDriverPrivate::PostgreSQL);
while (i < n) { while (i < n) {
QChar ch = query.at(i); QChar ch = query.at(i);
@ -160,7 +163,7 @@ QString QSqlResultPrivate::namedToPositionalBinding(const QString &query)
} else { } else {
if (ch == QLatin1Char('\'') || ch == QLatin1Char('"') || ch == QLatin1Char('`')) if (ch == QLatin1Char('\'') || ch == QLatin1Char('"') || ch == QLatin1Char('`'))
closingQuote = ch; closingQuote = ch;
else if (ch == QLatin1Char('[')) else if (!ignoreBraces && ch == QLatin1Char('['))
closingQuote = QLatin1Char(']'); closingQuote = QLatin1Char(']');
result += ch; result += ch;
++i; ++i;

View File

@ -1,7 +1,7 @@
TARGET = tst_qsqlresult TARGET = tst_qsqlresult
CONFIG += testcase CONFIG += testcase
QT = core sql testlib QT = core core-private sql sql-private testlib
SOURCES += tst_qsqlresult.cpp SOURCES += tst_qsqlresult.cpp
HEADERS += testsqldriver.h HEADERS += testsqldriver.h

View File

@ -45,6 +45,7 @@
#include <QtSql/QSqlResult> #include <QtSql/QSqlResult>
#include <QtSql/QSqlDriver> #include <QtSql/QSqlDriver>
#include <QtSql/QSqlRecord> #include <QtSql/QSqlRecord>
#include <private/qsqldriver_p.h>
class TestSqlDriverResult : public QSqlResult class TestSqlDriverResult : public QSqlResult
{ {
@ -77,6 +78,8 @@ protected:
class TestSqlDriver : public QSqlDriver class TestSqlDriver : public QSqlDriver
{ {
Q_DECLARE_PRIVATE(QSqlDriver)
public: public:
TestSqlDriver() {} TestSqlDriver() {}
~TestSqlDriver() {} ~TestSqlDriver() {}
@ -96,6 +99,12 @@ public:
int /* port */, const QString & /* options */) int /* port */, const QString & /* options */)
{ return false; } { return false; }
void close() {} void close() {}
QSqlDriverPrivate::DBMSType dbmsType() const
{
Q_D(const QSqlDriver);
return d->dbmsType;
}
QSqlResult *createResult() const { return new TestSqlDriverResult(this); } QSqlResult *createResult() const { return new TestSqlDriverResult(this); }
}; };

View File

@ -79,18 +79,30 @@ void tst_QSqlResult::parseOfBoundValues()
QVERIFY(result.savePrepare("SELECT :1 AS ':2'")); QVERIFY(result.savePrepare("SELECT :1 AS ':2'"));
QCOMPARE(result.boundValues().count(), 1); QCOMPARE(result.boundValues().count(), 1);
QVERIFY(result.savePrepare("SELECT :1 AS [:2]")); QVERIFY(result.savePrepare("SELECT :1 AS [:2]"));
QCOMPARE(result.boundValues().count(), 1); if (testDriver.dbmsType() == QSqlDriverPrivate::PostgreSQL)
QCOMPARE(result.boundValues().count(), 2);
else
QCOMPARE(result.boundValues().count(), 1);
QVERIFY(result.savePrepare("SELECT :1 AS [:2]]]")); QVERIFY(result.savePrepare("SELECT :1 AS [:2]]]"));
QCOMPARE(result.boundValues().count(), 1); if (testDriver.dbmsType() == QSqlDriverPrivate::PostgreSQL)
QCOMPARE(result.boundValues().count(), 2);
else
QCOMPARE(result.boundValues().count(), 1);
QVERIFY(result.savePrepare("SELECT :1 AS [:2]]]]]")); QVERIFY(result.savePrepare("SELECT :1 AS [:2]]]]]"));
QCOMPARE(result.boundValues().count(), 1); if (testDriver.dbmsType() == QSqlDriverPrivate::PostgreSQL)
QCOMPARE(result.boundValues().count(), 2);
else
QCOMPARE(result.boundValues().count(), 1);
QVERIFY(result.savePrepare("SELECT ? AS \"?\"")); QVERIFY(result.savePrepare("SELECT ? AS \"?\""));
QCOMPARE(result.boundValues().count(), 1); QCOMPARE(result.boundValues().count(), 1);
QVERIFY(result.savePrepare("SELECT ? AS '?'")); QVERIFY(result.savePrepare("SELECT ? AS '?'"));
QCOMPARE(result.boundValues().count(), 1); QCOMPARE(result.boundValues().count(), 1);
QVERIFY(result.savePrepare("SELECT ? AS [?]")); QVERIFY(result.savePrepare("SELECT ? AS [?]"));
QCOMPARE(result.boundValues().count(), 1); if (testDriver.dbmsType() == QSqlDriverPrivate::PostgreSQL)
QCOMPARE(result.boundValues().count(), 2);
else
QCOMPARE(result.boundValues().count(), 1);
QVERIFY(result.savePrepare("SELECT ? AS \"'?\"")); QVERIFY(result.savePrepare("SELECT ? AS \"'?\""));
QCOMPARE(result.boundValues().count(), 1); QCOMPARE(result.boundValues().count(), 1);