⭐opengauss数据库源码解析系列文章——角色管理⭐(代码片段)

Gauss松鼠会 Gauss松鼠会     2023-01-13     585

关键词:

❤️‍大家好,我是Gauss松鼠会,欢迎进来学习啦~❤️‍

在前面介绍过“9.1 安全管理整体架构和代码概览、9.2 安全认证”,本篇我们介绍第9章 安全管理源码解析中“9.3 角色管理”的相关精彩内容介绍。

9.3 角色管理

角色是拥有数据库对象和权限的实体,在不同的环境中角色可以认为是一个用户、一个组或者兼顾两者。角色管理包含了角色的创建、修改、删除、权限授予和回收操作。

9.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;

在上述的关键数据结构基础之上,完整的创建角色流程如图9-14所示。

图9-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);

至此就完成了整个角色创建的过程。

9.3.2 角色管理

1. 修改角色属性

修改一个数据库角色可以使用SQL命令ALTER ROLE。角色属性的修改是通过调用AlterRole函数来实现的,该函数只有一个类型为AlterRoleStmt结构的参数。相关代码如下:

typedef struct AlterRoleStmt 
    NodeTag  type;
    char*  role; /* 角色的名称 */
    List*  options; /* 需要修改的属性列表 */
    int  action;  /* +1增加成员关系, -1删除成员关系 */
    RoleLockType  lockstatus; /* 角色锁定状态 */
 AlterRoleStmt;

修改角色的流程如图9-15所示。

图9-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;

删除角色的流程如图9-16所示。

图9-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的实现流程如图9-17所示。

图9-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中相关的元组。

感谢大家学习第9章 安全管理源码解析中“9.3 角色管理”的精彩内容,下一篇我们开启“9.4 对象权限管理”的相关内容的介绍。
敬请期待。

💜走过路过,看到这里了,还请各位小伙伴点赞、收藏、评论,千言万语,不胜感谢💜

opengauss数据库源码解析系列文章——存储引擎源码解析(代码片段)

...aceUpdate更新模式,中文意思为:原地更新,是openGauss内核新增的一种存储模式。openGauss内核 查看详情

opengauss数据库源码解析系列文章——存储引擎源码解析(代码片段)

...储引擎,针对众核和大内存服务器进行了优化。MOT是openGauss数据库的一个先进特性& 查看详情

opengauss数据库源码解析系列文章——存储引擎源码解析(代码片段)

...绍。4.2.5行存储索引机制本节以B-Tree索引为例,介绍openGauss中行存储(格式)表的索引机制。索引本质上是对数据的一种物理有序聚簇。有序聚簇参考的排序字段被称 查看详情

opengauss数据库源码解析系列文章——存储引擎源码解析(代码片段)

上一篇我们讲述了“4.2磁盘引擎”中“4.2.1磁盘引擎整体框架及代码概览”与“4.2.2行存储统一访存接口”。本篇我们将讲述“4.2.3astore”。4.2.3astoreastore整体框架astore整体框架如图4-2所示。如上所述,作为行存储子格式之一&#... 查看详情

opengauss数据库源码解析系列文章——事务机制源码解析(代码片段)

上一篇为介绍完"5.1事务整体架构和代码概览"及“5.2事务并发控制”,本篇将继续介绍“5.3锁机制”的精彩内容。5.3锁机制数据库对公共资源的并发控制是通过锁来实现的,根据锁的用途不同,通常可以分为3种&... 查看详情

opengauss数据库源码解析系列文章——sql引擎源解析(代码片段)

...查询优化”及“6.4小结”的相关内容的介绍。6.3查询优化openGauss数据库的查询优化过程功能比较明晰,从源代码组织的角度来看,相关代码分布在不同的目录下,如表6-6所示。表6-6查询优化模块说明模块目录说明查询... 查看详情

opengauss数据库源码解析系列文章——审计与追踪(代码片段)

...常有两种:记录到数据库的表中、记录到OS文件中。openGauss采用记录到OS文件中(即审计日志& 查看详情

opengauss数据库源码解析系列文章——执行器解析(代码片段)

...线式的执行,对底层的存储引擎中的数据进行操作。openGauss数据库将执行的过程抽象成了不同类型的算子,同时结合编 查看详情

opengauss数据库源码解析系列文章——sql引擎源解析(代码片段)

本篇我们开启“SQL引擎源解析”中“6.1概述”及“6.2SQL解析”的精彩内容介绍。第6章SQL引擎源解析SQL引擎作为数据库系统的入口,主要承担了对SQL语言进行解析、优化、生成执行计划的作用。对于用户输入的SQL语句,SQL... 查看详情

⭐opengauss数据库源码解析系列文章——deepsql⭐(代码片段)

...另外一个大方向,即DB4AI。在本章中,我们将介绍openGauss的 查看详情

opengauss数据库源码解析系列文章——执行器解析(代码片段)

上一篇介绍了第七章执行器解析中“7.4表达式计算”及“7.5编译执行”的相关内容,本篇将介绍“7.6向量化引擎”及“7.7小结”的精彩内容。7.6向量化引擎传统的行执行引擎大多采用一次一元组的执行模式,这样在执行... 查看详情

opengauss数据库源码解析系列文章——ai技术(代码片段)

上一篇介绍了第七章执行器解析中“7.6向量化引擎”及“7.7小结”的相关内容,本篇我们开启第八章AI技术中“8.1概述”及“8.2自调优”的相关精彩内容介绍。AI技术最早可以追溯到20世纪50年代,甚至比数据库系统的发展... 查看详情

⭐opengauss数据库源码解析系列文章——ai查询时间预测⭐(代码片段)

上一篇介绍了“8.5指标采集、预测与异常检测”的相关内容,本篇我们介绍“8.6AI查询时间预测”的相关精彩内容介绍。8.6AI查询时间预测在前面介绍过“慢SQL发现”特性,该特性的典型场景是新业务上线前的检查,... 查看详情

opengauss数据库源码解析系列文章——ai技术之“指标采集预测与异常检测”(代码片段)

上一篇介绍了“8.4智能索引推荐”的相关内容,本篇我们介绍“8.5指标采集、预测与异常检测”的相关精彩内容介绍。8.5指标采集、预测与异常检测数据库指标监控与异常检测技术,通过监控数据库指标,并基于时序... 查看详情

opengauss数据库源码解析系列文章——数据安全技术(上)(代码片段)

...理源码解析中“9.6数据安全技术”的相关精彩内容介绍。openGauss采用了多种加密解密技术来提升数据在各个环节的安全性。9.6.1数据加解密接口用户在使用数据库时,除了需要基本的数据库安全之外,还会对导入的数据进... 查看详情

tensorflow源码解析系列文章索引

文章索引framework解析resourceallocatortensoropnodekernelgraphdevicefunctionshape_inferencecommon_runtime解析devicesessiongraph_optimizerexecutor-1executor-2direct_session后记关于起源阅读tensorflow源码时,为了敦促自己主动思考,把阅读的笔 查看详情

数据库迁移系列从oracle迁移到opengauss实战分享(代码片段)

之前的迁移系列中我们介绍了Mysql到openGauss的迁移方法,本篇介绍使用Ora2og工具从Oracle到openGauss数据库的迁移。文章目录简介迁移前准备环境软件安装ora2og工具安装创建迁移项目配置ora2pg.conf测试迁移导出导入Ora2Pg不足FAQ简介... 查看详情

数据库迁移系列从mysql到opengauss的数据库对象迁移实践(代码片段)

在之前这一篇中我们分享过使用chameleon工具完成MySQL到openGauss的全量数据复制、实时在线复制。9.30新发布的openGauss3.1.0版本,工具的全量迁移和增量迁移的性能不但有了全面提升,而且支持数据库对象视图、触发器、自定... 查看详情