海山数据库(He3DB)源码解读:T_CreateRoleStmt原理浅析

一、概述

   CreateRole 是 He3DB中的一项功能,用于创建新的数据库角色,并设置其权限和属性。角色可以是用户、组或其他权限实体。创建角色的过程中,系统需要更新多个系统目录,例如 pg_roles 和 pg_authid,以确保角色的存在与权限的正确设置。

二、CreateRole 命令的执行流程

  1. PostgresMain
  2. exec_simple_query →执行简单的 SQL 查询;
  3. StartTransactionCommand → 开始事务;
  4. pg_parse_query →解析为内部的抽象语法树(AST);
  5. PortalRun
  6. standard_ProcessUtility →权限检查和准备;
  7. CreateRloe(ParseState *pstate, CreateRoleStmt *stmt)→处理创建角色的具体逻辑;
  8. have_createrole_privilege→检查当前用户是否具有创建角色的权限;
  9. CommandCounterIncrement→增量更新当前的命令计数器;
  10. CommitTransactionCommand→ 提交当前事务;
  11. finish_xact_command→ 在事务结束时,执行必要的清理和关闭操作;
    在这里插入图片描述
图1 CreateRole 命令的执行流程图

三、核心结构体介绍

 (一)  CreateRoleStmt 是 He3DB 中用于表示创建角色 (CREATE ROLE) 语句的结构体。它包含了与角色创建相关的各种信息,包括角色类型、角色名称和角色选项。下面是对 CreateRoleStmt 结构体各个成员的详细解释:

typedef struct CreateRoleStmt
{
   
   
	NodeTag		type;
	RoleStmtType stmt_type;		/* ROLE/USER/GROUP */
	char	   *role;			/* role name */
	List	   *options;		/* List of DefElem nodes */
} CreateRoleStmt;
  1. NodeTag type 这个成员用于标识结构体的类型。在 He3DB 的抽象语法树 (AST) 中,每个节点都有一个类型标识符(NodeTag),用于区分不同类型的节点。CreateRoleStmt 会被标记为其特定的类型,以便在AST中进行正确的处理。

  2. RoleStmtType stmt_type:

typedef enum RoleStmtType
{
   
   
	ROLESTMT_ROLE,//表示一般的角色声明。这通常与创建、修改或删除角色的 SQL 语句相关。
	ROLESTMT_USER,//表示用户声明。用户通常是具有登录权限的角色,因此这个类型特指那些允许登录的角色。
	ROLESTMT_GROUP //表示组声明。组是多个角色的集合,主要用于简化权限管理,允许将权限授予一组角色。
} RoleStmtType;
  1. char *role:这个成员是一个指向字符串的指针,用于存储要创建的角色的名称。例如,如果你要创建一个名为 myuser 的用户,role 就会保存 “myuser”。

  2. 这个成员是一个指向 List 类型的指针,表示角色创建时可能附带的一系列选项。每个选项都是 DefElem 类型的节点,可能包括诸如 LOGIN、SUPERUSER、PASSWORD 等角色选项。这使得角色的定义更加灵活,可以通过附加的选项来调整角色的属性。

 (二)   DefElem 是 He3DB 中用来描述 SQL 命令参数的结构体,通常用于定义带有特定选项或参数的命令。以下是对 DefElem 结构体的详细解析,包括它的字段及其含义。

typedef struct DefElem
{
   
   
    NodeTag    type;              /* 节点类型标识 */
    char       *defnamespace;     /* 定义的命名空间,NULL 表示没有指定命名空间 */
    char       *defname;          /* 参数名称 */
    Node       *arg;              /* 通常为 Integer、Float、String 或 TypeName 类型,表示参数的值 */
    DefElemAction defaction;      /* 指定的操作类型(如 SET、ADD、DROP 等) */
    int        location;           /* 位置(token 位置),-1 表示位置未知 */
} DefElem;

四、核心代码解析

   在 He3DB 的源代码中,CreateRole(@src\backend\commands\user.c) 函数是处理 CREATE ROLE SQL 语句的主要函数。该函数负责根据传入的 CreateRoleStmt 结构来创建一个新的数据库角色。下面讲分析该函数源码

/*
 * CREATE ROLE
 */
Oid
CreateRole(ParseState *pstate, CreateRoleStmt *stmt)
{
   
   
	Relation	pg_authid_rel;
	TupleDesc	pg_authid_dsc;
	HeapTuple	tuple;
	Datum new_record[Natts_pg_authid] = {
   
   0};
	bool new_record_nulls[Natts_pg_authid] = {
   
   0};
	Oid roleid = 0;
	ListCell   *item = NULL;
	ListCell   *option = NULL;
	char	   *password = NULL;	/* user password */
	bool		issuper = false;	/* Make the user a superuser? */
	bool		inherit = true; /* Auto inherit privileges? */
	bool		createrole = false; /* Can this user create roles? */
	bool		createdb = false;	/* Can the user create databases? */
	bool		canlogin = false;	/* Can this user login? */
	bool		isreplication = false;	/* Is this a replication role? */
	bool		bypassrls = false;	/* Is this a row security enabled role? */
	int			connlimit = -1; /* maximum connections allowed */
	List	   *addroleto = NIL;	/* roles to make this a member of */
	List	   *rolemembers = NIL;	/* roles to be members of this role */
	List	   *adminmembers = NIL; /* roles to be admins of this role */
	char	   *validUntil = NULL;	/* time the login is valid until */
	Datum		validUntil_datum;	/* same, as timestamptz Datum */
	bool		validUntil_null = false;
	DefElem    *dpassword = NULL;
	DefElem    *dissuper = NULL;
	DefElem    *dinherit = NULL;
	DefElem    *dcreaterole = NULL;
	DefElem    *dcreatedb = NULL;
	DefElem    *dcanlogin = NULL;
	DefElem    *disreplication = NULL;
	DefElem    *dconnlimit = NULL;
	DefElem    *daddroleto = NULL;
	DefElem    *drolemembers = NULL;
	DefElem    *dadminmembers = NULL;
	DefElem    *dvalidUntil = NULL;
	DefElem    *dbypassRLS = NULL;

	/* The defaults can vary depending on the original statement type */
	switch (stmt->stmt_type)
	{
   
   
		case ROLESTMT_ROLE:
			break;
		case ROLESTMT_USER:
			canlogin = true;
			/* may eventually want inherit to default to false here */
			break;
		case ROLESTMT_GROUP:
			break;
	}

	/* Extract options from the statement node tree */
	foreach(option, stmt->options)
	{
   
   
		DefElem    *defel = (DefElem *) lfirst(option);

		if (strcmp(defel->defname, "password") == 0)
		{
   
   
			if (dpassword)
				errorConflictingDefElem(defel, pstate);
			dpassword = defel;
		}
		else if (strcmp(defel->defname, "sysid") == 0)
		{
   
   
			ereport(NOTICE,
					(errmsg("SYSID can no longer be specified")));
		}
		else if (strcmp(defel->defname, "superuser") == 0)
		{
   
   
			if (dissuper)
				errorConflictingDefElem(defel, pstate);
			dissuper = defel;
		}
		else if (strcmp(defel->defname, "inherit") == 0)
		{
   
   
			if (dinherit)
				errorConflictingDefElem(defel, pstate);
			dinherit = defel;
		}
		else if (strcmp(defel->defname, "createrole") == 0)
		{
   
   
			if (dcreaterole)
				errorConflictingDefElem(defel, pstate);
			dcreaterole = defel;
		}
		else if (strcmp(defel->defname, "createdb") == 0)
		{
   
   
			if (dcreatedb)
				errorConflictingDefElem(defel, pstate);
			dcreatedb = defel;
		}
		else if (strcmp(defel->defname, "canlogin") == 0)
		{
   
   
			if (dcanlogin)
				errorConflictingDefElem(defel, pstate);
			dcanlogin = defel;
		}
		else if (strcmp(defel->defname, "isreplication") == 0)
		{
   
   
			if (disreplication)
				errorConflictingDefElem(defel, pstate);
			disreplication = defel;
		}
		else if (strcmp(defel->defname, "connectionlimit") == 0)
		{
   
   
			if (dconnlimit)
				errorConflictingDefElem(defel, pstate);
			dconnlimit = defel;
		}
		else if (strcmp(defel->defname, "addroleto") == 0)
		{
   
   
			if (daddroleto)
				errorConflictingDefElem(defel, pstate);
			daddroleto = defel;
		}
		else if (strcmp(defel->defname, "rolemembers") == 0)
		{
   
   
			if (drolemembers)
				errorConflictingDefElem(defel, pstate);
			drolemembers = defel;
		}
		else if (strcmp(defel->defname, "adminmembers") == 0)
		{
   
   
			if (dadminmembers)
				errorConflictingDefElem(defel, pstate);
			dadminmembers = defel;
		}
		else if (strcmp(defel->defname, "validUntil") == 0)
		{
   
   
			if (dvalidUntil)
				errorConflictingDefElem(defel, pstate);
			dvalidUntil = defel;
		}
		else if (strcmp(defel->defname, "bypassrls") == 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值