fix: escape all LIKE specials in step-row cleanup
This commit is contained in:
+20
-3
@@ -602,6 +602,21 @@ def _write_skip_report(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def _escape_sql_like(text: str) -> str:
|
||||||
|
"""转义 SQL LIKE 模式中的全部特殊字符(`\\`、`%`、`_`)为字面匹配。
|
||||||
|
|
||||||
|
参数:
|
||||||
|
text: 待作为 LIKE 前缀字面使用的原始字符串。
|
||||||
|
|
||||||
|
返回:
|
||||||
|
可安全拼入 `LIKE ? ESCAPE '\\'` 模式的转义串。
|
||||||
|
|
||||||
|
关键实现细节:
|
||||||
|
反斜杠必须最先转义,否则会二次转义后续替换产生的转义符。
|
||||||
|
"""
|
||||||
|
return text.replace("\\", "\\\\").replace("%", r"\%").replace("_", r"\_")
|
||||||
|
|
||||||
|
|
||||||
def _clear_step_rows(db_path: str, *, baseline_run_id: str, epoch: int, step: int) -> None:
|
def _clear_step_rows(db_path: str, *, baseline_run_id: str, epoch: int, step: int) -> None:
|
||||||
"""清空一个 step 的全部旧行(rollout + gate 派生),保证崩溃重跑幂等。
|
"""清空一个 step 的全部旧行(rollout + gate 派生),保证崩溃重跑幂等。
|
||||||
|
|
||||||
@@ -621,13 +636,15 @@ def _clear_step_rows(db_path: str, *, baseline_run_id: str, epoch: int, step: in
|
|||||||
无。
|
无。
|
||||||
|
|
||||||
关键实现细节:
|
关键实现细节:
|
||||||
predictions/traces 的 gate 行按 LIKE 前缀删除,'_' 通配显式转义
|
predictions/traces 的 gate 行按 LIKE 前缀删除,`\\`/`%`/`_` 三个 LIKE
|
||||||
(ESCAPE)钉死字面匹配,避免 `..._s1` 误匹配 `..._s10` 类前缀陷阱。
|
特殊字符全部显式转义(ESCAPE)钉死字面匹配,避免 `..._s1` 误匹配
|
||||||
|
`..._s10` 类前缀陷阱,也防 run_id 含 `%`/`\\` 时通配误删他 run 行。
|
||||||
"""
|
"""
|
||||||
from app.harness.inference import PREDICTIONS_SCHEMA, TRACES_SCHEMA
|
from app.harness.inference import PREDICTIONS_SCHEMA, TRACES_SCHEMA
|
||||||
from app.harness.log import HarnessLog
|
from app.harness.log import HarnessLog
|
||||||
|
|
||||||
step_run_id = f"{baseline_run_id}_e{epoch}_s{step}"
|
step_run_id = f"{baseline_run_id}_e{epoch}_s{step}"
|
||||||
|
escaped = _escape_sql_like(step_run_id)
|
||||||
with HarnessLog(db_path, step_run_id, register_run=False) as log:
|
with HarnessLog(db_path, step_run_id, register_run=False) as log:
|
||||||
log.create_table("predictions", PREDICTIONS_SCHEMA)
|
log.create_table("predictions", PREDICTIONS_SCHEMA)
|
||||||
log.create_table("traces", TRACES_SCHEMA)
|
log.create_table("traces", TRACES_SCHEMA)
|
||||||
@@ -635,7 +652,7 @@ def _clear_step_rows(db_path: str, *, baseline_run_id: str, epoch: int, step: in
|
|||||||
log.execute(f"DELETE FROM {table} WHERE run_id=?", (step_run_id,))
|
log.execute(f"DELETE FROM {table} WHERE run_id=?", (step_run_id,))
|
||||||
log.execute(
|
log.execute(
|
||||||
f"DELETE FROM {table} WHERE run_id LIKE ? ESCAPE '\\'",
|
f"DELETE FROM {table} WHERE run_id LIKE ? ESCAPE '\\'",
|
||||||
(step_run_id.replace("_", r"\_") + r"\_gate\_%",),
|
(escaped + r"\_gate\_%",),
|
||||||
)
|
)
|
||||||
for table in ("gate_evidence", "quadrant_pair"):
|
for table in ("gate_evidence", "quadrant_pair"):
|
||||||
exists = log.query(
|
exists = log.query(
|
||||||
|
|||||||
@@ -67,3 +67,26 @@ def test_clear_step_rows_missing_tables_is_noop(tmp_path) -> None:
|
|||||||
conn.commit()
|
conn.commit()
|
||||||
conn.close()
|
conn.close()
|
||||||
_clear_step_rows(str(db), baseline_run_id="infer_adhoc", epoch=1, step=0)
|
_clear_step_rows(str(db), baseline_run_id="infer_adhoc", epoch=1, step=0)
|
||||||
|
|
||||||
|
|
||||||
|
def test_clear_step_rows_like_specials_in_run_id(tmp_path) -> None:
|
||||||
|
"""run_id 含 % 与反斜杠时不通配误删他 run 行(LIKE 全特殊字符转义回归锁)。"""
|
||||||
|
db = tmp_path / "harness.db"
|
||||||
|
conn = sqlite3.connect(db)
|
||||||
|
conn.execute("CREATE TABLE predictions (run_id TEXT, question_id TEXT)")
|
||||||
|
conn.execute("CREATE TABLE traces (run_id TEXT, question_id TEXT)")
|
||||||
|
rows = [
|
||||||
|
(r"we%ird\run_e1_s0", "q1"), # 本 step rollout
|
||||||
|
(r"we%ird\run_e1_s0_gate_x_base", "q2"), # 本 step gate 行
|
||||||
|
(r"weXird\run_e1_s0_gate_x_base", "q3"), # % 若未转义会误匹配此行
|
||||||
|
(r"we%irdXrun_e1_s0_gate_x_base", "q4"), # \ 若未转义会误匹配此行
|
||||||
|
]
|
||||||
|
conn.executemany("INSERT INTO predictions VALUES (?, ?)", rows)
|
||||||
|
conn.executemany("INSERT INTO traces VALUES (?, ?)", rows)
|
||||||
|
conn.commit()
|
||||||
|
conn.close()
|
||||||
|
_clear_step_rows(str(db), baseline_run_id=r"we%ird\run", epoch=1, step=0)
|
||||||
|
conn = sqlite3.connect(db)
|
||||||
|
left = {r[0] for r in conn.execute("SELECT run_id FROM predictions")}
|
||||||
|
conn.close()
|
||||||
|
assert left == {r"weXird\run_e1_s0_gate_x_base", r"we%irdXrun_e1_s0_gate_x_base"}
|
||||||
|
|||||||
Reference in New Issue
Block a user