1996-07-09 08:22:35 +02:00
|
|
|
/*-------------------------------------------------------------------------
|
|
|
|
*
|
|
|
|
* rewriteSupport.c--
|
1997-09-07 07:04:48 +02:00
|
|
|
*
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
|
|
|
* Copyright (c) 1994, Regents of the University of California
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* IDENTIFICATION
|
1998-04-27 06:08:07 +02:00
|
|
|
* $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteSupport.c,v 1.20 1998/04/27 04:06:26 momjian Exp $
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
#include "postgres.h"
|
1998-04-27 06:08:07 +02:00
|
|
|
|
|
|
|
#include "access/heapam.h"
|
1996-07-09 08:22:35 +02:00
|
|
|
#include "catalog/catname.h"
|
1998-04-27 06:08:07 +02:00
|
|
|
#include "catalog/indexing.h"
|
|
|
|
#include "catalog/pg_class.h"
|
1996-07-09 08:22:35 +02:00
|
|
|
#include "catalog/pg_rewrite.h"
|
1998-04-27 06:08:07 +02:00
|
|
|
#include "fmgr.h"
|
1996-07-09 08:22:35 +02:00
|
|
|
#include "nodes/parsenodes.h"
|
1998-04-27 06:08:07 +02:00
|
|
|
#include "nodes/pg_list.h"
|
1996-07-09 08:22:35 +02:00
|
|
|
#include "storage/buf.h" /* for InvalidBuffer */
|
1998-04-27 06:08:07 +02:00
|
|
|
#include "utils/builtins.h" /* for textout */
|
1996-07-09 08:22:35 +02:00
|
|
|
#include "utils/catcache.h" /* for CacheContext */
|
|
|
|
#include "utils/mcxt.h" /* MemoryContext stuff */
|
1998-04-27 06:08:07 +02:00
|
|
|
#include "utils/rel.h" /* for Relation, RelationData ... */
|
|
|
|
#include "utils/syscache.h" /* for SearchSysCache */
|
|
|
|
|
|
|
|
#include "rewrite/rewriteSupport.h"
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
/*
|
1996-07-09 08:22:35 +02:00
|
|
|
* RuleIdGetActionInfo -
|
1997-09-07 07:04:48 +02:00
|
|
|
* given a rule oid, look it up and return the rule-event-qual and
|
|
|
|
* list of parsetrees for the rule (in parseTrees)
|
1996-07-09 08:22:35 +02:00
|
|
|
*/
|
1996-11-08 07:02:30 +01:00
|
|
|
#ifdef NOT_USED
|
1997-09-08 04:41:22 +02:00
|
|
|
static Node *
|
1997-09-08 23:56:23 +02:00
|
|
|
RuleIdGetActionInfo(Oid ruleoid, bool *instead_flag, Query **parseTrees)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
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;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
ruleRelation = heap_openr(RewriteRelationName);
|
|
|
|
ruleTupdesc = RelationGetTupleDescriptor(ruleRelation);
|
|
|
|
ruletuple = SearchSysCacheTuple(RULOID,
|
|
|
|
ObjectIdGetDatum(ruleoid),
|
|
|
|
0, 0, 0);
|
|
|
|
if (ruletuple == NULL)
|
1998-01-07 22:07:04 +01:00
|
|
|
elog(ERROR, "rule %u isn't in rewrite system relation", ruleoid);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1998-02-26 05:46:47 +01:00
|
|
|
ruleaction = (char *) heap_getattr(ruletuple,
|
|
|
|
Anum_pg_rewrite_ev_action,
|
|
|
|
ruleTupdesc,
|
|
|
|
&action_is_null);
|
|
|
|
rule_evqual_string = (char *) heap_getattr(ruletuple,
|
|
|
|
Anum_pg_rewrite_ev_qual,
|
|
|
|
ruleTupdesc, &action_is_null);
|
1998-01-31 05:39:26 +01:00
|
|
|
*instead_flag = !!heap_getattr(ruletuple,
|
1997-09-07 07:04:48 +02:00
|
|
|
Anum_pg_rewrite_is_instead,
|
|
|
|
ruleTupdesc, &instead_is_null);
|
|
|
|
|
|
|
|
if (action_is_null || instead_is_null)
|
|
|
|
{
|
1998-01-07 22:07:04 +01:00
|
|
|
elog(ERROR, "internal error: rewrite rule not properly set up");
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1996-11-08 07:02:30 +01:00
|
|
|
#endif
|
1996-07-09 08:22:35 +02:00
|
|
|
|
|
|
|
int
|
|
|
|
IsDefinedRewriteRule(char *ruleName)
|
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
Relation RewriteRelation = NULL;
|
|
|
|
HeapScanDesc scanDesc = NULL;
|
|
|
|
ScanKeyData scanKey;
|
|
|
|
HeapTuple tuple = NULL;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 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,
|
1998-04-26 06:12:15 +02:00
|
|
|
F_NAMEEQ, PointerGetDatum(ruleName));
|
1997-09-07 07:04:48 +02:00
|
|
|
scanDesc = heap_beginscan(RewriteRelation,
|
1997-11-21 00:24:03 +01:00
|
|
|
0, false, 1, &scanKey);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
tuple = heap_getnext(scanDesc, 0, (Buffer *) NULL);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* return whether or not the rewrite rule existed
|
|
|
|
*/
|
|
|
|
heap_close(RewriteRelation);
|
|
|
|
heap_endscan(scanDesc);
|
|
|
|
return (HeapTupleIsValid(tuple));
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
setRelhasrulesInRelation(Oid relationId, bool relhasrules)
|
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
Relation relationRelation;
|
|
|
|
HeapTuple tuple;
|
|
|
|
HeapTuple newTuple;
|
|
|
|
Relation idescs[Num_pg_class_indices];
|
|
|
|
Form_pg_class relp;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* 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;
|
|
|
|
|
|
|
|
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);
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
prs2_addToRelation(Oid relid,
|
1997-09-07 07:04:48 +02:00
|
|
|
Oid ruleId,
|
|
|
|
CmdType event_type,
|
|
|
|
AttrNumber attno,
|
|
|
|
bool isInstead,
|
1997-09-08 23:56:23 +02:00
|
|
|
Node *qual,
|
|
|
|
List *actions)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
Relation relation;
|
|
|
|
RewriteRule *thisRule;
|
|
|
|
RuleLock *rulelock;
|
|
|
|
MemoryContext oldcxt;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
|
|
|
/*
|
1997-09-07 07:04:48 +02:00
|
|
|
* create an in memory RewriteRule data structure which is cached by
|
|
|
|
* every Relation descriptor. (see utils/cache/relcache.c)
|
1996-07-09 08:22:35 +02:00
|
|
|
*/
|
1997-09-07 07:04:48 +02:00
|
|
|
oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
|
|
|
|
thisRule = (RewriteRule *) palloc(sizeof(RewriteRule));
|
1996-07-09 08:22:35 +02:00
|
|
|
MemoryContextSwitchTo(oldcxt);
|
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
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);
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
/*
|
|
|
|
* 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
|
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
int numlock;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
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;
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
prs2_deleteFromRelation(Oid relid, Oid ruleId)
|
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
RuleLock *rulelock;
|
|
|
|
Relation relation;
|
|
|
|
int numlock;
|
|
|
|
int i;
|
|
|
|
MemoryContext oldcxt;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
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);
|
|
|
|
}
|