summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIsrael Lins <israelins85@yahoo.com.br>2013-02-07 16:18:05 -0300
committerThe Qt Project <gerrit-noreply@qt-project.org>2013-02-15 15:47:58 +0100
commit776c488b6f6a88eb8dacafa992bf61f0167df6a3 (patch)
treefae1cc622f4801896cbc39eb296e4167ce2f255a
parentc8e34ed678145f2e5709d39007e27e186d1bc1f9 (diff)
QSqlResult: fix parsing of bound SQL statements
Parsing for bound SQL parameters now handles identifier quoting using double quotes (") and square brackets ([]). The following has only 1 bound value but previously 2 were detected: SELECT 1 AS "A?b[?']]]de?ghi", ? Task-number: QTBUG-27159 Change-Id: Icfd02187e1126ff3b5ed11df8d4e599f574e61bf Reviewed-by: Mark Brand <mabrand@mabrand.nl>
-rw-r--r--src/sql/kernel/qsqlresult.cpp75
-rw-r--r--tests/auto/sql/kernel/qsqlresult/testsqldriver.h5
-rw-r--r--tests/auto/sql/kernel/qsqlresult/tst_qsqlresult.cpp34
3 files changed, 93 insertions, 21 deletions
diff --git a/src/sql/kernel/qsqlresult.cpp b/src/sql/kernel/qsqlresult.cpp
index 2ebfba0788..ea972abf50 100644
--- a/src/sql/kernel/qsqlresult.cpp
+++ b/src/sql/kernel/qsqlresult.cpp
@@ -87,17 +87,33 @@ QString QSqlResultPrivate::positionalToNamedBinding(const QString &query, QStrin
QString result;
result.reserve(n * 5 / 4);
- bool inQuote = false;
+ QChar closingQuote;
int count = 0;
for (int i = 0; i < n; ++i) {
QChar ch = query.at(i);
- if (ch == QLatin1Char('?') && !inQuote) {
- result += fieldSerialFunc(count++);
- } else {
- if (ch == QLatin1Char('\''))
- inQuote = !inQuote;
+ if (!closingQuote.isNull()) {
+ if (ch == closingQuote) {
+ if (closingQuote == QLatin1Char(']')
+ && i + 1 < n && query.at(i + 1) == closingQuote) {
+ // consume the extra character. don't close.
+ ++i;
+ result += ch;
+ } else {
+ closingQuote = QChar();
+ }
+ }
result += ch;
+ } else {
+ if (ch == QLatin1Char('?')) {
+ result += fieldSerialFunc(count++);
+ } else {
+ if (ch == QLatin1Char('\'') || ch == QLatin1Char('"') || ch == QLatin1Char('`'))
+ closingQuote = ch;
+ else if (ch == QLatin1Char('['))
+ closingQuote = QLatin1Char(']');
+ result += ch;
+ }
}
}
result.squeeze();
@@ -110,28 +126,45 @@ QString QSqlResultPrivate::namedToPositionalBinding(const QString &query)
QString result;
result.reserve(n);
- bool inQuote = false;
+ QChar closingQuote;
int count = 0;
int i = 0;
while (i < n) {
QChar ch = query.at(i);
- if (ch == QLatin1Char(':') && !inQuote
- && (i == 0 || query.at(i - 1) != QLatin1Char(':'))
- && (i + 1 < n && qIsAlnum(query.at(i + 1)))) {
- int pos = i + 2;
- while (pos < n && qIsAlnum(query.at(pos)))
- ++pos;
- QString holder(query.mid(i, pos - i));
- indexes[holder].append(count++);
- holders.append(QHolder(holder, i));
- result += QLatin1Char('?');
- i = pos;
- } else {
- if (ch == QLatin1Char('\''))
- inQuote = !inQuote;
+ if (!closingQuote.isNull()) {
+ if (ch == closingQuote) {
+ if (closingQuote == QLatin1Char(']')
+ && i + 1 < n && query.at(i + 1) == closingQuote) {
+ // consume the extra character. don't close.
+ ++i;
+ result += ch;
+ } else {
+ closingQuote = QChar();
+ }
+ }
result += ch;
++i;
+ } else {
+ if (ch == QLatin1Char(':')
+ && (i == 0 || query.at(i - 1) != QLatin1Char(':'))
+ && (i + 1 < n && qIsAlnum(query.at(i + 1)))) {
+ int pos = i + 2;
+ while (pos < n && qIsAlnum(query.at(pos)))
+ ++pos;
+ QString holder(query.mid(i, pos - i));
+ indexes[holder].append(count++);
+ holders.append(QHolder(holder, i));
+ result += QLatin1Char('?');
+ i = pos;
+ } else {
+ if (ch == QLatin1Char('\'') || ch == QLatin1Char('"') || ch == QLatin1Char('`'))
+ closingQuote = ch;
+ else if (ch == QLatin1Char('['))
+ closingQuote = QLatin1Char(']');
+ result += ch;
+ ++i;
+ }
}
}
result.squeeze();
diff --git a/tests/auto/sql/kernel/qsqlresult/testsqldriver.h b/tests/auto/sql/kernel/qsqlresult/testsqldriver.h
index 720b819839..7040ddf360 100644
--- a/tests/auto/sql/kernel/qsqlresult/testsqldriver.h
+++ b/tests/auto/sql/kernel/qsqlresult/testsqldriver.h
@@ -58,6 +58,11 @@ public:
return QSqlResult::savePrepare(sqlquery);
}
+ QVector<QVariant> boundValues() const
+ {
+ return QSqlResult::boundValues();
+ }
+
protected:
QVariant data(int /* index */) { return QVariant(); }
bool isNull(int /* index */) { return false; }
diff --git a/tests/auto/sql/kernel/qsqlresult/tst_qsqlresult.cpp b/tests/auto/sql/kernel/qsqlresult/tst_qsqlresult.cpp
index 7e901d4b2c..ba6b4d1fbf 100644
--- a/tests/auto/sql/kernel/qsqlresult/tst_qsqlresult.cpp
+++ b/tests/auto/sql/kernel/qsqlresult/tst_qsqlresult.cpp
@@ -53,6 +53,7 @@ public:
private slots:
void positionalToNamedBinding();
+ void parseOfBoundValues();
};
@@ -66,6 +67,39 @@ void tst_QSqlResult::positionalToNamedBinding()
TestSqlDriverResult result(&testDriver);
QString query("INSERT INTO MYTABLE (ID, NAME, BIRTH) VALUES(?, ?, ?)");
QVERIFY(result.savePrepare(query));
+ QCOMPARE(result.boundValues().count(), 3);
+}
+
+void tst_QSqlResult::parseOfBoundValues()
+{
+ TestSqlDriver testDriver;
+ TestSqlDriverResult result(&testDriver);
+ QVERIFY(result.savePrepare("SELECT :1 AS \":2\""));
+ QCOMPARE(result.boundValues().count(), 1);
+ QVERIFY(result.savePrepare("SELECT :1 AS ':2'"));
+ QCOMPARE(result.boundValues().count(), 1);
+ QVERIFY(result.savePrepare("SELECT :1 AS [:2]"));
+ QCOMPARE(result.boundValues().count(), 1);
+ QVERIFY(result.savePrepare("SELECT :1 AS [:2]]]"));
+ QCOMPARE(result.boundValues().count(), 1);
+ QVERIFY(result.savePrepare("SELECT :1 AS [:2]]]]]"));
+ QCOMPARE(result.boundValues().count(), 1);
+
+ QVERIFY(result.savePrepare("SELECT ? AS \"?\""));
+ QCOMPARE(result.boundValues().count(), 1);
+ QVERIFY(result.savePrepare("SELECT ? AS '?'"));
+ QCOMPARE(result.boundValues().count(), 1);
+ QVERIFY(result.savePrepare("SELECT ? AS [?]"));
+ QCOMPARE(result.boundValues().count(), 1);
+
+ QVERIFY(result.savePrepare("SELECT ? AS \"'?\""));
+ QCOMPARE(result.boundValues().count(), 1);
+ QVERIFY(result.savePrepare("SELECT ? AS '?\"'"));
+ QCOMPARE(result.boundValues().count(), 1);
+ QVERIFY(result.savePrepare("SELECT ? AS '?''?'"));
+ QCOMPARE(result.boundValues().count(), 1);
+ QVERIFY(result.savePrepare("SELECT ? AS [\"?']"));
+ QCOMPARE(result.boundValues().count(), 1);
}
QTEST_MAIN( tst_QSqlResult )