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:
parent
c8e34ed678
commit
776c488b6f
@ -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;
|
||||
|
@ -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; }
|
||||
|
@ -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 )
|
||||
|
Loading…
x
Reference in New Issue
Block a user