SQL: Change in QSqlResultPrivate::positionalToNamedBinding()
[profile/ivi/qtbase.git] / src / sql / kernel / qsqlresult.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
5 **
6 ** This file is part of the QtSql module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and Digia.  For licensing terms and
14 ** conditions see http://qt.digia.com/licensing.  For further information
15 ** use the contact form at http://qt.digia.com/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file.  Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights.  These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 **
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file.  Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qsqlresult.h"
43
44 #include "qvariant.h"
45 #include "qhash.h"
46 #include "qregexp.h"
47 #include "qsqlerror.h"
48 #include "qsqlfield.h"
49 #include "qsqlrecord.h"
50 #include "qvector.h"
51 #include "qsqldriver.h"
52 #include "qpointer.h"
53 #include <QDebug>
54
55 QT_BEGIN_NAMESPACE
56
57 struct QHolder {
58     QHolder(const QString& hldr = QString(), int index = -1): holderName(hldr), holderPos(index) {}
59     bool operator==(const QHolder& h) const { return h.holderPos == holderPos && h.holderName == holderName; }
60     bool operator!=(const QHolder& h) const { return h.holderPos != holderPos || h.holderName != holderName; }
61     QString holderName;
62     int holderPos;
63 };
64
65 class QSqlResultPrivate
66 {
67 public:
68     QSqlResultPrivate(QSqlResult* d)
69     : q(d), idx(QSql::BeforeFirstRow), active(false),
70       isSel(false), forwardOnly(false), precisionPolicy(QSql::LowPrecisionDouble), bindCount(0), binds(QSqlResult::PositionalBinding)
71     {}
72
73     void clearValues()
74     {
75         values.clear();
76         bindCount = 0;
77     }
78
79     void resetBindCount()
80     {
81         bindCount = 0;
82     }
83
84     void clearIndex()
85     {
86         indexes.clear();
87         holders.clear();
88         types.clear();
89     }
90
91     void clear()
92     {
93         clearValues();
94         clearIndex();;
95     }
96
97     QString positionalToNamedBinding();
98     QString namedToPositionalBinding();
99     QString holderAt(int index) const;
100
101 public:
102     QSqlResult* q;
103     QPointer<QSqlDriver> sqldriver;
104     int idx;
105     QString sql;
106     bool active;
107     bool isSel;
108     QSqlError error;
109     bool forwardOnly;
110     QSql::NumericalPrecisionPolicy precisionPolicy;
111
112     int bindCount;
113     QSqlResult::BindingSyntax binds;
114
115     QString executedQuery;
116     QHash<int, QSql::ParamType> types;
117     QVector<QVariant> values;
118     typedef QHash<QString, QList<int> > IndexMap;
119     IndexMap indexes;
120
121     typedef QVector<QHolder> QHolderVector;
122     QHolderVector holders;
123 };
124
125 static QString qFieldSerial(int);
126
127 QString QSqlResultPrivate::holderAt(int index) const
128 {
129     return holders.size() > index ? holders.at(index).holderName : qFieldSerial(index);
130 }
131
132 // return a unique id for bound names
133 static QString qFieldSerial(int i)
134 {
135     ushort arr[] = { ':', 'f', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
136     ushort *ptr = &arr[1];
137
138     while (i > 0) {
139         *(++ptr) = 'a' + i % 16;
140         i >>= 4;
141     }
142
143     return QString(reinterpret_cast<const QChar *>(arr), int(ptr - arr) + 1);
144 }
145
146 static bool qIsAlnum(QChar ch)
147 {
148     uint u = uint(ch.unicode());
149     // matches [a-zA-Z0-9_]
150     return u - 'a' < 26 || u - 'A' < 26 || u - '0' < 10 || u == '_';
151 }
152
153 QString QSqlResultPrivate::positionalToNamedBinding()
154 {
155     int n = sql.size();
156
157     QString result;
158     result.reserve(n * 5 / 4);
159     bool inQuote = false;
160     int count = 0;
161
162     for (int i = 0; i < n; ++i) {
163         QChar ch = sql.at(i);
164         if (ch == QLatin1Char('?') && !inQuote) {
165             result += qFieldSerial(count++);
166         } else {
167             if (ch == QLatin1Char('\''))
168                 inQuote = !inQuote;
169             result += ch;
170         }
171     }
172     result.squeeze();
173     return result;
174 }
175
176 QString QSqlResultPrivate::namedToPositionalBinding()
177 {
178     int n = sql.size();
179
180     QString result;
181     result.reserve(n);
182     bool inQuote = false;
183     int count = 0;
184     int i = 0;
185
186     while (i < n) {
187         QChar ch = sql.at(i);
188         if (ch == QLatin1Char(':') && !inQuote
189                 && (i == 0 || sql.at(i - 1) != QLatin1Char(':'))
190                 && (i + 1 < n && qIsAlnum(sql.at(i + 1)))) {
191             int pos = i + 2;
192             while (pos < n && qIsAlnum(sql.at(pos)))
193                 ++pos;
194             QString holder(sql.mid(i, pos - i));
195             indexes[holder].append(count++);
196             holders.append(QHolder(holder, i));
197             result += QLatin1Char('?');
198             i = pos;
199         } else {
200             if (ch == QLatin1Char('\''))
201                 inQuote = !inQuote;
202             result += ch;
203             ++i;
204         }
205     }
206     result.squeeze();
207     values.resize(holders.size());
208     return result;
209 }
210
211 /*!
212     \class QSqlResult
213     \brief The QSqlResult class provides an abstract interface for
214     accessing data from specific SQL databases.
215
216     \ingroup database
217     \inmodule QtSql
218
219     Normally, you would use QSqlQuery instead of QSqlResult, since
220     QSqlQuery provides a generic wrapper for database-specific
221     implementations of QSqlResult.
222
223     If you are implementing your own SQL driver (by subclassing
224     QSqlDriver), you will need to provide your own QSqlResult
225     subclass that implements all the pure virtual functions and other
226     virtual functions that you need.
227
228     \sa QSqlDriver
229 */
230
231 /*!
232     \enum QSqlResult::BindingSyntax
233
234     This enum type specifies the different syntaxes for specifying
235     placeholders in prepared queries.
236
237     \value PositionalBinding Use the ODBC-style positional syntax, with "?" as placeholders.
238     \value NamedBinding Use the Oracle-style syntax with named placeholders (e.g., ":id")
239
240     \sa bindingSyntax()
241 */
242
243 /*!
244     \enum QSqlResult::VirtualHookOperation
245     \internal
246 */
247
248 /*!
249     Creates a QSqlResult using database driver \a db. The object is
250     initialized to an inactive state.
251
252     \sa isActive(), driver()
253 */
254
255 QSqlResult::QSqlResult(const QSqlDriver *db)
256 {
257     d = new QSqlResultPrivate(this);
258     d->sqldriver = const_cast<QSqlDriver *>(db);
259     if(db) {
260         setNumericalPrecisionPolicy(db->numericalPrecisionPolicy());
261     }
262 }
263
264 /*!
265     Destroys the object and frees any allocated resources.
266 */
267
268 QSqlResult::~QSqlResult()
269 {
270     delete d;
271 }
272
273 /*!
274     Sets the current query for the result to \a query. You must call
275     reset() to execute the query on the database.
276
277     \sa reset(), lastQuery()
278 */
279
280 void QSqlResult::setQuery(const QString& query)
281 {
282     d->sql = query;
283 }
284
285 /*!
286     Returns the current SQL query text, or an empty string if there
287     isn't one.
288
289     \sa setQuery()
290 */
291
292 QString QSqlResult::lastQuery() const
293 {
294     return d->sql;
295 }
296
297 /*!
298     Returns the current (zero-based) row position of the result. May
299     return the special values QSql::BeforeFirstRow or
300     QSql::AfterLastRow.
301
302     \sa setAt(), isValid()
303 */
304 int QSqlResult::at() const
305 {
306     return d->idx;
307 }
308
309
310 /*!
311     Returns true if the result is positioned on a valid record (that
312     is, the result is not positioned before the first or after the
313     last record); otherwise returns false.
314
315     \sa at()
316 */
317
318 bool QSqlResult::isValid() const
319 {
320     return d->idx != QSql::BeforeFirstRow && d->idx != QSql::AfterLastRow;
321 }
322
323 /*!
324     \fn bool QSqlResult::isNull(int index)
325
326     Returns true if the field at position \a index in the current row
327     is null; otherwise returns false.
328 */
329
330 /*!
331     Returns true if the result has records to be retrieved; otherwise
332     returns false.
333 */
334
335 bool QSqlResult::isActive() const
336 {
337     return d->active;
338 }
339
340 /*!
341     This function is provided for derived classes to set the
342     internal (zero-based) row position to \a index.
343
344     \sa at()
345 */
346
347 void QSqlResult::setAt(int index)
348 {
349     d->idx = index;
350 }
351
352
353 /*!
354     This function is provided for derived classes to indicate whether
355     or not the current statement is a SQL \c SELECT statement. The \a
356     select parameter should be true if the statement is a \c SELECT
357     statement; otherwise it should be false.
358
359     \sa isSelect()
360 */
361
362 void QSqlResult::setSelect(bool select)
363 {
364     d->isSel = select;
365 }
366
367 /*!
368     Returns true if the current result is from a \c SELECT statement;
369     otherwise returns false.
370
371     \sa setSelect()
372 */
373
374 bool QSqlResult::isSelect() const
375 {
376     return d->isSel;
377 }
378
379 /*!
380     Returns the driver associated with the result. This is the object
381     that was passed to the constructor.
382 */
383
384 const QSqlDriver *QSqlResult::driver() const
385 {
386     return d->sqldriver;
387 }
388
389
390 /*!
391     This function is provided for derived classes to set the internal
392     active state to \a active.
393
394     \sa isActive()
395 */
396
397 void QSqlResult::setActive(bool active)
398 {
399     if (active && d->executedQuery.isEmpty())
400         d->executedQuery = d->sql;
401
402     d->active = active;
403 }
404
405 /*!
406     This function is provided for derived classes to set the last
407     error to \a error.
408
409     \sa lastError()
410 */
411
412 void QSqlResult::setLastError(const QSqlError &error)
413 {
414     d->error = error;
415 }
416
417
418 /*!
419     Returns the last error associated with the result.
420 */
421
422 QSqlError QSqlResult::lastError() const
423 {
424     return d->error;
425 }
426
427 /*!
428     \fn int QSqlResult::size()
429
430     Returns the size of the \c SELECT result, or -1 if it cannot be
431     determined or if the query is not a \c SELECT statement.
432
433     \sa numRowsAffected()
434 */
435
436 /*!
437     \fn int QSqlResult::numRowsAffected()
438
439     Returns the number of rows affected by the last query executed, or
440     -1 if it cannot be determined or if the query is a \c SELECT
441     statement.
442
443     \sa size()
444 */
445
446 /*!
447     \fn QVariant QSqlResult::data(int index)
448
449     Returns the data for field \a index in the current row as
450     a QVariant. This function is only called if the result is in
451     an active state and is positioned on a valid record and \a index is
452     non-negative. Derived classes must reimplement this function and
453     return the value of field \a index, or QVariant() if it cannot be
454     determined.
455 */
456
457 /*!
458     \fn  bool QSqlResult::reset(const QString &query)
459
460     Sets the result to use the SQL statement \a query for subsequent
461     data retrieval.
462
463     Derived classes must reimplement this function and apply the \a
464     query to the database. This function is only called after the
465     result is set to an inactive state and is positioned before the
466     first record of the new result. Derived classes should return
467     true if the query was successful and ready to be used, or false
468     otherwise.
469
470     \sa setQuery()
471 */
472
473 /*!
474     \fn bool QSqlResult::fetch(int index)
475
476     Positions the result to an arbitrary (zero-based) row \a index.
477
478     This function is only called if the result is in an active state.
479     Derived classes must reimplement this function and position the
480     result to the row \a index, and call setAt() with an appropriate
481     value. Return true to indicate success, or false to signify
482     failure.
483
484     \sa isActive(), fetchFirst(), fetchLast(), fetchNext(), fetchPrevious()
485 */
486
487 /*!
488     \fn bool QSqlResult::fetchFirst()
489
490     Positions the result to the first record (row 0) in the result.
491
492     This function is only called if the result is in an active state.
493     Derived classes must reimplement this function and position the
494     result to the first record, and call setAt() with an appropriate
495     value. Return true to indicate success, or false to signify
496     failure.
497
498     \sa fetch(), fetchLast()
499 */
500
501 /*!
502     \fn bool QSqlResult::fetchLast()
503
504     Positions the result to the last record (last row) in the result.
505
506     This function is only called if the result is in an active state.
507     Derived classes must reimplement this function and position the
508     result to the last record, and call setAt() with an appropriate
509     value. Return true to indicate success, or false to signify
510     failure.
511
512     \sa fetch(), fetchFirst()
513 */
514
515 /*!
516     Positions the result to the next available record (row) in the
517     result.
518
519     This function is only called if the result is in an active
520     state. The default implementation calls fetch() with the next
521     index. Derived classes can reimplement this function and position
522     the result to the next record in some other way, and call setAt()
523     with an appropriate value. Return true to indicate success, or
524     false to signify failure.
525
526     \sa fetch(), fetchPrevious()
527 */
528
529 bool QSqlResult::fetchNext()
530 {
531     return fetch(at() + 1);
532 }
533
534 /*!
535     Positions the result to the previous record (row) in the result.
536
537     This function is only called if the result is in an active state.
538     The default implementation calls fetch() with the previous index.
539     Derived classes can reimplement this function and position the
540     result to the next record in some other way, and call setAt()
541     with an appropriate value. Return true to indicate success, or
542     false to signify failure.
543 */
544
545 bool QSqlResult::fetchPrevious()
546 {
547     return fetch(at() - 1);
548 }
549
550 /*!
551     Returns true if you can only scroll forward through the result
552     set; otherwise returns false.
553
554     \sa setForwardOnly()
555 */
556 bool QSqlResult::isForwardOnly() const
557 {
558     return d->forwardOnly;
559 }
560
561 /*!
562     Sets forward only mode to \a forward. If \a forward is true, only
563     fetchNext() is allowed for navigating the results. Forward only
564     mode needs much less memory since results do not have to be
565     cached. By default, this feature is disabled.
566
567     Setting forward only to false is a suggestion to the database engine,
568     which has the final say on whether a result set is forward only or
569     scrollable. isForwardOnly() will always return the correct status of
570     the result set.
571
572     \note Calling setForwardOnly after execution of the query will result
573     in unexpected results at best, and crashes at worst.
574
575     \sa isForwardOnly(), fetchNext(), QSqlQuery::setForwardOnly()
576 */
577 void QSqlResult::setForwardOnly(bool forward)
578 {
579     d->forwardOnly = forward;
580 }
581
582 /*!
583     Prepares the given \a query, using the underlying database
584     functionality where possible. Returns true if the query is
585     prepared successfully; otherwise returns false.
586
587     \sa prepare()
588 */
589 bool QSqlResult::savePrepare(const QString& query)
590 {
591     if (!driver())
592         return false;
593     d->clear();
594     d->sql = query;
595     if (!driver()->hasFeature(QSqlDriver::PreparedQueries))
596         return prepare(query);
597
598     if (driver()->hasFeature(QSqlDriver::NamedPlaceholders)) {
599         // parse the query to memorize parameter location
600         d->namedToPositionalBinding();
601         d->executedQuery = d->positionalToNamedBinding();
602     } else {
603         d->executedQuery = d->namedToPositionalBinding();
604     }
605     return prepare(d->executedQuery);
606 }
607
608 /*!
609     Prepares the given \a query for execution; the query will normally
610     use placeholders so that it can be executed repeatedly. Returns
611     true if the query is prepared successfully; otherwise returns false.
612
613     \sa exec()
614 */
615 bool QSqlResult::prepare(const QString& query)
616 {
617     if (d->holders.isEmpty()) {
618         int n = query.size();
619
620         bool inQuote = false;
621         int i = 0;
622
623         while (i < n) {
624             QChar ch = query.at(i);
625             if (ch == QLatin1Char(':') && !inQuote
626                     && (i == 0 || query.at(i - 1) != QLatin1Char(':'))
627                     && (i + 1 < n && qIsAlnum(query.at(i + 1)))) {
628                 int pos = i + 2;
629                 while (pos < n && qIsAlnum(query.at(pos)))
630                     ++pos;
631
632                 QString holder(query.mid(i, pos - i));
633                 d->indexes[holder].append(d->holders.size());
634                 d->holders.append(QHolder(holder, i));
635                 i = pos;
636             } else {
637                 if (ch == QLatin1Char('\''))
638                     inQuote = !inQuote;
639                 ++i;
640             }
641         }
642         d->values.resize(d->holders.size());
643     }
644     d->sql = query;
645     return true; // fake prepares should always succeed
646 }
647
648 /*!
649     Executes the query, returning true if successful; otherwise returns
650     false.
651
652     \sa prepare()
653 */
654 bool QSqlResult::exec()
655 {
656     bool ret;
657     // fake preparation - just replace the placeholders..
658     QString query = lastQuery();
659     if (d->binds == NamedBinding) {
660         int i;
661         QVariant val;
662         QString holder;
663         for (i = d->holders.count() - 1; i >= 0; --i) {
664             holder = d->holders.at(i).holderName;
665             val = d->values.value(d->indexes.value(holder).value(0,-1));
666             QSqlField f(QLatin1String(""), val.type());
667             f.setValue(val);
668             query = query.replace(d->holders.at(i).holderPos,
669                                    holder.length(), driver()->formatValue(f));
670         }
671     } else {
672         QString val;
673         int i = 0;
674         int idx = 0;
675         for (idx = 0; idx < d->values.count(); ++idx) {
676             i = query.indexOf(QLatin1Char('?'), i);
677             if (i == -1)
678                 continue;
679             QVariant var = d->values.value(idx);
680             QSqlField f(QLatin1String(""), var.type());
681             if (var.isNull())
682                 f.clear();
683             else
684                 f.setValue(var);
685             val = driver()->formatValue(f);
686             query = query.replace(i, 1, driver()->formatValue(f));
687             i += val.length();
688         }
689     }
690
691     // have to retain the original query with placeholders
692     QString orig = lastQuery();
693     ret = reset(query);
694     d->executedQuery = query;
695     setQuery(orig);
696     d->resetBindCount();
697     return ret;
698 }
699
700 /*!
701     Binds the value \a val of parameter type \a paramType to position \a index
702     in the current record (row).
703
704     \sa addBindValue()
705 */
706 void QSqlResult::bindValue(int index, const QVariant& val, QSql::ParamType paramType)
707 {
708     d->binds = PositionalBinding;
709     d->indexes[qFieldSerial(index)].append(index);
710     if (d->values.count() <= index)
711         d->values.resize(index + 1);
712     d->values[index] = val;
713     if (paramType != QSql::In || !d->types.isEmpty())
714         d->types[index] = paramType;
715 }
716
717 /*!
718     \overload
719
720     Binds the value \a val of parameter type \a paramType to the \a
721     placeholder name in the current record (row).
722
723    Values cannot be bound to multiple locations in the query, eg:
724    \code
725    INSERT INTO testtable (id, name, samename) VALUES (:id, :name, :name)
726    \endcode
727    Binding to name will bind to the first :name, but not the second.
728
729     \note Binding an undefined placeholder will result in undefined behavior.
730
731     \sa QSqlQuery::bindValue()
732 */
733 void QSqlResult::bindValue(const QString& placeholder, const QVariant& val,
734                            QSql::ParamType paramType)
735 {
736     d->binds = NamedBinding;
737     // if the index has already been set when doing emulated named
738     // bindings - don't reset it
739     QList<int> indexes = d->indexes.value(placeholder);
740     foreach (int idx, indexes) {
741         if (d->values.count() <= idx)
742             d->values.resize(idx + 1);
743         d->values[idx] = val;
744         if (paramType != QSql::In || !d->types.isEmpty())
745             d->types[idx] = paramType;
746     }
747 }
748
749 /*!
750     Binds the value \a val of parameter type \a paramType to the next
751     available position in the current record (row).
752
753     \sa bindValue()
754 */
755 void QSqlResult::addBindValue(const QVariant& val, QSql::ParamType paramType)
756 {
757     d->binds = PositionalBinding;
758     bindValue(d->bindCount, val, paramType);
759     ++d->bindCount;
760 }
761
762 /*!
763     Returns the value bound at position \a index in the current record
764     (row).
765
766     \sa bindValue(), boundValues()
767 */
768 QVariant QSqlResult::boundValue(int index) const
769 {
770     return d->values.value(index);
771 }
772
773 /*!
774     \overload
775
776     Returns the value bound by the given \a placeholder name in the
777     current record (row).
778
779     \sa bindValueType()
780 */
781 QVariant QSqlResult::boundValue(const QString& placeholder) const
782 {
783     QList<int> indexes = d->indexes.value(placeholder);
784     return d->values.value(indexes.value(0,-1));
785 }
786
787 /*!
788     Returns the parameter type for the value bound at position \a index.
789
790     \sa boundValue()
791 */
792 QSql::ParamType QSqlResult::bindValueType(int index) const
793 {
794     return d->types.value(index, QSql::In);
795 }
796
797 /*!
798     \overload
799
800     Returns the parameter type for the value bound with the given \a
801     placeholder name.
802 */
803 QSql::ParamType QSqlResult::bindValueType(const QString& placeholder) const
804 {
805     return d->types.value(d->indexes.value(placeholder).value(0,-1), QSql::In);
806 }
807
808 /*!
809     Returns the number of bound values in the result.
810
811     \sa boundValues()
812 */
813 int QSqlResult::boundValueCount() const
814 {
815     return d->values.count();
816 }
817
818 /*!
819     Returns a vector of the result's bound values for the current
820     record (row).
821
822     \sa boundValueCount()
823 */
824 QVector<QVariant>& QSqlResult::boundValues() const
825 {
826     return d->values;
827 }
828
829 /*!
830     Returns the binding syntax used by prepared queries.
831 */
832 QSqlResult::BindingSyntax QSqlResult::bindingSyntax() const
833 {
834     return d->binds;
835 }
836
837 /*!
838     Clears the entire result set and releases any associated
839     resources.
840 */
841 void QSqlResult::clear()
842 {
843     d->clear();
844 }
845
846 /*!
847     Returns the query that was actually executed. This may differ from
848     the query that was passed, for example if bound values were used
849     with a prepared query and the underlying database doesn't support
850     prepared queries.
851
852     \sa exec(), setQuery()
853 */
854 QString QSqlResult::executedQuery() const
855 {
856     return d->executedQuery;
857 }
858
859 void QSqlResult::resetBindCount()
860 {
861     d->resetBindCount();
862 }
863
864 /*!
865     Returns the name of the bound value at position \a index in the
866     current record (row).
867
868     \sa boundValue()
869 */
870 QString QSqlResult::boundValueName(int index) const
871 {
872     return d->holderAt(index);
873 }
874
875 /*!
876     Returns true if at least one of the query's bound values is a \c
877     QSql::Out or a QSql::InOut; otherwise returns false.
878
879     \sa bindValueType()
880 */
881 bool QSqlResult::hasOutValues() const
882 {
883     if (d->types.isEmpty())
884         return false;
885     QHash<int, QSql::ParamType>::ConstIterator it;
886     for (it = d->types.constBegin(); it != d->types.constEnd(); ++it) {
887         if (it.value() != QSql::In)
888             return true;
889     }
890     return false;
891 }
892
893 /*!
894     Returns the current record if the query is active; otherwise
895     returns an empty QSqlRecord.
896
897     The default implementation always returns an empty QSqlRecord.
898
899     \sa isActive()
900 */
901 QSqlRecord QSqlResult::record() const
902 {
903     return QSqlRecord();
904 }
905
906 /*!
907     Returns the object ID of the most recent inserted row if the
908     database supports it.
909     An invalid QVariant will be returned if the query did not
910     insert any value or if the database does not report the id back.
911     If more than one row was touched by the insert, the behavior is
912     undefined.
913
914     Note that for Oracle databases the row's ROWID will be returned,
915     while for MySQL databases the row's auto-increment field will
916     be returned.
917
918     \sa QSqlDriver::hasFeature()
919 */
920 QVariant QSqlResult::lastInsertId() const
921 {
922     return QVariant();
923 }
924
925 /*! \internal
926 */
927 void QSqlResult::virtual_hook(int, void *)
928 {
929 }
930
931 /*! \internal
932     \since 4.2
933
934     Executes a prepared query in batch mode if the driver supports it,
935     otherwise emulates a batch execution using bindValue() and exec().
936     QSqlDriver::hasFeature() can be used to find out whether a driver
937     supports batch execution.
938
939     Batch execution can be faster for large amounts of data since it
940     reduces network roundtrips.
941
942     For batch executions, bound values have to be provided as lists
943     of variants (QVariantList).
944
945     Each list must contain values of the same type. All lists must
946     contain equal amount of values (rows).
947
948     NULL values are passed in as typed QVariants, for example
949     \c {QVariant(QVariant::Int)} for an integer NULL value.
950
951     Example:
952
953     \snippet code/src_sql_kernel_qsqlresult.cpp 0
954
955     Here, we insert two rows into a SQL table, with each row containing three values.
956
957     \sa exec(), QSqlDriver::hasFeature()
958 */
959 bool QSqlResult::execBatch(bool arrayBind)
960 {
961     Q_UNUSED(arrayBind);
962
963     QVector<QVariant> values = d->values;
964     if (values.count() == 0)
965         return false;
966     for (int i = 0; i < values.at(0).toList().count(); ++i) {
967         for (int j = 0; j < values.count(); ++j)
968             bindValue(j, values.at(j).toList().at(i), QSql::In);
969         if (!exec())
970             return false;
971     }
972     return true;
973 }
974
975 /*! \internal
976  */
977 void QSqlResult::detachFromResultSet()
978 {
979 }
980
981 /*! \internal
982  */
983 void QSqlResult::setNumericalPrecisionPolicy(QSql::NumericalPrecisionPolicy policy)
984 {
985     d->precisionPolicy = policy;
986 }
987
988 /*! \internal
989  */
990 QSql::NumericalPrecisionPolicy QSqlResult::numericalPrecisionPolicy() const
991 {
992     return d->precisionPolicy;
993 }
994
995 /*! \internal
996 */
997 bool QSqlResult::nextResult()
998 {
999     return false;
1000 }
1001
1002 /*!
1003     Returns the low-level database handle for this result set
1004     wrapped in a QVariant or an invalid QVariant if there is no handle.
1005
1006     \warning Use this with uttermost care and only if you know what you're doing.
1007
1008     \warning The handle returned here can become a stale pointer if the result
1009     is modified (for example, if you clear it).
1010
1011     \warning The handle can be NULL if the result was not executed yet.
1012
1013     The handle returned here is database-dependent, you should query the type
1014     name of the variant before accessing it.
1015
1016     This example retrieves the handle for a sqlite result:
1017
1018     \snippet code/src_sql_kernel_qsqlresult.cpp 1
1019
1020     This snippet returns the handle for PostgreSQL or MySQL:
1021
1022     \snippet code/src_sql_kernel_qsqlresult.cpp 2
1023
1024     \sa QSqlDriver::handle()
1025 */
1026 QVariant QSqlResult::handle() const
1027 {
1028     return QVariant();
1029 }
1030
1031 QT_END_NAMESPACE