aboutsummaryrefslogtreecommitdiff
path: root/src/backend/rewrite/rewriteSupport.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/rewrite/rewriteSupport.c')
-rw-r--r--src/backend/rewrite/rewriteSupport.c270
1 files changed, 270 insertions, 0 deletions
diff --git a/src/backend/rewrite/rewriteSupport.c b/src/backend/rewrite/rewriteSupport.c
new file mode 100644
index 00000000000..1a05fc87b03
--- /dev/null
+++ b/src/backend/rewrite/rewriteSupport.c
@@ -0,0 +1,270 @@
+/*-------------------------------------------------------------------------
+ *
+ * rewriteSupport.c--
+ *
+ *
+ * Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ * $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteSupport.c,v 1.1.1.1 1996/07/09 06:21:52 scrappy Exp $
+ *
+ *-------------------------------------------------------------------------
+ */
+#include "postgres.h"
+#include "catalog/catname.h"
+#include "catalog/pg_rewrite.h"
+#include "utils/syscache.h" /* for SearchSysCache */
+#include "nodes/pg_list.h"
+#include "nodes/parsenodes.h"
+#include "utils/builtins.h" /* for textout */
+#include "utils/rel.h" /* for Relation, RelationData ... */
+#include "utils/elog.h" /* for elog */
+#include "storage/buf.h" /* for InvalidBuffer */
+#include "rewrite/rewriteSupport.h"
+#include "access/heapam.h"
+#include "catalog/pg_class.h"
+#include "catalog/pg_proc.h"
+#include "catalog/indexing.h"
+#include "utils/catcache.h" /* for CacheContext */
+#include "utils/mcxt.h" /* MemoryContext stuff */
+#include "utils/palloc.h"
+#include "fmgr.h"
+
+/*
+ * RuleIdGetActionInfo -
+ * given a rule oid, look it up and return the rule-event-qual and
+ * list of parsetrees for the rule (in parseTrees)
+ */
+static Node *
+RuleIdGetActionInfo(Oid ruleoid, bool *instead_flag, Query **parseTrees)
+{
+ HeapTuple ruletuple;
+ char *ruleaction = NULL;
+ bool action_is_null = false;
+ bool instead_is_null = false;
+ Relation ruleRelation = NULL;
+ TupleDesc ruleTupdesc = NULL;
+ Query *ruleparse = NULL;
+ char *rule_evqual_string = NULL;
+ Node *rule_evqual = NULL;
+
+ ruleRelation = heap_openr (RewriteRelationName);
+ ruleTupdesc = RelationGetTupleDescriptor(ruleRelation);
+ ruletuple = SearchSysCacheTuple (RULOID,
+ ObjectIdGetDatum(ruleoid),
+ 0,0,0);
+ if (ruletuple == NULL)
+ elog(WARN, "rule %d isn't in rewrite system relation");
+
+ ruleaction = heap_getattr(ruletuple,
+ InvalidBuffer,
+ Anum_pg_rewrite_action,
+ ruleTupdesc,
+ &action_is_null ) ;
+ rule_evqual_string = heap_getattr(ruletuple, InvalidBuffer,
+ Anum_pg_rewrite_ev_qual,
+ ruleTupdesc, &action_is_null) ;
+ *instead_flag = (bool) heap_getattr(ruletuple, InvalidBuffer,
+ Anum_pg_rewrite_is_instead,
+ ruleTupdesc, &instead_is_null) ;
+
+ if (action_is_null || instead_is_null) {
+ elog(WARN, "internal error: rewrite rule not properly set up");
+ }
+
+ ruleaction = textout((struct varlena *)ruleaction);
+ rule_evqual_string = textout((struct varlena *)rule_evqual_string);
+
+ ruleparse = (Query*)stringToNode(ruleaction);
+ rule_evqual = (Node*)stringToNode(rule_evqual_string);
+
+ heap_close(ruleRelation);
+
+ *parseTrees = ruleparse;
+ return rule_evqual;
+}
+
+int
+IsDefinedRewriteRule(char *ruleName)
+{
+ Relation RewriteRelation = NULL;
+ HeapScanDesc scanDesc = NULL;
+ ScanKeyData scanKey;
+ HeapTuple tuple = NULL;
+
+
+ /*
+ * Open the pg_rewrite relation.
+ */
+ RewriteRelation = heap_openr(RewriteRelationName);
+
+ /*
+ * Scan the RuleRelation ('pg_rewrite') until we find a tuple
+ */
+ ScanKeyEntryInitialize(&scanKey, 0, Anum_pg_rewrite_rulename,
+ NameEqualRegProcedure, PointerGetDatum(ruleName));
+ scanDesc = heap_beginscan(RewriteRelation,
+ 0, NowTimeQual, 1, &scanKey);
+
+ tuple = heap_getnext(scanDesc, 0, (Buffer *)NULL);
+
+ /*
+ * return whether or not the rewrite rule existed
+ */
+ heap_close(RewriteRelation);
+ heap_endscan(scanDesc);
+ return (HeapTupleIsValid(tuple));
+}
+
+static void
+setRelhasrulesInRelation(Oid relationId, bool relhasrules)
+{
+ Relation relationRelation;
+ HeapTuple tuple;
+ HeapTuple newTuple;
+ Relation idescs[Num_pg_class_indices];
+ Form_pg_class relp;
+
+ /*
+ * Lock a relation given its Oid.
+ * Go to the RelationRelation (i.e. pg_relation), find the
+ * appropriate tuple, and add the specified lock to it.
+ */
+ relationRelation = heap_openr(RelationRelationName);
+ tuple = ClassOidIndexScan(relationRelation, relationId);
+
+ /*
+ * Create a new tuple (i.e. a copy of the old tuple
+ * with its rule lock field changed and replace the old
+ * tuple in the RelationRelation
+ * NOTE: XXX ??? do we really need to make that copy ????
+ */
+ newTuple = heap_copytuple(tuple);
+
+ relp = (Form_pg_class) GETSTRUCT(newTuple);
+ relp->relhasrules = relhasrules;
+
+ (void) heap_replace(relationRelation, &(tuple->t_ctid), newTuple);
+
+ /* keep the catalog indices up to date */
+ CatalogOpenIndices(Num_pg_class_indices, Name_pg_class_indices, idescs);
+ CatalogIndexInsert(idescs, Num_pg_class_indices, relationRelation,
+ newTuple);
+ CatalogCloseIndices(Num_pg_class_indices, idescs);
+
+ /* be tidy */
+ pfree(tuple);
+ pfree(newTuple);
+
+ heap_close(relationRelation);
+}
+
+void
+prs2_addToRelation(Oid relid,
+ Oid ruleId,
+ CmdType event_type,
+ AttrNumber attno,
+ bool isInstead,
+ Node *qual,
+ List *actions)
+{
+ Relation relation;
+ RewriteRule *thisRule;
+ RuleLock *rulelock;
+ MemoryContext oldcxt;
+
+ /*
+ * create an in memory RewriteRule data structure which is cached by
+ * every Relation descriptor. (see utils/cache/relcache.c)
+ */
+ oldcxt = MemoryContextSwitchTo((MemoryContext)CacheCxt);
+ thisRule = (RewriteRule *)palloc(sizeof(RewriteRule));
+ MemoryContextSwitchTo(oldcxt);
+
+ thisRule->ruleId = ruleId;
+ thisRule->event = event_type;
+ thisRule->attrno = attno;
+ thisRule->qual = qual;
+ thisRule->actions = actions;
+ thisRule->isInstead = isInstead;
+
+ relation = heap_open(relid);
+
+ /*
+ * modify or create a RuleLock cached by Relation
+ */
+ if (relation->rd_rules == NULL) {
+
+ oldcxt = MemoryContextSwitchTo((MemoryContext)CacheCxt);
+ rulelock = (RuleLock *)palloc(sizeof(RuleLock));
+ rulelock->numLocks = 1;
+ rulelock->rules = (RewriteRule **)palloc(sizeof(RewriteRule*));
+ rulelock->rules[0] = thisRule;
+ relation->rd_rules = rulelock;
+ MemoryContextSwitchTo(oldcxt);
+
+ /*
+ * the fact that relation->rd_rules is NULL means the relhasrules
+ * attribute of the tuple of this relation in pg_class is false. We
+ * need to set it to true.
+ */
+ setRelhasrulesInRelation(relid, TRUE);
+ } else {
+ int numlock;
+
+ rulelock = relation->rd_rules;
+ numlock = rulelock->numLocks;
+ /* expand, for safety reasons */
+ oldcxt = MemoryContextSwitchTo((MemoryContext)CacheCxt);
+ rulelock->rules =
+ (RewriteRule **)repalloc(rulelock->rules,
+ sizeof(RewriteRule*)*(numlock+1));
+ MemoryContextSwitchTo(oldcxt);
+ rulelock->rules[numlock] = thisRule;
+ rulelock->numLocks++;
+ }
+
+ heap_close(relation);
+
+ return;
+}
+
+void
+prs2_deleteFromRelation(Oid relid, Oid ruleId)
+{
+ RuleLock *rulelock;
+ Relation relation;
+ int numlock;
+ int i;
+ MemoryContext oldcxt;
+
+ relation = heap_open(relid);
+ rulelock = relation->rd_rules;
+ Assert(rulelock != NULL);
+
+ numlock = rulelock->numLocks;
+ for(i=0; i < numlock; i++) {
+ if (rulelock->rules[i]->ruleId == ruleId)
+ break;
+ }
+ Assert(i<numlock);
+ oldcxt = MemoryContextSwitchTo((MemoryContext)CacheCxt);
+ pfree(rulelock->rules[i]);
+ MemoryContextSwitchTo(oldcxt);
+ if (numlock==1) {
+ relation->rd_rules = NULL;
+ /*
+ * we don't have rules any more, flag the relhasrules attribute of
+ * the tuple of this relation in pg_class false.
+ */
+ setRelhasrulesInRelation(relid, FALSE);
+ } else {
+ rulelock->rules[i] = rulelock->rules[numlock-1];
+ rulelock->rules[numlock-1] = NULL;
+ rulelock->numLocks--;
+ }
+
+ heap_close(relation);
+}
+