File indexing completed on 2024-04-28 15:58:54

0001 /* This file is part of the KDE project
0002    Copyright (C) 2003-2016 Jarosław Staniek <staniek@kde.org>
0003 
0004    This program is free software; you can redistribute it and/or
0005    modify it under the terms of the GNU Library General Public
0006    License as published by the Free Software Foundation; either
0007    version 2 of the License, or (at your option) any later version.
0008 
0009    This program is distributed in the hope that it will be useful,
0010    but WITHOUT ANY WARRANTY; without even the implied warranty of
0011    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0012    Library General Public License for more details.
0013 
0014    You should have received a copy of the GNU Library General Public License
0015    along with this program; see the file COPYING.  If not, write to
0016    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0017  * Boston, MA 02110-1301, USA.
0018 */
0019 
0020 #ifndef KDB_SQLITECONN_P_H
0021 #define KDB_SQLITECONN_P_H
0022 
0023 #include "KDbConnection_p.h"
0024 #include "SqliteConnection.h"
0025 #include "KDbSqlField.h"
0026 #include "KDbSqlRecord.h"
0027 #include "KDbSqlResult.h"
0028 #include "KDbSqlString.h"
0029 
0030 #include <sqlite3.h>
0031 
0032 /*! Internal SQLite connection data. Also used by SqliteCursor. */
0033 class SqliteConnectionInternal : public KDbConnectionInternal
0034 {
0035 public:
0036     explicit SqliteConnectionInternal(KDbConnection *connection);
0037     virtual ~SqliteConnectionInternal();
0038 
0039     //! @return true if loading extensions is enabled
0040     bool extensionsLoadingEnabled() const;
0041 
0042     //! Sets loading extensions flag to @a set
0043     void setExtensionsLoadingEnabled(bool set);
0044 
0045     static QString serverResultName(int serverResultCode);
0046 
0047     void storeResult(KDbResult *result);
0048 
0049     sqlite3 *data;
0050     bool data_owned; //!< true if data pointer should be freed on destruction
0051 
0052 private:
0053     bool m_extensionsLoadingEnabled;
0054     Q_DISABLE_COPY(SqliteConnectionInternal)
0055 };
0056 
0057 class SqliteSqlField : public KDbSqlField
0058 {
0059 public:
0060     inline SqliteSqlField(sqlite3_stmt *st, int i) : prepared_st(st), index(i)
0061     {
0062     }
0063     //! @return column name
0064     inline QString name() override {
0065         return QString::fromUtf8(sqlite3_column_name(prepared_st, index));
0066     }
0067     //! @return column type
0068     inline int type() override {
0069         return sqlite3_column_type(prepared_st, index);
0070     }
0071     //! @return length limit - no limits for SQLite
0072     inline int length() override {
0073         return std::numeric_limits<int>::max();
0074     }
0075 private:
0076     sqlite3_stmt * const prepared_st;
0077     const int index;
0078     Q_DISABLE_COPY(SqliteSqlField)
0079 };
0080 
0081 class SqliteSqlRecord : public KDbSqlRecord
0082 {
0083 public:
0084     inline SqliteSqlRecord(sqlite3_stmt *st)
0085         : prepared_st(st)
0086     {
0087         Q_ASSERT(st);
0088     }
0089     inline ~SqliteSqlRecord() override {
0090     }
0091     inline QString stringValue(int index) override {
0092         return QString::fromUtf8(
0093                         (const char*)sqlite3_column_text(prepared_st, index),
0094                         sqlite3_column_bytes(prepared_st, index));
0095     }
0096     inline KDbSqlString cstringValue(int index) override {
0097         // sqlite3_column_text() returns UTF-8 but it's OK if the data is a C string
0098         return KDbSqlString((const char*)sqlite3_column_text(prepared_st, index),
0099                             sqlite3_column_bytes(prepared_st, index));
0100     }
0101     inline QByteArray toByteArray(int index) override {
0102         return QByteArray((const char*)sqlite3_column_blob(prepared_st, index),
0103                           sqlite3_column_bytes(prepared_st, index));
0104     }
0105 
0106 private:
0107     sqlite3_stmt * const prepared_st;
0108     Q_DISABLE_COPY(SqliteSqlRecord)
0109 };
0110 
0111 //! Used by SqliteSqlResult::cacheFieldInfo(const QString&)
0112 struct SqliteSqlFieldInfo {
0113     void setConstraints(KDbField* field);
0114     QString defaultValue;
0115     bool isNotNull;
0116     bool isPrimaryKey;
0117 };
0118 
0119 class SqliteSqlResult : public KDbSqlResult
0120 {
0121 public:
0122     inline SqliteSqlResult(SqliteConnection *c, sqlite3_stmt *st)
0123         : conn(c), prepared_st(st)
0124     {
0125         Q_ASSERT(c);
0126     }
0127 
0128     inline ~SqliteSqlResult() override {
0129         // don't check result here, done elsewhere already
0130         (void)sqlite3_finalize(prepared_st);
0131     }
0132 
0133     inline KDbConnection *connection() const override {
0134         return conn;
0135     }
0136 
0137     inline int fieldsCount() override {
0138         // We're using sqlite3_column_count instead of sqlite3_data_count to know
0139         // the column count before fetching. User will know if fetching succeeded anyway.
0140         return sqlite3_column_count(prepared_st);
0141     }
0142 
0143     Q_REQUIRED_RESULT inline KDbSqlField *field(int index) override
0144     {
0145         return prepared_st ? new SqliteSqlField(prepared_st, index) : nullptr;
0146     }
0147 
0148     Q_REQUIRED_RESULT KDbField *createField(const QString &tableName, int index) override;
0149 
0150     Q_REQUIRED_RESULT inline QSharedPointer<KDbSqlRecord> fetchRecord() override
0151     {
0152         SqliteSqlRecord *record;
0153         const int res = sqlite3_step(prepared_st);
0154         if (res == SQLITE_ROW) {
0155             record = new SqliteSqlRecord(prepared_st);
0156         } else {
0157             record = nullptr;
0158         }
0159         return QSharedPointer<KDbSqlRecord>(record);
0160     }
0161 
0162     inline KDbResult lastResult() override {
0163         KDbResult res;
0164         const int err = sqlite3_errcode(conn->d->data);
0165         if (err != SQLITE_ROW && err != SQLITE_OK && err != SQLITE_DONE) {
0166             res.setCode(ERR_OTHER);
0167             res.setServerErrorCode(err);
0168             conn->d->storeResult(&res);
0169         }
0170         return res;
0171     }
0172 
0173     inline quint64 lastInsertRecordId() override {
0174         return static_cast<quint64>(sqlite3_last_insert_rowid(conn->d->data));
0175     }
0176 
0177 protected:
0178     //! @return a KDb type for a SQLite type
0179     //! The returned type is a guess, for example KDbField::Integer is returned for SQLITE_INTEGER.
0180     //! For unsupported types returns KDbField::InvalidType.
0181     //! See https://www.sqlite.org/c3ref/c_blob.html
0182     static KDbField::Type type(int sqliteType);
0183 
0184     //! Sets constraints to a @a field based on SQLite's internal schema:
0185     //! - whether the column can be NULL
0186     //! - the default value for the column
0187     //! - whether the column is primary key
0188     //! @note @a field should have its name set
0189     //! See https://www.sqlite.org/pragma.html#pragma_table_info
0190     //! @todo support keys
0191     bool setConstraints(const QString &tableName, KDbField* field);
0192 
0193     //! Caches information about the fields, for setConstraints()
0194     //! @todo Support composite primary keys
0195     //! @todo Default values are only encoded as string
0196     bool cacheFieldInfo(const QString &tableName);
0197 
0198 private:
0199     SqliteConnection * const conn;
0200     sqlite3_stmt * const prepared_st;
0201     KDbUtils::AutodeletedHash<QString, SqliteSqlFieldInfo*> cachedFieldInfos;
0202     friend class SqlitePreparedStatement;
0203     Q_DISABLE_COPY(SqliteSqlResult)
0204 };
0205 
0206 #endif