Postgres pg_catalog 常量查找的策略
Strategies for Postgres pg_catalog constant lookups
短版:
我在 pg_catalog 上花费了一些时间,并希望显示使用字符代码的扩展定义。例如 "composite type" 而不是 "c" 用于 pg_class.relkind。我试过自定义函数和查找汤 table。我希望得到一些建议,并可能指出我忽略的明显事情。
Postgres 11.5,部署在 RDS 上(无超级用户。)
更长的版本:
对于我们的项目,我正在编写一些客户端代码生成器和报告屏幕,这意味着我需要深入研究 pg_type、pg_class、pg_attribute 等等。由于我认为是历史原因,pg_catalog 中的许多 table 和列名称是......不透明的。许多字段包含需要查找或记忆的字符代码。例如,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) 数据被烘焙到代码中,而不是数据结构中。所以,你不能以任何方式 reuse/display/validate 它。 2)我需要为每个常量类型定制一个函数。这让我想到了下一个想法,查找汤table。
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;
在进一步讨论之前,我会规定 grab-all 查找 table 通常值得嘲笑 。 不是我会用动态的、用户驱动的数据做的事情。因为不好。太糟了。但在这个狭窄的案例中,这似乎是一个可靠的想法:
数据被烘焙到 Postgres 中,并且只有在主要版本发布时才会更改。
None 这些数据将永远消失,或者至少不太可能。
添加一组新常量非常容易,一旦我 运行 感兴趣。
下面是 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');
由于数据在table中,你可以用正常的方式做正常的事情。或者甚至使用 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 = and
code = ),
'Undefined')
$$ LANGUAGE sql;
ALTER FUNCTION data.lookup (theme text, code text) OWNER TO user_bender;
最后,对目录 table 的查询给出了人类可读的结果:
select relowner::regrole,
relnamespace::regnamespace,
relname,
lookup('relkind',relkind) as relkind_name,
reltype::regtype
from pg_class
从上面你会看到,我找到了一些oid魔法施法工具,还有一些系统信息功能。我希望使用 lookup() 函数来填补一些空白。
如果有评论或建议,我将不胜感激,即使这相当于 "throw all of that out, there's a better way."
作为记录,我检查了自定义类型,magic::castings,CREATE DOMAIN(不适用),ENUM(不适用且不上诉。)我目前正在排除构建一堆自定义视图,因为感觉这会让下一个人更难修改我的代码。 (一个查找函数看起来不太好学。)
您可以按照自己喜欢的方式进行,如果您的味蕾对一次查找的反应更好 table,那就这样吧。
我觉得你的动机部分是为了好玩,因为经过一些接触后,你将能够轻松记住常用的单字母代码。
在这种情况下,我建议多玩一些类型:
您可以创建一个自定义类型,其内部表示与 "char"
一样,但类型输出函数会生成长描述。类型输入函数将理解单个字符串和长名称。
relkind
和其他短代码会有这样的类型。
然后在 "char"
和新类型之间创建 IMPLICIT
强制转换 WITHOUT FUNCTION
。如果需要,您还可以创建 (EXPLICIT
) 到 text
.
的强制转换
整个过程与 regclass
、regtype
和相关的便利类型非常相似。
如果不出意外,这是一篇很好的介绍如何破解 PostgreSQL 的文章。
短版: 我在 pg_catalog 上花费了一些时间,并希望显示使用字符代码的扩展定义。例如 "composite type" 而不是 "c" 用于 pg_class.relkind。我试过自定义函数和查找汤 table。我希望得到一些建议,并可能指出我忽略的明显事情。
Postgres 11.5,部署在 RDS 上(无超级用户。)
更长的版本: 对于我们的项目,我正在编写一些客户端代码生成器和报告屏幕,这意味着我需要深入研究 pg_type、pg_class、pg_attribute 等等。由于我认为是历史原因,pg_catalog 中的许多 table 和列名称是......不透明的。许多字段包含需要查找或记忆的字符代码。例如,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) 数据被烘焙到代码中,而不是数据结构中。所以,你不能以任何方式 reuse/display/validate 它。 2)我需要为每个常量类型定制一个函数。这让我想到了下一个想法,查找汤table。
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;
在进一步讨论之前,我会规定 grab-all 查找 table 通常值得嘲笑 。 不是我会用动态的、用户驱动的数据做的事情。因为不好。太糟了。但在这个狭窄的案例中,这似乎是一个可靠的想法:
数据被烘焙到 Postgres 中,并且只有在主要版本发布时才会更改。
None 这些数据将永远消失,或者至少不太可能。
添加一组新常量非常容易,一旦我 运行 感兴趣。
下面是 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');
由于数据在table中,你可以用正常的方式做正常的事情。或者甚至使用 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 = and
code = ),
'Undefined')
$$ LANGUAGE sql;
ALTER FUNCTION data.lookup (theme text, code text) OWNER TO user_bender;
最后,对目录 table 的查询给出了人类可读的结果:
select relowner::regrole,
relnamespace::regnamespace,
relname,
lookup('relkind',relkind) as relkind_name,
reltype::regtype
from pg_class
从上面你会看到,我找到了一些oid魔法施法工具,还有一些系统信息功能。我希望使用 lookup() 函数来填补一些空白。
如果有评论或建议,我将不胜感激,即使这相当于 "throw all of that out, there's a better way."
作为记录,我检查了自定义类型,magic::castings,CREATE DOMAIN(不适用),ENUM(不适用且不上诉。)我目前正在排除构建一堆自定义视图,因为感觉这会让下一个人更难修改我的代码。 (一个查找函数看起来不太好学。)
您可以按照自己喜欢的方式进行,如果您的味蕾对一次查找的反应更好 table,那就这样吧。
我觉得你的动机部分是为了好玩,因为经过一些接触后,你将能够轻松记住常用的单字母代码。
在这种情况下,我建议多玩一些类型:
您可以创建一个自定义类型,其内部表示与 "char"
一样,但类型输出函数会生成长描述。类型输入函数将理解单个字符串和长名称。
relkind
和其他短代码会有这样的类型。
然后在 "char"
和新类型之间创建 IMPLICIT
强制转换 WITHOUT FUNCTION
。如果需要,您还可以创建 (EXPLICIT
) 到 text
.
整个过程与 regclass
、regtype
和相关的便利类型非常相似。
如果不出意外,这是一篇很好的介绍如何破解 PostgreSQL 的文章。