PostgreSQL系统表或视图中pg_node_tree类型值解析

莱莱  论坛元老 | 2024-11-12 20:48:11 | 显示全部楼层 | 阅读模式
打印 上一主题 下一主题

主题 1868|帖子 1868|积分 5604

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

x
PostgreSQL系统表或视图中pg_node_tree类型值解析

pg_node_tree类型阐明

pg_node_tree是一种openGauss/PostgreSQL内部数据类型,用于表现树形结构的数据。这个数据类型通常对用户不可见,因此直接查询或操纵它的内容通常必要使用一些PostgreSQL的内置函数或工具。
包含pg_node_tree类型的系统视图/表,以pg12版本为例:
  1. postgres=# select table_schema,table_name,column_name from information_schema.columns where data_type = 'pg_node_tree';
  2. table_schema |      table_name      |  column_name
  3. --------------+----------------------+----------------
  4. pg_catalog   | pg_proc              | proargdefaults
  5. pg_catalog   | pg_type              | typdefaultbin
  6. pg_catalog   | pg_class             | relpartbound
  7. pg_catalog   | pg_attrdef           | adbin
  8. pg_catalog   | pg_constraint        | conbin
  9. pg_catalog   | pg_index             | indexprs
  10. pg_catalog   | pg_index             | indpred
  11. pg_catalog   | pg_rewrite           | ev_qual
  12. pg_catalog   | pg_rewrite           | ev_action
  13. pg_catalog   | pg_trigger           | tgqual
  14. pg_catalog   | pg_policy            | polqual
  15. pg_catalog   | pg_policy            | polwithcheck
  16. pg_catalog   | pg_partitioned_table | partexprs
  17. (13 rows)
  18. postgres=#
复制代码
解析对应关系
系统表/视图字段名解析使用表达式pg_procproargdefaultspg_get_expr(proargdefaults,'pg_proc'::regclass)
pg_get_function_arguments(oid)pg_typetypdefaultbinpg_classrelpartboundpg_get_expr(relpartbound,oid)pg_attrdefadbinpg_get_expr(adbin,adrelid)pg_constraintconbinpg_get_expr(conbin,conrelid)
pg_get_constraintdef(oid)pg_indexindexprspg_get_expr(indexprs,indrelid)pg_indexindpredpg_get_expr(indpred,indrelid)pg_rewriteev_qualpg_rewriteev_actionpg_triggertgqualpg_get_triggerdef(oid)pg_policypolqualpg_policypolwithcheckpg_partitioned_tablepartexprspg_get_expr(partexprs,partrelid)pg_node_tree类型值解析

对于存储再pg_node_tree类型中的数据,可以使用pg_get_expr()函数将其转换为可读的SQL表达式。这个函数将抽象的树形结构转换为一个人类可读的SQL表达式形式。
pg_get_expr函数阐明:
  1. pg_get_expr(pg_node_tree, relation_oid)
  2. pg_get_expr(pg_node_tree, relation_oid, pretty_bool)
  3. 返回类型:text
复制代码
反编译一个表达式的内部形式,假定其中的任何 Var 指向由第二个参数指示的关系
解析pg_attrdef.adbin

pg_attrdef存储列的默认值。列的主要信息存储在pg_attribute。只有那些显式指定了一个默认值的列才会在这个目录中有一个项。
  1. -- 创建测试表
  2. drop table if exists test_t;
  3. create table test_t (id int,name varchar(20) default 'test',update_time timestamp default current_timestamp);
  4. -- 原查询结果
  5. select t1.adrelid::regclass,t2.attname,adbin
  6. from pg_attrdef t1
  7. join pg_attribute t2 on t1.adrelid=t2.attrelid and t1.adnum=t2.attnum
  8. where t2.attnum>0
  9.       and t1.adrelid::regclass::text='test_t';
  10. -[ RECORD 1 ]------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  11. adrelid | test_t
  12. attname | name
  13. adbin   | {FUNCEXPR :funcid 669 :funcresulttype 1043 :funcretset false :funcvariadic false :funcformat 2 :funccollid 100 :inputcollid 100 :args ({CONST :consttype 1043 :consttypmod -1 :constcollid 100 :constlen -1 :constbyval false :constisnull false :location 53 :constvalue 8 [ 32 0 0 0 116 101 115 116 ]} {CONST :consttype 23 :consttypmod -1 :constcollid 0 :constlen 4 :constbyval true :constisnull false :location -1 :constvalue 4 [ 24 0 0 0 0 0 0 0 ]} {CONST :consttype 16 :consttypmod -1 :constcollid 0 :constlen 1 :constbyval true :constisnull false :location -1 :constvalue 1 [ 0 0 0 0 0 0 0 0 ]}) :location -1}
  14. -[ RECORD 2 ]------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  15. adrelid | test_t
  16. attname | update_time
  17. adbin   | {FUNCEXPR :funcid 2027 :funcresulttype 1114 :funcretset false :funcvariadic false :funcformat 2 :funccollid 0 :inputcollid 0 :args ({SQLVALUEFUNCTION :op 3 :type 1184 :typmod -1 :location 90}) :location -1}
  18. -- 解析后
  19. select t1.adrelid::regclass,t2.attname,pg_get_expr(adbin,t1.adrelid)
  20. from pg_attrdef t1
  21. join pg_attribute t2 on t1.adrelid=t2.attrelid and t1.adnum=t2.attnum
  22. where t2.attnum>0
  23.       and t1.adrelid::regclass::text='test_t';
  24. adrelid |   attname   |        pg_get_expr
  25. ---------+-------------+---------------------------
  26. test_t  | name        | 'test'::character varying
  27. test_t  | update_time | CURRENT_TIMESTAMP
  28. (2 rows)      
复制代码
解析pg_proc.proargdefaults
  1. -- 创建测试函数
  2. CREATE OR REPLACE FUNCTION test_fun(
  3.     arg1 INTEGER,
  4.     arg2 INTEGER DEFAULT 0,
  5.     arg3 TEXT DEFAULT 'default_value'
  6. )
  7. RETURNS INTEGER
  8. AS $$
  9. BEGIN
  10.     RETURN arg1 + arg2;
  11. END;
  12. $$ LANGUAGE plpgsql;
  13. -- 正常查询
  14. postgres=# select proargdefaults from pg_proc where proname = 'test_fun';
  15.                                         proargdefaults
  16. -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  17. ({CONST :consttype 23 :consttypmod -1 :constcollid 0 :constlen 4 :constbyval true :constisnull false :location 80 :constvalue 4 [ 0 0 0 0 0 0 0 0 ]} {CONST :consttype 25 :consttypmod -1 :constcollid 100 :constlen -1 :constbyval false :constisnull false :location 105 :constvalue 17 [ 68 0 0 0 100 101 102 97 117 108 116 95 118 97 108 117 101 ]})
  18. (1 row)
  19. postgres=#
  20. -- 解析后
  21. postgres=# select pg_get_expr(proargdefaults,'pg_proc'::regclass) from pg_proc where proname = 'test_fun';
  22.        pg_get_expr
  23. --------------------------
  24. 0, 'default_value'::text
  25. (1 row)
  26. -- 或者
  27. postgres=# select proname,pg_get_function_arguments(oid) from pg_proc where proname = 'test_fun';
  28. proname  |                           pg_get_function_arguments
  29. ----------+-------------------------------------------------------------------------------
  30. test_fun | arg1 integer, arg2 integer DEFAULT 0, arg3 text DEFAULT 'default_value'::text
  31. (1 row)
复制代码
解析pg_index.indexprs和pg_index.indpred
  1. -- 创建测试表和索引
  2. drop table if exists test_t;
  3. create table test_t(id int,name varchar(100));
  4. create index idx_name on test_t(lower(name)) where id >=100000;
  5. -- 查询
  6. select t3.relname as tablename,
  7.        t1.relname as indexname,
  8.        t2.indexprs,t2.indpred
  9.    from pg_class t1
  10.   join pg_index t2 on t1.oid=t2.indexrelid
  11.   join pg_class t3 on t3.oid=t2.indrelid
  12. where t3.relname = 'test_t';
  13. -- 原值
  14. tablename | test_t
  15. indexname | idx_name
  16. indexprs  | ({FUNCEXPR :funcid 870 :funcresulttype 25 :funcretset false :funcvariadic false :funcformat 0 :funccollid 100 :inputcollid 100 :args ({RELABELTYPE :arg {VAR :varno 1 :varattno 2 :vartype 1043 :vartypmod 104 :varcollid 100 :varlevelsup 0 :varnoold 1 :varoattno 2 :location 38} :resulttype 25 :resulttypmod -1 :resultcollid 100 :relabelformat 2 :location -1}) :location 32})
  17. indpred   | {OPEXPR :opno 525 :opfuncid 150 :opresulttype 16 :opretset false :opcollid 0 :inputcollid 0 :args ({VAR :varno 1 :varattno 1 :vartype 23 :vartypmod -1 :varcollid 0 :varlevelsup 0 :varnoold 1 :varoattno 1 :location 51} {CONST :consttype 23 :consttypmod -1 :constcollid 0 :constlen 4 :constbyval true :constisnull false :location 56 :constvalue 4 [ -96 -122 1 0 0 0 00 ]}) :location 54}
  18. -- 解析后的值
  19. select t3.relname as tablename,
  20.        t1.relname as indexname,
  21.        pg_get_expr(t2.indexprs,indrelid),
  22.        pg_get_expr(t2.indpred,indrelid)
  23.    from pg_class t1
  24.   join pg_index t2 on t1.oid=t2.indexrelid
  25.   join pg_class t3 on t3.oid=t2.indrelid
  26. where t3.relname = 'test_t';
  27. tablename | indexname |     pg_get_expr     |  pg_get_expr
  28. -----------+-----------+---------------------+----------------
  29. test_t    | idx_name  | lower((name)::text) | (id >= 100000)
  30. (1 row)
复制代码
解析pg_class.relpartbound
  1. -- 创建分区表
  2. CREATE TABLE test_range_t (id serial,date timestamp(6),data TEXT) PARTITION BY RANGE (date);
  3. CREATE TABLE test_range_2020 PARTITION OF test_range_t FOR VALUES FROM ('2020-01-01') TO ('2021-01-01');
  4. CREATE TABLE test_range_2021 PARTITION OF test_range_t FOR VALUES FROM ('2021-01-01') TO ('2022-01-01');
  5. CREATE TABLE test_range_2022 PARTITION OF test_range_t FOR VALUES FROM ('2022-01-01') TO ('2023-01-01');
  6. CREATE TABLE test_range_2023 PARTITION OF test_range_t FOR VALUES FROM ('2023-01-01') TO ('2024-01-01');
  7. -- 某一个分区的值查询
  8. postgres=# select relname,relpartbound from pg_class where relname = 'test_range_2020';
  9. -[ RECORD 1 ]+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  10. relname      | test_range_2020
  11. relpartbound | {PARTITIONBOUNDSPEC :strategy r :is_default false :modulus 0 :remainder 0 :listdatums <> :lowerdatums ({PARTITIONRANGEDATUM :kind 0 :value {CONST :consttype 1114 :consttypmod 6 :constcollid 0 :constlen 8 :constbyval true :constisnull false :location -1 :constvalue 8 [ 0 96 -62 -122 7 62 2 0 ]} :location 72}) :upperdatums ({PARTITIONRANGEDATUM :kind 0 :value {CONST :consttype 1114 :consttypmod 6 :constcollid 0 :constlen 8 :constbyval true :constisnull false :location -1 :constvalue 8 [0 -96 -83 48 -54 90 2 0 ]} :location 90}) :location 66}
  12. -- 解析后
  13. postgres=# select relname,pg_get_expr(relpartbound,oid) from pg_class where relname ~ 'test_range_\d+';
  14.      relname     |                            pg_get_expr
  15. -----------------+--------------------------------------------------------------------
  16. test_range_2020 | FOR VALUES FROM ('2020-01-01 00:00:00') TO ('2021-01-01 00:00:00')
  17. test_range_2021 | FOR VALUES FROM ('2021-01-01 00:00:00') TO ('2022-01-01 00:00:00')
  18. test_range_2022 | FOR VALUES FROM ('2022-01-01 00:00:00') TO ('2023-01-01 00:00:00')
  19. test_range_2023 | FOR VALUES FROM ('2023-01-01 00:00:00') TO ('2024-01-01 00:00:00')
  20. (4 rows)
复制代码
解析pg_constraint.conbin
  1. drop table if exists test_t;
  2. create table test_t (id int,name varchar(100),check(id>0),check(length(name)>3));
  3. -- 原值查询
  4. select connamespace::regnamespace as schema,
  5.        conrelid::regclass as tablename,
  6.            contype,
  7.            conname,
  8.            conbin
  9. from pg_constraint where conrelid::regclass::text='test_t';
  10. -[ RECORD 1 ]------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  11. schema    | public
  12. tablename | test_t
  13. contype   | c
  14. conname   | test_t_id_check
  15. conbin    | {OPEXPR :opno 521 :opfuncid 147 :opresulttype 16 :opretset false :opcollid 0 :inputcollid 0 :args ({VAR :varno 1 :varattno 1 :vartype 23 :vartypmod -1 :varcollid 0 :varlevelsup 0 :varnoold 1 :varoattno 1 :location 52} {CONST :consttype 23 :consttypmod -1 :constcollid 0 :constlen 4 :constbyval true :constisnull false :location 55 :constvalue 4 [ 0 0 0 0 0 0 0 0 ]}) :location 54}
  16. -[ RECORD 2 ]------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  17. schema    | public
  18. tablename | test_t
  19. contype   | c
  20. conname   | test_t_name_check
  21. conbin    | {OPEXPR :opno 521 :opfuncid 147 :opresulttype 16 :opretset false :opcollid 0 :inputcollid 0 :args ({FUNCEXPR :funcid 1317 :funcresulttype 23 :funcretset false :funcvariadic false :funcformat 0 :funccollid 0 :inputcollid 100 :args ({RELABELTYPE :arg {VAR :varno 1 :varattno 2 :vartype 1043 :vartypmod 104 :varcollid 100 :varlevelsup 0 :varnoold 1 :varoattno 2 :location 71} :resulttype 25 :resulttypmod -1 :resultcollid 100 :relabelformat 2 :location -1}) :location 64} {CONST :consttype 23 :consttypmod -1 :constcollid 0 :constlen 4 :constbyval true :constisnull false :location 77 :constvalue 4 [ 3 0 0 0 0 0 0 0 ]}) :location 76}
  22. -- 解析后
  23. select connamespace::regnamespace as schema,
  24.        conrelid::regclass as tablename,
  25.            contype,
  26.            conname,
  27.            pg_get_expr(conbin,conrelid)
  28. from pg_constraint where conrelid::regclass::text='test_t';
  29. schema | tablename | contype |      conname      |        pg_get_expr
  30. --------+-----------+---------+-------------------+----------------------------
  31. public | test_t    | c       | test_t_id_check   | (id > 0)
  32. public | test_t    | c       | test_t_name_check | (length((name)::text) > 3)
  33. (2 rows)
  34. -- 或者
  35. select connamespace::regnamespace as schema,
  36.        conrelid::regclass as tablename,
  37.            contype,
  38.            conname,
  39.            pg_get_constraintdef(oid)
  40. from pg_constraint where conrelid::regclass::text='test_t';
  41. schema | tablename | contype |      conname      |        pg_get_constraintdef
  42. --------+-----------+---------+-------------------+------------------------------------
  43. public | test_t    | c       | test_t_id_check   | CHECK ((id > 0))
  44. public | test_t    | c       | test_t_name_check | CHECK ((length((name)::text) > 3))
  45. (2 rows)
复制代码
解析pg_partitioned_table.partexprs
  1. CREATE TABLE sales (
  2.     id SERIAL,
  3.     sale_date DATE NOT NULL,
  4.     amount NUMERIC NOT NULL,
  5.     region TEXT NOT NULL
  6. ) PARTITION BY RANGE (EXTRACT(YEAR FROM sale_date));
  7. CREATE TABLE sales_2022 PARTITION OF sales FOR VALUES FROM (2022) TO (2023);
  8. CREATE TABLE sales_2023 PARTITION OF sales FOR VALUES FROM (2023) TO (2024);
  9. CREATE TABLE sales_2024 PARTITION OF sales FOR VALUES FROM (2024) TO (2025);
  10. -- 原值
  11. postgres=# select partrelid::regclass,partexprs from pg_partitioned_table where partrelid::regclass::text='sales';
  12. -[ RECORD 1 ]------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  13. partrelid | sales
  14. partexprs | ({FUNCEXPR :funcid 1384 :funcresulttype 701 :funcretset false :funcvariadic false :funcformat 0 :funccollid 0 :inputcollid 100 :args ({CONST :consttype 25 :consttypmod -1 :constcollid 100 :constlen -1 :constbyval false :constisnull false :location 149 :constvalue 8 [ 32 0 0 0 121 101 97 114 ]} {VAR :varno 1 :varattno 2 :vartype 1082 :vartypmod -1 :varcollid 0 :varlevelsup 0 :varnoold 1 :varoattno 2 :location 159}) :location 141})
  15. -- 解析后
  16. postgres=# select partrelid::regclass,pg_get_expr(partexprs,partrelid) from pg_partitioned_table where partrelid::regclass::text='sales';
  17. partrelid |            pg_get_expr
  18. -----------+------------------------------------
  19. sales     | date_part('year'::text, sale_date)
  20. (1 row)
复制代码
 注意:date_part函数等价与extract 
  1. postgres=# select extract(year from now()) as extract,date_part('year'::text,now()) as date_part;
  2. extract | date_part
  3. ---------+-----------
  4.     2024 |      2024
  5. (1 row)
  6. postgres=# select extract(year from current_date) as extract,date_part('year'::text,current_date) as date_part;
  7. extract | date_part
  8. ---------+-----------
  9.     2024 |      2024
  10. (1 row)
复制代码
解析pg_trigger.tgqual
  1. -- 创建order表
  2. CREATE TABLE orders (
  3.     id SERIAL PRIMARY KEY,
  4.     order_date DATE NOT NULL,
  5.     amount NUMERIC NOT NULL,
  6.     customer_name VARCHAR(100)
  7. );
  8. -- audit_log表
  9. CREATE TABLE audit_log (
  10.     id SERIAL PRIMARY KEY,
  11.     order_id INT,
  12.     action VARCHAR(50),
  13.     log_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP
  14. );
  15. -- 创建触发器函数
  16. CREATE OR REPLACE FUNCTION log_high_value_order()
  17. RETURNS TRIGGER AS $$
  18. BEGIN
  19.     -- 检查订单金额是否超过 1000
  20.     IF NEW.amount > 1000 THEN
  21.         -- 插入审计日志
  22.         INSERT INTO audit_log (order_id, action)
  23.         VALUES (NEW.id, 'High Value Order');
  24.     END IF;
  25.     RETURN NEW;
  26. END;
  27. $$ LANGUAGE plpgsql;
  28. -- 创建带有条件的触发器
  29. CREATE TRIGGER high_value_order_trigger
  30. AFTER INSERT ON orders
  31. FOR EACH ROW
  32. WHEN (NEW.amount > 1000)
  33. EXECUTE FUNCTION log_high_value_order();
复制代码
查询触发器信息
  1. -- 原值
  2. postgres=# select tgrelid::regclass,tgname,tgqual from pg_trigger where tgrelid::regclass::text='orders';
  3. -[ RECORD 1 ]--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  4. tgrelid | orders
  5. tgname  | high_value_order_trigger
  6. tgqual  | {OPEXPR :opno 1756 :opfuncid 1720 :opresulttype 16 :opretset false :opcollid 0 :inputcollid 0 :args ({VAR :varno 2 :varattno 3 :vartype 1700 :vartypmod -1 :varcollid 0 :varlevelsup 0 :varnoold 2 :varoattno 3 :location 82} {FUNCEXPR :funcid 1740 :funcresulttype 1700 :funcretset false :funcvariadic false :funcformat 2 :funccollid 0 :inputcollid 0 :args ({CONST :consttype 23 :consttypmod -1 :constcollid 0 :constlen 4 :constbyval true :constisnull false :location 95 :constvalue 4 [ -24 3 0 0 0 0 0 0 ]}) :location -1}) :location 93}
  7. -- 解析后
  8. postgres=# select tgrelid::regclass,tgname,pg_get_triggerdef(oid) as trigger_definition from pg_trigger where tgrelid::regclass::text='orders';
  9. -[ RECORD 1 ]------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------
  10. tgrelid            | orders
  11. tgname             | high_value_order_trigger
  12. trigger_definition | CREATE TRIGGER high_value_order_trigger AFTER INSERT ON public.orders FOR EACH ROW WHEN ((new.amount > (1000)::numeric)) EXECUTE FUNCTION log_high_value_order()
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

莱莱

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表