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>
This commit is contained in:
Israel Lins 2013-02-07 16:18:05 -03:00 committed by The Qt Project
parent c8e34ed678
commit 776c488b6f
3 changed files with 93 additions and 21 deletions

View File

@ -87,19 +87,35 @@ 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) {
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('\''))
inQuote = !inQuote;
if (ch == QLatin1Char('\'') || ch == QLatin1Char('"') || ch == QLatin1Char('`'))
closingQuote = ch;
else if (ch == QLatin1Char('['))
closingQuote = QLatin1Char(']');
result += ch;
}
}
}
result.squeeze();
return result;
}
@ -110,13 +126,27 @@ 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
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;
@ -128,12 +158,15 @@ QString QSqlResultPrivate::namedToPositionalBinding(const QString &query)
result += QLatin1Char('?');
i = pos;
} else {
if (ch == QLatin1Char('\''))
inQuote = !inQuote;
if (ch == QLatin1Char('\'') || ch == QLatin1Char('"') || ch == QLatin1Char('`'))
closingQuote = ch;
else if (ch == QLatin1Char('['))
closingQuote = QLatin1Char(']');
result += ch;
++i;
}
}
}
result.squeeze();
values.resize(holders.size());
return result;

View File

@ -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; }

View File

@ -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 )