PostgreSQL的学习心得和知识总结(一百六十一)|深入理解PostgreSQL数据库之 pg_get_acl 的使用和实现

目录结构

注:提前言明 本文借鉴了以下博主、书籍或网站的内容,其列表如下:

1、参考书籍:++《PostgreSQL数据库内核分析》++

2、参考书籍:++《数据库事务处理的艺术:事务管理与并发控制》++

3、++PostgreSQL数据库仓库链接,点击前往++

4、++日本著名PostgreSQL数据库专家 铃木启修 网站主页,点击前往++

5、参考书籍:++《PostgreSQL中文手册》++

6、++参考书籍:《PostgreSQL指南:内幕探索》,点击前往++


1、本文内容全部来源于开源社区 GitHub和以上博主的贡献,本文也免费开源(可能会存在问题,评论区等待大佬们的指正)

2、本文目的:开源共享 抛砖引玉 一起学习

3、本文不提供任何资源 不存在任何交易 与任何组织和机构无关

4、大家可以根据需要自行 复制粘贴以及作为其他个人用途,但是不允许转载 不允许商用 (写作不易,还请见谅 💖)

5、本文内容基于PostgreSQL master源码开发而成


深入理解PostgreSQL数据库之 pg_get_acl 的使用和实现



文章快速说明索引

学习目标:

做数据库内核开发久了就会有一种 少年得志,年少轻狂 的错觉,然鹅细细一品觉得自己其实不算特别优秀 远远没有达到自己想要的。也许光鲜的表面掩盖了空洞的内在,每每想到于此,皆有夜半临渊如履薄冰之感。为了睡上几个踏实觉,即日起 暂缓其他基于PostgreSQL数据库的兼容功能开发,近段时间 将着重于学习分享Postgres的基础知识和实践内幕。


学习内容:(详见目录)

1、深入理解PostgreSQL数据库之pg_get_acl的使用和实现


学习时间:

2024年12月01日 17:14:30


学习产出:

1、PostgreSQL数据库基础知识回顾 1个
2、CSDN 技术博客 1篇
3、PostgreSQL数据库内核深入学习


注:下面我们所有的学习环境是Centos8+PostgreSQL master+Oracle19C+MySQL8.0

sql 复制代码
postgres=# select version();
                                                  version                                                   
------------------------------------------------------------------------------------------------------------
 PostgreSQL 17devel on x86_64-pc-linux-gnu, compiled by gcc (GCC) 8.5.0 20210514 (Red Hat 8.5.0-21), 64-bit
(1 row)

postgres=#

#-----------------------------------------------------------------------------#

SQL> select * from v$version;          

BANNER        Oracle Database 19c EE Extreme Perf Release 19.0.0.0.0 - Production	
BANNER_FULL	  Oracle Database 19c EE Extreme Perf Release 19.0.0.0.0 - Production Version 19.17.0.0.0	
BANNER_LEGACY Oracle Database 19c EE Extreme Perf Release 19.0.0.0.0 - Production	
CON_ID 0


#-----------------------------------------------------------------------------#

mysql> select version();
+-----------+
| version() |
+-----------+
| 8.0.27    |
+-----------+
1 row in set (0.06 sec)

mysql>

功能使用背景说明

pg_get_acl 可用于检索和检查与数据库对象关联的权限,而无需查看特定目录。

sql 复制代码
postgres=# select version();
                                     version                                     
---------------------------------------------------------------------------------
 PostgreSQL 18devel on x86_64-pc-linux-gnu, compiled by gcc (GCC) 13.1.0, 64-bit
(1 row)

postgres=# \x
Expanded display is on.
postgres=# 
postgres=# \df+ pg_get_acl 
List of functions
-[ RECORD 1 ]-------+-----------------------------------------
Schema              | pg_catalog
Name                | pg_get_acl
Result data type    | aclitem[]
Argument data types | classid oid, objid oid, objsubid integer
Type                | func
Volatility          | stable
Parallel            | safe
Owner               | postgres
Security            | invoker
Access privileges   | 
Language            | internal
Internal name       | pg_get_acl
Description         | get ACL for SQL object

postgres=# \x
Expanded display is off.
postgres=#

案例一,如下:

sql 复制代码
postgres=# CREATE ROLE alice;
CREATE ROLE
postgres=# CREATE TABLE test (id int);
CREATE TABLE
postgres=# GRANT SELECT ON test TO alice;
GRANT
postgres=#
postgres=# DROP ROLE alice;
2024-12-02 00:09:00.859 PST [27893] ERROR:  role "alice" cannot be dropped because some objects depend on it
2024-12-02 00:09:00.859 PST [27893] DETAIL:  privileges for table test
2024-12-02 00:09:00.859 PST [27893] STATEMENT:  DROP ROLE alice;
ERROR:  role "alice" cannot be dropped because some objects depend on it
DETAIL:  privileges for table test
postgres=#
postgres=# select pg_get_acl(classid, objid, objsubid) from pg_shdepend;
                  pg_get_acl                   
-----------------------------------------------
 {postgres=arwdDxtm/postgres,alice=r/postgres}
(1 row)

postgres=# SELECT pg_get_acl('pg_class'::regclass, 'test'::regclass::oid, 0);
                  pg_get_acl                   
-----------------------------------------------
 {postgres=arwdDxtm/postgres,alice=r/postgres}
(1 row)

postgres=# GRANT DELETE ON test TO alice;
GRANT
postgres=# SELECT pg_get_acl('pg_class'::regclass, 'test'::regclass::oid, 0);
                   pg_get_acl                   
------------------------------------------------
 {postgres=arwdDxtm/postgres,alice=rd/postgres}
(1 row)

postgres=# select * from pg_shdepend ;
 dbid | classid | objid | objsubid | refclassid | refobjid | deptype 
------+---------+-------+----------+------------+----------+---------
    5 |    1259 | 16385 |        0 |       1260 |    16384 | a
(1 row)

postgres=# select pg_get_acl(classid, objid, objsubid) from pg_shdepend;
                   pg_get_acl                   
------------------------------------------------
 {postgres=arwdDxtm/postgres,alice=rd/postgres}
(1 row)

postgres=# REVOKE SELECT ON test FROM alice;
REVOKE
postgres=# select * from pg_shdepend ;
 dbid | classid | objid | objsubid | refclassid | refobjid | deptype 
------+---------+-------+----------+------------+----------+---------
    5 |    1259 | 16385 |        0 |       1260 |    16384 | a
(1 row)

postgres=# select pg_get_acl(classid, objid, objsubid) from pg_shdepend;
                  pg_get_acl                   
-----------------------------------------------
 {postgres=arwdDxtm/postgres,alice=d/postgres}
(1 row)

postgres=# \dp test
                                 Access privileges
 Schema | Name | Type  |     Access privileges      | Column privileges | Policies 
--------+------+-------+----------------------------+-------------------+----------
 public | test | table | postgres=arwdDxtm/postgres+|                   | 
        |      |       | alice=d/postgres           |                   | 
(1 row)

postgres=# \du
                             List of roles
 Role name |                         Attributes                         
-----------+------------------------------------------------------------
 alice     | Cannot login
 postgres  | Superuser, Create role, Create DB, Replication, Bypass RLS

postgres=# SET SESSION AUTHORIZATION alice ;
SET
postgres=> \dp test
                                 Access privileges
 Schema | Name | Type  |     Access privileges      | Column privileges | Policies 
--------+------+-------+----------------------------+-------------------+----------
 public | test | table | postgres=arwdDxtm/postgres+|                   | 
        |      |       | alice=d/postgres           |                   | 
(1 row)

postgres=> select * from test ;
2024-12-02 01:33:49.853 PST [32897] ERROR:  permission denied for table test
2024-12-02 01:33:49.853 PST [32897] STATEMENT:  select * from test ;
ERROR:  permission denied for table test
postgres=>

案例二,如下:

sql 复制代码
postgres=# CREATE ROLE zhangsan;
CREATE ROLE
postgres=# CREATE TABLE test2 (one int, two int unique, three int, four int unique);
CREATE TABLE
postgres=# GRANT SELECT (one), INSERT (two), UPDATE (three) ON test2 TO zhangsan ;
GRANT
postgres=# select pg_get_acl('pg_class'::regclass, 'test2'::regclass::oid, 1);
      pg_get_acl       
-----------------------
 {zhangsan=r/postgres}
(1 row)

postgres=# select pg_get_acl('pg_class'::regclass, 'test2'::regclass::oid, 2);
      pg_get_acl       
-----------------------
 {zhangsan=a/postgres}
(1 row)

postgres=# select pg_get_acl('pg_class'::regclass, 'test2'::regclass::oid, 3);
      pg_get_acl       
-----------------------
 {zhangsan=w/postgres}
(1 row)

postgres=# select pg_get_acl('pg_class'::regclass, 'test2'::regclass::oid, 4);
 pg_get_acl 
------------
 
(1 row)

postgres=# select pg_get_acl('pg_class'::regclass, 'test2'::regclass::oid, 0);
 pg_get_acl 
------------
 
(1 row)

postgres=# select pg_get_acl('pg_class'::regclass, 'test2'::regclass::oid, 5);
 pg_get_acl 
------------
 
(1 row)

postgres=# select * from pg_shdepend ;
 dbid | classid | objid | objsubid | refclassid | refobjid | deptype 
------+---------+-------+----------+------------+----------+---------
    5 |    1259 | 16389 |        0 |       1260 |    16388 | a
    5 |    1259 | 16393 |        1 |       1260 |    16392 | a
    5 |    1259 | 16393 |        2 |       1260 |    16392 | a
    5 |    1259 | 16393 |        3 |       1260 |    16392 | a
(4 rows)

postgres=# select pg_get_acl(classid, objid, objsubid) from pg_shdepend;
                  pg_get_acl                   
-----------------------------------------------
 {postgres=arwdDxtm/postgres,alice=d/postgres}
 {zhangsan=r/postgres}
 {zhangsan=a/postgres}
 {zhangsan=w/postgres}
(4 rows)

postgres=# \du
                             List of roles
 Role name |                         Attributes                         
-----------+------------------------------------------------------------
 alice     | Cannot login
 postgres  | Superuser, Create role, Create DB, Replication, Bypass RLS
 zhangsan  | Cannot login

postgres=# \dp test2
                               Access privileges
 Schema | Name  | Type  | Access privileges |   Column privileges   | Policies 
--------+-------+-------+-------------------+-----------------------+----------
 public | test2 | table |                   | one:                 +| 
        |       |       |                   |   zhangsan=r/postgres+| 
        |       |       |                   | two:                 +| 
        |       |       |                   |   zhangsan=a/postgres+| 
        |       |       |                   | three:               +| 
        |       |       |                   |   zhangsan=w/postgres | 
(1 row)

postgres=# table test2 ;
 one | two | three | four 
-----+-----+-------+------
(0 rows)

postgres=# SET SESSION AUTHORIZATION zhangsan ;
SET
postgres=> \dp test2
                               Access privileges
 Schema | Name  | Type  | Access privileges |   Column privileges   | Policies 
--------+-------+-------+-------------------+-----------------------+----------
 public | test2 | table |                   | one:                 +| 
        |       |       |                   |   zhangsan=r/postgres+| 
        |       |       |                   | two:                 +| 
        |       |       |                   |   zhangsan=a/postgres+| 
        |       |       |                   | three:               +| 
        |       |       |                   |   zhangsan=w/postgres | 
(1 row)

postgres=> table test2 ;
2024-12-02 01:36:51.234 PST [33353] ERROR:  permission denied for table test2
2024-12-02 01:36:51.234 PST [33353] STATEMENT:  table test2 ;
ERROR:  permission denied for table test2
postgres=> select one from test2;
 one 
-----
(0 rows)

postgres=> select four from test2;
2024-12-02 01:37:10.117 PST [33353] ERROR:  permission denied for table test2
2024-12-02 01:37:10.117 PST [33353] STATEMENT:  select four from test2;
ERROR:  permission denied for table test2
postgres=>
sql 复制代码
postgres=# GRANT DELETE ON test2 TO zhangsan;
GRANT
postgres=# \dp test2
                                   Access privileges
 Schema | Name  | Type  |     Access privileges      |   Column privileges   | Policies 
--------+-------+-------+----------------------------+-----------------------+----------
 public | test2 | table | postgres=arwdDxtm/postgres+| one:                 +| 
        |       |       | zhangsan=d/postgres        |   zhangsan=r/postgres+| 
        |       |       |                            | two:                 +| 
        |       |       |                            |   zhangsan=a/postgres+| 
        |       |       |                            | three:               +| 
        |       |       |                            |   zhangsan=w/postgres | 
(1 row)

postgres=# SET SESSION AUTHORIZATION zhangsan ;
SET
postgres=> \dp test2
                                   Access privileges
 Schema | Name  | Type  |     Access privileges      |   Column privileges   | Policies 
--------+-------+-------+----------------------------+-----------------------+----------
 public | test2 | table | postgres=arwdDxtm/postgres+| one:                 +| 
        |       |       | zhangsan=d/postgres        |   zhangsan=r/postgres+| 
        |       |       |                            | two:                 +| 
        |       |       |                            |   zhangsan=a/postgres+| 
        |       |       |                            | three:               +| 
        |       |       |                            |   zhangsan=w/postgres | 
(1 row)

postgres=> select pg_get_acl(classid, objid, objsubid) from pg_shdepend;
                    pg_get_acl                    
--------------------------------------------------
 {postgres=arwdDxtm/postgres,alice=d/postgres}
 {zhangsan=r/postgres}
 {zhangsan=a/postgres}
 {zhangsan=w/postgres}
 {postgres=arwdDxtm/postgres,zhangsan=d/postgres}
(5 rows)

postgres=> select pg_get_acl('pg_class'::regclass, 'test2'::regclass::oid, 0);
                    pg_get_acl                    
--------------------------------------------------
 {postgres=arwdDxtm/postgres,zhangsan=d/postgres}
(1 row)

postgres=>

尤其是与其他系统表结合使用的时候,更加方便高效。如下:

sql 复制代码
postgres=# SELECT *,
    pg_identify_object(classid, objid, objsubid) AS object,
    pg_identify_object(refclassid, refobjid, 0) AS ref_object,
    pg_get_acl(classid, objid, objsubid)
FROM pg_shdepend;
 dbid | classid | objid | objsubid | refclassid | refobjid | deptype |                      object                      |        ref_object         |                    pg_get_acl                    
------+---------+-------+----------+------------+----------+---------+--------------------------------------------------+---------------------------+--------------------------------------------------
    5 |    1259 | 16389 |        0 |       1260 |    16388 | a       | (table,public,test,public.test)                  | (role,,alice,alice)       | {postgres=arwdDxtm/postgres,alice=d/postgres}
    5 |    1259 | 16393 |        1 |       1260 |    16392 | a       | ("table column",public,test2,public.test2.one)   | (role,,zhangsan,zhangsan) | {zhangsan=r/postgres}
    5 |    1259 | 16393 |        2 |       1260 |    16392 | a       | ("table column",public,test2,public.test2.two)   | (role,,zhangsan,zhangsan) | {zhangsan=a/postgres}
    5 |    1259 | 16393 |        3 |       1260 |    16392 | a       | ("table column",public,test2,public.test2.three) | (role,,zhangsan,zhangsan) | {zhangsan=w/postgres}
    5 |    1259 | 16393 |        0 |       1260 |    16392 | a       | (table,public,test2,public.test2)                | (role,,zhangsan,zhangsan) | {postgres=arwdDxtm/postgres,zhangsan=d/postgres}
(5 rows)

postgres=#

功能实现源码解析


下面调试一下,如下:

sql 复制代码
postgres=# SELECT pg_get_acl('pg_class'::regclass, 'test'::regclass::oid, 0);
                  pg_get_acl                   
-----------------------------------------------
 {postgres=arwdDxtm/postgres,alice=d/postgres}
(1 row)

postgres=#

简单分析一下:

  • 开表pg_class
  • 查询出test表对应的tuple
  • 获取并返回relacl
  • ...

sql 复制代码
postgres=# SELECT pg_get_acl('pg_class'::regclass, 'test'::regclass::oid, 1);
 pg_get_acl 
------------
 
(1 row)

postgres=#

如果处理关系的属性(设置了 objsubid),则从 pg_attribute 中检索 ACL。

如上其实就是等同于执行了如下:

sql 复制代码
postgres=# select attacl from pg_attribute where attrelid = 16389 and attnum = 1;
 attacl 
--------
 
(1 row)

postgres=#

同理,如下:

sql 复制代码
postgres=# SELECT pg_get_acl('pg_class'::regclass, 'test2'::regclass::oid, 0);
                    pg_get_acl                    
--------------------------------------------------
 {postgres=arwdDxtm/postgres,zhangsan=d/postgres}
(1 row)

postgres=# SELECT pg_get_acl('pg_class'::regclass, 'test2'::regclass::oid, 1);
      pg_get_acl       
-----------------------
 {zhangsan=r/postgres}
(1 row)

postgres=# select attacl from pg_attribute where attrelid = 16393 and attnum = 1;
        attacl         
-----------------------
 {zhangsan=r/postgres}
(1 row)

postgres=# select relacl from pg_class where oid = 16393;
                      relacl                      
--------------------------------------------------
 {postgres=arwdDxtm/postgres,zhangsan=d/postgres}
(1 row)

postgres=#

这里示例就不再调试了,接下来看一下函数的返回值问题:

c 复制代码
// src/include/catalog/pg_proc.dat

{ oid => '8730', descr => 'get ACL for SQL object',
  proname => 'pg_get_acl', provolatile => 's', prorettype => '_aclitem',
  proargtypes => 'oid oid int4', proargnames => '{classid,objid,objsubid}',
  prosrc => 'pg_get_acl' },

调试如下:

此时的函数堆栈,如下:

c 复制代码
aclitemout(FunctionCallInfo fcinfo) (\home\postgres\postgres\src\backend\utils\adt\acl.c:652)
FunctionCall1Coll(FmgrInfo * flinfo, Oid collation, Datum arg1) (\home\postgres\postgres\src\backend\utils\fmgr\fmgr.c:1139)
OutputFunctionCall(FmgrInfo * flinfo, Datum val) (\home\postgres\postgres\src\backend\utils\fmgr\fmgr.c:1685)
array_out(FunctionCallInfo fcinfo) (\home\postgres\postgres\src\backend\utils\adt\arrayfuncs.c:1134)
FunctionCall1Coll(FmgrInfo * flinfo, Oid collation, Datum arg1) (\home\postgres\postgres\src\backend\utils\fmgr\fmgr.c:1139)
OutputFunctionCall(FmgrInfo * flinfo, Datum val) (\home\postgres\postgres\src\backend\utils\fmgr\fmgr.c:1685)
printtup(TupleTableSlot * slot, DestReceiver * self) (\home\postgres\postgres\src\backend\access\common\printtup.c:360)
ExecutePlan(EState * estate, PlanState * planstate, _Bool use_parallel_mode, CmdType operation, _Bool sendTuples, uint64 numberTuples, ScanDirection direction, DestReceiver * dest, _Bool execute_once) (\home\postgres\postgres\src\backend\executor\execMain.c:1686)
standard_ExecutorRun(QueryDesc * queryDesc, ScanDirection direction, uint64 count, _Bool execute_once) (\home\postgres\postgres\src\backend\executor\execMain.c:362)
ExecutorRun(QueryDesc * queryDesc, ScanDirection direction, uint64 count, _Bool execute_once) (\home\postgres\postgres\src\backend\executor\execMain.c:303)
PortalRunSelect(Portal portal, _Bool forward, long count, DestReceiver * dest) (\home\postgres\postgres\src\backend\tcop\pquery.c:924)
PortalRun(Portal portal, long count, _Bool isTopLevel, _Bool run_once, DestReceiver * dest, DestReceiver * altdest, QueryCompletion * qc) (\home\postgres\postgres\src\backend\tcop\pquery.c:768)
exec_simple_query(const char * query_string) (\home\postgres\postgres\src\backend\tcop\postgres.c:1283)
...

至此_aclitem类型的翻译工作就完成了!

相关推荐
老王笔记19 分钟前
MySQL如何区分幻读和不可重复读
数据库·mysql
不爱学习的啊Biao20 分钟前
【08】MySQL复杂查询:子查询语句详解与示例
数据库·mysql·子查询
st_3327 分钟前
Junit5 单元测试入门
数据库·单元测试·log4j
s***g54028 分钟前
MySQL-操作数据库备份与恢复
数据库·mysql
CQU_JIAKE1 小时前
11.5【算法】6-1 表彰优秀学生(多态)
数据库
Elastic 中国社区官方博客2 小时前
使用数据层进行数据生命周期管理
大数据·数据库·elasticsearch·搜索引擎·全文检索·时序数据库
我爱李星璇2 小时前
Spring Boot项目的创建
java·数据库·spring boot
锵锵锵锵~蒋2 小时前
实时数据开发|Flink异步IO--提升性能和吞吐量
jvm·数据库·flink·实时数据开发
小麦项目管理指南3 小时前
工程企业需要什么样的财务软件?
大数据·数据库·信息可视化·项目管理
涛思数据(TDengine)3 小时前
解密时序数据库的未来:TDengine Open Day技术沙龙精彩回顾
数据库·时序数据库·tdengine