如何修复损坏的 Firefox places.sqlite 数据库?

如何修复损坏的 Firefox places.sqlite 数据库?

我的 RAM 出现了一些问题(Windows XP 多次出现蓝屏),现在我的 Firefox 数据库也损坏了。Firefox 可以运行,但我的历史记录不见了,并且在执行pragma integrity_check以下操作时报告了几个不一致和错误places.sqlite

数据库磁盘映像格式不正确

现在的问题是,我该如何修复 SQLite 数据库?

答案1

笔记

由于必须关闭 Firefox 才能执行此过程,因此请确保在另一个 Web 浏览器中打开此页面或将其打印出来再继续。


经过几个小时的努力尝试恢复 Places 数据库,甚至阅读了 Firefox 源代码,我终于成功了。以下是我的方法:

  • 下载最新版本的 SQLite shell并将其解压到您的配置文件文件夹中。在 Windows Vista 和 Windows 7 中,它位于C:\Users\<username>\AppData\Roaming\Mozilla\Firefox\Profiles\<code>.default文件夹中。
  • 如果 Firefox 正在运行,请关闭它。
  • Places 数据库位于places.sqlite文件中。如果文件因损坏而被替换,请使用该places.sqlite.corrupt文件进行恢复。创建该文件的备份副本,命名为places.sqlite.bakplaces.sqlite.corrupt.bak
  • 使用 SQLite shell 打开数据库文件(sqlite3 places.sqlitesqlite3 places.sqlite.corrupt),然后输入:
.output dump.sql    -- sends output to file dump.sql
.dump               -- dumps database to file
  • 由于数据库已损坏,因此生成的数据库转储不完整,并且并非所有可恢复数据都已检索。要确定错误发生的位置,请ERROR在转储文件中的 SQL 注释中搜索单词(全部大写)dump.sql(我使用了记事本++执行此操作),然后阅读INSERT上面的 SQL 命令以确定有问题的表。 在我的例子中,损坏的表是moz_places。 (可以在 Places 数据库中找到有关表的描述这里,其中包括一个过时的 ER 图。)我将仅解释如何从该表中恢复其他数据;以下步骤可能不适用于其他表,因此如果涉及其他表,请跳过这些子步骤moz_places。)

    • 表中的每一行moz_places都有一个 ID。行将按照此 ID 的顺序从表中转储出来。1 ID是语句中左括号后面的第一个值INSERT。数据库损坏的区域可能是此表中的一小块行;这里的想法是跳过这个损坏的区域并恢复尽可能多的数据。此类块的起始区域在转储中表示为注释ERROR出现之前的行。使用此行的 ID,我们可以确定数据库损坏的位置。我们通过使用SELECT以 ID 为条件的语句来实现这一点;此过程需要反复试验。例如,如果错误之前的最后一个 ID 是 49999,并且错误紧随其后,则损坏的块从 ID 50000 开始。使用如下语句:

    -- 抑制不必要的输出
    -- 以下命令适用于 Windows 系统
    – 对于 Linux 和其他 Unix 及类 Unix 系统,使用 .output /dev/null
    .输出 NUL
    
    从 moz_places 中选择 id,其中 id >= 50100;
    
    • 调整后面的值id >=并重复上述SELECT命令,直到找到不会导致 SQLite 输出错误的最小值。这是指向我们可以从中恢复其他数据的行的 ID。我们假设这个 ID 是 50200。要转储​​此数据,请输入:

    .输出转储2.sql
    .模式插入
    从 moz_places 中选择 *,其中 id >= 50200;
    
    -- 恢复正常输出行为
    .输出标准输出
    .mode 列表
    
    • 请注意,文件INSERT中的语句dump2.sql以 开头INSERT INTO table VALUES,因此请使用文本编辑器中的查找和替换功能将此字符串的所有实例替换为INSERT INTO moz_places VALUES
    • 将文件的全部内容复制dump2.sql并粘贴到出现注释dump.sql的文件中ERROR
  • ROLLBACK; -- due to errors将文件末尾的替换为COMMIT;
  • 将以下代码添加到文件顶部dump.sql。替换<version>为正确的值,这是 Firefox 根据 Firefox 版本确定数据库架构版本所必需的,如下所示(这可以在 Firefox 源文件中找到toolkit/components/places/Database.cpp):
    • Firefox 52:架构版本 35
    • Firefox 53:架构版本 36
    • Firefox 57:架构版本 39
    • Firefox 58:架构版本 41
    • Firefox 60:架构版本 43
    • Firefox 61:架构版本 47
    • Firefox 62:架构版本 52
    • Firefox 69:架构版本 53

PRAGMA user_version=<版本>;
PRAGMA journal_mode = 截断;
PRAGMA 页面大小 = 32768;
真空;
PRAGMA 日志模式 = wal;
  • 退出 SQLite shell,删除places.sqlite,然后启动 SQLite shellplaces.sqlite使用 创建一个空数据库sqlite3 places.sqlite。键入.read dump.sql将 SQL 转储加载到数据库中。
  • 启动 Firefox 并确认历史记录和位置栏正常运行。确认一切正常后,从配置文件文件夹中删除数据库转储文件和 SQLite shell 可执行文件。

您可以在以下页面找到更多相关信息:

简化程序描述于这篇 MDN 文章但我还没有测试过。不过,我已经将PRAGMA那篇文章中的更新命令整合起来了。


1 SQL 通常不保证数据库输出按任何顺序给出,除非您使用该ORDER BY子句。但是,ORDER BY在损坏的数据库上可能无法生成任何输出(因为 SQLite 需要读取整个表才能生成任何输出)。据我所知,Firefox 总是moz_places使用连续 ID 写入表条目,因此我们可以假设所有输出都按 ID 排序。

答案2

MDN 上描述的流程帮助我解决了浏览器历史记录中未记录我访问的新页面的问题。我没有places.sqlite.corrupt(或)文件,但检查文件places.sqlite-corrupt完整性时发现了places.sqlite数据库磁盘映像格式不正确错误。

在继续下一步之前,请退出 Firefox 并备份您的 Firefox 配置文件。

$ cd /Users/<username>/Library/Application\ Support/Firefox/Profiles/<profile_dir>/
$ cp places.sqlite places.sqlite.bak  # for safety

$ sqlite3 places.sqlite
sqlite> PRAGMA integrity_check;
*** in database main ***
On tree page 2 cell 131: Rowid 20884 out of order
...
Error: database disk image is malformed
sqlite> .clone places-clone.sqlite
moz_places... done
moz_historyvisits... done
... more output like above plus a few errors (which I ignored) like
sqlite_sequence... Error: object name reserved for internal use: sqlite_sequence
SQL: [CREATE TABLE sqlite_sequence(name,seq)]
done
...
sqlite> PRAGMA user_version;
43  <----- TAKE NOTE OF THIS VALUE it may be different for you
sqlite> .exit

$ sqlite3 places-clone.sqlite
sqlite> PRAGMA integrity_check;
ok
sqlite> PRAGMA user_version = 43;  -- use the number you got from PRAGMA user_version; above
sqlite> PRAGMA journal_mode = truncate;
truncate
sqlite> PRAGMA page_size = 32768;
sqlite> VACUUM;
sqlite> PRAGMA journal_mode = wal;
wal
sqlite> .exit

$ mv places-clone.sqlite places.sqlite

启动 Firefox。历史记录应该可以再次工作。

我在 Mac 上使用 Firefox 60.0.1。您可能需要调整适合您平台的命令。

答案3

嗯,这取决于损坏程度,可能无法修复。最好的办法可能是尝试使用转储数据库sqlite,然后看看可以挽救什么。

如果失败,您可能必须从备份中恢复。

要转储并重新创建数据库,请使用以下命令.dump

sqlite places.sqlite .dump | sqlite places-new.sqlite

答案4

从非常旧的 Firefox 版本升级时,还可能出现“数据库损坏”问题的另一个原因。其他答案中的任何数据库维护建议在这种情况下都无济于事。

我最近屈服了,决定将我长期使用的 56 版 Firefox 升级到 90 版(最后一个可以禁用 Proton 的版本)。当我使用 90 版打开现有的配置文件时,它总是将我现有的 SQLite 数据库重命名为.corrupt。我在寻找解释时发现了这个问题,并在Database.cpp

// Firefox 60 uses schema version 43.
if (currentSchemaVersion < 43) {
    // These are versions older than Firefox 60 ESR that are not supported
    // anymore.  In this case it's safer to just replace the database.
    return NS_ERROR_FILE_CORRUPTED;
}

这意味着任何早于 Firefox 60 的配置文件都将绝不可在较新版本的 Firefox 中使用,并且总是被标记为损坏。

处理此问题并在升级到当前版本的 Firefox 时保留现有配置文件的最简单方法是使用较早的版本作为垫脚石。它将升级您的数据库到较新的版本,当前 Firefox 支持。

为此,我采用了以下步骤:

  1. 获取安装当前版本之前 Firefox 配置文件的备份。如果没有,您可以尝试复制现有配置文件,并将数据库.corrupt重命名为正常名称。

  2. 下载并解压支持您配置文件版本的旧版 Firefox。我使用了上一版本 ESR,版本 68.0.9。这是 64 位版本,但其他平台和语言也可用。exe可以使用 7zip 提取安装文件。

  3. 解压后的文件夹中会有一个core包含 Firefox 应用程序文件的文件夹。将您的配置文件副本(名为 的文件夹abcd1234.default)放入此文件夹中。

  4. 要禁用 Firefox 更新以避免出现问题,请创建一个名为distributioninside 的文件夹core,然后创建一个名为 inside 的文本文件policies.json。将以下内容放入 JSON 文件中并保存:

    { "policies": { "DisableAppUpdate": true } }

  5. 打开命令提示符core并运行:firefox.exe -no-remote -profile YOUR_PROFILE_NAME。这将使用您的配置文件运行独立版本的 Firefox,并升级数据库。

  6. 打开浏览器后,验证您的配置文件是否正确。浏览器历史记录和书签中显示的图标是两个很好的指标。关闭 Firefox 并检查配置文件文件夹,确保没有任何数据库被重命名.corrupt。(您可以根据需要多次重新运行该命令以验证和测试内容。)

  7. 将您刚刚更新的配置文件文件夹复制回您的常规 Firefox 配置文件文件夹(在 Windows 上%AppData%\Mozilla\Firefox\Profiles)。我建议重命名该位置的现有文件夹以保留备份。

  8. 再次安装当前版本的 Firefox。这次它应该能够升级您的配置文件,因为数据库已升级到受支持的版本。

另外,这种方法也是测试新 Firefox 版本的好方法。过去几年,我偶尔会用这种方法来查看我使用的插件是否有可用的 WebExtension 版本,以及查看从版本 56 更新到最新版本有多难。非常小心永远不要firefox.exe在未使用的情况下运行-no-remote,否则它会找到您现有的正常配置文件并进行更新(始终事先进行备份!)

相关内容