重写功能
-- 创建2个表 CREATE TABLE t1 (c1 INT, c2 TEXT); CREATE TABLE t2 (c1 INT, c2 TEXT); -- 创建1条重写规则 -- 触发条件:向t1表写入数据时 -- 执行操作:将SQL语句重写为:同时向t2写入相同数据 CREATE OR REPLACE RULE r1 AS ON INSERT TO t1 DO ALSO INSERT INTO t2 VALUES (new.c1, new.c2); -- 向t1写入一条数据 INSERT INTO t1 VALUES (1, 'abc'); -- 验证t2也写入了一条数据 SELECT * FROM t2; DROP TABLE t1,t2;重写规则
语法
定义重写规则的语法如下:CREATE [ OR REPLACE ] RULE name AS ON { SELECT | INSERT | UPDATE | DELETE } TO table_name [ WHERE condition ] DO [ ALSO | INSTEAD ] { NOTHING | command | ( command ; command ... ) }约束
- SELECT:只能有1个动作,不带条件的INSTEAD
- INSERT / UPDATE / DELETE:可以无动作,可以多动作;可使用伪关系NEW和OLD。可使用规则条件。不修改查询树,废弃院查询树,重建0或多个查询树
重写原理
创建重写规则
用户使用CREATE RULE语法定义重写规则时,将重写规则存储至系统表中CREATE TABLE t1 (c1 INT, c2 TEXT); CREATE TABLE t2 (c1 INT, c2 TEXT); CREATE OR REPLACE RULE r1 AS ON INSERT TO t1 WHERE c1 > 1 DO ALSO INSERT INTO t2 VALUES (new.c1 + 1, new.c2); -- 查看系统表 SELECT * FROM pg_rewrite WHERE rulename = 'r1'; -- 解释:如果在ev_class表上,执行ev_type,而且满足ev_qual操作,则执行ev_action中的动作 -- 在pg.10版本中,执行以下函数报错 SELECT pg_get_expr(ev_action, ev_class) FROM pg_rewrite WHERE rulename = 'r1'; -- 走读代码,发现以下SQL语句可查看所有视图 SELECT pg_get_ruledef((SELECT oid FROM pg_rewrite WHERE rulename = 'r1')); -- 扩展:以下SQL语句可查看所有视图 SELECT ev_class::regclass WHERE pg_rewrite; -- 查看视图 SELECT * FROM pg_rules;出发重写规则
pg_rewrite_query QueryRewrite RewriteQuery # 处理 INSERT / UPDATe / DELETE,因为可能包含ALSO,增加额外的SQL语句 if CMD_SELECT: rewriteTargetListIU elif CMD_UPDATE: rewriteTargetListUD elif CMD_DELETE: rewriteTargetListUD if not instead: # 如果不是 INSTEAD 类型的 重写规则 rewriteTargetView fireRIRules ApplyRetriiveRule get_row_security_policies # <安全模块> 行级访问控制,后面讲