PostgreSQL事件触发器拦截CREATE TABLE失效问题排查
问题原因分析
你的问题出在对pg_event_trigger_ddl_commands()返回字段的理解偏差上:object_identity字段返回的是包含模式(Schema)前缀的完整对象标识,比如在默认的public模式下,创建t_toto3表时,object_identity的值是public.t_toto3,而非单纯的t_toto3。
你的匹配条件NOT obj.object_identity LIKE 't?_%' ESCAPE '?'是在检查字符串是否以t_开头,但实际字符串以public.开头,导致条件永远为真,每次创建表都会触发异常。
解决方案
你需要使用object_name字段获取不带模式前缀的纯表名,再检查这个字段是否符合命名规则。修改后的完整代码如下:
修改后的函数与触发器
CREATE OR REPLACE FUNCTION e_ddl_create_table_func() RETURNS event_trigger LANGUAGE plpgsql AS $$ DECLARE obj record; BEGIN FOR obj IN SELECT * FROM pg_event_trigger_ddl_commands() WHERE command_tag = 'CREATE TABLE' LOOP -- 用object_name获取纯表名,校验是否以t_开头 IF NOT obj.object_name LIKE 't_%' THEN RAISE EXCEPTION 'The table name must begin with t_'; END IF; END LOOP; END; $$; CREATE EVENT TRIGGER trg_create_table ON ddl_command_end WHEN TAG IN ('CREATE TABLE') EXECUTE PROCEDURE e_ddl_create_table_func();
测试验证
- 执行合法创建语句:
CREATE TABLE t_toto3 (i INT);
此时不会触发异常,表将正常创建。
- 执行非法创建语句:
CREATE TABLE test_table (i INT);
会触发预期的异常:
ERROR: The table name must begin with t_
CONTEXT: fonction PL/pgSQL e_ddl_create_table_func(), ligne 10 à RAISE
补充说明
如果需要同时限制模式下的命名规则(比如要求任意模式下的表名都以t_开头),可以结合object_identity做更复杂的匹配:
IF NOT obj.object_identity LIKE '%.t_%' THEN RAISE EXCEPTION 'The table name must begin with t_ (in any schema)'; END IF;
这个条件会校验任意模式下的表名是否以t_开头。
内容的提问来源于stack exchange,提问作者SQLpro
相关产品推荐
相关产品推荐

