You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PostgreSQL触发器调用自定义函数报42601语法错误及解决

问题场景

我定义了以下自定义函数:

CREATE or replace FUNCTION get_column_names(param text) 
    RETURNS text AS $get_column_names$
    DECLARE
        return_value text;
        x record;
        y int;
    begin
    return_value := '';
    y := 0;
    for x in SELECT *
        FROM information_schema.columns
        WHERE table_schema = 'public'
        AND table_name   = param 
        ORDER BY ordinal_position
    loop
        if (y = 0)
            then 
            return_value = x.column_name;
        else
            return_value := return_value ||','|| x.column_name;
        end if; 
        Y = Y+1;
    end loop;
    return return_value;
END;
$get_column_names$ LANGUAGE plpgsql;

单独调用该函数可以正常工作:

select get_column_names('users');

返回结果:

first_name,middle_name,last_name,gender,locale,auth_user_id,identity_id,active,date_created,provisioned,user_id,timezone,last_seen

但在触发器函数中调用它时触发错误,触发器函数代码如下:

CREATE OR REPLACE FUNCTION process_users_audit() RETURNS TRIGGER AS $users_audit$
    BEGIN
        --
        -- 在users_audit表中插入一行,记录users表上执行的操作
        --
        IF (TG_OP = 'DELETE') THEN
            INSERT INTO users_audit (user_audit_id, stamp, operation, db_user, get_column_names(TG_TABLE_NAME)) values (uuid_generate_v4(), now(), 'D', user, OLD.*);
            RETURN OLD;
        ELSIF (TG_OP = 'UPDATE') THEN
            INSERT INTO users_audit (user_audit_id, stamp, operation, db_user, get_column_names(TG_TABLE_NAME)) values (uuid_generate_v4(), now(), 'U', user, NEW.*);
            RETURN NEW;
        ELSIF (TG_OP = 'INSERT') THEN
            INSERT INTO users_audit (user_audit_id, stamp, operation, db_user, get_column_names(TG_TABLE_NAME)) values (uuid_generate_v4(), now(), 'I', user, NEW.*);
            RETURN NEW;
        END IF;
        RETURN NULL; -- 因为是AFTER触发器,返回结果会被忽略
    END;
$users_audit$ LANGUAGE plpgsql;

收到的错误信息:

SQL Error [42601]: ERROR: syntax error at or near "("
  Position: 406
解决方案(更新)

调整@Ed Brook的方案后生效,主要修改了NEW的使用方式。可行代码如下:

CREATE OR REPLACE FUNCTION process_audit_table() RETURNS TRIGGER AS $audit_table$
    BEGIN
        --
        -- 在对应表的审计表中插入一行,记录原表上执行的操作,
        -- 利用特殊变量TG_OP判断操作类型
        --
        IF (TG_OP = 'DELETE') then
            EXECUTE 'INSERT INTO ' || concat(TG_TABLE_NAME, '_audit') || ' (' || get_primary_key_name(concat(TG_TABLE_NAME, '_audit')) || ', stamp, operation, db_user, ' || get_column_names(TG_TABLE_NAME) || ') values (uuid_generate_v4(), now(), ''D'', user, $1.*);'
            USING OLD;
        ELSIF (TG_OP = 'UPDATE') then
            EXECUTE 'INSERT INTO ' || concat(TG_TABLE_NAME, '_audit') || ' (' || get_primary_key_name(concat(TG_TABLE_NAME, '_audit')) || ', stamp, operation, db_user, ' || get_column_names(TG_TABLE_NAME) || ') values (uuid_generate_v4(), now(), ''U'', user, $1.*);'
            USING NEW;
        ELSIF (TG_OP = 'INSERT') then
            EXECUTE 'INSERT INTO ' || concat(TG_TABLE_NAME, '_audit') || ' (' || get_primary_key_name(concat(TG_TABLE_NAME, '_audit')) || ', stamp, operation, db_user, ' || get_column_names(TG_TABLE_NAME) || ') values (uuid_generate_v4(), now(), ''I'', user, $1.*);'
            USING NEW;
        END IF;
        RETURN NULL; -- 因为是AFTER触发器,返回结果会被忽略
    END;
$audit_table$ LANGUAGE plpgsql;

同时新增了动态获取审计表主键的逻辑,对应的get_primary_key_name函数代码:

CREATE OR REPLACE FUNCTION get_primary_key_name(table_name text) 
    RETURNS text AS $primary_key_name$
    DECLARE 
        return_value text;
    BEGIN 
        SELECT pg_attribute.attname INTO return_value
        FROM pg_index, pg_class, pg_attribute, pg_namespace 
        WHERE pg_class.oid = table_name::regclass
            AND indrelid = pg_class.oid
            AND nspname = 'public'
            AND pg_class.relnamespace = pg_namespace.oid 
            AND pg_attribute.attrelid = pg_class.oid  
            AND pg_attribute.attnum = any(pg_index.indkey)
            AND indisprimary;
        RETURN return_value;
    END
$primary_key_name$ LANGUAGE plpgsql;

内容的提问来源于stack exchange,提问作者gmaniac

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.02 18:01:29