在Postgres 16 BETA中,ParseNamespaceItem是否应该与RangeTableEntry具有相同的索引?

93ze6v8z  于 2023-08-03  发布在  其他
关注(0)|答案(1)|浏览(83)

我一直致力于用最新版本的Postgres(REL_16_BETA版本)更新Apache AGE。我面临的一个主要问题是,代码被重写以更新权限检查,现在一些查询返回ERROR: invalid perminfoindex <rte->perminfoindex> in RTE with relid <rte->relid>。这是由于具有perminfoindex = 0relid的一个RTEs包含值而发生的。
AGE允许我们在Postgres中执行openCypher命令,这样它就可以创建一个包含节点和边的图。创建了两个主表:_ag_label_vertex_ag_label_edge的三个不同的数据类型。它们都将是我们创建的每个其他顶点/边标签的父标签表。
当我们执行一个简单的MATCH查询来查找所有带有v标签的节点时:

SELECT * FROM cypher('cypher_set', $$
MATCH (n:v)
RETURN n
$$) AS (node agtype);

字符串
add_rtes_to_flat_rtable()函数中,它进入一个循环,我们可以看到root->parse->rtable中存储的RTEs:

// I've simplified what every RTE shows.

root->parse->rtable
[
    (rtekind = RTE_SUBQUERY, relid =     0, perminfoindex = 0),
    (rtekind = RTE_SUBQUERY, relid =     0, perminfoindex = 0),
    (rtekind = RTE_SUBQUERY, relid =     0, perminfoindex = 0),
    (rtekind = RTE_RELATION, relid = 16991, perminfoindex = 1)
]


但是使用一个简单的SET子句执行查询:

SELECT * FROM cypher('cypher_set', $$
MATCH (n) 
SET n.i = 3
$$) AS (a agtype);


具有非空值的RTE_RELATION类型和relid的其中一个RTE具有perminfoindex = 0

root->parse->rtable
[
    (rtekind = RTE_SUBQUERY, relid =     0, perminfoindex = 0),
    (rtekind = RTE_RELATION, relid = 16971, perminfoindex = 1),
    (rtekind = RTE_RELATION, relid = 16971, perminfoindex = 1),
    (rtekind = RTE_RELATION, relid = 16991, perminfoindex = 0)
]


我们可以看到relid = 16991与子顶点标签相关,relid = 16971与父顶点标签相关:

SELECT to_regclass('cypher_set._ag_label_vertex')::oid;
 to_regclass 
-------------
       16971

SELECT to_regclass('cypher_set.v')::oid;
 to_regclass 
-------------
       16991


通过进一步检查AGE的代码,在执行SET查询后,它进入transform_cypher_clause_as_subquery()函数,ParseNamespaceItem具有以下值:

{p_names = 0x1205638, p_rte = 0x11edb70, p_rtindex = 1, p_perminfo = 0x7f7f7f7f7f7f7f7f, 
  p_nscolumns = 0x1205848, p_rel_visible = true, p_cols_visible = true, p_lateral_only = false, 
  p_lateral_ok = true}


pnsi->p_rte

{type = T_RangeTblEntry, rtekind = RTE_SUBQUERY, relid = 0, relkind = 0 '\000', rellockmode = 0, 
  tablesample = 0x0, perminfoindex = 0, subquery = 0x11ed710, security_barrier = false, 
  jointype = JOIN_INNER, joinmergedcols = 0, joinaliasvars = 0x0, joinleftcols = 0x0, joinrightcols = 0x0, 
  join_using_alias = 0x0, functions = 0x0, funcordinality = false, tablefunc = 0x0, values_lists = 0x0, 
  ctename = 0x0, ctelevelsup = 0, self_reference = false, coltypes = 0x0, coltypmods = 0x0, 
  colcollations = 0x0, enrname = 0x0, enrtuples = 0, alias = 0x12055f0, eref = 0x1205638, lateral = false, 
  inh = false, inFromCl = true, securityQuals = 0x0}


然后调用addNSItemToQuery(pstate, pnsi, true, false, true);。此函数将给定的nsitem/RTE作为顶级条目添加到pstate的连接列表和/或名称空间列表中。我一直在想,这样添加nsitem/RTE是否不会导致此错误?
同样在handle_prev_clause中,它有下面一行,这将把所有rte的属性添加到当前查询的targetlist中,同样,我不确定这是否是导致问题的原因,因为rte的relid是0:

query->targetList = expandNSItemAttrs(pstate, pnsi, 0, true, -1);


如果有人知道更多关于它,我会很感激任何形式的回答或帮助。

cuxqih21

cuxqih211#

首先,我要感谢Amit Langote和Tom Lane在这件事上帮助我。我已经发送了一些emails到pgsql黑客关于这个问题,他们帮助我展示了可能的错误。
当我们使用AGE执行SET查询时,代码的执行会经过GetResultRTEPermissionInfo()并检查relinfo->ri_RootResultRelInfo。这个变量指向nil。正因为如此,Postgres将解释为ResultRelInfo必须仅为过滤触发器而创建,并且关系不会被插入。实际上,我们想触发第一个if语句

if (relinfo->ri_RootResultRelInfo)
    {
        /*
         * For inheritance child result relations (a partition routing target
         * of an INSERT or a child UPDATE target), this returns the root
         * parent's RTE to fetch the RTEPermissionInfo because that's the only
         * one that has one assigned.
         */
        rti = relinfo->ri_RootResultRelInfo->ri_RangeTableIndex;
    }

字符串
因此,它最终会有错误的索引并指向错误的RTE,从而触发getRTEPermissionInfo()中的错误。

相关问题