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 '\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}
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.
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()
.