/* * Strawberry Music Player * This file was part of Clementine. * Copyright 2010, David Sansome * * Strawberry is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Strawberry is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Strawberry. If not, see . * */ #ifndef DATABASE_H #define DATABASE_H #include "config.h" #include #include #include #include #include #include #include #include #include #include #include #include extern "C" { struct sqlite3_tokenizer; struct sqlite3_tokenizer_cursor; struct sqlite3_tokenizer_module; } class Application; class Database : public QObject { Q_OBJECT public: Database(Application *app, QObject *parent = nullptr, const QString &database_name = QString()); struct AttachedDatabase { AttachedDatabase() {} AttachedDatabase(const QString &filename, const QString &schema, bool is_temporary) : filename_(filename), schema_(schema), is_temporary_(is_temporary) {} QString filename_; QString schema_; bool is_temporary_; }; static const int kSchemaVersion; static const char *kDatabaseFilename; static const char *kMagicAllSongsTables; QSqlDatabase Connect(); bool CheckErrors(const QSqlQuery &query); QMutex *Mutex() { return &mutex_; } void RecreateAttachedDb(const QString &database_name); void ExecSchemaCommands(QSqlDatabase &db, const QString &schema, int schema_version, bool in_transaction = false); int startup_schema_version() const { return startup_schema_version_; } int current_schema_version() const { return kSchemaVersion; } void AttachDatabase(const QString &database_name, const AttachedDatabase &database); void AttachDatabaseOnDbConnection(const QString &database_name, const AttachedDatabase &database, QSqlDatabase &db); void DetachDatabase(const QString &database_name); signals: void Error(const QString &message); public slots: void DoBackup(); private: void UpdateMainSchema(QSqlDatabase *db); void ExecSchemaCommandsFromFile(QSqlDatabase &db, const QString &filename, int schema_version, bool in_transaction = false); void ExecSongTablesCommands(QSqlDatabase &db, const QStringList &song_tables, const QStringList &commands); void UpdateDatabaseSchema(int version, QSqlDatabase &db); void UrlEncodeFilenameColumn(const QString &table, QSqlDatabase &db); QStringList SongsTables(QSqlDatabase &db, int schema_version) const; bool IntegrityCheck(QSqlDatabase db); void BackupFile(const QString &filename); bool OpenDatabase(const QString &filename, sqlite3 **connection) const; Application *app_; // Alias -> filename QMap attached_databases_; QString directory_; QMutex connect_mutex_; QMutex mutex_; // This ID makes the QSqlDatabase name unique to the object as well as the thread int connection_id_; static QMutex sNextConnectionIdMutex; static int sNextConnectionId; // Used by tests QString injected_database_name_; uint query_hash_; QStringList query_cache_; // This is the schema version of Strawberry's DB from the app's last run. int startup_schema_version_; // Do static initialisation like loading sqlite functions. static void StaticInit(); typedef int (*Sqlite3CreateFunc)(sqlite3*, const char*, int, int, void*, void (*)(sqlite3_context*, int, sqlite3_value**), void (*)(sqlite3_context*, int, sqlite3_value**), void (*)(sqlite3_context*)); static sqlite3_tokenizer_module *sFTSTokenizer; static int FTSCreate(int argc, const char *const *argv, sqlite3_tokenizer **tokenizer); static int FTSDestroy(sqlite3_tokenizer *tokenizer); static int FTSOpen(sqlite3_tokenizer *tokenizer, const char *input, int bytes, sqlite3_tokenizer_cursor **cursor); static int FTSClose(sqlite3_tokenizer_cursor *cursor); static int FTSNext(sqlite3_tokenizer_cursor *cursor, const char **token, int *bytes, int *start_offset, int *end_offset, int *position); struct Token { Token(const QString &token, int start, int end); QString token; int start_offset; int end_offset; }; // Based on sqlite3_tokenizer. struct UnicodeTokenizer { const sqlite3_tokenizer_module *pModule; }; struct UnicodeTokenizerCursor { const sqlite3_tokenizer *pTokenizer; QList tokens; int position; QByteArray current_utf8; }; }; class MemoryDatabase : public Database { public: MemoryDatabase(Application *app, QObject *parent = nullptr) : Database(app, parent, ":memory:") {} ~MemoryDatabase() { // Make sure Qt doesn't reuse the same database QSqlDatabase::removeDatabase(Connect().connectionName()); } }; #endif // DATABASE_H