Skip to content

driver-memory analytics 面的 generateSql 对 in/notIn/set/notSet 输出错误 SQL:回退成 = 且只取第一个值($in: ['100','200'] → WHERE code = '100') #5433

Description

@os-zhuang

做 #5373(cube 比较数往返有损)时,为了钉住 generateSql 这个出口,逐个实测了它对各算子输出的 WHERE 子句。发现的这一条不属于 #5373 的范围面 —— #5373 裁的是比较数(值)层面的编码,而这一条在算子层面,修复前后都存在,与那个编码无关。按 Prime Directive #10 单独记在这里,unassigned。

位置

packages/plugins/driver-memory/src/memory-analytics.ts:

  • operatorToSql(约 :790)—— 映射表里只有 8 个算子:equals / notEquals / contains / notContains / gt / gte / lt / lte,并以 return opMap[operator] || '=' 兜底;
  • generateSql 的 WHERE 构建循环(约 :450)—— 只取 values[0]。

MONGO_TO_CUBE_OPERATOR 声明本面支持 11 个算子,其中 in($in)、notIn($nin)、set($exists)在 operatorToSql 里一个都没有。

现象(实测)

3 行固定数据,code 是 TEXT 列,分别存 '100' / '200' / '100':

where query() 取到 generateSql() 输出的 WHERE 该 SQL 若执行会取到
{code: {$in: ['100','200']}} 3 行(正确) WHERE code = '100' 2 行
{code: {$nin: ['100']}} 1 行(正确) WHERE code = '100' 2 行
{code: {$exists: true}} 3 行(正确) WHERE code = 1 —

两个缺陷叠在一起:

  1. 算子被兜底成 =。in / notIn 没有映射,|| '=' 把它们全变成等值比较 —— notIn 因此输出了与 in 完全相同的子句,语义正好相反。set($exists)同理,WHERE code = 1 与「该字段存在」毫无关系。
  2. 只取第一个比较数。values[0] 让 $in 的其余候选值直接消失,即使算子映射对了也还是错的。

注意方向:query() 那一半是对的($in/$nin 有各自的分支,$exists 也有),所以这是同一个 driver 的两个出口对同一个 where 给出不同含义 —— #5240 为本包立下的不变量所禁止的形状,只是这次分叉在 generateSql 一侧。

为什么是 bug

generateSql 是 IAnalyticsService 的公开方法,其返回值也是 AnalyticsResult.sql 承诺的「生成的 SQL」。它的用途是调试/透明性 —— 让作者看懂自己的查询到底问了什么。一个把 notIn 显示成 in、把三个候选值显示成一个的 SQL,恰恰在作者最需要它说实话的时候说了假话。

同时这是 declared ≠ enforced 的又一处:MONGO_TO_CUBE_OPERATOR 声明本面支持这些算子,query() 也确实支持,只有这一个出口没跟上。

未验证的部分

建议(不代裁决)

两条都在 generateSql 一侧,建议一起裁:补齐 operatorToSql 的映射(in → IN、notIn → NOT IN、set → IS NOT NULL、notSet → IS NULL),并让 WHERE 构建循环按算子决定用 values[0] 还是整个 values 列表。若认为「调试用 SQL 不值得维护」,那另一条路是让 generateSql 对无法忠实表达的算子拒收,与 #5345 同款 —— 但那会拒掉本面 query() 明明能算的查询,恐怕不是想要的答案。

关联:#5373(同函数、同一轮核对里发现;它裁的是比较数层,本条是算子层)、#5374(同为本面算子层缺陷,那条在 mingo 出口)、#5345(本面算子层的第一轮裁决,只裁了「无映射就丢弃」)、#5240(本包两面不得分叉)。

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions