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