#include "database.h" #include "subcommands.h" static inline void is_file(sqlite3_context* context, int argc, sqlite3_value** argv); void subcommand_prune(const Parser& parser) { if (parser.arguments.size() != 1) { fprintf(stderr, HELP_TEXT, parser.program_name); exit(1); } Database db = Database::find(false); // https://stackoverflow.com/a/4929486 int error_code = sqlite3_create_function(db.db.get(), "is_file", 1, SQLITE_UTF8 | SQLITE_DETERMINISTIC | SQLITE_DIRECTONLY, &db.path, is_file, nullptr, nullptr); if (error_code != SQLITE_OK) { throw Sqlite3Exception(error_code, &db.db); } Sqlite3Statement delete_stmt(db.db, "DELETE FROM memes WHERE NOT is_file(path)"); db.db.exec(delete_stmt); sqlite3_create_function(db.db.get(), "is_file", 1, SQLITE_UTF8 | SQLITE_DETERMINISTIC | SQLITE_DIRECTONLY, &db.path, nullptr, nullptr, nullptr); Sqlite3Statement vacuum_stmt(db.db, "VACUUM"); db.db.exec(vacuum_stmt); } static inline void is_file(sqlite3_context* context, int argc, sqlite3_value** argv) { if (argc != 1) { sqlite3_result_error(context, "is_file() expects one argument", -1); sqlite3_result_error_code(context, SQLITE_MISUSE); return; } const std::filesystem::path* db_path = static_cast(sqlite3_user_data(context)); std::filesystem::path file_path = db_path->parent_path() / reinterpret_cast(sqlite3_value_text(argv[0])); sqlite3_result_int(context, std::filesystem::is_regular_file(file_path)); }