diff --git a/src/sql/parser.ts b/src/sql/parser.ts index 32593d9..237430e 100644 --- a/src/sql/parser.ts +++ b/src/sql/parser.ts @@ -776,24 +776,48 @@ export class Parser { // 条件表达式 // =================================================================== - /** condition → simple_cond ((AND|OR) simple_cond)* */ + /** + * condition → or_expr + * + * v0.8.0 根治:AND 的优先级必须高于 OR(SQL 标准)。 + * + * 此前实现是**纯左折叠**的单层循环: + * `a = 1 OR a = 2 AND b = 3` → `(a = 1 OR a = 2) AND b = 3` ← 错 + * 标准语义应为: + * `a = 1 OR a = 2 AND b = 3` → `a = 1 OR (a = 2 AND b = 3)` ← 对 + * + * 影响面:任何"权限条件 OR 业务条件 AND 软删标记"的写法都会静默返回错误行集 + * (审计实测:4 行表上返回 1 行而非 3 行)。这是本层影响面最大、改动最小的缺陷。 + * + * 现在按标准文法分层:or_expr → and_expr (OR and_expr)* + * and_expr → unary (AND unary)* + * unary → [NOT] primary + * 并且只在**确实有多个操作数**时才包 $and/$or,避免生成 {$and:[x]} 这种冗余节点 + * (否则 `WHERE a = 1` 的结构会从 `{a:{$eq:1}}` 变成 `{$and:[{a:{$eq:1}}]}`, + * 破坏既有 AST 契约与下游引擎的索引下推识别)。 + */ private parseCondition(): WhereCondition { - let left = this.parseSimpleCondition(); + return this.parseOrExpression(); + } - while (this.curTokenIs(TokenType.AND) || this.curTokenIs(TokenType.OR)) { - const isAnd = this.curTokenIs(TokenType.AND); + /** or_expr → and_expr (OR and_expr)* */ + private parseOrExpression(): WhereCondition { + const operands: WhereCondition[] = [this.parseAndExpression()]; + while (this.curTokenIs(TokenType.OR)) { this.nextToken(); - const right = this.parseSimpleCondition(); - - if (isAnd) { - // 合并到 $and - left = { $and: [left, right] } as unknown as WhereCondition; - } else { - left = { $or: [left, right] } as unknown as WhereCondition; - } + operands.push(this.parseAndExpression()); } + return operands.length === 1 ? operands[0] : ({ $or: operands } as unknown as WhereCondition); + } - return left; + /** and_expr → simple_cond (AND simple_cond)* */ + private parseAndExpression(): WhereCondition { + const operands: WhereCondition[] = [this.parseSimpleCondition()]; + while (this.curTokenIs(TokenType.AND)) { + this.nextToken(); + operands.push(this.parseSimpleCondition()); + } + return operands.length === 1 ? operands[0] : ({ $and: operands } as unknown as WhereCondition); } /** 公共 WHERE 条件入口(供 CASE WHEN 求值等外部场景,v0.3.1) */