【发布时间】:2019-09-05 03:38:23
【问题描述】:
短版: 我在 pg_catalog 中花费了一些时间,并希望显示使用 char 代码的扩展定义。例如 pg_class.relkind 的“复合类型”而不是“c”。我尝试过自定义函数和查找汤表。我希望得到一些建议,并且很可能会指出我忽略的明显事情。
Postgres 11.5,在 RDS 上部署(无超级用户。)
加长版: 对于我们的项目,我正在编写相当多的客户端代码生成器和报告屏幕,这意味着我需要深入研究 pg_type、pg_class、pg_attribute 等等。由于我认为是历史原因,pg_catalog 中的许多表名和列名都是....不透明的。并且大量字段包括需要查找或记忆的字符代码。例如,pg_class.relkind 保存值 I、S、c、f、i、m、p、r、t 或 v 之一。嗯?我可以记住这些含义并在脑海中翻译它们,但这是计算机可以更轻松地完成的事情。所以,我想我会写一个函数:
CREATE OR REPLACE FUNCTION data.relkind_name (relkind text, out relkind_name text)
RETURNS text
AS $$
SELECT CASE
WHEN relkind = 'r' THEN 'table'
WHEN relkind = 'i' THEN 'index'
WHEN relkind = 'S' THEN 'sequence'
WHEN relkind = 't' THEN 'TOAST table'
WHEN relkind = 'v' THEN 'view'
WHEN relkind = 'm' THEN 'materialized view'
WHEN relkind = 'c' THEN 'composite type'
WHEN relkind = 'f' THEN 'foreign table'
WHEN relkind = 'p' THEN 'partitioned table'
WHEN relkind = 'I' THEN 'partitioned index'
ELSE 'Unexpected relkind ' || relkind
END;
$$ LANGUAGE sql;
ALTER FUNCTION data.relkind_name (relkind text, out relkind_name text) OWNER TO user_bender;
那……很好。它可以工作,但我不喜欢这样的函数,原因有两个: 1)数据被写入代码,而不是数据结构。因此,您不能以任何方式重用/显示/验证它。 2)我需要为每个常量类型提供一个自定义函数。这让我想到了下一个想法,查找汤表。
BEGIN;
DROP TABLE IF EXISTS data.constant CASCADE;
CREATE TABLE IF NOT EXISTS data.constant (
theme text NOT NULL DEFAULT NULL,
code text NOT NULL DEFAULT NULL,
label text NOT NULL DEFAULT NULL,
PRIMARY KEY (theme, code)
);
ALTER TABLE data.constant OWNER TO user_change_structure;
COMMIT;
在继续之前,我将规定抓取所有查找表通常值得嘲笑。这不是我会用动态的、用户驱动的数据做的事情。因为不好。太糟了。但在这个狭隘的案例中,这似乎是一个可靠的想法:
数据被烘焙到 Postgres 中,并且仅在主要版本中发生变化。
这些数据都不会消失,或者至少不会消失。
一旦我遇到感兴趣的事情,添加一组新常量非常容易。
以下是 pg_catalog 中几个常量列表的一些设置:
INSERT INTO constant
(theme,code,label)
VALUES
('typcategory','A','Array types'),
('typcategory','B','Boolean types'),
('typcategory','C','Composite types'),
('typcategory','D','Date/time types'),
('typcategory','E','Enum types'),
('typcategory','G','Geometric types'),
('typcategory','I','Network address types'),
('typcategory','N','Numeric types'),
('typcategory','P','Pseudo-types'),
('typcategory','R','Range types'),
('typcategory','S','String types'),
('typcategory','T','Timespan types'),
('typcategory','U','User-defined types'),
('typcategory','V','Bit-string types'),
('typcategory','X','unknown type'),
('relkind','r','ordinary table'),
('relkind','i','index'),
('relkind','S','sequence'),
('relkind','t','TOAST table'),
('relkind','v','view'),
('relkind','m','materialized view'),
('relkind','c','composite type'),
('relkind','f','foreign table'),
('relkind','p','partitioned table'),
('relkind','I','partitioned index');
由于数据在表格中,您可以以正常的方式做正常的事情。甚至可以使用 Postgres 美妙的 string_agg 函数:
select theme,
string_agg(code, ', ' order by code) as constants
from constant
group by theme
order by theme;
relkind I, S, c, f, i, m, p, r, t, v
typcategory A, B, C, D, E, G, I, N, P, R, S, T, U, V, X
或者一个简单的查询来进行查找:
-- I want a default/error result label if there is no match.
select coalesce((select label from constant where theme = 'relkind' and code = 'X'),
'Undefined')
可以封装成函数:
DROP FUNCTION IF EXISTS data.lookup (theme text, code text);
CREATE OR REPLACE FUNCTION data.lookup (theme text, code text)
RETURNS TEXT
AS $$
-- I want a default/error result label if there is no match, hence the subquery.
select coalesce(
(select label
from constant
where theme = $1 and
code = $2),
'Undefined')
$$ LANGUAGE sql;
ALTER FUNCTION data.lookup (theme text, code text) OWNER TO user_bender;
然后,最后,对目录表进行查询,得到人类可读的结果:
select relowner::regrole,
relnamespace::regnamespace,
relname,
lookup('relkind',relkind) as relkind_name,
reltype::regtype
from pg_class
从上面你会看到,我发现了一些oid魔法施法工具,以及一些系统信息函数。我正在寻找使用 lookup() 函数来填补一些空白。
如果您提出评论或建议,我将不胜感激,即使这相当于“抛弃所有这些,有更好的方法”。
为了记录,我检查了自定义类型,magic::castings,CREATE DOMAIN(不适用),ENUM(不适用并且不上诉。)我目前正在排除构建一堆自定义视图,因为感觉这样会让下一个人更难修改我的代码。 (一个查找功能似乎不太好学。)
【问题讨论】:
-
我会选择第一个函数(出于性能原因将其定义为
immutable)。与其他解决方案相比,更易于维护、更易于理解且代码更少。我不明白为什么它不应该是“可重复使用的”
标签: postgresql catalog