#include "SQLiteUtils.h" #if USE_SQLITE #include #include namespace fs = std::filesystem; namespace DB { namespace ErrorCodes { extern const int PATH_ACCESS_DENIED; } void processSQLiteError(const String & message, bool throw_on_error) { if (throw_on_error) throw Exception(ErrorCodes::PATH_ACCESS_DENIED, message); else LOG_ERROR(&Poco::Logger::get("SQLiteEngine"), message); } String validateSQLiteDatabasePath(const String & path, const String & user_files_path, bool throw_on_error) { String canonical_user_files_path = fs::canonical(user_files_path); String canonical_path; std::error_code err; if (fs::path(path).is_relative()) canonical_path = fs::canonical(fs::path(user_files_path) / path, err); else canonical_path = fs::canonical(path, err); if (err) processSQLiteError(fmt::format("SQLite database path '{}' is invalid. Error: {}", path, err.message()), throw_on_error); if (!canonical_path.starts_with(canonical_user_files_path)) processSQLiteError(fmt::format("SQLite database file path '{}' must be inside 'user_files' directory", path), throw_on_error); return canonical_path; } SQLitePtr openSQLiteDB(const String & database_path, ContextPtr context, bool throw_on_error) { auto validated_path = validateSQLiteDatabasePath(database_path, context->getUserFilesPath(), throw_on_error); sqlite3 * tmp_sqlite_db = nullptr; int status = sqlite3_open(validated_path.c_str(), &tmp_sqlite_db); if (status != SQLITE_OK) { processSQLiteError(fmt::format("Cannot access sqlite database. Error status: {}. Message: {}", status, sqlite3_errstr(status)), throw_on_error); return nullptr; } return std::shared_ptr(tmp_sqlite_db, sqlite3_close); } } #endif