PostgreSQL:求使j->quals为SubLink/and/not子句的SQL示例及递归必要性
以下代码片段来自PostgreSQL 14.4的pull_up_sublinks_qual_recurse()函数:
if ((j = convert_ANY_sublink_to_join(root, sublink, available_rels1)) != NULL) { /* Yes; insert the new join node into the join tree */ j->larg = *jtlink1; *jtlink1 = (Node *) j; /* Recursively process pulled-up jointree nodes */ j->rarg = pull_up_sublinks_jointree_recurse(root, j->rarg, &child_rels); /* * Now recursively process the pulled-up quals. Any inserted * joins can get stacked onto either j->larg or j->rarg, * depending on which rels they reference. */ j->quals = pull_up_sublinks_qual_recurse(root, j->quals, &j->larg, available_rels1, &j->rarg, child_rels); /* Return NULL representing constant TRUE */ return NULL; }
当convert_ANY_sublink_to_join()返回非空值时,pull_up_sublinks_qual_recurse()会递归调用自身,但只有当第二个参数为SubLink、and-clause或not-clause时,该递归调用才会产生有效操作。
我测试了如下SQL查询:
select a from A where a in (select b from B);
在这个查询中,convert_ANY_sublink_to_join()返回后,j->quals为OpExpr类型。我找不到能使j->quals成为SubLink、and-clause或not-clause的SQL查询,因此质疑此处的递归调用是否有必要,希望能得到符合条件的SQL示例。
通过构造包含逻辑组合、多层嵌套子查询的语句,就能让j->quals成为目标类型,以下是具体示例:
示例1:带AND逻辑的嵌套IN子查询
select a from A where a in (select b from B where c in (select d from C)) and a > 10;
处理外层IN子查询后,j->quals会是BoolExpr(and-clause类型),包含a > 10条件和未处理的内层SubLink(第二层IN子查询),此时递归调用会继续处理内层SubLink,将其转换为连接节点。
示例2:带NOT的IN子查询
select a from A where not (a in (select b from B where b < 5));
此时j->quals会是BoolExpr(not-clause类型),包裹着IN子查询对应的表达式,递归调用会处理这个逻辑结构。
示例3:多层嵌套的IN子查询
select a from A where a in ( select b from B where b in (select d from C where d > 0) );
处理外层IN子查询后,j->quals会保留内层的SubLink(第二层IN子查询),递归调用会继续处理这个内层SubLink,完成连接转换。
这些场景下,递归调用会产生实际的处理动作,证明这段代码的必要性。
内容的提问来源于stack exchange,提问作者abigaile

