39QString QSqlResultPrivate::positionalToNamedBinding(
const QString &query)
const
41 if (!positionalBindingEnabled)
44 const qsizetype n = query.size();
47 result.reserve(n * 5 / 4);
50 bool ignoreBraces = (sqldriver->dbmsType() == QSqlDriver::PostgreSQL);
52 for (qsizetype i = 0; i < n; ++i) {
53 QChar ch = query.at(i);
54 if (!closingQuote.isNull()) {
55 if (ch == closingQuote) {
56 if (closingQuote == u']'
57 && i + 1 < n && query.at(i + 1) == closingQuote) {
62 closingQuote = QChar();
68 result += fieldSerial(count++);
70 if (ch == u'\'' || ch == u'"' || ch == u'`')
72 else if (!ignoreBraces && ch == u'[')
82QString QSqlResultPrivate::namedToPositionalBinding(
const QString &query)
87 const QSqlDriver::DbmsType dbmsType = sqldriver->dbmsType();
88 if ((dbmsType == QSqlDriver::Interbase || dbmsType == QSqlDriver::FirebirdSQL) &&
89 query.trimmed().startsWith(
"EXECUTE BLOCK"_L1, Qt::CaseInsensitive))
92 const qsizetype n = query.size();
99 bool ignoreBraces = (sqldriver->dbmsType() == QSqlDriver::PostgreSQL);
100 const bool qmarkNotationSupported = (sqldriver->dbmsType() != QSqlDriver::PostgreSQL);
103 QChar ch = query.at(i);
104 if (!closingQuote.isNull()) {
105 if (ch == closingQuote) {
106 if (closingQuote == u']'
107 && i + 1 < n && query.at(i + 1) == closingQuote) {
112 closingQuote = QChar();
119 && (i == 0 || query.at(i - 1) != u':')
120 && (i + 1 < n && qIsAlnum(query.at(i + 1)))) {
122 while (pos < n && qIsAlnum(query.at(pos)))
127 if (qmarkNotationSupported)
130 result += fieldSerial(count);
131 QString holder(query.mid(i, pos - i));
132 indexes[holder].append(count++);
133 holders.append(QHolder(holder, i));
136 if (ch == u'\'' || ch == u'"' || ch == u'`')
138 else if (!ignoreBraces && ch == u'[')
146 values.resize(holders.size());
562bool QSqlResult::savePrepare(
const QString& query)
569 if (!driver()->hasFeature(QSqlDriver::PreparedQueries))
570 return prepare(query);
573 d->executedQuery = d->namedToPositionalBinding(query);
575 if (driver()->hasFeature(QSqlDriver::NamedPlaceholders))
576 d->executedQuery = d->positionalToNamedBinding(query);
578 return prepare(d->executedQuery);
599bool QSqlResultPrivate::isVariantNull(
const QVariant &variant)
601 if (variant.isNull())
604 switch (variant.typeId()) {
605 case qMetaTypeId<QString>():
606 return static_cast<
const QString*>(variant.constData())->isNull();
607 case qMetaTypeId<QByteArray>():
608 return static_cast<
const QByteArray*>(variant.constData())->isNull();
609 case qMetaTypeId<QDateTime>():
611 return !
static_cast<
const QDateTime*>(variant.constData())->isValid();
612 case qMetaTypeId<QDate>():
613 return static_cast<
const QDate*>(variant.constData())->isNull();
614 case qMetaTypeId<QTime>():
616 return !
static_cast<
const QTime*>(variant.constData())->isValid();
617 case qMetaTypeId<QUuid>():
618 return static_cast<
const QUuid*>(variant.constData())->isNull();
632bool QSqlResult::exec()
637 QString query = lastQuery();
638 if (d->binds == NamedBinding) {
639 for (qsizetype i = d->holders.size() - 1; i >= 0; --i) {
640 const QString &holder = d->holders.at(i).holderName;
641 const QVariant val = d->values.value(d->indexes.value(holder).value(0,-1));
642 QSqlField f(
""_L1, val.metaType());
643 if (QSqlResultPrivate::isVariantNull(val))
644 f.setValue(QVariant());
647 query = query.replace(d->holders.at(i).holderPos,
648 holder.size(), driver()->formatValue(f));
652 for (
const QVariant &var : std::as_const(d->values)) {
653 i = query.indexOf(u'?', i);
656 QSqlField f(
""_L1, var.metaType());
657 if (QSqlResultPrivate::isVariantNull(var))
661 const QString val = driver()->formatValue(f);
662 query = query.replace(i, 1, val);
668 QString orig = lastQuery();
670 d->executedQuery = query;
682void QSqlResult::bindValue(
int index,
const QVariant& val, QSql::ParamType paramType)
685 d->binds = PositionalBinding;
686 QList<
int> &indexes = d->indexes[d->fieldSerial(index)];
687 if (!indexes.contains(index))
688 indexes.append(index);
689 if (d->values.size() <= index)
690 d->values.resize(index + 1);
691 d->values[index] = val;
692 if (paramType != QSql::In || !d->types.isEmpty())
693 d->types[index] = paramType;
706void QSqlResult::bindValue(
const QString& placeholder,
const QVariant& val,
707 QSql::ParamType paramType)
710 d->binds = NamedBinding;
713 const QList<
int> indexes = d->indexes.value(placeholder);
714 for (
int idx : indexes) {
715 if (d->values.size() <= idx)
716 d->values.resize(idx + 1);
717 d->values[idx] = val;
718 if (paramType != QSql::In || !d->types.isEmpty())
719 d->types[idx] = paramType;
729void QSqlResult::addBindValue(
const QVariant& val, QSql::ParamType paramType)
732 d->binds = PositionalBinding;
733 bindValue(d->bindCount, val, paramType);
976bool QSqlResult::execBatch(
bool arrayBind)
981 const QList<QVariant> values = d->values;
982 if (values.size() == 0)
984 const qsizetype batchCount = values.at(0).toList().size();
985 const qsizetype valueCount = values.size();
986 for (qsizetype i = 0; i < batchCount; ++i) {
987 for (qsizetype j = 0; j < valueCount; ++j)
988 bindValue(j, values.at(j).toList().at(i), QSql::In);