openGauss学习——替换空FROM

引言

本篇博客对查询规划的预处理过程中空FROM语句结点的替换过程进行介绍。

文件路径

/src/gausskernel/optimizer/prep/ prepjointree.cpp

函数replace_empty_jointree()

在之前的博客中我们介绍过,在optimizer查询规划的预处理过程中,包含一步“替换掉空的FROM语句”的处理步骤,这一过程是由prepjointree.cpp中的函数replace_empty_jointree完成的。值得一提的是,PostgreSQL的源码中并不包含这个函数,这个函数是openGauss中新加的函数。

void replace_empty_jointree(Query *parse)
{
    RangeTblEntry *rte;
    Index           rti;
    RangeTblRef *rtr;
    /* Nothing to do if jointree is already nonempty */
    if (parse->jointree->fromlist != NIL)
        return;
    /* We mustn't change it in the top level of a setop tree, either */
    if (parse->setOperations)
        return;
    /* Create suitable RTE */
    rte = makeNode(RangeTblEntry);
    rte->rtekind = RTE_RESULT;
    rte->eref = makeAlias("*RESULT*", NIL);
    /* Add it to rangetable */
    parse->rtable = lappend(parse->rtable, rte);
    rti = list_length(parse->rtable);
    /* And jam a reference into the jointree */
    rtr = makeNode(RangeTblRef);
    rtr->rtindex = rti;
    parse->jointree->fromlist = list_make1(rtr);
}

函数的作用是,如果当前的查询结点(输入的查询结点)的jointree是空树,即结点的fromlist字段是一个空指针,那么替换其为将其指向一个RTE_RESULT类型的“假”关系表。这样做的好处是可以避免以前在SELECT中使用遗漏的FROM子句时出现的一些特殊情况,比如,以前带有空联接树的子查询不能被提取出来,因为这会导致一个空的relid集使得子查询不能唯一地标识联接。

    /* Nothing to do if jointree is already nonempty */
    if (parse->jointree->fromlist != NIL)
        return;

如果当前结点拥有一棵非空的jointree,直接返回不做替换。

    /* We mustn't change it in the top level of a setop tree, either */
    if (parse->setOperations)
        return;

如果当前结点 setOperations 字段不为空,同样不做任何处理。Query结构体的setOperations字段用于表示查询中的集合操作,例如UNION、INTERSECT和EXCEPT,它允许将多个查询结果组合在一起并返回一个结果集,以此实现对多个子查询结果进行合并或筛选的功能。setOperations字段是一个SetOperationTree结构体,它包含了查询中使用的集合操作类型以及对应的子查询。也就是说这是集合操作树的顶层结点,函数同样不对其做任何处理。

    /* Create suitable RTE */
    rte = makeNode(RangeTblEntry);
    rte->rtekind = RTE_RESULT;
    rte->eref = makeAlias("*RESULT*", NIL);
    /* Add it to rangetable */
    parse->rtable = lappend(parse->rtable, rte);
    rti = list_length(parse->rtable);

接下来构造一个新的RangeTblEntry结点并将其附加到当前结点的range table的末尾。rtekind字段表示RangeTableEntry的类型,当rtekind字段取值为RTE_RESULT时,表示该RangeTableEntry是一个结果表,即查询中的一个子查询的结果作为表。这种情况下,该RangeTableEntry的relid字段对应的是子查询的查询计划。但是此处函数并没有构造结点的relid字段,这表明本结果表所引用的实体表并不存在,即本结果表的结果不包含任何可以被引用的元组,是一个空表。

    /* And jam a reference into the jointree */
    rtr = makeNode(RangeTblRef);
    rtr->rtindex = rti;
    parse->jointree->fromlist = list_make1(rtr);

之后调用函数list_make1(),通过一个新建的初始RTE结点创建一个空的List* 类型结构,并让当前结点的jointree->fromlist字段指向这个空表(原先其值为NULL,是一个空指针),并且这个空表与刚刚添加的RTE结点是对应的。完成上述操作,就实现了将fromlist指针替换为一个RTE_RESULT类型的“假”关系表。为什么说是假关系表呢?因为其并不与任何的实体关系表绑定,也不包含任何可以被引用的元组条目,是一张空表。通过这样做,可以避免子查询的FROM语句引用的 jointree 为空树的情况下,子查询不能被唯一标识的问题。

我将函数的作用过程简单绘制如下图。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值