88 *
99 *
1010 * IDENTIFICATION
11- * $PostgreSQL: pgsql/src/backend/rewrite/rewriteDefine.c,v 1.134 2009/01/01 17:23:47 momjian Exp $
11+ * $PostgreSQL: pgsql/src/backend/rewrite/rewriteDefine.c,v 1.135 2009/01/22 17:27:54 petere Exp $
1212 *
1313 *-------------------------------------------------------------------------
1414 */
1515#include "postgres.h"
1616
1717#include "access/heapam.h"
18+ #include "access/xact.h"
1819#include "catalog/dependency.h"
1920#include "catalog/indexing.h"
2021#include "catalog/namespace.h"
2526#include "parser/parse_utilcmd.h"
2627#include "rewrite/rewriteDefine.h"
2728#include "rewrite/rewriteManip.h"
29+ #include "rewrite/rewriteRemove.h"
2830#include "rewrite/rewriteSupport.h"
2931#include "utils/acl.h"
3032#include "utils/builtins.h"
@@ -39,6 +41,7 @@ static void checkRuleResultList(List *targetList, TupleDesc resultDesc,
3941bool isSelect );
4042static bool setRuleCheckAsUser_walker (Node * node ,Oid * context );
4143static void setRuleCheckAsUser_Query (Query * qry ,Oid userid );
44+ static const char * rule_event_string (CmdType evtype );
4245
4346
4447/*
@@ -52,6 +55,7 @@ InsertRule(char *rulname,
5255Oid eventrel_oid ,
5356AttrNumber evslot_index ,
5457bool evinstead ,
58+ bool is_auto ,
5559Node * event_qual ,
5660List * action ,
5761bool replace )
@@ -84,6 +88,7 @@ InsertRule(char *rulname,
8488values [i ++ ]= CharGetDatum (evtype + '0' );/* ev_type */
8589values [i ++ ]= CharGetDatum (RULE_FIRES_ON_ORIGIN );/* ev_enabled */
8690values [i ++ ]= BoolGetDatum (evinstead );/* is_instead */
91+ values [i ++ ]= BoolGetDatum (is_auto );/* is_auto */
8792values [i ++ ]= CStringGetTextDatum (evqual );/* ev_qual */
8893values [i ++ ]= CStringGetTextDatum (actiontree );/* ev_action */
8994
@@ -102,7 +107,11 @@ InsertRule(char *rulname,
102107
103108if (HeapTupleIsValid (oldtup ))
104109{
105- if (!replace )
110+ /*
111+ * If REPLACE was not used we still check if the old rule is
112+ * automatic: Then we replace it anyway.
113+ */
114+ if (!replace && !((Form_pg_rewrite )GETSTRUCT (oldtup ))-> is_auto )
106115ereport (ERROR ,
107116(errcode (ERRCODE_DUPLICATE_OBJECT ),
108117errmsg ("rule \"%s\" for relation \"%s\" already exists" ,
@@ -115,6 +124,7 @@ InsertRule(char *rulname,
115124replaces [Anum_pg_rewrite_ev_attr - 1 ]= true;
116125replaces [Anum_pg_rewrite_ev_type - 1 ]= true;
117126replaces [Anum_pg_rewrite_is_instead - 1 ]= true;
127+ replaces [Anum_pg_rewrite_is_auto - 1 ]= true;
118128replaces [Anum_pg_rewrite_ev_qual - 1 ]= true;
119129replaces [Anum_pg_rewrite_ev_action - 1 ]= true;
120130
@@ -205,6 +215,7 @@ DefineRule(RuleStmt *stmt, const char *queryString)
205215whereClause ,
206216stmt -> event ,
207217stmt -> instead ,
218+ false,/* not is_auto */
208219stmt -> replace ,
209220actions );
210221}
@@ -223,6 +234,7 @@ DefineQueryRewrite(char *rulename,
223234Node * event_qual ,
224235CmdType event_type ,
225236bool is_instead ,
237+ bool is_auto ,
226238bool replace ,
227239List * action )
228240{
@@ -446,6 +458,42 @@ DefineQueryRewrite(char *rulename,
446458RelationGetDescr (event_relation ),
447459false);
448460}
461+
462+ /*
463+ * If defining a non-automatic DO INSTEAD rule, drop all
464+ * automatic rules on the same event.
465+ */
466+ if (!is_auto && is_instead )
467+ {
468+ RemoveAutomaticRulesOnEvent (event_relation ,event_type );
469+ CommandCounterIncrement ();
470+ }
471+
472+ /*
473+ * If defining an automatic rule and there is a manual rule on
474+ * the same event, warn and don't do it.
475+ */
476+ if (is_auto && event_relation -> rd_rules != NULL )
477+ {
478+ int i ;
479+
480+ for (i = 0 ;i < event_relation -> rd_rules -> numLocks ;i ++ )
481+ {
482+ RewriteRule * rule = event_relation -> rd_rules -> rules [i ];
483+
484+ if (rule -> event == event_type && !rule -> is_auto && rule -> isInstead == is_instead )
485+ {
486+ ereport (WARNING ,
487+ (errmsg ("automatic %s rule not created because manually created %s rule exists" ,
488+ rule_event_string (event_type ),rule_event_string (event_type )),
489+ errhint ("If you prefer to have the automatic rule, drop the manually created rule and run CREATE OR REPLACE VIEW again." )));
490+
491+ heap_close (event_relation ,NoLock );
492+ return ;
493+ }
494+ }
495+ }
496+
449497}
450498
451499/*
@@ -461,6 +509,7 @@ DefineQueryRewrite(char *rulename,
461509event_relid ,
462510event_attno ,
463511is_instead ,
512+ is_auto ,
464513event_qual ,
465514action ,
466515replace );
@@ -754,3 +803,16 @@ RenameRewriteRule(Oid owningRel, const char *oldName,
754803}
755804
756805#endif
806+
807+
808+ static const char *
809+ rule_event_string (CmdType type )
810+ {
811+ if (type == CMD_INSERT )
812+ return "INSERT" ;
813+ if (type == CMD_UPDATE )
814+ return "UPDATE" ;
815+ if (type == CMD_DELETE )
816+ return "DELETE" ;
817+ return "???" ;
818+ }