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;
有了上述的关键数据结构,完整的创建角色流程:
创建角色时先判断所要创建的角色类型。如果是创建用户,则设置其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中获取optionforeach (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);
此时,完成整个角色创建的过程。
更多详情请参考GaussDB 文档中心:doc.hcs.huawei.com/db/zh-cn/ga…