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

huangapple go评论77阅读模式
英文:

In Postgres 16 BETA, should the ParseNamespaceItem have the same index as it's RangeTableEntry?

问题

我一直在更新Apache AGE到最新的Postgres版本REL_16_BETA。我面临的主要问题之一是代码被重新修改以更新权限检查,现在一些查询返回ERROR: invalid perminfoindex <rte->perminfoindex> in RTE with relid <rte->relid>。这是由于一个RTE的perminfoindex = 0,而relid包含一个值而引起的。

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:

// 我已经简化了每个RTE显示的内容。

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类型的一个RTE和具有非空值的relid具有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 '
{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}
0', 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的属性,再次,我不确定是否这是引发问题的原因,因为rte的relid为0:

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

如果有人对此了解更多,我将非常感谢任何形式的答案或帮助。

英文:

I have been working on updating Apache AGE with the latest version of Postgres, the REL_16_BETA version. One of the main problems that I am facing is the fact that the code was reworked to update the permission checking and now some of the queries return ERROR: invalid perminfoindex <rte->perminfoindex> in RTE with relid <rte->relid>. This occurs due to one of the RTEs having perminfoindex = 0 and the relid containing a value.

AGE allows us to execute openCypher commands within Postgres so that it can create a graph with nodes and edges. There are two main tables that are created: _ag_label_vertex and _ag_label_edge. Both of them will be the parent label tables of every other vertex/edge label we create.

When we do a simple MATCH query to find all nodes with the v label:

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

inside the add_rtes_to_flat_rtable() function, it goes inside a loop where we can see the stored RTEs in root->parse->rtable:

// 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)
]

But executing the query with a simple SET clause:

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

One of the RTEs of the RTE_RELATION type and relid with a not null value has 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)
]

We can see that the relid = 16991 is related to the child vertex label and the relid = 16971 related to the parent vertex label:


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

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

With further inspection in AGE's code, after executing the SET query, it goes inside transform_cypher_clause_as_subquery() function and the ParseNamespaceItem has the following values:

{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}

And the pnsi->p_rte has:

{type = T_RangeTblEntry, rtekind = RTE_SUBQUERY, relid = 0, relkind = 0 '
{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}
0', 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}

Then it calls addNSItemToQuery(pstate, pnsi, true, false, true);. This function adds the given nsitem/RTE as a top-level entry in the pstate's join list and/or namespace list. I've been thinking if adding the nsitem/RTE like this won't cause this error?

Also in handle_prev_clause it has the following line, which is going to add all the rte's attributes to the current queries targetlist which, again, I'm not sure if that's what causing the problem because the relid of the rte is 0:

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

If someone knows more about it, I would be grateful for any kind of answer or help.

答案1

得分: 0

首先,我要感谢Amit Langote和Tom Lane在这个问题上给我的帮助。我向pgsql-hackers发送了一些邮件,关于这个问题,他们帮助我展示了可能的错误是什么。

当我们执行一个带有AGE的SET查询时,代码的执行会经过GetResultRTEPermissionInfo(),它会检查relinfo->ri_RootResultRelInfo。这个变量指向了空值。因此,Postgres会解释为ResultRelInfo只能为过滤触发器创建,而关系没有被插入。实际上,我们想要触发第一个if语句:

if (relinfo->ri_RootResultRelInfo)
	{
		/*
		 * 对于继承子结果关系(插入的分区路由目标或子UPDATE目标),
		 * 这将返回根父级的RTE以获取RTEPermissionInfo,
		 * 因为只有它分配了一个。
		 */
		rti = relinfo->ri_RootResultRelInfo->ri_RangeTableIndex;
	}

因此,它最终会得到错误的索引并指向错误的RTE,触发了getRTEPermissionInfo()中的错误。

英文:

First of all, I want to thank Amit Langote and Tom Lane for helping me out on this one. I've sent some emails to pgsql-hackers regarding this issue and they have helped me on showing what could be the possible error.

When we do a SET query with AGE, the execution of the code goes through GetResultRTEPermissionInfo() and it checks for relinfo->ri_RootResultRelInfo. This variable is pointing to nil. Because of this, Postgres will interpret that the ResultRelInfo must've been created only for filtering triggers and the relation is not being inserted into. Actually, we want to trigger the first if-statement

    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;
	}

Because of that, it ends up having the wrong index and pointing to the wrong RTE, triggering the error in getRTEPermissionInfo().

huangapple
  • 本文由 发表于 2023年7月14日 02:11:59
  • 转载请务必保留本文链接:https://go.coder-hub.com/76682195.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定