openGauss 数据库源码解析系列文章——安全管理源码解析(三)
- 2023-08-12  北京
- 本文字数:11471 字 - 阅读完需:约 38 分钟 
Gauss 松鼠会 [openGauss](javascript:void(0);) 2023-07-29 17:58 发表于四川
在上篇openGauss数据库源码解析系列文章——安全管理源码解析(一)我们围绕安全管理整体架构和代码概览、安全认证原理介绍和代码解析进行了简单介绍。本篇将继续角色管理、对象权限管理的学习,全文阅读需要 35 分钟,欢迎收藏阅读。
三、角色管理
角色是拥有数据库对象和权限的实体,在不同的环境中角色可以认为是一个用户、一个组或者兼顾两者。角色管理包含了角色的创建、修改、删除、权限授予和回收操作。
3.1 角色创建
如果在 openGauss 上需要创建一个角色,可以使用 SQL 命令 CREATE ROLE,其语法为:
CREATE ROLE role_name [ [ WITH ] option [ ... ] ] [ ENCRYPTED | UNENCRYPTED ] { PASSWORD | IDENTIFIED BY } { 'password' | DISABLE };
创建角色是通过函数 CreateRole 实现的,其函数接口为:
void CreateRole(CreateRoleStmt* stmt)
其中,CreateRoleStmt 为创建角色时所需的数据结构,具体数据结构代码如下:
typedef struct CreateRoleStmt {    NodeTag type;    RoleStmtType stmt_type;  /* 将要创建的角色类型 ROLE/USER/GROUP  */    char* role;              /* 角色名 */    List* options;            /* 角色属性列表 */} CreateRoleStmt;
字段 stmt_type 是枚举类型,相关代码如下:
typedef enum RoleStmtType {ROLESTMT_ROLE,    /* 代表创建角色 */ROLESTMT_USER,    /* 代表创建用户 */ROLESTMT_GROUP,  /* 代表创建组用户 */ } RoleStmtType;
字段 option 用来存储角色的属性信息,具体的数据结构为:
typedef struct DefElem {    NodeTag type;    char* defnamespace;     /* 节点对应的命名空间  */    char* defname;          /* 节点对应的角色属性名  */    Node* arg;              /* 表示值或类型名  */    DefElemAction defaction;  /* SET/ADD/DROP 等其他未指定的行为  */} DefElem;
在上述的关键数据结构基础之上,完整的创建角色流程如图 14 所示。
 
 图 14 openGauss 角色创建流程
创建角色时先判断所要创建的角色类型。如果是创建用户,则设置其 canlogin 属性为 true,因为用户默认具有登录权限。而创建角色和创建组时,若角色属性参数没有声明的话,则 canlogin 属性默认为 false。相关代码如下:
/* 默认值可能因原始语句类型而异 */switch (stmt->stmt_type) {case ROLESTMT_ROLE:        break;    case ROLESTMT_USER:         canlogin = true;         break;     case ROLESTMT_GROUP:         break;     default:         break;}
检查完所要创建的角色类型以后,开始循环获取角色属性 options 中的内容,并将其转换成对应的角色属性值类型。相关代码如下:
/* 从node tree中获取option */foreach (option, stmt->options) {    DefElem* defel = (DefElem*)lfirst(option);
    if (strcmp(defel->defname, "password") == 0 || strcmp(defel->defname, "encryptedPassword") == 0 ||        strcmp(defel->defname, "unencryptedPassword") == 0) {        if (dpassword != NULL) {            clean_role_password(dpassword);            ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("conflicting or redundant options")));        }        dpassword = defel;        if (strcmp(defel->defname, "encryptedPassword") == 0)            encrypt_password = true;        else if (strcmp(defel->defname, "unencryptedPassword") == 0) {            clean_role_password(dpassword);            ereport(ERROR,                (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),                    errmsg("Permission denied to create role with option UNENCRYPTED.")));        }    } else if (strcmp(defel->defname, "sysid") == 0) {        ereport(NOTICE, (errmsg("SYSID can no longer be specified")));    } else if (strcmp(defel->defname, "inherit") == 0) {        if (dinherit != NULL) {            clean_role_password(dpassword);            ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("conflicting or redundant options")));        }        dinherit = defel;    } else if (strcmp(defel->defname, "createrole") == 0) {        if (dcreaterole != NULL) {            clean_role_password(dpassword);            ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("conflicting or redundant options")));        }        dcreaterole = defel;    } else if (strcmp(defel->defname, "createdb") == 0) {        if (dcreatedb != NULL) {            clean_role_password(dpassword);            ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("conflicting or redundant options")));        }        dcreatedb = defel;    } else if (strcmp(defel->defname, "useft") == 0) {        if (duseft != NULL) {            clean_role_password(dpassword);            ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("conflicting or redundant options")));        }        duseft = defel;……
根据对应的参数信息转换需要的角色属性值类型,如提取 issuper 值和 createrole 值等。相关代码如下:
if (dissuper != NULL)        issuper = intVal(dissuper->arg) != 0;    if (dinherit != NULL)        inherit = intVal(dinherit->arg) != 0;    if (dcreaterole != NULL)        createrole = intVal(dcreaterole->arg) != 0;    if (dcreatedb != NULL)        createdb = intVal(dcreatedb->arg) != 0;   ……
在完成了转换以后,将角色属性值以及角色的信息一起构建一个 pg_authid 的元组,再写回系统表并更新索引。作相关代码如下:
/* 检查pg_authid relation,确认该角色没有存在*/Relation pg_authid_rel = heap_open(AuthIdRelationId, RowExclusiveLock);    TupleDesc pg_authid_dsc = RelationGetDescr(pg_authid_rel);
    if (OidIsValid(get_role_oid(stmt->role, true))) {        str_reset(password);        ereport(ERROR, (errcode(ERRCODE_DUPLICATE_OBJECT), errmsg("role \"%s\" already exists", stmt->role)));}……    /* 创建一个插入的tuple */    errno_t errorno = memset_s(new_record, sizeof(new_record), 0, sizeof(new_record));    securec_check(errorno, "\0", "\0");    errorno = memset_s(new_record_nulls, sizeof(new_record_nulls), false, sizeof(new_record_nulls));    securec_check(errorno, "\0", "\0");
    new_record[Anum_pg_authid_rolname - 1] = DirectFunctionCall1(namein, CStringGetDatum(stmt->role));
    new_record[Anum_pg_authid_rolsuper - 1] = BoolGetDatum(issuper);    new_record[Anum_pg_authid_rolinherit - 1] = BoolGetDatum(inherit);    new_record[Anum_pg_authid_rolcreaterole - 1] = BoolGetDatum(createrole);    new_record[Anum_pg_authid_rolcreatedb - 1] = BoolGetDatum(createdb);        new_record[Anum_pg_authid_rolcatupdate - 1] = BoolGetDatum(issuper);    new_record[Anum_pg_authid_rolcanlogin - 1] = BoolGetDatum(canlogin);    new_record[Anum_pg_authid_rolreplication - 1] = BoolGetDatum(isreplication);    new_record[Anum_pg_authid_rolauditadmin - 1] = BoolGetDatum(isauditadmin);    new_record[Anum_pg_authid_rolsystemadmin - 1] = BoolGetDatum(issystemadmin);new_record[Anum_pg_authid_rolconnlimit - 1] = Int32GetDatum(connlimit);……    HeapTuple tuple = heap_form_tuple(pg_authid_dsc, new_record, new_record_nulls);
    if (u_sess->proc_cxt.IsBinaryUpgrade && OidIsValid(u_sess->upg_cxt.binary_upgrade_next_pg_authid_oid)) {        HeapTupleSetOid(tuple, u_sess->upg_cxt.binary_upgrade_next_pg_authid_oid);        u_sess->upg_cxt.binary_upgrade_next_pg_authid_oid = InvalidOid;    }
    roleid = simple_heap_insert(pg_authid_rel, tuple);
    if (IsUnderPostmaster) {        if (OidIsValid(rpoid) && (rpoid != DEFAULT_POOL_OID))            recordDependencyOnRespool(AuthIdRelationId, roleid, rpoid);
        u_sess->wlm_cxt->wlmcatalog_update_user = true;}……
完成更新以后,将新创建的角色加入指定存在的父角色中。相关代码如下:
/* 将新角色添加到指定的现有角色中 */    foreach (item, addroleto) {        char* oldrolename = strVal(lfirst(item));        Oid oldroleid = get_role_oid(oldrolename, false);
        AddRoleMems(            oldrolename, oldroleid, list_make1(makeString(stmt->role)), list_make1_oid(roleid), GetUserId(), false);    }
    AddRoleMems(stmt->role, roleid, adminmembers, roleNamesToIds(adminmembers), GetUserId(), true);    AddRoleMems(stmt->role, roleid, rolemembers, roleNamesToIds(rolemembers), GetUserId(), false);
至此就完成了整个角色创建的过程。
3.2 角色管理
1. 修改角色属性
修改一个数据库角色可以使用 SQL 命令 ALTER ROLE。角色属性的修改是通过调用 AlterRole 函数来实现的,该函数只有一个类型为 AlterRoleStmt 结构的参数。相关代码如下:
typedef struct AlterRoleStmt {    NodeTag  type;    char*  role; /* 角色的名称 */    List*  options; /* 需要修改的属性列表 */    int  action;  /* +1增加成员关系, -1删除成员关系 */    RoleLockType  lockstatus; /* 角色锁定状态 */} AlterRoleStmt;
修改角色的流程如图 15 所示。
 
 图 15 openGauss 角色管理流程图
调用函数 AlterRole 修改用户角色属性时,首先循环判断 options,依次提取要修改的角色属性;然后查看系统表 pg_authid 判断是否已存在该角色,如果不存在则提示报错;再进行相应的权限判断,检查执行者是否有权限去更改该角色的属性;最后构建一个新的元组,将要更改的属性更新到新元组中,存入系统表 pg_authid。同时 AlterRole 函数也可以用来调整角色的成员关系,结构体中的 action 字段值设置为 1 和-1 分别表示增加和删除成员关系,该选项将在授予和回收角色章节具体描述。AlterRole 函数的具体实现代码如下:
void AlterRole(AlterRoleStmt* stmt){    . . .    /* 循环提取角色的属性options */    foreach (option, stmt->options) {        DefElem* defel = (DefElem*)lfirst(option);
        if (strcmp(defel->defname, "password") == 0 || strcmp(defel->defname, "encryptedPassword") == 0 ||            strcmp(defel->defname, "unencryptedPassword") == 0) {            if (dpassword != NULL) {                clean_role_password(dpassword);                ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("conflicting or redundant options")));            }            dpassword = defel;            if (strcmp(defel->defname, "encryptedPassword") == 0)                encrypt_password = true;            else if (strcmp(defel->defname, "unencryptedPassword") == 0) {                clean_role_password(dpassword);                ereport(ERROR,                    (errcode(ERRCODE_INVALID_ROLE_SPECIFICATION),                        errmsg("Permission denied to create role with option UNENCRYPTED.")));            }        } else if (strcmp(defel->defname, "createrole") == 0) {            if (dcreaterole != NULL) {                clean_role_password(dpassword);                ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("conflicting or redundant options")));            }            dcreaterole = defel;        } else if (strcmp(defel->defname, "inherit") == 0) {            if (dinherit != NULL) {                clean_role_password(dpassword);                ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("conflicting or redundant options")));            }            dinherit = defel;        }. . .        else {            clean_role_password(dpassword);            ereport(ERROR,                (errcode(ERRCODE_UNRECOGNIZED_NODE_TYPE), errmsg("option \"%s\" not recognized", defel->defname)));        }    }/* 将提取的属性赋值给对应的变量 */    if (dpassword != NULL && dpassword->arg != NULL) {        head = list_head((List*)dpassword->arg);        if (head != NULL) {            pwdargs = (A_Const*)linitial((List*)dpassword->arg);            if (pwdargs != NULL) {                password = strVal(&pwdargs->val);            }            if (lnext(head)) {                pwdargs = (A_Const*)lsecond((List*)dpassword->arg);                if (pwdargs != NULL) {                    replPasswd = strVal(&pwdargs->val);                }            }        }    }    if (dinherit != NULL)        inherit = intVal(dinherit->arg);    if (dcreaterole != NULL)        createrole = intVal(dcreaterole->arg); . . .    /* 查看要修改的角色是否存在,不存在则提示报错 */    Relation pg_authid_rel = heap_open(AuthIdRelationId, RowExclusiveLock);
    HeapTuple tuple = SearchSysCache1(AUTHNAME, PointerGetDatum(stmt->role));    if (!HeapTupleIsValid(tuple)) {        str_reset(password);        str_reset(replPasswd);
        if (!have_createrole_privilege())            ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), errmsg("Permission denied.")));        else            ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("role \"%s\" does not exist", stmt->role)));    }roleid = HeapTupleGetOid(tuple);. . ./* 检查是否有权限更改相应角色的属性,权限不足则提示报错 */    if (roleid == BOOTSTRAP_SUPERUSERID) {        if (!(issuper < 0 && inherit < 0 && createrole < 0 && createdb < 0 && canlogin < 0 && isreplication < 0 &&                isauditadmin < 0 && issystemadmin < 0 && isvcadmin < 0 && useft < 0 && dconnlimit == NULL &&                rolemembers == NULL && validBegin == NULL && validUntil == NULL && drespool == NULL &&                dparent == NULL && dnode_group == NULL && dspacelimit == NULL && dtmpspacelimit == NULL &&                dspillspacelimit == NULL)) {            str_reset(password);            str_reset(replPasswd);            ereport(ERROR,                (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),                    errmsg("Permission denied to change privilege of the initial account.")));        }    }    if (dpassword != NULL && roleid == BOOTSTRAP_SUPERUSERID && GetUserId() != BOOTSTRAP_SUPERUSERID) {        str_reset(password);        str_reset(replPasswd);        ereport(ERROR,            (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),                errmsg("Permission denied to change password of the initial account.")));    }    . . .    } else if (!have_createrole_privilege()) {        if (!(inherit < 0 && createrole < 0 && createdb < 0 && canlogin < 0 && isreplication < 0 && isauditadmin < 0 &&                issystemadmin < 0 && isvcadmin < 0 && useft < 0 && dconnlimit == NULL && rolemembers == NULL &&                validBegin == NULL && validUntil == NULL && !*respool && !OidIsValid(parentid) && dnode_group == NULL &&                !spacelimit && !tmpspacelimit && !spillspacelimit &&                /* if not superuser or have createrole privilege, permission of lock and unlock is denied */                stmt->lockstatus == DO_NOTHING &&                /* if alter password, it will be handled below */                roleid == GetUserId()) ||            (roleid != GetUserId() && dpassword == NULL)) {            str_reset(password);            str_reset(replPasswd);            ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), errmsg("Permission denied.")));        }}...    /* 将要更改的角色属性值分别更新到新元组中,再将新元组替代旧元组存入系统表pg_authid中 */    if (issuper >= 0) {        new_record[Anum_pg_authid_rolsuper - 1] = BoolGetDatum(issuper > 0);        new_record_repl[Anum_pg_authid_rolsuper - 1] = true;
        new_record[Anum_pg_authid_rolcatupdate - 1] = BoolGetDatum(issuper > 0);        new_record_repl[Anum_pg_authid_rolcatupdate - 1] = true;    }    if (inherit >= 0) {        new_record[Anum_pg_authid_rolinherit - 1] = BoolGetDatum(inherit > 0);        new_record_repl[Anum_pg_authid_rolinherit - 1] = true;    }  . . .    HeapTuple new_tuple = heap_modify_tuple(tuple, pg_authid_dsc, new_record, new_record_nulls, new_record_repl);    simple_heap_update(pg_authid_rel, &tuple->t_self, new_tuple);
    CatalogUpdateIndexes(pg_authid_rel, new_tuple);   . . ./* 判断成员关系,增加或删除成员 */    if (stmt->action == 1)         AddRoleMems(stmt->role, roleid, rolemembers, roleNamesToIds(rolemembers), GetUserId(), false);    else if (stmt->action == -1) /* drop members FROM role */        DelRoleMems(stmt->role, roleid, rolemembers, roleNamesToIds(rolemembers), false);
    . . .    heap_close(pg_authid_rel, NoLock);}
2. 删除角色
如果要删除一个角色,可以使用 SQL 命令 DROP ROLE。角色的删除是通过调用 DropRole 函数来实现的,该函数只有一个类型为 DropRoleStmt 结构的参数。相关代码如下:
typedef struct DropRoleStmt {    NodeTagtype;    List*roles;               /*  要删除的角色列表  */    boolmissing_ok;          /*  判断角色是否存在  */    boolis_user;             /*  要删除的是角色还是用户  */    boolinherit_from_parent;  /*  是否继承自父角色*/    DropBehavior behavior;            /*  是否级联删除依赖对象  */} DropRoleStmt;
删除角色的流程如图 16 所示。
 
 图 16 openGauss 角色删除流程图
角色删除的执行流程为:首先判断当前操作者是否有权限执行该操作,若没有则报错退出;然后检查待删除的角色是否存在,若不存在,则根据 missing_ok 选择返回 ERROR 或 NOTICE 提示信息;再通过扫描系统表 pg_authid 和 pg_auth_members,删除所有涉及待删除角色的元组执行;若 behavior 取值 DROP_CASCADE,则级联删除该角色所拥有的所有数据库对象;最后删除该角色在系统表 pg_auth_history 和 pg_user_status 中对应的信息。具体的实现过程代码如下:
void DropRole(DropRoleStmt* stmt){    . . ./*  检查执行者是否有权限删除角色  */    if (!have_createrole_privilege())        ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), errmsg("Permission denied to drop role.")));/*  循环处理要删除的角色  */    foreach (item, stmt->roles) {. . ./*  检查要删除的角色是否存在,若不存在则提示报错  */        HeapTuple tuple = SearchSysCache1(AUTHNAME, PointerGetDatum(role));        if (!HeapTupleIsValid(tuple)) {            if (!stmt->missing_ok) {                ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("role \"%s\" does not exist", role)));            } else {                ereport(NOTICE, (errmsg("role \"%s\" does not exist, skipping", role)));            }            continue;        }        . . ./*  当前用户不允许删除  */        if (roleid == GetUserId())            ereport(ERROR, (errcode(ERRCODE_OBJECT_IN_USE), errmsg("current user cannot be dropped")));        if (roleid == GetOuterUserId())            ereport(ERROR, (errcode(ERRCODE_OBJECT_IN_USE), errmsg("current user cannot be dropped")));        if (roleid == GetSessionUserId())            ereport(ERROR, (errcode(ERRCODE_OBJECT_IN_USE), errmsg("session user cannot be dropped")));        /*  校验执行者和被删除角色的权限,如系统管理员才有权限删除其他系统管理员  */        if((((Form_pg_authid)GETSTRUCT(tuple))->rolsuper|| ((Form_pg_authid)GETSTRUCT(tuple))->rolsystemadmin) &&            !isRelSuperuser())            ereport(ERROR,(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), errmsg("Permission denied.")));        if ((((Form_pg_authid)GETSTRUCT(tuple))->rolauditadmin) &&            g_instance.attr.attr_security.enablePrivilegesSeparate && !isRelSuperuser())            ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), errmsg("Permission denied.")));        . . .    /*  针对CASCADE(级联)的情况,删除该角色拥有的对象  */        if (stmt->behavior == DROP_CASCADE) {            char* user = NULL;            CancelQuery(role);            user = (char*)palloc(sizeof(char) * strlen(role) + 1);            errno_t errorno = strncpy_s(user, strlen(role) + 1, role, strlen(role));            securec_check(errorno, "\0", "\0");            drop_objectstmt.behavior = stmt->behavior;            drop_objectstmt.type = T_DropOwnedStmt;            drop_objectstmt.roles = list_make1(makeString(user));
            DropOwnedObjects(&drop_objectstmt);            list_free_deep(drop_objectstmt.roles);        }
        /*  检查是否有对象依赖于该角色,若还存在依赖,则提示报错  */        if (checkSharedDependencies(AuthIdRelationId, roleid, &detail, &detail_log))            ereport(ERROR,                (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),                    errmsg("role \"%s\" cannot be dropped because some objects depend on it", role),                    errdetail_internal("%s", detail),                    errdetail_log("%s", detail_log)));        /*  从相关系统表中删除涉及待删除角色的元组  */        simple_heap_delete(pg_authid_rel, &tuple->t_self);. . .        while (HeapTupleIsValid(tmp_tuple = systable_getnext(sscan))) {            simple_heap_delete(pg_auth_members_rel, &tmp_tuple->t_self);        }
        systable_endscan(sscan);        DropAuthHistory(roleid);        DropUserStatus(roleid);        DeleteSharedComments(roleid, AuthIdRelationId);        DeleteSharedSecurityLabel(roleid, AuthIdRelationId);        DropSetting(InvalidOid, roleid);. . .    heap_close(pg_auth_members_rel, NoLock);    heap_close(pg_authid_rel, NoLock);}
3. 授予和回收角色
如果要授予或回收角色的成员关系,可以使用 SQL 命令“GRANT/REVOKE”。如果声明了“WITH ADMIN OPTION”选项,那么被加入的成员角色还可以将其他角色加入到父角色中。角色的授予或回收通过调用 GrantRole 函数来实现,该函数只有一个类型为 GrantRoleStmt 结构的参数。相关代码如下:
typedef struct GrantRoleStmt {    NodeTag type;    List* granted_roles;/*  被授予或回收的角色集合  */    List* grantee_roles;/*  从granted_roles中增加或删除的角色集合  */    Bool is_grant;/*  true代表授权,false代表回收  */    Bool admin_opt;/*  是否带有with admin option选项  */    char* grantor;/*  授权者  */    Drop Behaviorbehavior;/*  是否级联回收角色  */} GrantRoleStmt;
授予角色时,grantee_roles 中的角色将被添加到 granted_roles,通过调用函数 AddRoleMems 实现;回收角色时,将 grantee_roles 中的角色从 granted_roles 中删除,通过调用函数 DelRoleMems 实现。
函数 AddRoleMems 的实现流程如图 17 所示。
 
 图 17 openGauss 增加用户成员流程图
函数 AddRoleMems 的具体实现代码如下,其中:
(1) rolename 和 roleid 分别表示要被加入成员的角色的名称和 OID。
(2) memberNames 和 memberIds 分别是要添加的角色名称和 OID 的列表。
(3) grantorId 表示授权者的 OID。
(4) admin_opt 表示是否带有 with admin option 选项。
static void AddRoleMems(    const char* rolename, Oid roleid, const List* memberNames, List* memberIds, Oid grantorId, bool admin_opt){. . .    /*  校验执行者的权限  */    if (superuser_arg(roleid)) {        if (!isRelSuperuser())            ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), errmsg("Permission denied.")));    . . .    } . . .    if (grantorId != GetUserId() && !superuser())        ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), errmsg("must be system admin to set grantor")));/*  循环处理要添加的角色  */    pg_authmem_rel = heap_open(AuthMemRelationId, RowExclusiveLock);    pg_authmem_dsc = RelationGetDescr(pg_authmem_rel);
    forboth(nameitem, memberNames, iditem, memberIds)    {        /*  针对角色和成员信息创建pg_auth_members元组,再将新元组插入到系统表中  */. . .        new_record[Anum_pg_auth_members_roleid - 1] = ObjectIdGetDatum(roleid);        new_record[Anum_pg_auth_members_member -1] = ObjectIdGetDatum(memberid);        new_record[Anum_pg_auth_members_grantor -  1] = ObjectIdGetDatum(grantorId);        new_record[Anum_pg_auth_members_admin_option - 1] = BoolGetDatum(admin_opt);
        if (HeapTupleIsValid(authmem_tuple)) {            new_record_repl[Anum_pg_auth_members_grantor - 1] = true;            new_record_repl[Anum_pg_auth_members_admin_option - 1] = true;            tuple = heap_modify_tuple(authmem_tuple, pg_authmem_dsc, new_record, new_record_nulls, new_record_repl);            simple_heap_update(pg_authmem_rel, &tuple->t_self, tuple);            CatalogUpdateIndexes(pg_authmem_rel, tuple);            ReleaseSysCache(authmem_tuple);        } else {            tuple = heap_form_tuple(pg_authmem_dsc, new_record, new_record_nulls);            (void)simple_heap_insert(pg_authmem_rel, tuple);            CatalogUpdateIndexes(pg_authmem_rel, tuple);        }    }. . .    heap_close(pg_authmem_rel, NoLock);}
函数 DelRoleMems 的实现过程类似。首先对执行者的相关权限进行校验,然后循环处理要删除的角色,删除系统表 pg_auth_member 中相关的元组。

daydayup
还未添加个人签名 2023-07-18 加入
还未添加个人简介










 
    
评论