diff options
Diffstat (limited to 'src/backend/rewrite/rewriteSupport.c')
-rw-r--r-- | src/backend/rewrite/rewriteSupport.c | 270 |
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); +} + |