从任意 %ROWTYPE 或 RECORD 值获取 table-name

Get table-name from an arbitrary %ROWTYPE or RECORD value

所需设置

为了提高某些代码的优雅,我想知道是否was/is可以做与%ROWTYPE variable from table name相反的事情——提取一个table's name from a %ROWTYPE or RECORD (最相关的是,在它被传递到一个函数之后接受 ANYELEMENT 伪类型):

CREATE OR REPLACE FUNCTION generic_function(row_data ANYELEMENT)
RETURNS INT AS $$
DECLARE
    table_name TEXT = get_table_name(row_data);
BEGIN
    -- [ work goes here ]
END;
$$ LANGUAGE plpgsql;

当前解决方法

CREATE OR REPLACE FUNCTION generic_function(row_data ANYELEMENT, table_name TEXT) 
RETURNS INT AS $$
BEGIN
    -- [ work goes here ]
END;
$$ LANGUAGE plpgsql;

解决方法感觉 有点 多余,如果您能想象它在调用代码中的样子:

SELECT INTO x * FROM mytable WHERE foo = bar; 
PERFORM generic_function(x,'mytable');

优雅但愚蠢的解决方案

为了允许我在顶部显示呼叫签名,我能想到的最佳解决方案是高开销的猜测和检查方法,这可能是 非常 在生产中使用的坏主意。你可以找到 sqlfiddle here.

plpgsql 级别没有任何解决方案。从理论上讲,您可以在 C 扩展的某些情况下这样做,但代码会非常复杂。 Postgres,PLpgSQL 被设计为静态的,类型严格的环境——动态的 SQL 不会改变太多(设计更喜欢速度,更少的内存使用)。只是不要在 Postgres 中设计过于动态的代码。

有一个简单的解决方案。使用 pg_typeof():

CREATE OR REPLACE FUNCTION generic_function(row_data ANYELEMENT)
  RETURNS text AS
$func$
DECLARE
   table_name text := pg_typeof();
BEGIN
   RETURN table_name;
END
$func$ LANGUAGE plpgsql;

显然,这只适用于已注册的复合类型。 每个 table 或视图都属于这一类。但是没有导出tables.

测试:

CREATE TEMP TABLE foo (id int);
SELECT generic_function(NULL::foo);

Here is a search for related answers.