Skip to content

[finding] filter-normalizer 的 $not allowNull 守卫在 #5298 第二批之后变成冗余的第二层(谓词等价,SQL 多一层括号) #6005

Description

@os-zhuang

PR #6004(#5977 / #5298 第二批)实施途中的范围外观察,按 Prime Directive #10 记录,不指派。观察类:今天没有任何用户会撞到它,谓词逐行等价,执行计划不变 —— 故挂 finding、不挂 pm:queue,严重度交分诊轮判。

事实

packages/services/service-analytics/src/strategies/filter-normalizer.ts

#5146$not 引入了 nullSafeNegationOperandguardFieldEntrynullGuardForFieldSpec,后者对一个字段 spec 给三种判定:none / requireValue / allowNull

PR #6004 之后,fieldLeaves叶子层自己发守卫,条件恰好就是 nullValueSatisfiesOperator(op, v) && !operatorIsNullTotal(op, v) —— 也就是 nullGuardForFieldSpecallowNull 判定本身。于是 allowNull 这一支变成冗余的第二层:

{$not: {stage: {$ne: 'won'}}}
→ NOT ((stage IS NULL OR (stage IS NULL OR stage != $1)))
              ^^^^^^^^^^^^^^^  guardFieldEntry 的 allowNull 支
                                ^^^^^^^^^^^^^^^  fieldLeaves 的叶子守卫

X OR (X OR Y)X OR Y,所以行为完全等价(PR #6004 实测钉住:$not of $ne / $nin 仍答 ['1'],极性未被拓宽)。#5146 的 header 本来就把「引擎路径守卫两次、幂等」写成已接受的代价,这条只是把同一笔代价又叠了一层。

requireValue不受影响,仍然必需(正向比较、以及多算子 spec 里只要有一个算子不接受 NULL 的情况)。

为什么可能值得清

allowNull 支能到达的算子,恰好只有 $ne(非 null 比较数)/ $nin(非空)/ $notContains —— 其余要么 total($null / $exists / $eq: null / $ne: null / 空 $nin)走 none,要么正向走 requireValue。也就是说这三个算子现在每一个都自带守卫,allowNull 支再没有独占的落点。

去掉它(改为 none)在多算子 spec 上也成立,靠分配律:

  • 现在:(c IS NULL OR (X AND Y))
  • 去掉后:(c IS NULL OR X) AND (c IS NULL OR Y)

两者逐行等价。

为什么 PR #6004 没有顺手做

  1. 它改的是 $not 的语义在 driver-sql 与 driver-memory / formula 之间分叉:NULL 行的去留相反,$not: {} 一个是 TRUE 一个是 FALSE #5146 的守卫代码,不在 [#5298 第二批] filter-normalizer(Cube 面)NULL-safe 对齐:先实测既有 NULL 行为,分叉则改写;N1 入表按后落地者规则 #5977 的验收范围内(「scope = the issue」);
  2. 删肢需要按 fixture 三分诊重新逐条判 filter-normalizer-not-null-safe.test.ts$not 的语义在 driver-sql 与 driver-memory / formula 之间分叉:NULL 行的去留相反,$not: {} 一个是 TRUE 一个是 FALSE #5146 的钉子 —— 其中至少一条($not of $ne 的生成 SQL 断言)会跟着变形,值得单独一轮而不是搭车;
  3. 收益是可读性 / SQL 噪音,不是正确性。

关联

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions