| /**************************************************************************** |
| ** |
| ** Copyright (C) 2016 The Qt Company Ltd. |
| ** Contact: https://www.qt.io/licensing/ |
| ** |
| ** This file is part of the QtSql module of the Qt Toolkit. |
| ** |
| ** $QT_BEGIN_LICENSE:LGPL$ |
| ** Commercial License Usage |
| ** Licensees holding valid commercial Qt licenses may use this file in |
| ** accordance with the commercial license agreement provided with the |
| ** Software or, alternatively, in accordance with the terms contained in |
| ** a written agreement between you and The Qt Company. For licensing terms |
| ** and conditions see https://www.qt.io/terms-conditions. For further |
| ** information use the contact form at https://www.qt.io/contact-us. |
| ** |
| ** GNU Lesser General Public License Usage |
| ** Alternatively, this file may be used under the terms of the GNU Lesser |
| ** General Public License version 3 as published by the Free Software |
| ** Foundation and appearing in the file LICENSE.LGPL3 included in the |
| ** packaging of this file. Please review the following information to |
| ** ensure the GNU Lesser General Public License version 3 requirements |
| ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. |
| ** |
| ** GNU General Public License Usage |
| ** Alternatively, this file may be used under the terms of the GNU |
| ** General Public License version 2.0 or (at your option) the GNU General |
| ** Public license version 3 or any later version approved by the KDE Free |
| ** Qt Foundation. The licenses are as published by the Free Software |
| ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 |
| ** included in the packaging of this file. Please review the following |
| ** information to ensure the GNU General Public License requirements will |
| ** be met: https://www.gnu.org/licenses/gpl-2.0.html and |
| ** https://www.gnu.org/licenses/gpl-3.0.html. |
| ** |
| ** $QT_END_LICENSE$ |
| ** |
| ****************************************************************************/ |
| |
| #include "qsqlresult.h" |
| |
| #include "qvariant.h" |
| #include "qhash.h" |
| #include "qsqlerror.h" |
| #include "qsqlfield.h" |
| #include "qsqlrecord.h" |
| #include "qvector.h" |
| #include "qsqldriver.h" |
| #include "qpointer.h" |
| #include "qsqlresult_p.h" |
| #include "private/qsqldriver_p.h" |
| #include <QDebug> |
| |
| QT_BEGIN_NAMESPACE |
| |
| QString QSqlResultPrivate::holderAt(int index) const |
| { |
| return holders.size() > index ? holders.at(index).holderName : fieldSerial(index); |
| } |
| |
| // return a unique id for bound names |
| QString QSqlResultPrivate::fieldSerial(int i) const |
| { |
| ushort arr[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; |
| ushort *end = &arr[(sizeof(arr)/sizeof(*arr))]; |
| ushort *ptr = end; |
| |
| while (i > 0) { |
| *(--ptr) = 'a' + i % 16; |
| i >>= 4; |
| } |
| |
| const int nb = end - ptr; |
| *(--ptr) = 'a' + nb; |
| *(--ptr) = ':'; |
| |
| return QString::fromUtf16(ptr, int(end - ptr)); |
| } |
| |
| static bool qIsAlnum(QChar ch) |
| { |
| uint u = uint(ch.unicode()); |
| // matches [a-zA-Z0-9_] |
| return u - 'a' < 26 || u - 'A' < 26 || u - '0' < 10 || u == '_'; |
| } |
| |
| QString QSqlResultPrivate::positionalToNamedBinding(const QString &query) const |
| { |
| int n = query.size(); |
| |
| QString result; |
| result.reserve(n * 5 / 4); |
| QChar closingQuote; |
| int count = 0; |
| bool ignoreBraces = (sqldriver->dbmsType() == QSqlDriver::PostgreSQL); |
| |
| for (int i = 0; i < n; ++i) { |
| 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 += fieldSerial(count++); |
| } else { |
| if (ch == QLatin1Char('\'') || ch == QLatin1Char('"') || ch == QLatin1Char('`')) |
| closingQuote = ch; |
| else if (!ignoreBraces && ch == QLatin1Char('[')) |
| closingQuote = QLatin1Char(']'); |
| result += ch; |
| } |
| } |
| } |
| result.squeeze(); |
| return result; |
| } |
| |
| QString QSqlResultPrivate::namedToPositionalBinding(const QString &query) |
| { |
| int n = query.size(); |
| |
| QString result; |
| result.reserve(n); |
| QChar closingQuote; |
| int count = 0; |
| int i = 0; |
| bool ignoreBraces = (sqldriver->dbmsType() == QSqlDriver::PostgreSQL); |
| |
| while (i < n) { |
| 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 (!ignoreBraces && ch == QLatin1Char('[')) |
| closingQuote = QLatin1Char(']'); |
| result += ch; |
| ++i; |
| } |
| } |
| } |
| result.squeeze(); |
| values.resize(holders.size()); |
| return result; |
| } |
| |
| /*! |
| \class QSqlResult |
| \brief The QSqlResult class provides an abstract interface for |
| accessing data from specific SQL databases. |
| |
| \ingroup database |
| \inmodule QtSql |
| |
| Normally, you would use QSqlQuery instead of QSqlResult, since |
| QSqlQuery provides a generic wrapper for database-specific |
| implementations of QSqlResult. |
| |
| If you are implementing your own SQL driver (by subclassing |
| QSqlDriver), you will need to provide your own QSqlResult |
| subclass that implements all the pure virtual functions and other |
| virtual functions that you need. |
| |
| \sa QSqlDriver |
| */ |
| |
| /*! |
| \enum QSqlResult::BindingSyntax |
| |
| This enum type specifies the different syntaxes for specifying |
| placeholders in prepared queries. |
| |
| \value PositionalBinding Use the ODBC-style positional syntax, with "?" as placeholders. |
| \value NamedBinding Use the Oracle-style syntax with named placeholders (e.g., ":id") |
| |
| \sa bindingSyntax() |
| */ |
| |
| /*! |
| \enum QSqlResult::VirtualHookOperation |
| \internal |
| */ |
| |
| /*! |
| Creates a QSqlResult using database driver \a db. The object is |
| initialized to an inactive state. |
| |
| \sa isActive(), driver() |
| */ |
| |
| QSqlResult::QSqlResult(const QSqlDriver *db) |
| { |
| d_ptr = new QSqlResultPrivate(this, db); |
| Q_D(QSqlResult); |
| if (d->sqldriver) |
| setNumericalPrecisionPolicy(d->sqldriver->numericalPrecisionPolicy()); |
| } |
| |
| /*! \internal |
| */ |
| QSqlResult::QSqlResult(QSqlResultPrivate &dd) |
| : d_ptr(&dd) |
| { |
| Q_D(QSqlResult); |
| if (d->sqldriver) |
| setNumericalPrecisionPolicy(d->sqldriver->numericalPrecisionPolicy()); |
| } |
| |
| /*! |
| Destroys the object and frees any allocated resources. |
| */ |
| |
| QSqlResult::~QSqlResult() |
| { |
| Q_D(QSqlResult); |
| delete d; |
| } |
| |
| /*! |
| Sets the current query for the result to \a query. You must call |
| reset() to execute the query on the database. |
| |
| \sa reset(), lastQuery() |
| */ |
| |
| void QSqlResult::setQuery(const QString& query) |
| { |
| Q_D(QSqlResult); |
| d->sql = query; |
| } |
| |
| /*! |
| Returns the current SQL query text, or an empty string if there |
| isn't one. |
| |
| \sa setQuery() |
| */ |
| |
| QString QSqlResult::lastQuery() const |
| { |
| Q_D(const QSqlResult); |
| return d->sql; |
| } |
| |
| /*! |
| Returns the current (zero-based) row position of the result. May |
| return the special values QSql::BeforeFirstRow or |
| QSql::AfterLastRow. |
| |
| \sa setAt(), isValid() |
| */ |
| int QSqlResult::at() const |
| { |
| Q_D(const QSqlResult); |
| return d->idx; |
| } |
| |
| |
| /*! |
| Returns \c true if the result is positioned on a valid record (that |
| is, the result is not positioned before the first or after the |
| last record); otherwise returns \c false. |
| |
| \sa at() |
| */ |
| |
| bool QSqlResult::isValid() const |
| { |
| Q_D(const QSqlResult); |
| return d->idx != QSql::BeforeFirstRow && d->idx != QSql::AfterLastRow; |
| } |
| |
| /*! |
| \fn bool QSqlResult::isNull(int index) |
| |
| Returns \c true if the field at position \a index in the current row |
| is null; otherwise returns \c false. |
| */ |
| |
| /*! |
| Returns \c true if the result has records to be retrieved; otherwise |
| returns \c false. |
| */ |
| |
| bool QSqlResult::isActive() const |
| { |
| Q_D(const QSqlResult); |
| return d->active; |
| } |
| |
| /*! |
| This function is provided for derived classes to set the |
| internal (zero-based) row position to \a index. |
| |
| \sa at() |
| */ |
| |
| void QSqlResult::setAt(int index) |
| { |
| Q_D(QSqlResult); |
| d->idx = index; |
| } |
| |
| |
| /*! |
| This function is provided for derived classes to indicate whether |
| or not the current statement is a SQL \c SELECT statement. The \a |
| select parameter should be true if the statement is a \c SELECT |
| statement; otherwise it should be false. |
| |
| \sa isSelect() |
| */ |
| |
| void QSqlResult::setSelect(bool select) |
| { |
| Q_D(QSqlResult); |
| d->isSel = select; |
| } |
| |
| /*! |
| Returns \c true if the current result is from a \c SELECT statement; |
| otherwise returns \c false. |
| |
| \sa setSelect() |
| */ |
| |
| bool QSqlResult::isSelect() const |
| { |
| Q_D(const QSqlResult); |
| return d->isSel; |
| } |
| |
| /*! |
| Returns the driver associated with the result. This is the object |
| that was passed to the constructor. |
| */ |
| |
| const QSqlDriver *QSqlResult::driver() const |
| { |
| Q_D(const QSqlResult); |
| return d->sqldriver; |
| } |
| |
| |
| /*! |
| This function is provided for derived classes to set the internal |
| active state to \a active. |
| |
| \sa isActive() |
| */ |
| |
| void QSqlResult::setActive(bool active) |
| { |
| Q_D(QSqlResult); |
| if (active) |
| d->executedQuery = d->sql; |
| |
| d->active = active; |
| } |
| |
| /*! |
| This function is provided for derived classes to set the last |
| error to \a error. |
| |
| \sa lastError() |
| */ |
| |
| void QSqlResult::setLastError(const QSqlError &error) |
| { |
| Q_D(QSqlResult); |
| d->error = error; |
| } |
| |
| |
| /*! |
| Returns the last error associated with the result. |
| */ |
| |
| QSqlError QSqlResult::lastError() const |
| { |
| Q_D(const QSqlResult); |
| return d->error; |
| } |
| |
| /*! |
| \fn int QSqlResult::size() |
| |
| Returns the size of the \c SELECT result, or -1 if it cannot be |
| determined or if the query is not a \c SELECT statement. |
| |
| \sa numRowsAffected() |
| */ |
| |
| /*! |
| \fn int QSqlResult::numRowsAffected() |
| |
| Returns the number of rows affected by the last query executed, or |
| -1 if it cannot be determined or if the query is a \c SELECT |
| statement. |
| |
| \sa size() |
| */ |
| |
| /*! |
| \fn QVariant QSqlResult::data(int index) |
| |
| Returns the data for field \a index in the current row as |
| a QVariant. This function is only called if the result is in |
| an active state and is positioned on a valid record and \a index is |
| non-negative. Derived classes must reimplement this function and |
| return the value of field \a index, or QVariant() if it cannot be |
| determined. |
| */ |
| |
| /*! |
| \fn bool QSqlResult::reset(const QString &query) |
| |
| Sets the result to use the SQL statement \a query for subsequent |
| data retrieval. |
| |
| Derived classes must reimplement this function and apply the \a |
| query to the database. This function is only called after the |
| result is set to an inactive state and is positioned before the |
| first record of the new result. Derived classes should return |
| true if the query was successful and ready to be used, or false |
| otherwise. |
| |
| \sa setQuery() |
| */ |
| |
| /*! |
| \fn bool QSqlResult::fetch(int index) |
| |
| Positions the result to an arbitrary (zero-based) row \a index. |
| |
| This function is only called if the result is in an active state. |
| Derived classes must reimplement this function and position the |
| result to the row \a index, and call setAt() with an appropriate |
| value. Return true to indicate success, or false to signify |
| failure. |
| |
| \sa isActive(), fetchFirst(), fetchLast(), fetchNext(), fetchPrevious() |
| */ |
| |
| /*! |
| \fn bool QSqlResult::fetchFirst() |
| |
| Positions the result to the first record (row 0) in the result. |
| |
| This function is only called if the result is in an active state. |
| Derived classes must reimplement this function and position the |
| result to the first record, and call setAt() with an appropriate |
| value. Return true to indicate success, or false to signify |
| failure. |
| |
| \sa fetch(), fetchLast() |
| */ |
| |
| /*! |
| \fn bool QSqlResult::fetchLast() |
| |
| Positions the result to the last record (last row) in the result. |
| |
| This function is only called if the result is in an active state. |
| Derived classes must reimplement this function and position the |
| result to the last record, and call setAt() with an appropriate |
| value. Return true to indicate success, or false to signify |
| failure. |
| |
| \sa fetch(), fetchFirst() |
| */ |
| |
| /*! |
| Positions the result to the next available record (row) in the |
| result. |
| |
| This function is only called if the result is in an active |
| state. The default implementation calls fetch() with the next |
| index. Derived classes can reimplement this function and position |
| the result to the next record in some other way, and call setAt() |
| with an appropriate value. Return true to indicate success, or |
| false to signify failure. |
| |
| \sa fetch(), fetchPrevious() |
| */ |
| |
| bool QSqlResult::fetchNext() |
| { |
| return fetch(at() + 1); |
| } |
| |
| /*! |
| Positions the result to the previous record (row) in the result. |
| |
| This function is only called if the result is in an active state. |
| The default implementation calls fetch() with the previous index. |
| Derived classes can reimplement this function and position the |
| result to the next record in some other way, and call setAt() |
| with an appropriate value. Return true to indicate success, or |
| false to signify failure. |
| */ |
| |
| bool QSqlResult::fetchPrevious() |
| { |
| return fetch(at() - 1); |
| } |
| |
| /*! |
| Returns \c true if you can only scroll forward through the result |
| set; otherwise returns \c false. |
| |
| \sa setForwardOnly() |
| */ |
| bool QSqlResult::isForwardOnly() const |
| { |
| Q_D(const QSqlResult); |
| return d->forwardOnly; |
| } |
| |
| /*! |
| Sets forward only mode to \a forward. If \a forward is true, only |
| fetchNext() is allowed for navigating the results. Forward only |
| mode needs much less memory since results do not have to be |
| cached. By default, this feature is disabled. |
| |
| Setting forward only to false is a suggestion to the database engine, |
| which has the final say on whether a result set is forward only or |
| scrollable. isForwardOnly() will always return the correct status of |
| the result set. |
| |
| \note Calling setForwardOnly after execution of the query will result |
| in unexpected results at best, and crashes at worst. |
| |
| \note To make sure the forward-only query completed successfully, |
| the application should check lastError() for an error not only after |
| executing the query, but also after navigating the query results. |
| |
| \warning PostgreSQL: While navigating the query results in forward-only |
| mode, do not execute any other SQL command on the same database |
| connection. This will cause the query results to be lost. |
| |
| \sa isForwardOnly(), fetchNext(), QSqlQuery::setForwardOnly() |
| */ |
| void QSqlResult::setForwardOnly(bool forward) |
| { |
| Q_D(QSqlResult); |
| d->forwardOnly = forward; |
| } |
| |
| /*! |
| Prepares the given \a query, using the underlying database |
| functionality where possible. Returns \c true if the query is |
| prepared successfully; otherwise returns \c false. |
| |
| Note: This method should have been called "safePrepare()". |
| |
| \sa prepare() |
| */ |
| bool QSqlResult::savePrepare(const QString& query) |
| { |
| Q_D(QSqlResult); |
| if (!driver()) |
| return false; |
| d->clear(); |
| d->sql = query; |
| if (!driver()->hasFeature(QSqlDriver::PreparedQueries)) |
| return prepare(query); |
| |
| // parse the query to memorize parameter location |
| d->executedQuery = d->namedToPositionalBinding(query); |
| |
| if (driver()->hasFeature(QSqlDriver::NamedPlaceholders)) |
| d->executedQuery = d->positionalToNamedBinding(query); |
| |
| return prepare(d->executedQuery); |
| } |
| |
| /*! |
| Prepares the given \a query for execution; the query will normally |
| use placeholders so that it can be executed repeatedly. Returns |
| true if the query is prepared successfully; otherwise returns \c false. |
| |
| \sa exec() |
| */ |
| bool QSqlResult::prepare(const QString& query) |
| { |
| Q_D(QSqlResult); |
| d->sql = query; |
| if (d->holders.isEmpty()) { |
| // parse the query to memorize parameter location |
| d->namedToPositionalBinding(query); |
| } |
| return true; // fake prepares should always succeed |
| } |
| |
| /*! |
| Executes the query, returning true if successful; otherwise returns |
| false. |
| |
| \sa prepare() |
| */ |
| bool QSqlResult::exec() |
| { |
| Q_D(QSqlResult); |
| bool ret; |
| // fake preparation - just replace the placeholders.. |
| QString query = lastQuery(); |
| if (d->binds == NamedBinding) { |
| int i; |
| QVariant val; |
| QString holder; |
| for (i = d->holders.count() - 1; i >= 0; --i) { |
| holder = d->holders.at(i).holderName; |
| val = d->values.value(d->indexes.value(holder).value(0,-1)); |
| QSqlField f(QLatin1String(""), QVariant::Type(val.userType())); |
| f.setValue(val); |
| query = query.replace(d->holders.at(i).holderPos, |
| holder.length(), driver()->formatValue(f)); |
| } |
| } else { |
| QString val; |
| int i = 0; |
| int idx = 0; |
| for (idx = 0; idx < d->values.count(); ++idx) { |
| i = query.indexOf(QLatin1Char('?'), i); |
| if (i == -1) |
| continue; |
| QVariant var = d->values.value(idx); |
| QSqlField f(QLatin1String(""), QVariant::Type(var.userType())); |
| if (var.isNull()) |
| f.clear(); |
| else |
| f.setValue(var); |
| val = driver()->formatValue(f); |
| query = query.replace(i, 1, driver()->formatValue(f)); |
| i += val.length(); |
| } |
| } |
| |
| // have to retain the original query with placeholders |
| QString orig = lastQuery(); |
| ret = reset(query); |
| d->executedQuery = query; |
| setQuery(orig); |
| d->resetBindCount(); |
| return ret; |
| } |
| |
| /*! |
| Binds the value \a val of parameter type \a paramType to position \a index |
| in the current record (row). |
| |
| \sa addBindValue() |
| */ |
| void QSqlResult::bindValue(int index, const QVariant& val, QSql::ParamType paramType) |
| { |
| Q_D(QSqlResult); |
| d->binds = PositionalBinding; |
| QVector<int> &indexes = d->indexes[d->fieldSerial(index)]; |
| if (!indexes.contains(index)) |
| indexes.append(index); |
| if (d->values.count() <= index) |
| d->values.resize(index + 1); |
| d->values[index] = val; |
| if (paramType != QSql::In || !d->types.isEmpty()) |
| d->types[index] = paramType; |
| } |
| |
| /*! |
| \overload |
| |
| Binds the value \a val of parameter type \a paramType to the \a |
| placeholder name in the current record (row). |
| |
| \note Binding an undefined placeholder will result in undefined behavior. |
| |
| \sa QSqlQuery::bindValue() |
| */ |
| void QSqlResult::bindValue(const QString& placeholder, const QVariant& val, |
| QSql::ParamType paramType) |
| { |
| Q_D(QSqlResult); |
| d->binds = NamedBinding; |
| // if the index has already been set when doing emulated named |
| // bindings - don't reset it |
| const QVector<int> indexes = d->indexes.value(placeholder); |
| for (int idx : indexes) { |
| if (d->values.count() <= idx) |
| d->values.resize(idx + 1); |
| d->values[idx] = val; |
| if (paramType != QSql::In || !d->types.isEmpty()) |
| d->types[idx] = paramType; |
| } |
| } |
| |
| /*! |
| Binds the value \a val of parameter type \a paramType to the next |
| available position in the current record (row). |
| |
| \sa bindValue() |
| */ |
| void QSqlResult::addBindValue(const QVariant& val, QSql::ParamType paramType) |
| { |
| Q_D(QSqlResult); |
| d->binds = PositionalBinding; |
| bindValue(d->bindCount, val, paramType); |
| ++d->bindCount; |
| } |
| |
| /*! |
| Returns the value bound at position \a index in the current record |
| (row). |
| |
| \sa bindValue(), boundValues() |
| */ |
| QVariant QSqlResult::boundValue(int index) const |
| { |
| Q_D(const QSqlResult); |
| return d->values.value(index); |
| } |
| |
| /*! |
| \overload |
| |
| Returns the value bound by the given \a placeholder name in the |
| current record (row). |
| |
| \sa bindValueType() |
| */ |
| QVariant QSqlResult::boundValue(const QString& placeholder) const |
| { |
| Q_D(const QSqlResult); |
| const QVector<int> indexes = d->indexes.value(placeholder); |
| return d->values.value(indexes.value(0,-1)); |
| } |
| |
| /*! |
| Returns the parameter type for the value bound at position \a index. |
| |
| \sa boundValue() |
| */ |
| QSql::ParamType QSqlResult::bindValueType(int index) const |
| { |
| Q_D(const QSqlResult); |
| return d->types.value(index, QSql::In); |
| } |
| |
| /*! |
| \overload |
| |
| Returns the parameter type for the value bound with the given \a |
| placeholder name. |
| */ |
| QSql::ParamType QSqlResult::bindValueType(const QString& placeholder) const |
| { |
| Q_D(const QSqlResult); |
| return d->types.value(d->indexes.value(placeholder).value(0,-1), QSql::In); |
| } |
| |
| /*! |
| Returns the number of bound values in the result. |
| |
| \sa boundValues() |
| */ |
| int QSqlResult::boundValueCount() const |
| { |
| Q_D(const QSqlResult); |
| return d->values.count(); |
| } |
| |
| /*! |
| Returns a vector of the result's bound values for the current |
| record (row). |
| |
| \sa boundValueCount() |
| */ |
| QVector<QVariant>& QSqlResult::boundValues() const |
| { |
| Q_D(const QSqlResult); |
| return const_cast<QSqlResultPrivate *>(d)->values; |
| } |
| |
| /*! |
| Returns the binding syntax used by prepared queries. |
| */ |
| QSqlResult::BindingSyntax QSqlResult::bindingSyntax() const |
| { |
| Q_D(const QSqlResult); |
| return d->binds; |
| } |
| |
| /*! |
| Clears the entire result set and releases any associated |
| resources. |
| */ |
| void QSqlResult::clear() |
| { |
| Q_D(QSqlResult); |
| d->clear(); |
| } |
| |
| /*! |
| Returns the query that was actually executed. This may differ from |
| the query that was passed, for example if bound values were used |
| with a prepared query and the underlying database doesn't support |
| prepared queries. |
| |
| \sa exec(), setQuery() |
| */ |
| QString QSqlResult::executedQuery() const |
| { |
| Q_D(const QSqlResult); |
| return d->executedQuery; |
| } |
| |
| /*! |
| Resets the number of bind parameters. |
| */ |
| void QSqlResult::resetBindCount() |
| { |
| Q_D(QSqlResult); |
| d->resetBindCount(); |
| } |
| |
| /*! |
| Returns the name of the bound value at position \a index in the |
| current record (row). |
| |
| \sa boundValue() |
| */ |
| QString QSqlResult::boundValueName(int index) const |
| { |
| Q_D(const QSqlResult); |
| return d->holderAt(index); |
| } |
| |
| /*! |
| Returns \c true if at least one of the query's bound values is a \c |
| QSql::Out or a QSql::InOut; otherwise returns \c false. |
| |
| \sa bindValueType() |
| */ |
| bool QSqlResult::hasOutValues() const |
| { |
| Q_D(const QSqlResult); |
| if (d->types.isEmpty()) |
| return false; |
| QHash<int, QSql::ParamType>::ConstIterator it; |
| for (it = d->types.constBegin(); it != d->types.constEnd(); ++it) { |
| if (it.value() != QSql::In) |
| return true; |
| } |
| return false; |
| } |
| |
| /*! |
| Returns the current record if the query is active; otherwise |
| returns an empty QSqlRecord. |
| |
| The default implementation always returns an empty QSqlRecord. |
| |
| \sa isActive() |
| */ |
| QSqlRecord QSqlResult::record() const |
| { |
| return QSqlRecord(); |
| } |
| |
| /*! |
| Returns the object ID of the most recent inserted row if the |
| database supports it. |
| An invalid QVariant will be returned if the query did not |
| insert any value or if the database does not report the id back. |
| If more than one row was touched by the insert, the behavior is |
| undefined. |
| |
| Note that for Oracle databases the row's ROWID will be returned, |
| while for MySQL databases the row's auto-increment field will |
| be returned. |
| |
| \sa QSqlDriver::hasFeature() |
| */ |
| QVariant QSqlResult::lastInsertId() const |
| { |
| return QVariant(); |
| } |
| |
| /*! \internal |
| */ |
| void QSqlResult::virtual_hook(int, void *) |
| { |
| } |
| |
| /*! \internal |
| \since 4.2 |
| |
| Executes a prepared query in batch mode if the driver supports it, |
| otherwise emulates a batch execution using bindValue() and exec(). |
| QSqlDriver::hasFeature() can be used to find out whether a driver |
| supports batch execution. |
| |
| Batch execution can be faster for large amounts of data since it |
| reduces network roundtrips. |
| |
| For batch executions, bound values have to be provided as lists |
| of variants (QVariantList). |
| |
| Each list must contain values of the same type. All lists must |
| contain equal amount of values (rows). |
| |
| NULL values are passed in as typed QVariants, for example |
| \c {QVariant(QVariant::Int)} for an integer NULL value. |
| |
| Example: |
| |
| \snippet code/src_sql_kernel_qsqlresult.cpp 0 |
| |
| Here, we insert two rows into a SQL table, with each row containing three values. |
| |
| \sa exec(), QSqlDriver::hasFeature() |
| */ |
| bool QSqlResult::execBatch(bool arrayBind) |
| { |
| Q_UNUSED(arrayBind); |
| Q_D(QSqlResult); |
| |
| QVector<QVariant> values = d->values; |
| if (values.count() == 0) |
| return false; |
| for (int i = 0; i < values.at(0).toList().count(); ++i) { |
| for (int j = 0; j < values.count(); ++j) |
| bindValue(j, values.at(j).toList().at(i), QSql::In); |
| if (!exec()) |
| return false; |
| } |
| return true; |
| } |
| |
| /*! \internal |
| */ |
| void QSqlResult::detachFromResultSet() |
| { |
| } |
| |
| /*! \internal |
| */ |
| void QSqlResult::setNumericalPrecisionPolicy(QSql::NumericalPrecisionPolicy policy) |
| { |
| Q_D(QSqlResult); |
| d->precisionPolicy = policy; |
| } |
| |
| /*! \internal |
| */ |
| QSql::NumericalPrecisionPolicy QSqlResult::numericalPrecisionPolicy() const |
| { |
| Q_D(const QSqlResult); |
| return d->precisionPolicy; |
| } |
| |
| /*! \internal |
| */ |
| bool QSqlResult::nextResult() |
| { |
| return false; |
| } |
| |
| /*! |
| Returns the low-level database handle for this result set |
| wrapped in a QVariant or an invalid QVariant if there is no handle. |
| |
| \warning Use this with uttermost care and only if you know what you're doing. |
| |
| \warning The handle returned here can become a stale pointer if the result |
| is modified (for example, if you clear it). |
| |
| \warning The handle can be NULL if the result was not executed yet. |
| |
| \warning PostgreSQL: in forward-only mode, the handle of QSqlResult can change |
| after calling fetch(), fetchFirst(), fetchLast(), fetchNext(), fetchPrevious(), |
| nextResult(). |
| |
| The handle returned here is database-dependent, you should query the type |
| name of the variant before accessing it. |
| |
| This example retrieves the handle for a sqlite result: |
| |
| \snippet code/src_sql_kernel_qsqlresult.cpp 1 |
| |
| This snippet returns the handle for PostgreSQL or MySQL: |
| |
| \snippet code/src_sql_kernel_qsqlresult_snippet.cpp 2 |
| |
| \sa QSqlDriver::handle() |
| */ |
| QVariant QSqlResult::handle() const |
| { |
| return QVariant(); |
| } |
| |
| QT_END_NAMESPACE |