/* ** Register a tokenizer implementation with FTS3 or FTS4. */ static int registerTokenizer( sqlite3 *db, char *zName, const sqlite3_tokenizer_module *p ) { int rc; sqlite3_stmt *pStmt; const char *zSql = "SELECT fts3_tokenizer(?, ?)"; #ifdef HAVE_FTS3_TOKENIZER /* Enable the 2-argument form of fts3_tokenizer in SQLite >= 3.12 */ rc = sqlite3_db_config(db,SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER,1,0); if( rc!=SQLITE_OK ) { return rc; } #endif rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0); if( rc!=SQLITE_OK ) { return rc; } sqlite3_bind_text(pStmt, 1, zName, -1, SQLITE_STATIC); sqlite3_bind_blob(pStmt, 2, &p, sizeof(p), SQLITE_STATIC); sqlite3_step(pStmt); return sqlite3_finalize(pStmt); }
// Load an extension into the sqlite database. Only affects the current connection. // Parameter details can be found here: http://www.sqlite.org/c3ref/load_extension.html void Database::loadExtension(const char* apExtensionName, const char *apEntryPointName) { #ifdef SQLITE_OMIT_LOAD_EXTENSION // Unused (void)apExtensionName; (void)apEntryPointName; throw std::runtime_error("sqlite extensions are disabled"); #else #ifdef SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION // Since SQLite 3.13 (2016-05-18): // Security warning: // It is recommended that the SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION method be used to enable only this interface. // The use of the sqlite3_enable_load_extension() interface should be avoided to keep the SQL load_extension() // disabled and prevent SQL injections from giving attackers access to extension loading capabilities. // (NOTE: not using nullptr: cannot pass object of non-POD type 'std::__1::nullptr_t' through variadic function) int ret = sqlite3_db_config(mpSQLite, SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION, 1, NULL); // NOTE: not using nullptr #else int ret = sqlite3_enable_load_extension(mpSQLite, 1); #endif check(ret); ret = sqlite3_load_extension(mpSQLite, apExtensionName, apEntryPointName, 0); check(ret); #endif }
void Handle::setConfig(Handle::Config config, bool enable) { int dbConfig; switch (config) { case Config::Fts3Tokenizer: dbConfig = SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER; break; } sqlite3_db_config((sqlite3 *) m_handle, dbConfig, enable, nullptr); }
bool DB::Connection::connect(const char * #if HAVE_SQL_TRACE connectionLabel #endif ) { // Create and set file permissions if the DB does not exist. int fd = open(_dbpath.c_str(), O_CREAT, S_IRUSR | S_IWUSR); if (fd == -1) { DB::logError("Could not open database: %s (errno %i)", _dbpath.c_str(), errno); return false; } ::close(fd); int rv = sqlite3_open_v2(_dbpath.c_str(), &_db, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_FULLMUTEX, NULL); if (rv != SQLITE_OK) { reportErrorDB(_db); return false; } int foreignKeyEnabled = 0; rv = sqlite3_db_config(_db,SQLITE_DBCONFIG_ENABLE_FKEY,1,&foreignKeyEnabled); if (rv != SQLITE_OK) { reportErrorDB(_db); return false; } if (foreignKeyEnabled != 1) { DB::logError("Connection::connect: foreign key support not enabled"); return false; } rv = sqlite3_busy_timeout(_db, 15000); // 15 seconds if (rv != SQLITE_OK) { reportErrorDB(_db); return false; } #if HAVE_SQL_TRACE sqlite3_trace(_db, xTrace, const_cast<char *>(connectionLabel)); #endif return true; }
bool DB::Connection::connect(const char * #if HAVE_SQL_TRACE connectionLabel #endif ) { // Circumvent the sqlite3 reliance on umask to enforce secure permissions mode_t saved_umask = umask(S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH); int rv = sqlite3_open_v2(_dbpath.c_str(), &_db, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_FULLMUTEX, NULL); // Restore umask to avoid side effects (void) umask(saved_umask); if (rv != SQLITE_OK) { reportErrorDB(_db); return false; } int foreignKeyEnabled = 0; rv = sqlite3_db_config(_db,SQLITE_DBCONFIG_ENABLE_FKEY,1,&foreignKeyEnabled); if (rv != SQLITE_OK) { reportErrorDB(_db); return false; } if (foreignKeyEnabled != 1) { DB::logError("Connection::connect: foreign key support not enabled"); return false; } rv = sqlite3_busy_timeout(_db, 15000); // 15 seconds if (rv != SQLITE_OK) { reportErrorDB(_db); return false; } #if HAVE_SQL_TRACE sqlite3_trace(_db, xTrace, const_cast<char *>(connectionLabel)); #endif return true; }
int database::enable_triggers(bool enable) { return sqlite3_db_config(db_, SQLITE_DBCONFIG_ENABLE_TRIGGER, enable ? 1 : 0, nullptr); }
int database::enable_foreign_keys(bool enable) { return sqlite3_db_config(db_, SQLITE_DBCONFIG_ENABLE_FKEY, enable ? 1 : 0, nullptr); }
/** @SYMTestCaseID SYSLIB-SQLITE3-UT-4004 @SYMTestCaseDesc Database handle SQLITE3 tests. List of called SQLITE3 functions: - sqlite3_config; - sqlite3_initialize; - sqlite3_threadsafe; - sqlite3_vfs_find; - sqlite3_open; - sqlite3_db_config; - sqlite3_libversion; - sqlite3_libversion_number; - sqlite3_set_authorizer; - sqlite3_commit_hook; - sqlite3_rollback_hook; - sqlite3_update_hook; - sqlite3_close; - sqlite3_shutdown; @SYMTestPriority High @SYMTestActions Database handle SQLITE3 tests. @SYMTestExpectedResults Test must not fail @SYMREQ REQ8782 */ static void TestSqliteApi() { void* prev = 0; const char* libverstr = 0; int libvernum = 0; int err; int threadSafe = -1; sqlite3_vfs* vfs = 0; TEST(!TheDb); TestStart("@SYMTestCaseID:SYSLIB-SQLITE3-UT-4004: Test \"sqlite3_config()\""); err = sqlite3_config(SQLITE_CONFIG_MEMSTATUS, 0); TEST2(err, SQLITE_OK); TestNext("Test \"sqlite3_initialize()\""); err = sqlite3_initialize(); TEST2(err, SQLITE_OK); TestNext("Test \"sqlite3_threadsafe()\""); threadSafe = sqlite3_threadsafe(); PrintI("SQLITE_THREADSAFE=%d\r\n", threadSafe); vfs = sqlite3_vfs_find(0); TEST(vfs != NULL); PrintS("Vfs name=\"%s\"\r\n", vfs->zName); err = sqlite3_open(TheTestDbName, &TheDb); TEST2(err, SQLITE_OK); TEST(TheDb != 0); err = sqlite3_db_config(TheDb, SQLITE_DBCONFIG_LOOKASIDE, 0, 128, 100); TEST2(err, SQLITE_OK); libverstr = sqlite3_libversion(); libvernum = sqlite3_libversion_number(); PrintSI("SQLITE version: \"%s\", Number: %d\r\n", libverstr, libvernum); err = sqlite3_set_authorizer(TheDb, &authorizer_callback, 0); TEST2(err, SQLITE_OK); prev = sqlite3_commit_hook(TheDb, &commit_hook, 0); TEST(!prev); prev = sqlite3_rollback_hook(TheDb, &rollback_hook, 0); TEST(!prev); prev = sqlite3_update_hook(TheDb, &update_hook, 0); TEST(!prev); TestNext("@SYMTestCaseID:SYSLIB-SQLITE3-UT-4001: Test \"sqlite3\" handle API"); TestExec(); TestNext("@SYMTestCaseID:SYSLIB-SQLITE3-UT-4002: Test \"sqlite3_stmt\" handle API-1"); TestStatement1(); TestNext("@SYMTestCaseID:SYSLIB-SQLITE3-UT-4003: Test \"sqlite3_stmt\" handle API-2"); TestStatement2(); TestNext("@SYMTestCaseID:PDS-SQLITE3-UT-4038: Test more sqlite3 API"); TestSqliteApi2(); TestNext("@SYMTestCaseID:PDS-SQLITE3-UT-4039: Test blob API"); TestSqliteBlobApi(); TestNext("@SYMTestCaseID:PDS-SQLITE3-UT-4040: Test mutex API"); TestSqliteMutexApi(); err = sqlite3_close(TheDb); TEST2(err, SQLITE_OK); TheDb = 0; TestNext("Test \"sqlite3_shutdown()\""); err = sqlite3_shutdown(); TEST2(err, SQLITE_OK); err = remove(TheTestDbName); TEST2(err, 0); }
QSqlDatabase Database::Connect() { QMutexLocker l(&connect_mutex_); // Create the directory if it doesn't exist if (!QFile::exists(directory_)) { QDir dir; if (!dir.mkpath(directory_)) { } } const QString connection_id = QString("%1_thread_%2").arg(connection_id_).arg( reinterpret_cast<quint64>(QThread::currentThread())); // Try to find an existing connection for this thread QSqlDatabase db = QSqlDatabase::database(connection_id); if (db.isOpen()) { return db; } db = QSqlDatabase::addDatabase("QSQLITE", connection_id); if (!injected_database_name_.isNull()) db.setDatabaseName(injected_database_name_); else db.setDatabaseName(directory_ + "/" + kDatabaseFilename); if (!db.open()) { app_->AddError("Database: " + db.lastError().text()); return db; } // Find Sqlite3 functions in the Qt plugin. StaticInit(); { #ifdef SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER // In case sqlite>=3.12 is compiled without -DSQLITE_ENABLE_FTS3_TOKENIZER (generally a good idea // due to security reasons) the fts3 support should be enabled explicitly. // see https://github.com/clementine-player/Clementine/issues/5297 // // See https://www.sqlite.org/fts3.html#custom_application_defined_tokenizers QVariant v = db.driver()->handle(); if (v.isValid() && qstrcmp(v.typeName(), "sqlite3*") == 0) { sqlite3* handle = *static_cast<sqlite3**>(v.data()); if (!handle || sqlite3_db_config(handle, SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER, 1, nullptr) != SQLITE_OK) { qLog(Fatal) << "Failed to enable FTS3 tokenizer"; } } #endif QSqlQuery set_fts_tokenizer("SELECT fts3_tokenizer(:name, :pointer)", db); set_fts_tokenizer.bindValue(":name", "unicode"); set_fts_tokenizer.bindValue( ":pointer", QByteArray(reinterpret_cast<const char*>(&sFTSTokenizer), sizeof(&sFTSTokenizer))); if (!set_fts_tokenizer.exec()) { qLog(Warning) << "Couldn't register FTS3 tokenizer"; } // Implicit invocation of ~QSqlQuery() when leaving the scope // to release any remaining database locks! } if (db.tables().count() == 0) { // Set up initial schema qLog(Info) << "Creating initial database schema"; UpdateDatabaseSchema(0, db); } // Attach external databases for (const QString& key : attached_databases_.keys()) { QString filename = attached_databases_[key].filename_; if (!injected_database_name_.isNull()) filename = injected_database_name_; // Attach the db QSqlQuery q("ATTACH DATABASE :filename AS :alias", db); q.bindValue(":filename", filename); q.bindValue(":alias", key); if (!q.exec()) { qFatal("Couldn't attach external database '%s'", key.toAscii().constData()); } } if (startup_schema_version_ == -1) { UpdateMainSchema(&db); } // We might have to initialise the schema in some attached databases now, if // they were deleted and don't match up with the main schema version. for (const QString& key : attached_databases_.keys()) { if (attached_databases_[key].is_temporary_ && attached_databases_[key].schema_.isEmpty()) continue; // Find out if there are any tables in this database QSqlQuery q(QString( "SELECT ROWID FROM %1.sqlite_master" " WHERE type='table'").arg(key), db); if (!q.exec() || !q.next()) { q.finish(); ExecSchemaCommandsFromFile(db, attached_databases_[key].schema_, 0); } } return db; }