summaryrefslogtreecommitdiffstats
path: root/src/sql
diff options
context:
space:
mode:
Diffstat (limited to 'src/sql')
-rw-r--r--src/sql/drivers/db2/qsql_db2.cpp2
-rw-r--r--src/sql/drivers/psql/qsql_psql.cpp27
-rw-r--r--src/sql/kernel/qsqlresult.cpp101
-rw-r--r--src/sql/kernel/qsqlresult_p.h10
4 files changed, 78 insertions, 62 deletions
diff --git a/src/sql/drivers/db2/qsql_db2.cpp b/src/sql/drivers/db2/qsql_db2.cpp
index 537f77a8a3..9406861d4c 100644
--- a/src/sql/drivers/db2/qsql_db2.cpp
+++ b/src/sql/drivers/db2/qsql_db2.cpp
@@ -1030,7 +1030,7 @@ QVariant QDB2Result::data(int field)
v = new QVariant(qGetIntData(d->hStmt, field, isNull));
break;
case QSql::LowPrecisionInt64:
- v = new QVariant(qGetBigIntData(d->hStmt, field, isNull));
+ v = new QVariant((qint64) qGetBigIntData(d->hStmt, field, isNull));
break;
case QSql::LowPrecisionDouble:
v = new QVariant(qGetDoubleData(d->hStmt, field, isNull));
diff --git a/src/sql/drivers/psql/qsql_psql.cpp b/src/sql/drivers/psql/qsql_psql.cpp
index 1d96e9f93b..0eadceb1d1 100644
--- a/src/sql/drivers/psql/qsql_psql.cpp
+++ b/src/sql/drivers/psql/qsql_psql.cpp
@@ -53,6 +53,7 @@
#include <qsocketnotifier.h>
#include <qstringlist.h>
#include <qmutex.h>
+#include <QtSql/private/qsqlresult_p.h>
#include <libpq-fe.h>
#include <pg_config.h>
@@ -183,6 +184,7 @@ class QPSQLResultPrivate
{
public:
QPSQLResultPrivate(QPSQLResult *qq): q(qq), driver(0), result(0), currentSize(-1), preparedQueriesEnabled(false) {}
+ static QString fieldSerial(int i) { return QLatin1Char('$') + QString::number(i + 1); }
QPSQLResult *q;
const QPSQLDriverPrivate *driver;
@@ -515,29 +517,6 @@ void QPSQLResult::virtual_hook(int id, void *data)
QSqlResult::virtual_hook(id, data);
}
-static QString qReplacePlaceholderMarkers(const QString &query)
-{
- const int originalLength = query.length();
- bool inQuote = false;
- int markerIdx = 0;
- QString result;
- result.reserve(originalLength + 23);
- for (int i = 0; i < originalLength; ++i) {
- const QChar ch = query.at(i);
- if (ch == QLatin1Char('?') && !inQuote) {
- result += QLatin1Char('$');
- result += QString::number(++markerIdx);
- } else {
- if (ch == QLatin1Char('\''))
- inQuote = !inQuote;
- result += ch;
- }
- }
-
- result.squeeze();
- return result;
-}
-
static QString qCreateParamString(const QVector<QVariant> boundValues, const QSqlDriver *driver)
{
if (boundValues.isEmpty())
@@ -581,7 +560,7 @@ bool QPSQLResult::prepare(const QString &query)
qDeallocatePreparedStmt(d);
const QString stmtId = qMakePreparedStmtId();
- const QString stmt = QString::fromLatin1("PREPARE %1 AS ").arg(stmtId).append(qReplacePlaceholderMarkers(query));
+ const QString stmt = QString::fromLatin1("PREPARE %1 AS ").arg(stmtId).append(QSqlResultPrivate::positionalToNamedBinding(query, QPSQLResultPrivate::fieldSerial));
PGresult *result = d->driver->exec(stmt);
diff --git a/src/sql/kernel/qsqlresult.cpp b/src/sql/kernel/qsqlresult.cpp
index b3e7ad5b38..ea972abf50 100644
--- a/src/sql/kernel/qsqlresult.cpp
+++ b/src/sql/kernel/qsqlresult.cpp
@@ -55,15 +55,13 @@
QT_BEGIN_NAMESPACE
-static QString qFieldSerial(int);
-
QString QSqlResultPrivate::holderAt(int index) const
{
- return holders.size() > index ? holders.at(index).holderName : qFieldSerial(index);
+ return holders.size() > index ? holders.at(index).holderName : fieldSerial(index);
}
// return a unique id for bound names
-static QString qFieldSerial(int i)
+QString QSqlResultPrivate::fieldSerial(int i)
{
ushort arr[] = { ':', 'f', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
ushort *ptr = &arr[1];
@@ -83,57 +81,90 @@ static bool qIsAlnum(QChar ch)
return u - 'a' < 26 || u - 'A' < 26 || u - '0' < 10 || u == '_';
}
-QString QSqlResultPrivate::positionalToNamedBinding()
+QString QSqlResultPrivate::positionalToNamedBinding(const QString &query, QString (fieldSerialFunc)(int idx))
{
- int n = sql.size();
+ int n = query.size();
QString result;
result.reserve(n * 5 / 4);
- bool inQuote = false;
+ QChar closingQuote;
int count = 0;
for (int i = 0; i < n; ++i) {
- QChar ch = sql.at(i);
- if (ch == QLatin1Char('?') && !inQuote) {
- result += qFieldSerial(count++);
- } else {
- if (ch == QLatin1Char('\''))
- inQuote = !inQuote;
+ QChar ch = query.at(i);
+ 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();
return result;
}
-QString QSqlResultPrivate::namedToPositionalBinding()
+QString QSqlResultPrivate::namedToPositionalBinding(const QString &query)
{
- int n = sql.size();
+ int n = query.size();
QString result;
result.reserve(n);
- bool inQuote = false;
+ QChar closingQuote;
int count = 0;
int i = 0;
while (i < n) {
- QChar ch = sql.at(i);
- if (ch == QLatin1Char(':') && !inQuote
- && (i == 0 || sql.at(i - 1) != QLatin1Char(':'))
- && (i + 1 < n && qIsAlnum(sql.at(i + 1)))) {
- int pos = i + 2;
- while (pos < n && qIsAlnum(sql.at(pos)))
- ++pos;
- QString holder(sql.mid(i, pos - i));
- indexes[holder].append(count++);
- holders.append(QHolder(holder, i));
- result += QLatin1Char('?');
- i = pos;
- } else {
- if (ch == QLatin1Char('\''))
- inQuote = !inQuote;
+ QChar ch = query.at(i);
+ 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();
@@ -531,10 +562,10 @@ bool QSqlResult::savePrepare(const QString& query)
return prepare(query);
// parse the query to memorize parameter location
- d->executedQuery = d->namedToPositionalBinding();
+ d->executedQuery = d->namedToPositionalBinding(query);
if (driver()->hasFeature(QSqlDriver::NamedPlaceholders))
- d->executedQuery = d->positionalToNamedBinding();
+ d->executedQuery = QSqlResultPrivate::positionalToNamedBinding(query);
return prepare(d->executedQuery);
}
@@ -551,7 +582,7 @@ bool QSqlResult::prepare(const QString& query)
d->sql = query;
if (d->holders.isEmpty()) {
// parse the query to memorize parameter location
- d->namedToPositionalBinding();
+ d->namedToPositionalBinding(query);
}
return true; // fake prepares should always succeed
}
@@ -617,7 +648,7 @@ bool QSqlResult::exec()
void QSqlResult::bindValue(int index, const QVariant& val, QSql::ParamType paramType)
{
d->binds = PositionalBinding;
- d->indexes[qFieldSerial(index)].append(index);
+ d->indexes[QSqlResultPrivate::fieldSerial(index)].append(index);
if (d->values.count() <= index)
d->values.resize(index + 1);
d->values[index] = val;
diff --git a/src/sql/kernel/qsqlresult_p.h b/src/sql/kernel/qsqlresult_p.h
index 65f9be7a05..246b914ec7 100644
--- a/src/sql/kernel/qsqlresult_p.h
+++ b/src/sql/kernel/qsqlresult_p.h
@@ -106,8 +106,14 @@ public:
clearIndex();;
}
- QString positionalToNamedBinding();
- QString namedToPositionalBinding();
+ // positionalToNamedBinding uses fieldSerial() by default, which converts to Oracle-style names,
+ // because this style is used in the API. A driver can reuse positionalToNamedBinding()
+ // internally for its own naming style by supplying its own fieldSerialFunc. We cannot make
+ // fieldSerial() virtual because it would allow a driver to impose its naming style on
+ // executedQuery when set by QSqlResult::savePrepare().
+ static QString fieldSerial(int);
+ static QString positionalToNamedBinding(const QString &query, QString (fieldSerialFunc)(int idx) = fieldSerial);
+ QString namedToPositionalBinding(const QString &query);
QString holderAt(int index) const;
QSqlResult *q;