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 
622  sqlite3_enable_shared_cache(sharedCache);
623 
624  if (sqlite3_open_v2(db.toUtf8().constData(), &d->access, openMode, nullptr) == SQLITE_OK) {
625  sqlite3_busy_timeout(d->access, timeout);
626  sqlite3_extended_result_codes(d->access, 1);
627  setOpen(true);
628  setOpenError(false);
629  return true;
630  } else {
631  if (d->access) {
632  sqlite3_close(d->access);
633  d->access = nullptr;
634  }
635 
636  setLastError(qMakeError(d->access, tr("Error opening database"), QSqlError::ConnectionError));
637  setOpenError(true);
638  return false;
639  }
640 }
641 
642 void QSQLiteDriver::close()
643 {
644  Q_D(QSQLiteDriver);
645 
646  if (isOpen()) {
647  for (QSQLiteResult *result : std::as_const(d->results)) {
648  result->d_func()->finalize();
649  }
650 
651  if (sqlite3_close(d->access) != SQLITE_OK) {
652  setLastError(qMakeError(d->access, tr("Error closing database"), QSqlError::ConnectionError));
653  }
654  d->access = nullptr;
655  setOpen(false);
656  setOpenError(false);
657  }
658 }
659 
660 QSqlResult *QSQLiteDriver::createResult() const
661 {
662  return new QSQLiteResult(this);
663 }
664 
665 bool QSQLiteDriver::beginTransaction()
666 {
667  if (!isOpen() || isOpenError()) {
668  return false;
669  }
670 
671  QSqlQuery q(createResult());
672  if (!q.exec(QStringLiteral("BEGIN"))) {
673  setLastError(QSqlError(tr("Unable to begin transaction"), q.lastError().databaseText(), QSqlError::TransactionError));
674  return false;
675  }
676 
677  return true;
678 }
679 
680 bool QSQLiteDriver::commitTransaction()
681 {
682  if (!isOpen() || isOpenError()) {
683  return false;
684  }
685 
686  QSqlQuery q(createResult());
687  if (!q.exec(QStringLiteral("COMMIT"))) {
688  setLastError(QSqlError(tr("Unable to commit transaction"), q.lastError().databaseText(), QSqlError::TransactionError));
689  return false;
690  }
691 
692  return true;
693 }
694 
695 bool QSQLiteDriver::rollbackTransaction()
696 {
697  if (!isOpen() || isOpenError()) {
698  return false;
699  }
700 
701  QSqlQuery q(createResult());
702  if (!q.exec(QStringLiteral("ROLLBACK"))) {
703  setLastError(QSqlError(tr("Unable to rollback transaction"), q.lastError().databaseText(), QSqlError::TransactionError));
704  return false;
705  }
706 
707  return true;
708 }
709 
710 QStringList QSQLiteDriver::tables(QSql::TableType type) const
711 {
712  QStringList res;
713  if (!isOpen()) {
714  return res;
715  }
716 
717  QSqlQuery q(createResult());
718  q.setForwardOnly(true);
719 
720  QString sql = QStringLiteral(
721  "SELECT name FROM sqlite_master WHERE %1 "
722  "UNION ALL SELECT name FROM sqlite_temp_master WHERE %1");
723  if ((type & QSql::Tables) && (type & QSql::Views)) {
724  sql = sql.arg(QStringLiteral("type='table' OR type='view'"));
725  } else if (type & QSql::Tables) {
726  sql = sql.arg(QStringLiteral("type='table'"));
727  } else if (type & QSql::Views) {
728  sql = sql.arg(QStringLiteral("type='view'"));
729  } else {
730  sql.clear();
731  }
732 
733  if (!sql.isEmpty() && q.exec(sql)) {
734  while (q.next()) {
735  res.append(q.value(0).toString());
736  }
737  }
738 
739  if (type & QSql::SystemTables) {
740  // there are no internal tables beside this one:
741  res.append(QStringLiteral("sqlite_master"));
742  }
743 
744  return res;
745 }
746 
747 static QSqlIndex qGetTableInfo(QSqlQuery &q, const QString &tableName, bool onlyPIndex = false)
748 {
749  QString schema;
750  QString table(tableName);
751  int indexOfSeparator = tableName.indexOf(QLatin1Char('.'));
752  if (indexOfSeparator > -1) {
753  schema = tableName.left(indexOfSeparator).append(QLatin1Char('.'));
754  table = tableName.mid(indexOfSeparator + 1);
755  }
756  q.exec(QStringLiteral("PRAGMA ") + schema + QStringLiteral("table_info (") + _q_escapeIdentifier(table) + QLatin1Char(')'));
757 
758  QSqlIndex ind;
759  while (q.next()) {
760  bool isPk = q.value(5).toInt();
761  if (onlyPIndex && !isPk) {
762  continue;
763  }
764  QString typeName = q.value(2).toString().toLower();
765  QSqlField fld(q.value(1).toString(), qGetColumnType(typeName));
766  if (isPk && (typeName == QLatin1String("integer")))
767  // INTEGER PRIMARY KEY fields are auto-generated in sqlite
768  // INT PRIMARY KEY is not the same as INTEGER PRIMARY KEY!
769  {
770  fld.setAutoValue(true);
771  }
772  fld.setRequired(q.value(3).toInt() != 0);
773  fld.setDefaultValue(q.value(4));
774  ind.append(fld);
775  }
776  return ind;
777 }
778 
779 QSqlIndex QSQLiteDriver::primaryIndex(const QString &tblname) const
780 {
781  if (!isOpen()) {
782  return QSqlIndex();
783  }
784 
785  QString table = tblname;
786  if (isIdentifierEscaped(table, QSqlDriver::TableName)) {
787  table = stripDelimiters(table, QSqlDriver::TableName);
788  }
789 
790  QSqlQuery q(createResult());
791  q.setForwardOnly(true);
792  return qGetTableInfo(q, table, true);
793 }
794 
795 QSqlRecord QSQLiteDriver::record(const QString &tbl) const
796 {
797  if (!isOpen()) {
798  return QSqlRecord();
799  }
800 
801  QString table = tbl;
802  if (isIdentifierEscaped(table, QSqlDriver::TableName)) {
803  table = stripDelimiters(table, QSqlDriver::TableName);
804  }
805 
806  QSqlQuery q(createResult());
807  q.setForwardOnly(true);
808  return qGetTableInfo(q, table);
809 }
810 
811 QVariant QSQLiteDriver::handle() const
812 {
813  Q_D(const QSQLiteDriver);
814  return QVariant::fromValue(d->access);
815 }
816 
817 QString QSQLiteDriver::escapeIdentifier(const QString &identifier, IdentifierType type) const
818 {
819  Q_UNUSED(type)
820  return _q_escapeIdentifier(identifier);
821 }
822 
823 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)
KGuiItem reset()
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
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-2022 The KDE developers.
Generated on Thu Jun 30 2022 03:51:46 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.