You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Apache AGE中RTE转PNSI结构体时perminfoindex错误的解决方法问询

解决PostgreSQL 13-16版本升级中Apache AGE的RTE/PNSI权限信息错误问题

版本变更背景

从PostgreSQL 13到16,RangeTblEntry(RTE)和ParseNamespaceItem(PNSI)的结构体成员发生了关键变化:

----------------------------------
RTE <RangeTblEntry>

新增成员:
 + perinfoindex: Index
 + join_using_alias: Alias

移除成员:
 - requiredPerms: AclMode
 - checkAsUser: Oid
 - selectedCols: Bitmapset*
 - insertedCols: Bitmapset*
 - updatedCols: Bitmapset*
 - extraUpdatedCols: Bitmapset*
----------------------------------

PNSI <ParseNamespaceItem>

新增成员:
 + p_names: *Alias
 + p_perminfo: *RTEPermissioninfo
----------------------------------

Apache AGE正在验证用PNSI替换RTE的可行性,但在某段代码中触发了权限检查错误:调用markVarForSelectPriv时,内部调用markRTEForSelectPriv和getRTEPermissionInfo,抛出"invalid perminfoindex 1 in RTE with relid..."的错误。

触发错误的AGE代码

static List *expand_pnsi_attrs(ParseState *pstate, ParseNamespaceItem *pnsi,
                   int sublevels_up, bool require_col_privs, int location)
{
    RangeTblEntry *rte = pnsi->p_rte;
    RTEPermissionInfo *perminfo = pnsi->p_perminfo;
    List *names, *vars;
    ListCell *name, *var;
    List *te_list = NIL;
    int var_prefix_len = strlen(AGE_DEFAULT_VARNAME_PREFIX);
    int alias_prefix_len = strlen(AGE_DEFAULT_ALIAS_PREFIX);

    expandRTE(rte, pnsi->p_rtindex, sublevels_up, location, false, &names, &vars);

    /*
     * Require read access to the table.  This is normally redundant with the
     * markVarForSelectPriv calls below, but not if the table has zero
     * columns.
     */
    if (rte->rtekind == RTE_RELATION)
     {
         Assert(perminfo != NULL);
         perminfo->requiredPerms |= ACL_SELECT;
     }

    /* iterate through the variables */
    forboth(name, names, var, vars)
    {
        char *label = strVal(lfirst(name));
        Var *varnode = (Var *)lfirst(var);
        TargetEntry *te;

        /* we want to skip our "hidden" variables */
        if (strncmp(AGE_DEFAULT_VARNAME_PREFIX, label, var_prefix_len) == 0)
            continue;

        /* we want to skip out "hidden" aliases */
        if (strncmp(AGE_DEFAULT_ALIAS_PREFIX, label, alias_prefix_len) == 0)
            continue;

        /* add this variable to the list */
        te = makeTargetEntry((Expr *)varnode,
                             (AttrNumber)pstate->p_next_resno++, label, false);
        te_list = lappend(te_list, te);

        /* Require read access to each column */
        markVarForSelectPriv(pstate, varnode);
    }

    Assert(name == NULL && var == NULL);    /* lists not the same length? */

    return te_list;
}

问题根源

PostgreSQL 16中,RTE通过perminfoindex字段关联到ParseState结构体中p_perminfos列表对应的RTEPermissionInfo实例,权限检查函数(如getRTEPermissionInfo)依赖这个索引查找权限信息。

当前AGE代码直接操作PNSI的p_perminfo,但未同步设置RTE的perminfoindex,导致权限检查时找不到对应的权限信息,触发索引无效的错误。

修复方案

核心是让RTE的perminfoindex正确关联到ParseState中对应的RTEPermissionInfo实例,修改expand_pnsi_attrs函数中的权限处理逻辑:

修改后的代码片段

if (rte->rtekind == RTE_RELATION)
{
    Assert(perminfo != NULL);
    // 确保perminfo已加入ParseState的权限列表,并同步RTE的perminfoindex
    if (rte->perminfoindex == 0) // PG中0表示未初始化的索引
    {
        // 将perminfo添加到ParseState的权限信息列表
        pstate->p_perminfos = lappend(pstate->p_perminfos, perminfo);
        // 设置RTE的索引为列表的当前长度(列表索引从1开始)
        rte->perminfoindex = list_length(pstate->p_perminfos);
    }
    perminfo->requiredPerms |= ACL_SELECT;
}

修复逻辑说明

  1. 检查RTE的perminfoindex是否为0(PG中默认未初始化的索引值),如果是,说明该RTE还未关联到ParseState的权限列表。
  2. 将PNSI持有的perminfo添加到pstate->p_perminfos列表中。
  3. 将RTE的perminfoindex设置为列表的当前长度(因为PG的列表索引从1开始计数)。
  4. 之后再修改perminfo->requiredPerms的操作就能被权限检查函数正确识别。

这样修改后,markVarForSelectPriv内部的权限检查流程就能通过RTE的perminfoindex找到正确的RTEPermissionInfo实例,避免触发索引无效的错误。

内容的提问来源于stack exchange,提问作者Matheus Farias

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 08:12:06