fix: v0.7.2 语句级原子性 + 事务 DDL 拒绝 + 约束/绑定硬化 — 6 项修复 + 43 回归 + CI 重型套件串行
- UPDATE 语句级部分提交(P1,四引擎):两阶段全量预检后执行,批内唯一互查, 任何一行失败整句不执行(aria 场景 WAL 与内存不再错位) - 事务内 ALTER/CREATE INDEX/DROP INDEX 残留(P1):Memory/KVStore 显式拒绝 (对齐 Aria),createTable/dropTable 保持可回滚 - SET NULL 级联绕过 required 约束(P1):预检阶段整体拒绝 FOREIGN_KEY_VIOLATION - bindParameters 注释误判(P2):行注释/块注释中的 ? 与引号不再参与绑定 - 未闭合字符串静默接受 → lexer 抛 PARSE_ERROR;未知 where 操作符抛 QUERY_ERROR - UPDATE undefined 覆盖列值 → 语义化为不更新(null 仍置空) - Hybrid 写穿透非原子(P1):磁盘失败自动重载内存对齐磁盘再抛原错误 - CI:Run tests 拆常规并行 + 重型串行(runInBand),重型测试超时余量提升, 性能护栏 kv 120→240s / opfs 150→300s(仍拦截悬崖回归) - 测试 1155 → 1198(74 套件),覆盖率 89.82% 保持
This commit is contained in:
@@ -6,6 +6,7 @@
|
||||
*/
|
||||
|
||||
import { TokenType, type Token, KEYWORDS } from './tokens';
|
||||
import { DatabaseError } from '../constants';
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Lexer
|
||||
@@ -217,6 +218,15 @@ export class Lexer {
|
||||
this.readChar();
|
||||
}
|
||||
|
||||
// v0.7.2: 未闭合字符串字面量显式报错(此前静默返回残缺 STRING token,
|
||||
// 上层可解析出错误结果,如 `SELECT 'abc` 被当作合法常量列)
|
||||
if (this.ch === '') {
|
||||
throw new DatabaseError(
|
||||
`Unterminated string literal at position ${start}`,
|
||||
'PARSE_ERROR',
|
||||
);
|
||||
}
|
||||
|
||||
return {
|
||||
type: TokenType.STRING,
|
||||
value,
|
||||
|
||||
+29
-1
@@ -6,6 +6,10 @@
|
||||
* 绑定在词法层面完成:仅替换字符串字面量之外的 `?`,
|
||||
* 值按 SQL 字面量编码(字符串 `''` 转义、数字/布尔/JSON 直出),
|
||||
* 从根上规避 SQL 注入(不经过字符串拼接由用户自行转义)。
|
||||
*
|
||||
* v0.7.2: 词法扫描感知注释 —— 行注释(`--`)与块注释(slash-star 包裹)中的 `?`
|
||||
* 与引号不再参与占位符识别与字符串状态机(此前注释中的 `?` 计入占位符导致
|
||||
* PARAM_ERROR 错位、注释中的单引号触发 "Unterminated string literal")。
|
||||
*/
|
||||
|
||||
import { DatabaseError } from '../constants';
|
||||
@@ -27,7 +31,7 @@ function encodeParam(value: unknown): string {
|
||||
}
|
||||
|
||||
/**
|
||||
* 将 SQL 中的位置参数 `?`(字符串字面量之外)替换为编码后的字面量。
|
||||
* 将 SQL 中的位置参数 `?`(字符串字面量与注释之外)替换为编码后的字面量。
|
||||
* @param sql 含 `?` 占位符的 SQL
|
||||
* @param params 位置参数数组
|
||||
* @throws PARAM_ERROR 参数数量不匹配
|
||||
@@ -66,6 +70,30 @@ export function bindParameters(sql: string, params?: unknown[]): string {
|
||||
continue;
|
||||
}
|
||||
|
||||
// v0.7.2: 行注释 `-- ...`(含其中的 ? 与引号)原样保留、不参与绑定
|
||||
if (ch === '-' && sql[i + 1] === '-') {
|
||||
while (i < sql.length && sql[i] !== '\n' && sql[i] !== '\r') {
|
||||
out += sql[i];
|
||||
i++;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// v0.7.2: 块注释(slash-star 包裹)同样跳过
|
||||
if (ch === '/' && sql[i + 1] === '*') {
|
||||
out += sql[i] + sql[i + 1];
|
||||
i += 2;
|
||||
while (i < sql.length && !(sql[i] === '*' && sql[i + 1] === '/')) {
|
||||
out += sql[i];
|
||||
i++;
|
||||
}
|
||||
if (i < sql.length) {
|
||||
out += sql[i] + sql[i + 1];
|
||||
i += 2;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ch === '?') {
|
||||
if (pIdx >= params.length) {
|
||||
throw new DatabaseError(
|
||||
|
||||
Reference in New Issue
Block a user