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