15#include <QtSql/private/qsqlcachedresult_p.h>
16#include <QtSql/private/qsqldriver_p.h>
19#if QT_CONFIG(regularexpression)
23#include <QScopedValueRollback>
44using namespace
Qt::StringLiterals;
51 return QMetaType::Int;
55 ||
typeName.startsWith(
"numeric"_L1))
56 return QMetaType::Double;
58 return QMetaType::QByteArray;
60 return QMetaType::Bool;
61 return QMetaType::QString;
104 bool isIdentifierEscaped(
QStringView identifier)
const;
106 bool onlyPIndex =
false)
const;
115 return identifier.
size() > 2
122 bool onlyPIndex)
const
128 if (indexOfSeparator > -1) {
131 if (isIdentifierEscaped(leftName) && isIdentifierEscaped(rightName)) {
132 schema = leftName.toString() + u
'.';
133 table = rightName.toString();
137 query.exec(
"PRAGMA "_L1 + schema +
"table_info ("_L1 +
table + u
')');
139 while (
query.next()) {
141 if (onlyPIndex && !isPk)
145 if (!defVal.isEmpty() && defVal.at(0) == u
'\'') {
148 defVal = defVal.mid(1,
end - 1);
152 if (isPk && (
typeName ==
"integer"_L1))
155 fld.setAutoValue(
true);
156 fld.setRequired(
query.value(3).toInt() != 0);
157 fld.setDefaultValue(defVal);
169 using QSqlCachedResultPrivate::QSqlCachedResultPrivate;
173 void initColumns(
bool emptyResultset);
179 bool skippedStatus =
false;
180 bool skipRow =
false;
188 skippedStatus =
false;
200 sqlite3_finalize(stmt);
207 int nCols = sqlite3_column_count(stmt);
213 for (
int i = 0;
i < nCols; ++
i) {
215 sqlite3_column_name16(stmt,
i))
218 sqlite3_column_table_name16(stmt,
i))
222 sqlite3_column_decltype16(stmt,
i)));
224 int stp = emptyResultset ? -1 : sqlite3_column_type(stmt,
i);
234 fieldType = QMetaType::Int;
237 fieldType = QMetaType::Double;
240 fieldType = QMetaType::QByteArray;
243 fieldType = QMetaType::QString;
265 for(
int i=0;
i<firstRow.size();
i++)
267 return skippedStatus;
269 skipRow = initialFetch;
273 firstRow.resize(sqlite3_column_count(stmt));
282 int res = sqlite3_step(stmt);
289 if (idx < 0 && !initialFetch)
291 for (
int i = 0;
i < rInf.count(); ++
i) {
292 switch (sqlite3_column_type(stmt,
i)) {
295 sqlite3_column_blob(stmt,
i)),
296 sqlite3_column_bytes(stmt,
i));
299 values[
i + idx] = sqlite3_column_int64(stmt,
i);
302 switch(
q->numericalPrecisionPolicy()) {
304 values[
i + idx] = sqlite3_column_int(stmt,
i);
307 values[
i + idx] = sqlite3_column_int64(stmt,
i);
312 values[
i + idx] = sqlite3_column_double(stmt,
i);
321 sqlite3_column_text16(stmt,
i)),
322 sqlite3_column_bytes16(stmt,
i) /
sizeof(
QChar));
334 case SQLITE_CONSTRAINT:
338 res = sqlite3_reset(stmt);
393 const void *pzTail =
nullptr;
396#if (SQLITE_VERSION_NUMBER >= 3003011)
397 int res = sqlite3_prepare16_v2(
d->drv_d_func()->access,
query.constData(),
size,
400 int res = sqlite3_prepare16(
d->access,
query.constData(),
size,
404 if (
res != SQLITE_OK) {
409 }
else if (pzTail && !
QString(
reinterpret_cast<const QChar *
>(pzTail)).trimmed().isEmpty()) {
422 QScopedValueRollback<QList<QVariant>> valuesScope(
d->values);
423 QList<QVariant>
values =
d->values;
429 QScopedValueRollback<QHash<QString, QList<int>>> indexesScope(
d->indexes);
446 d->skippedStatus =
false;
452 int res = sqlite3_reset(
d->stmt);
453 if (
res != SQLITE_OK) {
460 int paramCount = sqlite3_bind_parameter_count(
d->stmt);
461 bool paramCountIsValid = paramCount ==
values.size();
463#if (SQLITE_VERSION_NUMBER >= 3003011)
468 if (paramCount >= 1 && paramCount <
values.size()) {
469 const auto countIndexes = [](
int counter,
const QList<int> &indexList) {
470 return counter + indexList.size();
473 const int bindParamCount = std::accumulate(
d->indexes.cbegin(),
478 paramCountIsValid = bindParamCount ==
values.size();
482 QList<QVariant> prunedValues;
483 QList<int> handledIndexes;
484 for (
int i = 0, currentIndex = 0;
i <
values.size(); ++
i) {
485 if (handledIndexes.contains(
i))
487 const char *parameterName = sqlite3_bind_parameter_name(
d->stmt, currentIndex + 1);
488 if (!parameterName) {
489 paramCountIsValid =
false;
493 const auto &indexes =
d->indexes.value(placeHolder);
494 handledIndexes << indexes;
495 prunedValues <<
values.at(indexes.first());
502 if (paramCountIsValid) {
503 for (
int i = 0;
i < paramCount; ++
i) {
508 res = sqlite3_bind_null(
d->stmt,
i + 1);
510 switch (
value.userType()) {
511 case QMetaType::QByteArray: {
514 ba->
size(), SQLITE_STATIC);
517 case QMetaType::Bool:
518 res = sqlite3_bind_int(
d->stmt,
i + 1,
value.toInt());
520 case QMetaType::Double:
521 res = sqlite3_bind_double(
d->stmt,
i + 1,
value.toDouble());
523 case QMetaType::UInt:
524 case QMetaType::LongLong:
525 res = sqlite3_bind_int64(
d->stmt,
i + 1,
value.toLongLong());
527 case QMetaType::QDateTime: {
535 case QMetaType::QTime: {
543 case QMetaType::QString: {
559 if (
res != SQLITE_OK) {
571 d->skippedStatus =
d->fetchNext(
d->firstRow, 0,
true);
585 return d->fetchNext(
row, idx,
false);
596 return sqlite3_changes(
d->drv_d_func()->access);
603 qint64 id = sqlite3_last_insert_rowid(
d->drv_d_func()->access);
622 sqlite3_reset(
d->stmt);
633#if QT_CONFIG(regularexpression)
634static void _q_regexp(sqlite3_context*
context,
int argc, sqlite3_value** argv)
637 sqlite3_result_int(
context, 0);
642 reinterpret_cast<const char*
>(sqlite3_value_text(argv[0])));
644 reinterpret_cast<const char*
>(sqlite3_value_text(argv[1])));
646 auto cache =
static_cast<QCache<QString, QRegularExpression>*
>(sqlite3_user_data(
context));
648 const bool wasCached = regexp;
653 const bool found = subject.
contains(*regexp);
658 sqlite3_result_int(
context,
int(found));
661static void _q_regexp_cleanup(
void *
cache)
663 delete static_cast<QCache<QString, QRegularExpression>*
>(
cache);
670 sqlite3_result_text(
context,
nullptr, 0,
nullptr);
674 reinterpret_cast<const char*
>(sqlite3_value_text(argv[0]))).toLower();
682 sqlite3_result_text(
context,
nullptr, 0,
nullptr);
686 reinterpret_cast<const char*
>(sqlite3_value_text(argv[0]))).toUpper();
731#if (SQLITE_VERSION_NUMBER < 3003011)
753 bool sharedCache =
false;
754 bool openReadOnlyOption =
false;
755 bool openUriOption =
false;
756 bool useExtendedResultCodes =
true;
757 bool useQtVfs =
false;
758 bool useQtCaseFolding =
false;
759 bool openNoFollow =
false;
760#if QT_CONFIG(regularexpression)
761 static const auto regexpConnectOption =
"QSQLITE_ENABLE_REGEXP"_L1;
762 bool defineRegexp =
false;
763 int regexpCacheSize = 25;
767 for (
auto option : opts) {
769 if (
option.startsWith(
"QSQLITE_BUSY_TIMEOUT"_L1)) {
771 if (
option.startsWith(u
'=')) {
773 const int nt =
option.mid(1).trimmed().toInt(&
ok);
777 }
else if (
option ==
"QSQLITE_USE_QT_VFS"_L1) {
779 }
else if (
option ==
"QSQLITE_OPEN_READONLY"_L1) {
780 openReadOnlyOption =
true;
781 }
else if (
option ==
"QSQLITE_OPEN_URI"_L1) {
782 openUriOption =
true;
783 }
else if (
option ==
"QSQLITE_ENABLE_SHARED_CACHE"_L1) {
785 }
else if (
option ==
"QSQLITE_NO_USE_EXTENDED_RESULT_CODES"_L1) {
786 useExtendedResultCodes =
false;
787 }
else if (
option ==
"QSQLITE_ENABLE_NON_ASCII_CASE_FOLDING"_L1) {
788 useQtCaseFolding =
true;
789 }
else if (
option ==
"QSQLITE_OPEN_NOFOLLOW"_L1) {
792#if QT_CONFIG(regularexpression)
793 else if (
option.startsWith(regexpConnectOption)) {
794 option =
option.mid(regexpConnectOption.size()).trimmed();
797 }
else if (
option.startsWith(u
'=')) {
812 int openMode = (openReadOnlyOption ? SQLITE_OPEN_READONLY : (SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE));
813 openMode |= (sharedCache ? SQLITE_OPEN_SHAREDCACHE : SQLITE_OPEN_PRIVATECACHE);
815 openMode |= SQLITE_OPEN_URI;
817#if defined(SQLITE_OPEN_NOFOLLOW)
818 openMode |= SQLITE_OPEN_NOFOLLOW;
820 qCWarning(lcSqlite,
"SQLITE_OPEN_NOFOLLOW not supported with the SQLite version %s", sqlite3_libversion());
824 openMode |= SQLITE_OPEN_NOMUTEX;
826 const int res = sqlite3_open_v2(
db.toUtf8().constData(), &
d->access, openMode, useQtVfs ?
"QtVFS" :
nullptr);
828 if (
res == SQLITE_OK) {
829 sqlite3_busy_timeout(
d->access, timeOut);
830 sqlite3_extended_result_codes(
d->access, useExtendedResultCodes);
833#if QT_CONFIG(regularexpression)
835 auto cache =
new QCache<QString, QRegularExpression>(regexpCacheSize);
836 sqlite3_create_function_v2(
d->access,
"regexp", 2, SQLITE_UTF8,
cache,
838 nullptr, &_q_regexp_cleanup);
841 if (useQtCaseFolding) {
842 sqlite3_create_function_v2(
d->access,
"lower", 1, SQLITE_UTF8,
nullptr,
843 &
_q_lower,
nullptr,
nullptr,
nullptr);
844 sqlite3_create_function_v2(
d->access,
"upper", 1, SQLITE_UTF8,
nullptr,
845 &
_q_upper,
nullptr,
nullptr,
nullptr);
854 sqlite3_close(
d->access);
867 result->d_func()->finalize();
869 if (
d->access && (
d->notificationid.size() > 0)) {
870 d->notificationid.clear();
871 sqlite3_update_hook(
d->access,
nullptr,
nullptr);
874 const int res = sqlite3_close(
d->access);
876 if (
res != SQLITE_OK)
895 if (!
q.exec(
"BEGIN"_L1)) {
910 if (!
q.exec(
"COMMIT"_L1)) {
925 if (!
q.exec(
"ROLLBACK"_L1)) {
941 q.setForwardOnly(
true);
943 QString sql =
"SELECT name FROM sqlite_master WHERE %1 "
944 "UNION ALL SELECT name FROM sqlite_temp_master WHERE %1"_L1;
946 sql = sql.
arg(
"type='table' OR type='view'"_L1);
948 sql = sql.
arg(
"type='table'"_L1);
950 sql = sql.
arg(
"type='view'"_L1);
954 if (!sql.
isEmpty() &&
q.exec(sql)) {
956 res.append(
q.value(0).toString());
961 res.append(
"sqlite_master"_L1);
974 q.setForwardOnly(
true);
975 return d->getTableInfo(
q, tablename,
true);
985 q.setForwardOnly(
true);
986 return d->getTableInfo(
q, tablename);
1001 const auto indexOfSeparator = identifier.
indexOf(u
'.');
1002 if (indexOfSeparator > -1) {
1005 const QStringView leftEnclose =
d->isIdentifierEscaped(leftName) ? u
"" : u
"\"";
1006 const QStringView rightEnclose =
d->isIdentifierEscaped(rightName) ? u
"" : u
"\"";
1007 if (leftEnclose.isEmpty() || rightEnclose.isEmpty())
1008 return (leftEnclose + leftName + leftEnclose + u
'.' + rightEnclose + rightName
1011 return u
'"' + identifier + u
'"';
1018 return d->isIdentifierEscaped(
QStringView{identifier});
1024 const auto indexOfSeparator = identifier.
indexOf(u
'.');
1025 if (indexOfSeparator > -1) {
1028 const auto leftEscaped =
d->isIdentifierEscaped(leftName);
1029 const auto rightEscaped =
d->isIdentifierEscaped(rightName);
1030 if (leftEscaped || rightEscaped) {
1035 return leftName + u
'.' + rightName;
1040 return identifier.
mid(1, identifier.
size() - 2);
1046 sqlite3_int64 arowid)
1061 qCWarning(lcSqlite,
"QSQLiteDriver::subscribeToNotification: Database not open.");
1065 if (
d->notificationid.contains(
name)) {
1066 qCWarning(lcSqlite,
"QSQLiteDriver::subscribeToNotification: Already subscribing to '%ls'.",
1072 d->notificationid <<
name;
1073 if (
d->notificationid.size() == 1)
1083 qCWarning(lcSqlite,
"QSQLiteDriver::unsubscribeFromNotification: Database not open.");
1087 if (!
d->notificationid.contains(
name)) {
1088 qCWarning(lcSqlite,
"QSQLiteDriver::unsubscribeFromNotification: Not subscribed to '%ls'.",
1093 d->notificationid.removeAll(
name);
1094 if (
d->notificationid.isEmpty())
1095 sqlite3_update_hook(
d->access,
nullptr,
nullptr);
1103 return d->notificationid;
1106void QSQLiteDriver::handleNotification(
const QString &tableName,
qint64 rowid)
1109 if (
d->notificationid.contains(tableName))
1115#include "moc_qsql_sqlite_p.cpp"
char * data()
\macro QT_NO_CAST_FROM_BYTEARRAY
qsizetype size() const noexcept
Returns the number of bytes in this byte array.
const char * constData() const noexcept
Returns a pointer to the const data stored in the byte array.
static QString translate(const char *context, const char *key, const char *disambiguation=nullptr, int n=-1)
\threadsafe
\inmodule QtCore\reentrant
bool removeOne(const AT &t)
void append(parameter_type t)
\inmodule QtCore \reentrant
QList< QSQLiteResult * > results
QSqlIndex getTableInfo(QSqlQuery &query, const QString &tableName, bool onlyPIndex=false) const
QStringList notificationid
bool isIdentifierEscaped(QStringView identifier) const
QSQLiteDriver(QObject *parent=nullptr)
QStringList subscribedToNotifications() const override
Returns a list of the names of the event notifications that are currently subscribed to.
QStringList tables(QSql::TableType) const override
Returns a list of the names of the tables in the database.
void close() override
Derived classes must reimplement this pure virtual function in order to close the database connection...
bool commitTransaction() override
This function is called to commit a transaction.
bool beginTransaction() override
This function is called to begin a transaction.
QVariant handle() const override
Returns the low-level database handle wrapped in a QVariant or an invalid variant if there is no hand...
QString escapeIdentifier(const QString &identifier, IdentifierType type) const override
Returns the identifier escaped according to the database rules.
QSqlResult * createResult() const override
Creates an empty SQL result on the database.
QSqlIndex primaryIndex(const QString &tablename) const override
Returns the primary index for table tableName.
bool unsubscribeFromNotification(const QString &name) override
This function is called to unsubscribe from event notifications from the database.
bool subscribeToNotification(const QString &name) override
This function is called to subscribe to event notifications from the database.
QString stripDelimiters(const QString &identifier, IdentifierType type) const override
Returns the identifier with the leading and trailing delimiters removed, identifier can either be a t...
bool rollbackTransaction() override
This function is called to rollback a transaction.
bool open(const QString &db, const QString &user, const QString &password, const QString &host, int port, const QString &connOpts) override
Derived classes must reimplement this pure virtual function to open a database connection on database...
bool hasFeature(DriverFeature f) const override
Returns true if the driver supports feature feature; otherwise returns false.
QSqlRecord record(const QString &tablename) const override
Returns a QSqlRecord populated with the names of the fields in table tableName.
bool isIdentifierEscaped(const QString &identifier, IdentifierType type) const override
Returns whether identifier is escaped according to the database rules.
QList< QVariant > firstRow
bool fetchNext(QSqlCachedResult::ValueCache &values, int idx, bool initialFetch)
void initColumns(bool emptyResultset)
int size() override
Returns the size of the SELECT result, or -1 if it cannot be determined or if the query is not a SELE...
bool execBatch(bool arrayBind) override
bool reset(const QString &query) override
Sets the result to use the SQL statement query for subsequent data retrieval.
QSqlRecord record() const override
Returns the current record if the query is active; otherwise returns an empty QSqlRecord.
void virtual_hook(int id, void *data) override
QSQLiteResult(const QSQLiteDriver *db)
bool exec() override
Executes the query, returning true if successful; otherwise returns false.
bool prepare(const QString &query) override
Prepares the given query for execution; the query will normally use placeholders so that it can be ex...
QVariant lastInsertId() const override
Returns the object ID of the most recent inserted row if the database supports it.
QVariant handle() const override
Returns the low-level database handle for this result set wrapped in a QVariant or an invalid QVarian...
bool gotoNext(QSqlCachedResult::ValueCache &row, int idx) override
void detachFromResultSet() override
int numRowsAffected() override
Returns the number of rows affected by the last query executed, or -1 if it cannot be determined or i...
const_iterator constBegin() const noexcept
const_iterator constEnd() const noexcept
void virtual_hook(int id, void *data) override
The QSqlDriver class is an abstract base class for accessing specific SQL databases.
IdentifierType
This enum contains a list of SQL identifier types.
DriverFeature
This enum contains a list of features a driver might support.
bool isOpenError() const
Returns true if the there was an error opening the database connection; otherwise returns false.
virtual void setLastError(const QSqlError &e)
This function is used to set the value of the last error, error, that occurred on the database.
void notification(const QString &name, QSqlDriver::NotificationSource source, const QVariant &payload)
virtual bool isOpen() const
Returns true if the database connection is open; otherwise returns false.
virtual void setOpenError(bool e)
This function sets the open error state of the database to error.
virtual void setOpen(bool o)
This function sets the open state of the database to open.
The QSqlError class provides SQL database error information.
ErrorType
This enum type describes the context in which the error occurred, e.g., a connection error,...
The QSqlField class manipulates the fields in SQL database tables and views.
The QSqlIndex class provides functions to manipulate and describe database indexes.
void append(const QSqlField &field)
Appends the field field to the list of indexed fields.
The QSqlQuery class provides a means of executing and manipulating SQL statements.
The QSqlRecord class encapsulates a database record.
QVariant value(int i) const
Returns the value of the field located at position index in the record.
static bool isVariantNull(const QVariant &variant)
The QSqlResult class provides an abstract interface for accessing data from specific SQL databases.
bool isSelect() const
Returns true if the current result is from a SELECT statement; otherwise returns false.
virtual void setSelect(bool s)
This function is provided for derived classes to indicate whether or not the current statement is a S...
virtual void setActive(bool a)
This function is provided for derived classes to set the internal active state to active.
QVariantList & boundValues(QT6_DECL_NEW_OVERLOAD)
QSqlError lastError() const
Returns the last error associated with the result.
virtual void setLastError(const QSqlError &e)
This function is provided for derived classes to set the last error to error.
const QSqlDriver * driver() const
Returns the driver associated with the result.
bool isValid() const
Returns true if the result is positioned on a valid record (that is, the result is not positioned bef...
virtual void bindValue(int pos, const QVariant &val, QSql::ParamType type)
Binds the value val of parameter type paramType to position index in the current record (row).
bool isActive() const
Returns true if the result has records to be retrieved; otherwise returns false.
bool startsWith(QStringView s, Qt::CaseSensitivity cs=Qt::CaseSensitive) const noexcept
constexpr qsizetype size() const noexcept
Returns the size of this string view, in UTF-16 code units (that is, surrogate pairs count as two for...
constexpr QStringView first(qsizetype n) const noexcept
bool endsWith(QStringView s, Qt::CaseSensitivity cs=Qt::CaseSensitive) const noexcept
Q_CORE_EXPORT QList< QStringView > split(QStringView sep, Qt::SplitBehavior behavior=Qt::KeepEmptyParts, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Splits the view into substring views wherever sep occurs, and returns the list of those string views.
constexpr QStringView sliced(qsizetype pos) const noexcept
\macro QT_RESTRICTED_CAST_FROM_ASCII
qsizetype indexOf(QLatin1StringView s, qsizetype from=0, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
qsizetype lastIndexOf(QChar c, Qt::CaseSensitivity cs=Qt::CaseSensitive) const noexcept
QString sliced(qsizetype pos) const &
QString chopped(qsizetype n) const &
QString mid(qsizetype position, qsizetype n=-1) const &
bool isEmpty() const noexcept
Returns true if the string has no characters; otherwise returns false.
void clear()
Clears the contents of the string and makes it null.
qsizetype size() const noexcept
Returns the number of characters in this string.
static QString fromUtf8(QByteArrayView utf8)
This is an overloaded member function, provided for convenience. It differs from the above function o...
QString arg(qlonglong a, int fieldwidth=0, int base=10, QChar fillChar=u' ') const
QString first(qsizetype n) const &
QChar * data()
Returns a pointer to the data stored in the QString.
bool contains(QChar c, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
static QString number(int, int base=10)
This is an overloaded member function, provided for convenience. It differs from the above function o...
QString & remove(qsizetype i, qsizetype len)
Removes n characters from the string, starting at the given position index, and returns a reference t...
QByteArray toUtf8() const &
const QChar * unicode() const
Returns a Unicode representation of the string.
\inmodule QtCore \reentrant
int toInt(bool *ok=nullptr) const
Returns the variant as an int if the variant has userType() \l QMetaType::Int, \l QMetaType::Bool,...
static auto fromValue(T &&value) noexcept(std::is_nothrow_copy_constructible_v< T > &&Private::CanUseInternalSpace< T >) -> std::enable_if_t< std::conjunction_v< std::is_copy_constructible< T >, std::is_destructible< T > >, QVariant >
QCache< int, Employee > cache
[0]
QSet< QString >::iterator it
Combined button and popup list for selecting options.
DBusConnection * connection
typedef QByteArray(EGLAPIENTRYP PFNQGSGETDISPLAYSPROC)()
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
#define Q_LOGGING_CATEGORY(name,...)
#define qCWarning(category,...)
#define Q_ARG(Type, data)
GLenum GLsizei GLsizei GLint * values
[15]
GLuint64 GLenum void * handle
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLdouble GLdouble GLdouble GLdouble q
GLenum GLenum GLsizei void * row
GLenum GLenum GLsizei void * table
static quint64 cacheSize()
static QSqlError qMakeError(const QString &err, QSqlError::ErrorType type, const QDB2DriverPrivate *p)
static QList< QVariant > toList(char **buf, int count)
static void _q_lower(sqlite3_context *context, int argc, sqlite3_value **argv)
static void _q_upper(sqlite3_context *context, int argc, sqlite3_value **argv)
static QSqlError qMakeError(sqlite3 *access, const QString &descr, QSqlError::ErrorType type, int errorCode)
static QT_BEGIN_NAMESPACE static Q_LOGGING_CATEGORY(lcSqlite, "qt.sql.sqlite") using namespace Qt int qGetColumnType(const QString &tpName)
static void handle_sqlite_callback(void *qobj, int aoperation, char const *adbname, char const *atablename, sqlite3_int64 arowid)
#define Q_DECLARE_SQLDRIVER_PRIVATE(Class)
#define qUtf16Printable(string)