1 /*-------------------------------------------------------------------------
2  *
3  * rewriteSupport.c
4  *
5  *
6  * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  *
10  * IDENTIFICATION
11  *	  src/backend/rewrite/rewriteSupport.c
12  *
13  *-------------------------------------------------------------------------
14  */
15 #include "postgres.h"
16 
17 #include "access/heapam.h"
18 #include "access/htup_details.h"
19 #include "catalog/indexing.h"
20 #include "catalog/pg_rewrite.h"
21 #include "rewrite/rewriteSupport.h"
22 #include "utils/fmgroids.h"
23 #include "utils/inval.h"
24 #include "utils/lsyscache.h"
25 #include "utils/rel.h"
26 #include "utils/syscache.h"
27 #include "utils/tqual.h"
28 
29 
30 /*
31  * Is there a rule by the given name?
32  */
33 bool
IsDefinedRewriteRule(Oid owningRel,const char * ruleName)34 IsDefinedRewriteRule(Oid owningRel, const char *ruleName)
35 {
36 	return SearchSysCacheExists2(RULERELNAME,
37 								 ObjectIdGetDatum(owningRel),
38 								 PointerGetDatum(ruleName));
39 }
40 
41 
42 /*
43  * SetRelationRuleStatus
44  *		Set the value of the relation's relhasrules field in pg_class.
45  *
46  * NOTE: caller must be holding an appropriate lock on the relation.
47  *
48  * NOTE: an important side-effect of this operation is that an SI invalidation
49  * message is sent out to all backends --- including me --- causing relcache
50  * entries to be flushed or updated with the new set of rules for the table.
51  * This must happen even if we find that no change is needed in the pg_class
52  * row.
53  */
54 void
SetRelationRuleStatus(Oid relationId,bool relHasRules)55 SetRelationRuleStatus(Oid relationId, bool relHasRules)
56 {
57 	Relation	relationRelation;
58 	HeapTuple	tuple;
59 	Form_pg_class classForm;
60 
61 	/*
62 	 * Find the tuple to update in pg_class, using syscache for the lookup.
63 	 */
64 	relationRelation = heap_open(RelationRelationId, RowExclusiveLock);
65 	tuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relationId));
66 	if (!HeapTupleIsValid(tuple))
67 		elog(ERROR, "cache lookup failed for relation %u", relationId);
68 	classForm = (Form_pg_class) GETSTRUCT(tuple);
69 
70 	if (classForm->relhasrules != relHasRules)
71 	{
72 		/* Do the update */
73 		classForm->relhasrules = relHasRules;
74 
75 		CatalogTupleUpdate(relationRelation, &tuple->t_self, tuple);
76 	}
77 	else
78 	{
79 		/* no need to change tuple, but force relcache rebuild anyway */
80 		CacheInvalidateRelcacheByTuple(tuple);
81 	}
82 
83 	heap_freetuple(tuple);
84 	heap_close(relationRelation, RowExclusiveLock);
85 }
86 
87 /*
88  * Find rule oid.
89  *
90  * If missing_ok is false, throw an error if rule name not found.  If
91  * true, just return InvalidOid.
92  */
93 Oid
get_rewrite_oid(Oid relid,const char * rulename,bool missing_ok)94 get_rewrite_oid(Oid relid, const char *rulename, bool missing_ok)
95 {
96 	HeapTuple	tuple;
97 	Oid			ruleoid;
98 
99 	/* Find the rule's pg_rewrite tuple, get its OID */
100 	tuple = SearchSysCache2(RULERELNAME,
101 							ObjectIdGetDatum(relid),
102 							PointerGetDatum(rulename));
103 	if (!HeapTupleIsValid(tuple))
104 	{
105 		if (missing_ok)
106 			return InvalidOid;
107 		ereport(ERROR,
108 				(errcode(ERRCODE_UNDEFINED_OBJECT),
109 				 errmsg("rule \"%s\" for relation \"%s\" does not exist",
110 						rulename, get_rel_name(relid))));
111 	}
112 	Assert(relid == ((Form_pg_rewrite) GETSTRUCT(tuple))->ev_class);
113 	ruleoid = HeapTupleGetOid(tuple);
114 	ReleaseSysCache(tuple);
115 	return ruleoid;
116 }
117