Skip to content

fix: 修复点击「重试失败条目」必然报错 Please enter a LIKE clause with bindings#87

Open
reoLantern wants to merge 1 commit into
cookjohn:mainfrom
reoLantern:main
Open

fix: 修复点击「重试失败条目」必然报错 Please enter a LIKE clause with bindings#87
reoLantern wants to merge 1 commit into
cookjohn:mainfrom
reoLantern:main

Conversation

@reoLantern

Copy link
Copy Markdown

问题现象

在语义搜索设置页点击 「重试失败条目」 按钮,界面立即弹出红色错误:

索引错误: Error: Please enter a LIKE clause with bindings

该错误与库中是否真的存在失败条目无关

  • 「重试失败条目」按钮在索引空闲时常驻显示updateControlButtons 中按 status === 'idle' 控制,preferences.xhtml 里也没有默认隐藏),并非"构建失败后才出现的选项"。
  • 错误在 SQL 执行前的校验阶段就抛出(尚未读取任何数据),因此即使在全新、零失败条目的库上点击该按钮,也会复现同样的报错。

范围说明:本 PR 只修复「重试失败条目」按钮的这处 SQL 报错。它不涉及语义索引能否成功构建、增量更新、条目重复索引等其他问题。

根因

错误来自 Firefox 内置的 toolkit/modules/Sqlite.sys.mjs(Zotero 作为 Gecko 应用复用该模块)。它在语句执行前用正则校验 SQL:LIKE 之后若不是绑定占位符(@ / : / ?),直接抛错——此时尚未触碰数据库数据。

// toolkit/modules/Sqlite.sys.mjs
var likeSqlRegex = /\bLIKE\b\s(?![@:?])/i;

function isInvalidBoundLikeQuery(sql) {
  return likeSqlRegex.test(sql);
}

execute(sql, params = null, onRow = null) {
  if (isInvalidBoundLikeQuery(sql)) {
    throw new Error("Please enter a LIKE clause with bindings");
  }
  // ...
}

vectorStore.ts 中有 4 处查询使用了内联字符串字面量 LIKE 'failed:%',会被上述正则拦截。

触发链:点击按钮 → SemanticSearchService.retryFailedItems() 第一步调用 vectorStore.getFailedItemKeys() → 执行 SELECT item_key FROM index_status WHERE content_hash LIKE 'failed:%' → 在 SQL 校验阶段直接抛错 → 被 preferenceScript.ts 的 catch 捕获,以「索引错误: ...」形式显示。

为何容易被忽视:同样的写法也存在于 getSuccessfullyIndexedItems()(用于语义索引列的对勾显示),但其调用方 semanticIndexColumn.tstry/catch 将错误静默吞掉,用户看不到;只有 retryFailedItems() 的调用方未捕获,才把错误暴露到 UI。

修复

vectorStore.ts 中所有内联 LIKE 字面量改为参数绑定。绑定值中的 % 通配符语义不变,仅满足 Firefox 的校验要求,行为完全等价。

函数 修改前 修改后
getSuccessfullyIndexedItems ... NOT LIKE 'failed:%' ... NOT LIKE ? , 参数 ['failed:%']
getFailedItemKeys ... LIKE 'failed:%' ... LIKE ? , 参数 ['failed:%']
clearFailedMarkers(按 key) ... item_key = ? AND content_hash LIKE 'failed:%' , [key] ... item_key = ? AND content_hash LIKE ? , [key, 'failed:%']
clearFailedMarkers(清空全部) ... LIKE 'failed:%' ... LIKE ? , 参数 ['failed:%']

复现与验证

复现(修复前)

  1. 打开语义搜索设置页,确保索引处于空闲状态;
  2. 直接点击「重试失败条目」(无需构造失败条目);
  3. 立即弹出红色错误:索引错误: Error: Please enter a LIKE clause with bindings

验证(修复后)

  • 无失败条目时:提示「没有需要重试的失败条目」;
  • 有失败条目时:正常启动重试流程并重新索引。

….sys.mjs validation

Firefox's Sqlite.sys.mjs rejects LIKE clauses with inline string literals
(regex: /\bLIKE\b\s(?![@:?])/i), throwing "Please enter a LIKE clause with
bindings". This caused "重试失败条目" to always fail with an index error,
while the same issue in getSuccessfullyIndexedItems was silently swallowed
by a catch block in semanticIndexColumn.ts.

Replace all four occurrences of LIKE 'failed:%' with LIKE ? and pass
'failed:%' as a bound parameter.
Copilot AI review requested due to automatic review settings June 16, 2026 12:48

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

This PR parameterizes SQL LIKE/NOT LIKE clauses that match the failed:% pattern in the vector store’s index-status queries.

Changes:

  • Converted hard-coded LIKE 'failed:%' / NOT LIKE 'failed:%' SQL to parameterized queries.
  • Updated deletion queries to bind the failed:% pattern as a parameter (including the per-key delete path).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.


// IMPORTANT: Single-line query to avoid Zotero queryAsync bug with multi-line SQL
const rows = await this.db.queryAsync(`SELECT item_key FROM index_status WHERE content_hash NOT LIKE 'failed:%'`);
const rows = await this.db.queryAsync(`SELECT item_key FROM index_status WHERE content_hash NOT LIKE ?`, ['failed:%']);

// IMPORTANT: Single-line query to avoid Zotero queryAsync bug with multi-line SQL
const rows = await this.db.queryAsync(`SELECT item_key FROM index_status WHERE content_hash LIKE 'failed:%'`);
const rows = await this.db.queryAsync(`SELECT item_key FROM index_status WHERE content_hash LIKE ?`, ['failed:%']);
Comment on lines +827 to +830
await this.db.queryAsync(`DELETE FROM index_status WHERE item_key = ? AND content_hash LIKE ?`, [key, 'failed:%']);
}
} else {
await this.db.queryAsync(`DELETE FROM index_status WHERE content_hash LIKE 'failed:%'`);
await this.db.queryAsync(`DELETE FROM index_status WHERE content_hash LIKE ?`, ['failed:%']);
Comment on lines 825 to 831
if (keys && keys.length > 0) {
for (const key of keys) {
await this.db.queryAsync(`DELETE FROM index_status WHERE item_key = ? AND content_hash LIKE 'failed:%'`, [key]);
await this.db.queryAsync(`DELETE FROM index_status WHERE item_key = ? AND content_hash LIKE ?`, [key, 'failed:%']);
}
} else {
await this.db.queryAsync(`DELETE FROM index_status WHERE content_hash LIKE 'failed:%'`);
await this.db.queryAsync(`DELETE FROM index_status WHERE content_hash LIKE ?`, ['failed:%']);
}
@jingkaimori

Copy link
Copy Markdown

已测试,可修复 索引错误: Error: Please enter a LIKE clause with bindings

@reoLantern

Copy link
Copy Markdown
Author

报错截图是这个:
image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants