feat: v0.7.0 参数化查询 + 事务增量 flush + 复合主键语义硬化 + EXPLAIN 真实索引信息
CI / test (22.x) (push) Successful in 17m29s
CI / test (24.x) (push) Failing after 17m32s
CI / e2e (push) Successful in 9m53s
CI / test (18.x) (push) Successful in 19m17s
CI / test (20.x) (push) Successful in 18m15s

- 参数化查询 db.query(sql, params):词法层 ? 绑定 + SQL 字面量安全编码
  ('' 转义/注入防护);参数计数不匹配 PARAM_ERROR;对象参数显式拒绝
- KVStoreEngine 事务增量 flush:行级变更追踪,commit 仅写改动行
  (1000 行表改 1 行:日志 1 条目 vs 整表 1000 条目);级联影响表漏写修复
  (txFullTables 同步加入 txDirtyTables);移除每次 commit 全量 checkpoint
  (阈值自动 checkpoint + close 统一截断)
- 复合主键显式拒绝:createSchema 校验期 SCHEMA_ERROR + ALTER ADD 主键列防护
  (此前静默取第一个主键,其余标记失效)
- EXPLAIN usingIndex 真实命中信息:pk / index:col / none

测试 1126 → 1147(72 套件);行覆盖率 89.8%;版本 0.7.0
This commit is contained in:
thzxx
2026-08-13 10:57:26 +08:00
parent f97c5a6001
commit 57415975ea
20 changed files with 1542 additions and 69 deletions
+31 -1
View File
@@ -207,6 +207,24 @@ export class QueryExecutor {
plan = compileStatement(stmt.query);
} catch { /* 非查询语句无 QueryPlan */ }
// v0.7.0: 真实索引命中信息(此前 usingIndex 恒为 'auto' 占位)。
// 引擎无关启发式:WHERE 中存在主键/索引/唯一列条件 → 对应引擎索引路径。
let usingIndex: string = plan?.table ? 'none' : 'none';
if (plan && plan.table && plan.where && Object.keys(plan.where).length > 0) {
try {
const schema = await this.engine.getTableSchema(plan.table);
if (schema) {
for (const col of Object.keys(plan.where)) {
if (col.startsWith('$')) continue;
const colDef = schema.columns[col];
if (!colDef) continue;
if (colDef.primaryKey) { usingIndex = 'pk'; break; }
if (colDef.index || colDef.unique) { usingIndex = `index:${col}`; break; }
}
}
} catch { /* schema 读取失败保持 none */ }
}
return {
type: stmt.query.type,
table: plan?.table,
@@ -215,7 +233,7 @@ export class QueryExecutor {
orderBy: plan?.orderBy || [],
limit: plan?.limit,
offset: plan?.offset,
usingIndex: plan?.table ? 'auto' : 'none',
usingIndex,
estimatedRows: rows,
actualTimeMs: elapsed,
};
@@ -713,6 +731,18 @@ export class QueryExecutor {
const schema = await this.engine.getTableSchema(stmt.name);
if (!schema) return;
// v0.7.0: ALTER ADD 主键列防护 —— 复合主键不支持(与 createSchema 校验对齐),
// 避免绕过建表校验添加第二个主键列导致语义陷阱
if (stmt.action === 'ADD' && stmt.column.primaryKey) {
const hasPk = Object.values(schema.columns).some((c) => c.primaryKey);
if (hasPk) {
throw new DatabaseError(
`Composite primary keys are not supported yet: table "${stmt.name}" already has a primary key column`,
'SCHEMA_ERROR',
);
}
}
// v0.4.1: 引擎级 alterTableAria 需重写存储行 + 持久化 schema;其余引擎走通用引用路径)
if (typeof this.engine.alterTable === 'function') {
return this.engine.alterTable(stmt.name, stmt.action, { ...astColumnToColumnDef(stmt.column), name: stmt.column.name });