Akonadi

qsql_sqlite.cpp
1 /****************************************************************************
2 **
3 ** SPDX-FileCopyrightText: 2009 Nokia Corporation and /or its subsidiary(-ies).
4 ** Contact: Nokia Corporation ([email protected])
5 **
6 ** This file is part of the QtSql module of the Qt Toolkit.
7 **
8 ** SPDX-FileCopyrightText: LGPL-2.1-only WITH Qt-LGPL-exception-1.1 OR GPL-3.0-only
9 **
10 ****************************************************************************/
11 
12 #include "qsql_sqlite.h"
13 
14 #include <QCoreApplication>
15 #include <QDateTime>
16 #include <QSqlError>
17 #include <QSqlField>
18 #include <QSqlIndex>
19 #include <QSqlQuery>
20 #include <QStringList>
21 #include <QVariant>
22 #include <QVector>
23 
24 #include <QtSql/private/qsqldriver_p.h>
25 
26 #if defined Q_OS_WIN
27 #include <qt_windows.h>
28 #else
29 #include <unistd.h>
30 #endif
31 
32 #include <sqlite3.h>
33 
34 #include "sqlite_blocking.h"
35 #include <QThread>
36 
37 Q_DECLARE_OPAQUE_POINTER(sqlite3 *)
38 Q_DECLARE_OPAQUE_POINTER(sqlite3_stmt *)
39 
40 Q_DECLARE_METATYPE(sqlite3 *)
41 Q_DECLARE_METATYPE(sqlite3_stmt *)
42 
43 QT_BEGIN_NAMESPACE
44 
45 static QString _q_escapeIdentifier(const QString &identifier)
46 {
47  QString res = identifier;
48  if (!identifier.isEmpty() && identifier.at(0) != QString(QLatin1Char('"')) && identifier.right(1) != QString(QLatin1Char('"'))) {
49  res.replace(QLatin1Char('"'), QStringLiteral("\"\""));
50  res.prepend(QLatin1Char('"')).append(QLatin1Char('"'));
51  res.replace(QLatin1Char('.'), QStringLiteral("\".\""));
52  }
53  return res;
54 }
55 
56 static QVariant::Type qGetColumnType(const QString &tpName)
57 {
58  const QString typeName = tpName.toLower();
59 
60  if (typeName == QLatin1String("integer") || typeName == QLatin1String("int")) {
61  return QVariant::Int;
62  }
63  if (typeName == QLatin1String("double") || typeName == QLatin1String("float") || typeName == QLatin1String("real")
64  || typeName.startsWith(QLatin1String("numeric"))) {
65  return QVariant::Double;
66  }
67  if (typeName == QLatin1String("blob")) {
68  return QVariant::ByteArray;
69  }
70  if (typeName == QLatin1String("boolean") || typeName == QLatin1String("bool")) {
71  return QVariant::Bool;
72  }
73  return QVariant::String;
74 }
75 
76 static QSqlError qMakeError(sqlite3 *access, const QString &descr, QSqlError::ErrorType type, int errorCode = -1)
77 {
78  return QSqlError(descr, QString(reinterpret_cast<const QChar *>(sqlite3_errmsg16(access))), type, QString::number(errorCode));
79 }
80 
81 class QSQLiteResultPrivate;
82 
83 class QSQLiteResult : public QSqlCachedResult
84 {
85  friend class QSQLiteDriver;
86  friend class QSQLiteResultPrivate;
87 
88 public:
89  explicit QSQLiteResult(const QSQLiteDriver *db);
90  ~QSQLiteResult() override;
91  QVariant handle() const override;
92 
93 protected:
94  bool gotoNext(QSqlCachedResult::ValueCache &row, int idx) override;
95  bool reset(const QString &query) override;
96  bool prepare(const QString &query) override;
97  bool exec() override;
98  int size() override;
99  int numRowsAffected() override;
100  QVariant lastInsertId() const override;
101  QSqlRecord record() const override;
102  void detachFromResultSet() override;
103  void virtual_hook(int id, void *data) override;
104 
105 private:
106  Q_DECLARE_PRIVATE(QSQLiteResult)
107 };
108 
109 class QSQLiteDriverPrivate : public QSqlDriverPrivate
110 {
111 public:
112  inline QSQLiteDriverPrivate()
113  : access(nullptr)
114  {
115  dbmsType = QSqlDriver::SQLite;
116  }
117  sqlite3 *access;
118  QList<QSQLiteResult *> results;
119 };
120 
121 class QSQLiteResultPrivate : public QSqlCachedResultPrivate
122 {
123 public:
124  QSQLiteResultPrivate(QSQLiteResult *res, const QSQLiteDriver *drv);
125 
126  void cleanup();
127  bool fetchNext(QSqlCachedResult::ValueCache &values, int idx, bool initialFetch);
128  // initializes the recordInfo and the cache
129  void initColumns(bool emptyResultset);
130  void finalize();
131 
132  sqlite3 *access;
133 
134  sqlite3_stmt *stmt;
135 
136  bool skippedStatus; // the status of the fetchNext() that's skipped
137  bool skipRow; // skip the next fetchNext()?
138  QSqlRecord rInf;
139  QVector<QVariant> firstRow;
140 
141  Q_DECLARE_PUBLIC(QSQLiteResult)
142 };
143 
144 QSQLiteResultPrivate::QSQLiteResultPrivate(QSQLiteResult *res, const QSQLiteDriver *drv)
145  : QSqlCachedResultPrivate(res, drv)
146  , access(nullptr)
147  , stmt(nullptr)
148  , skippedStatus(false)
149  , skipRow(false)
150 {
151 }
152 
153 void QSQLiteResultPrivate::cleanup()
154 {
155  Q_Q(QSQLiteResult);
156  finalize();
157  rInf.clear();
158  skippedStatus = false;
159  skipRow = false;
160  q->setAt(QSql::BeforeFirstRow);
161  q->setActive(false);
162  q->cleanup();
163 }
164 
165 void QSQLiteResultPrivate::finalize()
166 {
167  if (!stmt) {
168  return;
169  }
170 
171  sqlite3_finalize(stmt);
172  stmt = nullptr;
173 }
174 
175 void QSQLiteResultPrivate::initColumns(bool emptyResultset)
176 {
177  Q_Q(QSQLiteResult);
178  int nCols = sqlite3_column_count(stmt);
179  if (nCols <= 0) {
180  return;
181  }
182 
183  q->init(nCols);
184 
185  for (int i = 0; i < nCols; ++i) {
186  QString colName = QString::fromUtf16(static_cast<const ushort *>(sqlite3_column_name16(stmt, i))).remove(QLatin1Char('"'));
187 
188  // must use typeName for resolving the type to match QSqliteDriver::record
189  QString typeName = QString::fromUtf16(static_cast<const ushort *>(sqlite3_column_decltype16(stmt, i)));
190 
191  // sqlite3_column_type is documented to have undefined behavior if the result set is empty
192  int stp = emptyResultset ? -1 : sqlite3_column_type(stmt, i);
193 
194  QVariant::Type fieldType;
195 
196  if (typeName.isEmpty()) {
197  fieldType = qGetColumnType(typeName);
198  } else {
199  // Get the proper type for the field based on stp value
200  switch (stp) {
201  case SQLITE_INTEGER:
202  fieldType = QVariant::Int;
203  break;
204  case SQLITE_FLOAT:
205  fieldType = QVariant::Double;
206  break;
207  case SQLITE_BLOB:
208  fieldType = QVariant::ByteArray;
209  break;
210  case SQLITE_TEXT:
211  fieldType = QVariant::String;
212  break;
213  case SQLITE_NULL:
214  default:
215  fieldType = QVariant::Invalid;
216  break;
217  }
218  }
219 
220  QSqlField fld(colName, fieldType);
221  fld.setSqlType(stp);
222  rInf.append(fld);
223  }
224 }
225 
226 bool QSQLiteResultPrivate::fetchNext(QSqlCachedResult::ValueCache &values, int idx, bool initialFetch)
227 {
228  Q_Q(QSQLiteResult);
229 
230  int res;
231  int i;
232 
233  if (skipRow) {
234  // already fetched
235  Q_ASSERT(!initialFetch);
236  skipRow = false;
237  for (int i = 0; i < firstRow.count(); i++) {
238  values[i] = firstRow[i];
239  }
240  return skippedStatus;
241  }
242  skipRow = initialFetch;
243 
244  if (initialFetch) {
245  firstRow.clear();
246  firstRow.resize(sqlite3_column_count(stmt));
247  }
248 
249  if (!stmt) {
250  q->setLastError(QSqlError(QCoreApplication::translate("QSQLiteResult", "Unable to fetch row"),
251  QCoreApplication::translate("QSQLiteResult", "No query"),
253  q->setAt(QSql::AfterLastRow);
254  return false;
255  }
256  res = sqlite3_blocking_step(stmt);
257 
258  switch (res) {
259  case SQLITE_ROW:
260  // check to see if should fill out columns
261  if (rInf.isEmpty())
262  // must be first call.
263  {
264  initColumns(false);
265  }
266  if (idx < 0 && !initialFetch) {
267  return true;
268  }
269  for (i = 0; i < rInf.count(); ++i) {
270  switch (sqlite3_column_type(stmt, i)) {
271  case SQLITE_BLOB:
272  values[i + idx] = QByteArray(static_cast<const char *>(sqlite3_column_blob(stmt, i)), sqlite3_column_bytes(stmt, i));
273  break;
274  case SQLITE_INTEGER:
275  values[i + idx] = sqlite3_column_int64(stmt, i);
276  break;
277  case SQLITE_FLOAT:
278  switch (q->numericalPrecisionPolicy()) {
280  values[i + idx] = sqlite3_column_int(stmt, i);
281  break;
283  values[i + idx] = sqlite3_column_int64(stmt, i);
284  break;
286  case QSql::HighPrecision:
287  default:
288  values[i + idx] = sqlite3_column_double(stmt, i);
289  break;
290  };
291  break;
292  case SQLITE_NULL:
293  values[i + idx] = QVariant(QVariant::String);
294  break;
295  default:
296  values[i + idx] = QString(reinterpret_cast<const QChar *>(sqlite3_column_text16(stmt, i)), sqlite3_column_bytes16(stmt, i) / sizeof(QChar));
297  break;
298  }
299  }
300  return true;
301  case SQLITE_DONE:
302  if (rInf.isEmpty())
303  // must be first call.
304  {
305  initColumns(true);
306  }
307  q->setAt(QSql::AfterLastRow);
308  sqlite3_reset(stmt);
309  return false;
310  case SQLITE_CONSTRAINT:
311  case SQLITE_ERROR:
312  // SQLITE_ERROR is a generic error code and we must call sqlite3_reset()
313  // to get the specific error message.
314  res = sqlite3_reset(stmt);
315  q->setLastError(qMakeError(access, QCoreApplication::translate("QSQLiteResult", "Unable to fetch row"), QSqlError::ConnectionError, res));
316  q->setAt(QSql::AfterLastRow);
317  return false;
318  case SQLITE_MISUSE:
319  case SQLITE_BUSY:
320  default:
321  // something wrong, don't get col info, but still return false
322  q->setLastError(qMakeError(access, QCoreApplication::translate("QSQLiteResult", "Unable to fetch row"), QSqlError::ConnectionError, res));
323  sqlite3_reset(stmt);
324  q->setAt(QSql::AfterLastRow);
325  return false;
326  }
327  return false;
328 }
329 
330 QSQLiteResult::QSQLiteResult(const QSQLiteDriver *db)
331  : QSqlCachedResult(*new QSQLiteResultPrivate(this, db))
332 {
333  Q_D(QSQLiteResult);
334  d->access = db->d_func()->access;
335  const_cast<QSQLiteDriverPrivate *>(db->d_func())->results.append(this);
336 }
337 
338 QSQLiteResult::~QSQLiteResult()
339 {
340  Q_D(QSQLiteResult);
341  const QSqlDriver *sqlDriver = driver();
342  if (sqlDriver) {
343  const_cast<QSQLiteDriverPrivate *>(qobject_cast<const QSQLiteDriver *>(sqlDriver)->d_func())->results.removeOne(this);
344  }
345  d->cleanup();
346 }
347 
348 void QSQLiteResult::virtual_hook(int id, void *data)
349 {
350  QSqlCachedResult::virtual_hook(id, data);
351 }
352 
353 bool QSQLiteResult::reset(const QString &query)
354 {
355  if (!prepare(query)) {
356  return false;
357  }
358  return exec();
359 }
360 
361 bool QSQLiteResult::prepare(const QString &query)
362 {
363  Q_D(QSQLiteResult);
364 
365  if (!driver() || !driver()->isOpen() || driver()->isOpenError()) {
366  return false;
367  }
368 
369  d->cleanup();
370 
371  setSelect(false);
372 
373  const void *pzTail = nullptr;
374 
375 #if (SQLITE_VERSION_NUMBER >= 3003011)
376  // int res = sqlite3_prepare16_v2(d->access, query.constData(), (query.size() + 1) * sizeof(QChar),
377  // &d->stmt, 0);
378  int res = sqlite3_blocking_prepare16_v2(d->access, query.constData(), (query.size() + 1) * sizeof(QChar), &d->stmt, &pzTail);
379 #else
380  int res = sqlite3_prepare16(d->access, query.constData(), (query.size() + 1) * sizeof(QChar), &d->stmt, &pzTail);
381 #endif
382 
383  if (res != SQLITE_OK) {
384  setLastError(qMakeError(d->access, QCoreApplication::translate("QSQLiteResult", "Unable to execute statement"), QSqlError::StatementError, res));
385  d->finalize();
386  return false;
387  } else if (pzTail && !QString(reinterpret_cast<const QChar *>(pzTail)).trimmed().isEmpty()) {
388  setLastError(qMakeError(d->access,
389  QCoreApplication::translate("QSQLiteResult", "Unable to execute multiple statements at a time"),
391  SQLITE_MISUSE));
392  d->finalize();
393  return false;
394  }
395  return true;
396 }
397 
398 bool QSQLiteResult::exec()
399 {
400  Q_D(QSQLiteResult);
401  const QVector<QVariant> values = boundValues();
402 
403  d->skippedStatus = false;
404  d->skipRow = false;
405  d->rInf.clear();
406  clearValues();
407  setLastError(QSqlError());
408 
409  int res = sqlite3_reset(d->stmt);
410  if (res != SQLITE_OK) {
411  setLastError(qMakeError(d->access, QCoreApplication::translate("QSQLiteResult", "Unable to reset statement"), QSqlError::StatementError, res));
412  d->finalize();
413  return false;
414  }
415  int paramCount = sqlite3_bind_parameter_count(d->stmt);
416  if (paramCount == values.count()) {
417  for (int i = 0; i < paramCount; ++i) {
418  res = SQLITE_OK;
419  const QVariant value = values.at(i);
420 
421  if (value.isNull()) {
422  res = sqlite3_bind_null(d->stmt, i + 1);
423  } else {
424  switch (value.type()) {
425  case QVariant::ByteArray: {
426  const auto ba = static_cast<const QByteArray *>(value.constData());
427  res = sqlite3_bind_blob(d->stmt, i + 1, ba->constData(), ba->size(), SQLITE_STATIC);
428  break;
429  }
430  case QVariant::Int:
431  case QVariant::Bool:
432  res = sqlite3_bind_int(d->stmt, i + 1, value.toInt());
433  break;
434  case QVariant::Double:
435  res = sqlite3_bind_double(d->stmt, i + 1, value.toDouble());
436  break;
437  case QVariant::UInt:
438  case QVariant::LongLong:
439  res = sqlite3_bind_int64(d->stmt, i + 1, value.toLongLong());
440  break;
441  case QVariant::DateTime: {
442  const QDateTime dateTime = value.toDateTime();
443  const QString str = dateTime.toString(QStringLiteral("yyyy-MM-ddThh:mm:ss.zzz"));
444  res = sqlite3_bind_text16(d->stmt, i + 1, str.utf16(), str.size() * sizeof(ushort), SQLITE_TRANSIENT);
445  break;
446  }
447  case QVariant::Time: {
448  const QTime time = value.toTime();
449  const QString str = time.toString(QStringLiteral("hh:mm:ss.zzz"));
450  res = sqlite3_bind_text16(d->stmt, i + 1, str.utf16(), str.size() * sizeof(ushort), SQLITE_TRANSIENT);
451  break;
452  }
453  case QVariant::String: {
454  // lifetime of string == lifetime of its qvariant
455  const auto str = static_cast<const QString *>(value.constData());
456  res = sqlite3_bind_text16(d->stmt, i + 1, str->utf16(), (str->size()) * sizeof(QChar), SQLITE_STATIC);
457  break;
458  }
459  default: {
460  QString str = value.toString();
461  // SQLITE_TRANSIENT makes sure that sqlite buffers the data
462  res = sqlite3_bind_text16(d->stmt, i + 1, str.utf16(), (str.size()) * sizeof(QChar), SQLITE_TRANSIENT);
463  break;
464  }
465  }
466  }
467  if (res != SQLITE_OK) {
468  setLastError(qMakeError(d->access, QCoreApplication::translate("QSQLiteResult", "Unable to bind parameters"), QSqlError::StatementError, res));
469  d->finalize();
470  return false;
471  }
472  }
473  } else {
474  setLastError(QSqlError(QCoreApplication::translate("QSQLiteResult", "Parameter count mismatch"), QString(), QSqlError::StatementError));
475  return false;
476  }
477  d->skippedStatus = d->fetchNext(d->firstRow, 0, true);
478  if (lastError().isValid()) {
479  setSelect(false);
480  setActive(false);
481  return false;
482  }
483  setSelect(!d->rInf.isEmpty());
484  setActive(true);
485  return true;
486 }
487 
488 bool QSQLiteResult::gotoNext(QSqlCachedResult::ValueCache &row, int idx)
489 {
490  return d_func()->fetchNext(row, idx, false);
491 }
492 
493 int QSQLiteResult::size()
494 {
495  return -1;
496 }
497 
498 int QSQLiteResult::numRowsAffected()
499 {
500  return sqlite3_changes(d_func()->access);
501 }
502 
503 QVariant QSQLiteResult::lastInsertId() const
504 {
505  if (isActive()) {
506  qint64 id = sqlite3_last_insert_rowid(d_func()->access);
507  if (id) {
508  return id;
509  }
510  }
511  return QVariant();
512 }
513 
514 QSqlRecord QSQLiteResult::record() const
515 {
516  if (!isActive() || !isSelect()) {
517  return QSqlRecord();
518  }
519  return d_func()->rInf;
520 }
521 
522 void QSQLiteResult::detachFromResultSet()
523 {
524  if (d_func()->stmt) {
525  sqlite3_reset(d_func()->stmt);
526  }
527 }
528 
529 QVariant QSQLiteResult::handle() const
530 {
531  return QVariant::fromValue(d_func()->stmt);
532 }
533 
534 /////////////////////////////////////////////////////////
535 
536 QSQLiteDriver::QSQLiteDriver(QObject *parent)
537  : QSqlDriver(*new QSQLiteDriverPrivate, parent)
538 {
539 }
540 
541 QSQLiteDriver::QSQLiteDriver(sqlite3 *connection, QObject *parent)
542  : QSqlDriver(*new QSQLiteDriverPrivate, parent)
543 {
544  Q_D(QSQLiteDriver);
545 
546  d->access = connection;
547  setOpen(true);
548  setOpenError(false);
549 }
550 
551 QSQLiteDriver::~QSQLiteDriver()
552 {
553 }
554 
555 bool QSQLiteDriver::hasFeature(DriverFeature f) const
556 {
557  switch (f) {
558  case BLOB:
559  case Transactions:
560  case Unicode:
561  case LastInsertId:
562  case PreparedQueries:
563  case PositionalPlaceholders:
564  case SimpleLocking:
565  case FinishQuery:
566  case LowPrecisionNumbers:
567  return true;
568  case QuerySize:
569  case NamedPlaceholders:
570  case BatchOperations:
571  case EventNotifications:
572  case MultipleResultSets:
573  case CancelQuery:
574  return false;
575  }
576  return false;
577 }
578 
579 /*
580  SQLite dbs have no user name, passwords, hosts or ports.
581  just file names.
582 */
583 bool QSQLiteDriver::open(const QString &db, const QString &, const QString &, const QString &, int, const QString &conOpts)
584 {
585  Q_D(QSQLiteDriver);
586 
587  if (isOpen()) {
588  close();
589  }
590 
591  int timeout = 5000;
592  bool sharedCache = false;
593  bool openReadOnlyOption = false;
594  bool openUriOption = false;
595 
596  const QStringList opts = QString(conOpts).remove(QLatin1Char(' ')).split(QLatin1Char(';'));
597  for (const QString &option : opts) {
598  if (option.startsWith(QLatin1String("QSQLITE_BUSY_TIMEOUT="))) {
599  bool ok;
600 #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
601  const int nt = QStringView(option).mid(21).toInt(&ok);
602 #else
603  const int nt = option.midRef(21).toInt(&ok);
604 #endif
605  if (ok) {
606  timeout = nt;
607  }
608  } else if (option == QLatin1String("QSQLITE_OPEN_READONLY")) {
609  openReadOnlyOption = true;
610  } else if (option == QLatin1String("QSQLITE_OPEN_URI")) {
611  openUriOption = true;
612  } else if (option == QLatin1String("QSQLITE_ENABLE_SHARED_CACHE")) {
613  sharedCache = true;
614  }
615  }
616 
617  int openMode = (openReadOnlyOption ? SQLITE_OPEN_READONLY : (SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE));
618  if (openUriOption) {
619  openMode |= SQLITE_OPEN_URI;
620  }
621  // Use multi-threaded mode
622  openMode |= SQLITE_OPEN_NOMUTEX;
623 
624  sqlite3_enable_shared_cache(sharedCache);
625 
626  if (sqlite3_open_v2(db.toUtf8().constData(), &d->access, openMode, nullptr) == SQLITE_OK) {
627  sqlite3_busy_timeout(d->access, timeout);
628  sqlite3_extended_result_codes(d->access, 1);
629  setOpen(true);
630  setOpenError(false);
631  return true;
632  } else {
633  if (d->access) {
634  sqlite3_close(d->access);
635  d->access = nullptr;
636  }
637 
638  setLastError(qMakeError(d->access, tr("Error opening database"), QSqlError::ConnectionError));
639  setOpenError(true);
640  return false;
641  }
642 }
643 
644 void QSQLiteDriver::close()
645 {
646  Q_D(QSQLiteDriver);
647 
648  if (isOpen()) {
649  for (QSQLiteResult *result : std::as_const(d->results)) {
650  result->d_func()->finalize();
651  }
652 
653  if (sqlite3_close(d->access) != SQLITE_OK) {
654  setLastError(qMakeError(d->access, tr("Error closing database"), QSqlError::ConnectionError));
655  }
656  d->access = nullptr;
657  setOpen(false);
658  setOpenError(false);
659  }
660 }
661 
662 QSqlResult *QSQLiteDriver::createResult() const
663 {
664  return new QSQLiteResult(this);
665 }
666 
667 bool QSQLiteDriver::beginTransaction()
668 {
669  if (!isOpen() || isOpenError()) {
670  return false;
671  }
672 
673  QSqlQuery q(createResult());
674  if (!q.exec(QStringLiteral("BEGIN"))) {
675  setLastError(QSqlError(tr("Unable to begin transaction"), q.lastError().databaseText(), QSqlError::TransactionError));
676  return false;
677  }
678 
679  return true;
680 }
681 
682 bool QSQLiteDriver::commitTransaction()
683 {
684  if (!isOpen() || isOpenError()) {
685  return false;
686  }
687 
688  QSqlQuery q(createResult());
689  if (!q.exec(QStringLiteral("COMMIT"))) {
690  setLastError(QSqlError(tr("Unable to commit transaction"), q.lastError().databaseText(), QSqlError::TransactionError));
691  return false;
692  }
693 
694  return true;
695 }
696 
697 bool QSQLiteDriver::rollbackTransaction()
698 {
699  if (!isOpen() || isOpenError()) {
700  return false;
701  }
702 
703  QSqlQuery q(createResult());
704  if (!q.exec(QStringLiteral("ROLLBACK"))) {
705  setLastError(QSqlError(tr("Unable to rollback transaction"), q.lastError().databaseText(), QSqlError::TransactionError));
706  return false;
707  }
708 
709  return true;
710 }
711 
712 QStringList QSQLiteDriver::tables(QSql::TableType type) const
713 {
714  QStringList res;
715  if (!isOpen()) {
716  return res;
717  }
718 
719  QSqlQuery q(createResult());
720  q.setForwardOnly(true);
721 
722  QString sql = QStringLiteral(
723  "SELECT name FROM sqlite_master WHERE %1 "
724  "UNION ALL SELECT name FROM sqlite_temp_master WHERE %1");
725  if ((type & QSql::Tables) && (type & QSql::Views)) {
726  sql = sql.arg(QStringLiteral("type='table' OR type='view'"));
727  } else if (type & QSql::Tables) {
728  sql = sql.arg(QStringLiteral("type='table'"));
729  } else if (type & QSql::Views) {
730  sql = sql.arg(QStringLiteral("type='view'"));
731  } else {
732  sql.clear();
733  }
734 
735  if (!sql.isEmpty() && q.exec(sql)) {
736  while (q.next()) {
737  res.append(q.value(0).toString());
738  }
739  }
740 
741  if (type & QSql::SystemTables) {
742  // there are no internal tables beside this one:
743  res.append(QStringLiteral("sqlite_master"));
744  }
745 
746  return res;
747 }
748 
749 static QSqlIndex qGetTableInfo(QSqlQuery &q, const QString &tableName, bool onlyPIndex = false)
750 {
751  QString schema;
752  QString table(tableName);
753  int indexOfSeparator = tableName.indexOf(QLatin1Char('.'));
754  if (indexOfSeparator > -1) {
755  schema = tableName.left(indexOfSeparator).append(QLatin1Char('.'));
756  table = tableName.mid(indexOfSeparator + 1);
757  }
758  q.exec(QStringLiteral("PRAGMA ") + schema + QStringLiteral("table_info (") + _q_escapeIdentifier(table) + QLatin1Char(')'));
759 
760  QSqlIndex ind;
761  while (q.next()) {
762  bool isPk = q.value(5).toInt();
763  if (onlyPIndex && !isPk) {
764  continue;
765  }
766  QString typeName = q.value(2).toString().toLower();
767  QSqlField fld(q.value(1).toString(), qGetColumnType(typeName));
768  if (isPk && (typeName == QLatin1String("integer")))
769  // INTEGER PRIMARY KEY fields are auto-generated in sqlite
770  // INT PRIMARY KEY is not the same as INTEGER PRIMARY KEY!
771  {
772  fld.setAutoValue(true);
773  }
774  fld.setRequired(q.value(3).toInt() != 0);
775  fld.setDefaultValue(q.value(4));
776  ind.append(fld);
777  }
778  return ind;
779 }
780 
781 QSqlIndex QSQLiteDriver::primaryIndex(const QString &tblname) const
782 {
783  if (!isOpen()) {
784  return QSqlIndex();
785  }
786 
787  QString table = tblname;
788  if (isIdentifierEscaped(table, QSqlDriver::TableName)) {
789  table = stripDelimiters(table, QSqlDriver::TableName);
790  }
791 
792  QSqlQuery q(createResult());
793  q.setForwardOnly(true);
794  return qGetTableInfo(q, table, true);
795 }
796 
797 QSqlRecord QSQLiteDriver::record(const QString &tbl) const
798 {
799  if (!isOpen()) {
800  return QSqlRecord();
801  }
802 
803  QString table = tbl;
804  if (isIdentifierEscaped(table, QSqlDriver::TableName)) {
805  table = stripDelimiters(table, QSqlDriver::TableName);
806  }
807 
808  QSqlQuery q(createResult());
809  q.setForwardOnly(true);
810  return qGetTableInfo(q, table);
811 }
812 
813 QVariant QSQLiteDriver::handle() const
814 {
815  Q_D(const QSQLiteDriver);
816  return QVariant::fromValue(d->access);
817 }
818 
819 QString QSQLiteDriver::escapeIdentifier(const QString &identifier, IdentifierType type) const
820 {
821  Q_UNUSED(type)
822  return _q_escapeIdentifier(identifier);
823 }
824 
825 QT_END_NAMESPACE
void append(const T &value)
bool isNull() const const
void setForwardOnly(bool forward)
QVariant value(int index) const const
QString number(int n, int base)
int size() const const
QVariant fromValue(const T &value)
QString translate(const char *context, const char *sourceText, const char *disambiguation, int n)
QStringList split(const QString &sep, QString::SplitBehavior behavior, Qt::CaseSensitivity cs) const const
void clear()
QStringView mid(qsizetype start) const const
void append(const QSqlField &field)
QString & prepend(QChar ch)
LowPrecisionInt32
qlonglong toLongLong(bool *ok) const const
const QList< QKeySequence > & close()
bool exec(const QString &query)
KSERVICE_EXPORT KService::List query(FilterFunc filterFunc)
int size() const const
double toDouble(bool *ok) const const
QVariant::Type type() const const
bool isEmpty() const const
QByteArray toUtf8() const const
int toInt(bool *ok) const const
bool next()
int indexOf(QChar ch, int from, Qt::CaseSensitivity cs) const const
QString fromUtf16(const ushort *unicode, int size)
QString & replace(int position, int n, QChar after)
QString & remove(int position, int n)
bool startsWith(const QString &s, Qt::CaseSensitivity cs) const const
QString toLower() const const
const ushort * utf16() const const
QDateTime toDateTime() const const
const char * constData() const const
QString arg(qlonglong a, int fieldWidth, int base, QChar fillChar) const const
QString left(int n) const const
QString right(int n) const const
bool isValid(QStringView ifopt)
QTime toTime() const const
const QChar at(int position) const const
QString toString(Qt::DateFormat format) const const
KGuiItem reset()
QString toString(Qt::DateFormat format) const const
QString mid(int position, int n) const const
BeforeFirstRow
QVector< V > values(const QMultiHash< K, V > &c)
QString & append(QChar ch)
Q_D(Todo)
int access(const QString &path, int mode)
QString toString() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Mon May 8 2023 03:52:16 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.