【openGauss】如何通过pg_trigger.tgtype获取触发器的各种触发条件

前言

最近有客户反馈兼容的dba_triggers视图中,同一个触发器的trigger_event被拆成了多行,和ORACLE中表现不一致,于是我进行了一些分析,发现是在其引用的information_schema.triggers视图中就已经拆开成了INSERT/DELETE/UPDATE,但是这些属性都是通过tgtype这一个int2整型的字段获取的,甚至连before/after/instead of/row/statement 等都是通过这一个字段。一个值存多种信息,这在ORACLE的数据字典视图里很常见,无非就是按二进制位来判断,于是我尝试自己猜一猜,看能不能从这个数字中识别出规律。

测试和分析

先建一堆测试触发器

create schema test1;
create schema test2;CREATE TABLE test1.test_trigger_src_tbl(id1 INT, id2 INT, id3 INT);CREATE OR REPLACE FUNCTION test1.tri_test_func() RETURNS TRIGGER AS$$DECLAREBEGININSERT INTO test_trigger_des_tbl VALUES(NEW.id1, NEW.id2, NEW.id3);RETURN NEW;END$$ LANGUAGE PLPGSQL;--before insert/update row
CREATE TRIGGER test_triggerBEFORE insert or update ON test1.test_trigger_src_tblFOR EACH ROWEXECUTE PROCEDURE test1.tri_test_func();CREATE TABLE test2.test_trigger_src_tbl(id1 INT, id2 INT, id3 INT);CREATE OR REPLACE FUNCTION test2.tri_test_func() RETURNS TRIGGER AS$$DECLAREBEGININSERT INTO test_trigger_des_tbl VALUES(NEW.id1, NEW.id2, NEW.id3);RETURN NEW;END$$ LANGUAGE PLPGSQL;--不同schema下的同名触发器
CREATE TRIGGER test_triggerBEFORE insert or update ON test2.test_trigger_src_tblFOR EACH ROWEXECUTE PROCEDURE test2.tri_test_func();CREATE OR REPLACE FUNCTION test1.tri_test_func1() RETURNS TRIGGER AS$$DECLAREBEGININSERT INTO test_trigger_des_tbl VALUES(NEW.id1, NEW.id2, NEW.id3);RETURN NEW;END$$ LANGUAGE PLPGSQL;-- before insert row
CREATE TRIGGER test_trigger1BEFORE insert  ON test1.test_trigger_src_tblFOR EACH ROWEXECUTE PROCEDURE test1.tri_test_func1();CREATE OR REPLACE FUNCTION test1.tri_test_func2() RETURNS TRIGGER AS$$DECLAREBEGININSERT INTO test_trigger_des_tbl VALUES(NEW.id1, NEW.id2, NEW.id3);RETURN NEW;END$$ LANGUAGE PLPGSQL;--before insert/delete row
CREATE TRIGGER test_trigger2BEFORE insert or DELETE ON test1.test_trigger_src_tblFOR EACH ROWEXECUTE PROCEDURE test1.tri_test_func2();CREATE OR REPLACE FUNCTION test1.tri_test_func3() RETURNS TRIGGER AS$$DECLAREBEGININSERT INTO test_trigger_des_tbl VALUES(NEW.id1, NEW.id2, NEW.id3);RETURN NEW;END$$ LANGUAGE PLPGSQL;--after insert/delete/update row
CREATE TRIGGER test_trigger3AFTER insert or delete or UPDATE ON test1.test_trigger_src_tblFOR EACH ROWEXECUTE PROCEDURE test1.tri_test_func3();CREATE OR REPLACE FUNCTION test1.tri_test_func4() RETURNS TRIGGER AS$$DECLAREBEGININSERT INTO test_trigger_des_tbl VALUES(NEW.id1, NEW.id2, NEW.id3);RETURN NEW;END$$ LANGUAGE PLPGSQL;create view test1.test_trigger_src_tbl_V as select * from test1.test_trigger_src_tbl;--instead delete row
CREATE TRIGGER test_trigger4instead OF DELETE ON test1.test_trigger_src_tbl_VFOR EACH ROWEXECUTE PROCEDURE test1.tri_test_func4();CREATE OR REPLACE FUNCTION test1.tri_test_func5() RETURNS TRIGGER AS$$DECLAREBEGININSERT INTO test_trigger_des_tbl VALUES(NEW.id1, NEW.id2, NEW.id3);RETURN NEW;END$$ LANGUAGE PLPGSQL;--before truncate statement
CREATE TRIGGER test_trigger5before truncate ON test1.test_trigger_src_tblFOR EACH STATEMENT EXECUTE PROCEDURE test1.tri_test_func5();CREATE OR REPLACE FUNCTION test1.tri_test_func6() RETURNS TRIGGER AS$$DECLAREBEGININSERT INTO test_trigger_des_tbl VALUES(NEW.id1, NEW.id2, NEW.id3);RETURN NEW;END$$ LANGUAGE PLPGSQL;--after delete row
CREATE TRIGGER test_trigger6AFTER delete  ON test1.test_trigger_src_tblFOR EACH ROWEXECUTE PROCEDURE test1.tri_test_func6();CREATE OR REPLACE FUNCTION test1.tri_test_func7() RETURNS TRIGGER AS$$DECLAREBEGININSERT INTO test_trigger_des_tbl VALUES(NEW.id1, NEW.id2, NEW.id3);RETURN NEW;END$$ LANGUAGE PLPGSQL;--after truncate statement
CREATE TRIGGER test_trigger7AFTER truncate ON test1.test_trigger_src_tblFOR EACH STATEMENT EXECUTE PROCEDURE test1.tri_test_func7();CREATE OR REPLACE FUNCTION test1.tri_test_func8() RETURNS TRIGGER AS$$DECLAREBEGININSERT INTO test_trigger_des_tbl VALUES(NEW.id1, NEW.id2, NEW.id3);RETURN NEW;END$$ LANGUAGE PLPGSQL;--after update/delete row
CREATE TRIGGER test_trigger8AFTER update or delete  ON test1.test_trigger_src_tblFOR EACH ROWEXECUTE PROCEDURE test1.tri_test_func8();

然后查询pg_trigger表,并将tgtype转换成二进制数值显示(注意这里int2无法直接转换成bit类型)

select tgname,tgtype,tgtype::int4::bit(8) from pg_trigger;
tgnametgtypetgtype实际类型
test_trigger2300010111before insert update row
test_trigger2300010111before insert update
test_trigger1700000111before insert row
test_trigger21500001111before insert/delete row
test_trigger32900011101after insert/delete/update row
test_trigger47301001001instead delete row
test_trigger53400100010before truncate statement
test_trigger6900001001after delete row
test_trigger73200100000after truncate statement
test_trigger82500011001after update/delete row

得到这个信息,小学二年级都能看出规律。我们在表格中转置一下看看

tgnametest_triggertest_triggertest_trigger1test_trigger2test_trigger3test_trigger4test_trigger5test_trigger6test_trigger7test_trigger8
tgtype232371529733493225
70000000000
60000010000
50000001010
41100100001
30001110101
21111100000
11111001000
01111110101
实际类型before insert update rowbefore insert updatebefore insert rowbefore insert/delete rowafter insert/delete/update rowinstead delete rowbefore truncate statementafter delete rowafter truncate statementafter update/delete row

然后很容易就能对比得到每个二进制位所表示的含义

第几位含义
7无用位
6是否insead of
5是否truncate
4是否update
3是否delete
2是否insert
1是否before(不是before就是after)
0是否row(不是row就是statement)

以上都是纯用SQL查询比较猜出来的,虽然过程也比较简单,但还是有点费时间。但实际上,如果能看懂C语言源码,一眼就能知道应该怎么去解析tgtype
openGauss-server\src\include\catalog\pg_trigger.h

/* Bits within tgtype */
#define TRIGGER_TYPE_ROW                (1 << 0)
#define TRIGGER_TYPE_BEFORE             (1 << 1)
#define TRIGGER_TYPE_INSERT             (1 << 2)
#define TRIGGER_TYPE_DELETE             (1 << 3)
#define TRIGGER_TYPE_UPDATE             (1 << 4)
#define TRIGGER_TYPE_TRUNCATE           (1 << 5)
#define TRIGGER_TYPE_INSTEAD            (1 << 6)

另外,为什么明明有INSERT/DELETE/UPDATE/TRUNCATE四种,但information_schema.triggers里为什么没有truncate的呢?其实在视图里,明确有写

         -- hard-wired refs to TRIGGER_TYPE_INSERT, TRIGGER_TYPE_DELETE,-- TRIGGER_TYPE_UPDATE; we intentionally omit TRIGGER_TYPE_TRUNCATE(VALUES (4, 'INSERT'),(8, 'DELETE'),(16, 'UPDATE')) AS em (num, text)

我们故意省略TRIGGER_TYPE_TRUNCATE

至于原作者为什么故意省略,这个就猜不到了。
知道以上规则后,我们可以尝试自己写一个dba_trigger视图,这里对event提供两种写法

case when tgtype&32<>0 then 'TRUNCATE'when tgtype&6<>0 and tgtype&16<>0 and tgtype&8<>0 then 'INSERT OR UPDATE OR DELETE'when tgtype&6<>0 and tgtype&16<>0 and tgtype&8=0 then 'INSERT OR UPDATE'when tgtype&6<>0 and tgtype&16=0 and tgtype&8=0 then 'INSERT'when tgtype&6=0 and tgtype&16<>0 and tgtype&8<>0 then 'UPDATE OR DELETE'when tgtype&6=0 and tgtype&16<>0 and tgtype&8=0 then 'UPDATE'when tgtype&6=0 and tgtype&16=0 and tgtype&8<>0 then 'DELETE'when tgtype&6<>0 and tgtype&16=0 and tgtype&8<>0 then 'INSERT OR DELETE'
end
case substring(tgtype::int4::bit(8) from 3 for 5)when B'01110' then 'INSERT OR UPDATE OR DELETE'when B'01011' then 'INSERT OR UPDATE'when B'00011' then 'INSERT'when B'01100' then 'UPDATE OR DELETE'when B'00100' then 'DELETE'when B'00111' then 'INSERT OR DELETE'when B'10001' then 'TRUNCATE'
end

视图代码地址:

https://gitee.com/enmotech/cmpat-tools/blob/master/Oracle_Views.sql

结尾

开头有提到,在ORACLE中也经常这样处理属性值,比如以下就是一个oracle的user_triggers视图的一段节选,用这一个property字段表示了很多种属性

decode(bitand(t.property, 8192),8192, decode(bitand(t.property, 131072),131072, 'REVERSE', 'FORWARD'), 'NO'),
decode(bitand(t.property, 16384),16384, 'YES', 'NO'),
decode(bitand(t.property, 32768),32768, 'YES', 'NO'),

好的设计都是相通的,虽然这种方式不利于直接用SQL从数据字典基表中查询明确的属性值,但是能节省很多存储空间,并且在内存中直接判断二进制会更快比字符串更快。

  • 本文作者: DarkAthena
  • 本文链接: https://www.darkathena.top/archives/opengauss-pgtrigger-tgtype-decode
  • 版权声明: 本博客所有文章除特别声明外,均采用CC BY-NC-SA 3.0 许可协议。转载请注明出处!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/189294.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

人工智能基础创新的第二增长曲线

编者按&#xff1a;2023年是微软亚洲研究院建院25周年。借此机会&#xff0c;我们特别策划了“智启未来”系列文章&#xff0c;邀请到微软亚洲研究院不同研究领域的领军人物&#xff0c;以署名文章的形式分享他们对人工智能、计算机及其交叉学科领域的观点洞察及前沿展望。希望…

逆向exe

前言 在使用一个上位机程序时&#xff0c;弹出了试用期已结束&#xff0c;由于有使用它的需求&#xff0c;便想着能不能把它的防御措施给干掉。 0x1 思路 ①通过字符串查找定位弹窗的代码→找到弹窗的条件→fail ②分析main函数→找到弹窗的调用函数 0x2 实操 首先通过在main…

PVE系列-LVM安装MacOS的各个版本

PVE系列-LVM安装MacOS的各个版本 环境配置大概过程&#xff1a;详细步骤&#xff1a;1.建立安装环境和下载安装工具2. 重启后&#xff0c;执行osx-setup配置虚拟机3. 安装到硬盘&#xff0c;4.设定引导盘&#xff0c;以方便自动开机启动5.打开屏幕共享和系统VNC最后的结果 引子…

安装vscode插件与安装vue项目

前提先安装nvm然后安装需要的nodejs 1&#xff1a;点击下载vscode&#xff0c;选择安装目录&#xff0c;一直点击安装就行 2&#xff1a;安装vue-cli脚手架 npm install -g vuecli5.0.4查看vue版本 vue --version卸载脚手架 npm uninstall vue/clinpm uninstall vue创建vue2…

记一次:Python的学习笔记二(Django项目1)

前言&#xff1a;书接上回&#xff0c;认识了Python项目环境&#xff0c;那么开始做一些案例了&#xff0c;笔者是Java出身&#xff0c;接触的也大都是web项目&#xff0c;那么Python的web项目有哪些呢&#xff1f;了解了一下有很多&#xff0c;37个之多&#xff0c;有 Django …

spring cloud gateway源码分析,一个请求进来的默认处理流程

1.前言 spring cloud gateway的基本组成和作用就不细赘述&#xff0c;此篇适合对此有一定了解的人阅读。 spring cloud gateway版本: Hoxton.SR1 spring cloud gateway的配置使用yml配置&#xff1a; server:port: 9527y#根据微服务名称进行动态路由的配置 spring:applicati…

Python实现pdf文件转word文件

日常生活中&#xff0c;当遇到需要将某个PDF文件转换为Word格式文件时&#xff0c;一般是通过一些在线格式转换的网站&#xff0c;或者软件来完成&#xff0c;但我们也可以使用python来完成这个需求&#xff08;当然&#xff0c;这种方法仅能够满足大部分的格式&#xff09;。 …

《Effective C++》条款28

避免返回handles指向对象内部成分 有这样一个类&#xff0c;用左上角和右下角的坐标表示一个矩形&#xff1a; class point { public:point(int a,int b):x(a),y(b){}point& changeX(int _x){point newpoint(_x, y);return newpoint;} private:int x;int y; }; struct Pdat…

人机协同

人机协同是指人和机器之间进行合作和协同工作的方式&#xff0c;人机协同是人工智能技术发展的一个重要方向&#xff0c;通过人机协同的方式&#xff0c;可以充分利用机器的智能和人的智慧&#xff0c;共同实现更高效、更智能的工作和生活方式。人机协同可以应用于各种领域和场…

Docker的常用基本命令(基础命令)

文章目录 1. Docker简介2. Docker环境安装Linux安装 3. 配置镜像加速4. Docker镜像常用命令列出镜像列表搜索镜像下载镜像查看镜像版本删除镜像构建镜像推送镜像 5. Docker容器常用命令新建并启动容器列出容器停止容器启动容器进入容器删除容器&#xff08;慎用&#xff09;查看…

基于Spring MVC的前后端交互案例及应用分层的实现

目录 分析程序报错的步骤 案例 一.加法计算器 二.实现用户登录 1.登录接口 2.获取用户的登录信息 三.留言板 1.接口定义 2.完成后端代码 3.测试后端代码 四.图书管理系统 1.定义接口 2.后端代码 3.测试后端代码 4.前端交互代码 应用分层 1.三层架构 分析程序报…

QT Creator 保存(Ctrl+S)时,会将Tab制表符转换为空格

今天在写makefile文件时&#xff0c;发现QT Creator 保存(CtrlS)时&#xff0c;会将Tab制表符转换为空格&#xff0c;之前没有发现&#xff0c;略坑&#xff0c;官网上也有说明&#xff0c;点这里 简单来说&#xff0c;解决办法如下 依次点击&#xff1a;Tools ->Options-&g…

JPA数据源Oracle异常记录

代码执行异常 ObjectOptimisticLockingFailureException org.springframework.orm.ObjectOptimisticLockingFailureException: Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1; nested exception is org.hibernate.StaleSta…

Linux 文件管理

内容概述 1 文件系统目录结构 存放的是内存中正在运行的系统状态信息&#xff0c;数据不在硬盘而是在内存中 echo 1 > /proc/sys/net/ipv4/icmp_echo_ignore_all1.1 文件系统的目录结构 Linux 操作系统 ext / xfs 文件系统是区分大小写&#xff0c;大小写敏感 Linux的文件…

MySQL导出ER图为图片或PDF

目录 1、Navicat 生成ER图 1、选择数据库&#xff0c;逆向数据库到模型 2、查看ER图 3、导出ER图 2、使用MySQL官方工具&#xff1a;MySQL Workbench 1、首先连接MySQL数据库 2、点击Database&#xff0c;选择Reverse Engineer 3、填写数据库信息&#xff0c;点Next …

【鸿蒙应用ArkTS开发系列】-自定义底部菜单列表弹窗

文章目录 前言创建Demo工程创建dialog 文件夹创建ListMenu 接口创建自定义弹窗 ListMenuDialog使用自定义弹窗 打包测试效果演示默认效果菜单带图标效果设置文本颜色效果不同文本颜色效果无标题效果 前言 上一篇文章中我们实现了选择图片、选择文件、拍照的功能 。 链接在这里…

每日一练2023.12.1——输出GPLT【PTA】

题目链接&#xff1a;L1-023 输出GPLT 题目要求&#xff1a; 给定一个长度不超过10000的、仅由英文字母构成的字符串。请将字符重新调整顺序&#xff0c;按GPLTGPLT....这样的顺序输出&#xff0c;并忽略其它字符。当然&#xff0c;四种字符&#xff08;不区分大小写&#x…

对小程序的初了解

WXML和HTML的区别 标签名称不同 HTML&#xff1a;div、a、span、img WXML&#xff1a;view、text、image、navigator 属性节点不同 <a href"#">超链接</a> <navigator url"/pages/home/home"></navigator> 提供了类似vue的…

计算机视觉(OpenCV+TensorFlow)

计算机视觉&#xff08;OpenCVTensorFlow&#xff09; 文章目录 计算机视觉&#xff08;OpenCVTensorFlow&#xff09;前言7. 图像直方图绘制直方图绘制直方图有两种方式&#xff1a; 掩膜 8. 直方图均衡化直方图均衡化的介绍直方图均衡化的步骤自适应直方图均衡化 9. 图像转换…

SAP_ABAP_编程基础_数据集_创建并填充摘录数据集 / 处理摘录数据集

SAP ABAP 顾问&#xff08;开发工程师&#xff09;能力模型_Terry谈企业数字化的博客-CSDN博客文章浏览阅读494次。目标&#xff1a;基于对SAP abap 顾问能力模型的梳理&#xff0c;给一年左右经验的abaper 快速成长为三年经验提供超级燃料&#xff01;https://blog.csdn.net/j…