*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/catalog/index.c,v 1.120 2000/06/28 03:31:23 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/catalog/index.c,v 1.121 2000/06/30 07:04:17 tgl Exp $
*
*
* INTERFACE ROUTINES
/* ----------------------------------------------------------------
* AccessMethodObjectIdGetForm
- * Returns the formated access method tuple given its object identifier.
+ * Returns an access method tuple given its object identifier,
+ * or NULL if no such AM tuple can be found.
*
- * XXX ADD INDEXING
+ * Scanning is done using CurrentMemoryContext as working storage,
+ * but the returned tuple will be allocated in resultCxt (which is
+ * typically CacheMemoryContext).
*
- * Note:
- * Assumes object identifier is valid.
+ * There was a note here about adding indexing, but I don't see a need
+ * for it. There are so few tuples in pg_am that an indexscan would
+ * surely be slower.
* ----------------------------------------------------------------
*/
Form_pg_am
-AccessMethodObjectIdGetForm(Oid accessMethodObjectId)
+AccessMethodObjectIdGetForm(Oid accessMethodObjectId,
+ MemoryContext resultCxt)
{
Relation pg_am_desc;
HeapScanDesc pg_am_scan;
}
/* ----------------
- * if found am tuple, then copy the form and return the copy
+ * if found AM tuple, then copy it into resultCxt and return the copy
* ----------------
*/
- aform = (Form_pg_am) palloc(sizeof *aform);
+ aform = (Form_pg_am) MemoryContextAlloc(resultCxt, sizeof *aform);
memcpy(aform, GETSTRUCT(pg_am_tuple), sizeof *aform);
heap_endscan(pg_am_scan);
static void
ConstructIndexReldesc(Relation indexRelation, Oid amoid)
{
- MemoryContext oldcxt;
-
- /* ----------------
- * here we make certain to allocate the access method
- * tuple within the cache context lest it vanish when the
- * context changes
- * ----------------
- */
- if (!CacheMemoryContext)
- CreateCacheMemoryContext();
-
- oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
-
- indexRelation->rd_am = AccessMethodObjectIdGetForm(amoid);
-
- MemoryContextSwitchTo(oldcxt);
+ indexRelation->rd_am = AccessMethodObjectIdGetForm(amoid,
+ CacheMemoryContext);
/* ----------------
* XXX missing the initialization of some other fields
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/commands/trigger.c,v 1.70 2000/06/28 03:31:28 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/commands/trigger.c,v 1.71 2000/06/30 07:04:17 tgl Exp $
*
*-------------------------------------------------------------------------
*/
heap_close(tgrel, RowExclusiveLock);
}
+/*
+ * Build trigger data to attach to the given relcache entry.
+ *
+ * Note that trigger data must be allocated in CacheMemoryContext
+ * to ensure it survives as long as the relcache entry. But we
+ * are probably running in a less long-lived working context.
+ */
void
RelationBuildTriggers(Relation relation)
{
- TriggerDesc *trigdesc = (TriggerDesc *) palloc(sizeof(TriggerDesc));
+ TriggerDesc *trigdesc;
int ntrigs = relation->rd_rel->reltriggers;
Trigger *triggers = NULL;
Trigger *build;
int found;
bool hasindex;
+ trigdesc = (TriggerDesc *) MemoryContextAlloc(CacheMemoryContext,
+ sizeof(TriggerDesc));
MemSet(trigdesc, 0, sizeof(TriggerDesc));
ScanKeyEntryInitialize(&skey,
pg_trigger = (Form_pg_trigger) GETSTRUCT(htup);
if (triggers == NULL)
- triggers = (Trigger *) palloc(sizeof(Trigger));
+ triggers = (Trigger *) MemoryContextAlloc(CacheMemoryContext,
+ sizeof(Trigger));
else
- triggers = (Trigger *) repalloc(triggers, (found + 1) * sizeof(Trigger));
+ triggers = (Trigger *) repalloc(triggers,
+ (found + 1) * sizeof(Trigger));
build = &(triggers[found]);
build->tgoid = htup->t_data->t_oid;
- build->tgname = nameout(&pg_trigger->tgname);
+ build->tgname = MemoryContextStrdup(CacheMemoryContext,
+ nameout(&pg_trigger->tgname));
build->tgfoid = pg_trigger->tgfoid;
build->tgfunc.fn_oid = InvalidOid; /* mark FmgrInfo as uninitialized */
build->tgtype = pg_trigger->tgtype;
build->tgdeferrable = pg_trigger->tgdeferrable;
build->tginitdeferred = pg_trigger->tginitdeferred;
build->tgnargs = pg_trigger->tgnargs;
- memcpy(build->tgattr, &(pg_trigger->tgattr), FUNC_MAX_ARGS * sizeof(int16));
+ memcpy(build->tgattr, &(pg_trigger->tgattr),
+ FUNC_MAX_ARGS * sizeof(int16));
val = (struct varlena *) fastgetattr(htup,
Anum_pg_trigger_tgargs,
tgrel->rd_att, &isnull);
elog(ERROR, "RelationBuildTriggers: tgargs IS NULL for rel %s",
RelationGetRelationName(relation));
p = (char *) VARDATA(val);
- build->tgargs = (char **) palloc(build->tgnargs * sizeof(char *));
+ build->tgargs = (char **)
+ MemoryContextAlloc(CacheMemoryContext,
+ build->tgnargs * sizeof(char *));
for (i = 0; i < build->tgnargs; i++)
{
- build->tgargs[i] = pstrdup(p);
+ build->tgargs[i] = MemoryContextStrdup(CacheMemoryContext,
+ p);
p += strlen(p) + 1;
}
}
{
tp = &(t[TRIGGER_EVENT_INSERT]);
if (*tp == NULL)
- *tp = (Trigger **) palloc(sizeof(Trigger *));
+ *tp = (Trigger **) MemoryContextAlloc(CacheMemoryContext,
+ sizeof(Trigger *));
else
*tp = (Trigger **) repalloc(*tp, (n[TRIGGER_EVENT_INSERT] + 1) *
sizeof(Trigger *));
{
tp = &(t[TRIGGER_EVENT_DELETE]);
if (*tp == NULL)
- *tp = (Trigger **) palloc(sizeof(Trigger *));
+ *tp = (Trigger **) MemoryContextAlloc(CacheMemoryContext,
+ sizeof(Trigger *));
else
*tp = (Trigger **) repalloc(*tp, (n[TRIGGER_EVENT_DELETE] + 1) *
sizeof(Trigger *));
{
tp = &(t[TRIGGER_EVENT_UPDATE]);
if (*tp == NULL)
- *tp = (Trigger **) palloc(sizeof(Trigger *));
+ *tp = (Trigger **) MemoryContextAlloc(CacheMemoryContext,
+ sizeof(Trigger *));
else
*tp = (Trigger **) repalloc(*tp, (n[TRIGGER_EVENT_UPDATE] + 1) *
sizeof(Trigger *));
/* ----------
* Internal data to the deferred trigger mechanism is held
- * during entire session in a global memor created at startup and
- * over statements/commands in a separate global memory which
- * is created at transaction start and destroyed at transaction
- * end.
+ * during entire session in a global context created at startup and
+ * over statements/commands in a separate context which
+ * is created at transaction start and destroyed at transaction end.
* ----------
*/
static MemoryContext deftrig_gcxt = NULL;
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteDefine.c,v 1.47 2000/06/28 03:31:56 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteDefine.c,v 1.48 2000/06/30 07:04:22 tgl Exp $
*
*-------------------------------------------------------------------------
*/
* InsertRule -
* takes the arguments and inserts them as attributes into the system
* relation "pg_rewrite"
- *
- * ARGS : rulname - name of the rule
- * evtype - one of RETRIEVE,REPLACE,DELETE,APPEND
- * evobj - name of relation
- * evslot - comma delimited list of slots
- * if null => multi-attr rule
- * evinstead - is an instead rule
- * actiontree - parsetree(s) of rule action
*/
static Oid
InsertRule(char *rulname,
int evtype,
- char *evobj,
- char *evslot,
- char *evqual,
+ Oid eventrel_oid,
+ AttrNumber evslot_index,
bool evinstead,
+ char *evqual,
char *actiontree)
{
- Relation eventrel;
- Oid eventrel_oid;
- AttrNumber evslot_index;
int i;
Datum values[Natts_pg_rewrite];
char nulls[Natts_pg_rewrite];
HeapTuple tup;
Oid rewriteObjectId;
- eventrel = heap_openr(evobj, AccessShareLock);
- eventrel_oid = RelationGetRelid(eventrel);
-
- /*
- * if the slotname is null, we know that this is a multi-attr rule
- */
- if (evslot == NULL)
- evslot_index = -1;
- else
- evslot_index = attnameAttNum(eventrel, evslot);
- heap_close(eventrel, AccessShareLock);
-
- if (evqual == NULL)
- evqual = "<>";
-
if (IsDefinedRewriteRule(rulname))
elog(ERROR, "Attempt to insert rule '%s' failed: already exists",
rulname);
Node *event_qual = stmt->whereClause;
bool is_instead = stmt->instead;
List *action = stmt->actions;
- Relation event_relation = NULL;
+ Relation event_relation;
+ Oid ev_relid;
Oid ruleId;
- Oid ev_relid = 0;
char *eslot_string = NULL;
- int event_attno = 0;
- Oid event_attype = 0;
+ int event_attno;
+ Oid event_attype;
char *actionP,
*event_qualP;
List *l;
Query *query;
+ /*
+ * If we are installing an ON SELECT rule, we had better grab
+ * AccessExclusiveLock to ensure no SELECTs are currently running on
+ * the event relation. For other types of rules, it might be sufficient
+ * to grab ShareLock to lock out insert/update/delete actions. But
+ * for now, let's just grab AccessExclusiveLock all the time.
+ */
+ event_relation = heap_openr(event_obj->relname, AccessExclusiveLock);
+ ev_relid = RelationGetRelid(event_relation);
+
/* ----------
* The current rewrite handler is known to work on relation level
* rules only. And for SELECT events, it expects one non-nothing
/*
* No rule actions that modify OLD or NEW
*/
- if (action != NIL)
- foreach(l, action)
+ foreach(l, action)
{
query = (Query *) lfirst(l);
if (query->resultRelation == 1)
{
- elog(NOTICE, "rule actions on OLD currently not supported");
- elog(ERROR, " use views or triggers instead");
+ elog(ERROR, "rule actions on OLD currently not supported"
+ "\n\tuse views or triggers instead");
}
if (query->resultRelation == 2)
{
- elog(NOTICE, "rule actions on NEW currently not supported");
- elog(ERROR, " use triggers instead");
+ elog(ERROR, "rule actions on NEW currently not supported"
+ "\n\tuse triggers instead");
}
}
*/
if (length(action) == 0)
{
- elog(NOTICE, "instead nothing rules on select currently not supported");
- elog(ERROR, " use views instead");
+ elog(ERROR, "instead nothing rules on select currently not supported"
+ "\n\tuse views instead");
}
/*
* ... the targetlist of the SELECT action must exactly match the
* event relation, ...
*/
- event_relation = heap_openr(event_obj->relname, AccessShareLock);
-
if (event_relation->rd_att->natts != length(query->targetList))
elog(ERROR, "select rules target list must match event relations structure");
tle = (TargetEntry *) nth(i - 1, query->targetList);
resdom = tle->resdom;
attr = event_relation->rd_att->attrs[i - 1];
- attname = pstrdup(NameStr(attr->attname));
+ attname = NameStr(attr->attname);
if (strcmp(resdom->resname, attname) != 0)
elog(ERROR, "select rules target entry %d has different column name from %s", i, attname);
}
}
- heap_close(event_relation, AccessShareLock);
-
/*
* LIMIT in view is not supported
*/
/*
* This rule is allowed - install it.
*/
-
- event_relation = heap_openr(event_obj->relname, AccessShareLock);
- ev_relid = RelationGetRelid(event_relation);
-
if (eslot_string == NULL)
{
event_attno = -1;
- event_attype = -1; /* XXX - don't care */
+ event_attype = InvalidOid;
}
else
{
event_attno = attnameAttNum(event_relation, eslot_string);
event_attype = attnumTypeId(event_relation, event_attno);
}
- heap_close(event_relation, AccessShareLock);
/* fix bug about instead nothing */
ValidateRule(event_type, event_obj->relname,
eslot_string, event_qual, &action,
is_instead, event_attype);
- if (action == NULL)
- {
- if (!is_instead)
- return; /* doesn't do anything */
-
- event_qualP = nodeToString(event_qual);
-
- ruleId = InsertRule(stmt->rulename,
- event_type,
- event_obj->relname,
- eslot_string,
- event_qualP,
- true,
- "<>");
- prs2_addToRelation(ev_relid, ruleId, event_type, event_attno, TRUE,
- event_qual, NIL);
-
- }
- else
+ /* discard rule if it's null action and not INSTEAD; it's a no-op */
+ if (action != NULL || is_instead)
{
event_qualP = nodeToString(event_qual);
actionP = nodeToString(action);
ruleId = InsertRule(stmt->rulename,
event_type,
- event_obj->relname,
- eslot_string,
- event_qualP,
+ ev_relid,
+ event_attno,
is_instead,
+ event_qualP,
actionP);
- /* what is the max size of type text? XXX -- glass */
- if (length(action) > 15)
- elog(ERROR, "max # of actions exceeded");
- prs2_addToRelation(ev_relid, ruleId, event_type, event_attno,
- is_instead, event_qual, action);
+ /*
+ * Set pg_class 'relhasrules' field TRUE for event relation.
+ *
+ * Important side effect: an SI notice is broadcast to force all
+ * backends (including me!) to update relcache entries with the new
+ * rule.
+ */
+ setRelhasrulesInRelation(ev_relid, true);
}
+
+ /* Close rel, but keep lock till commit... */
+ heap_close(event_relation, NoLock);
}
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteHandler.c,v 1.76 2000/06/15 03:32:22 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteHandler.c,v 1.77 2000/06/30 07:04:22 tgl Exp $
*
*-------------------------------------------------------------------------
*/
rt_entry = rt_fetch(result_relation, parsetree->rtable);
rt_entry_relation = heap_openr(rt_entry->relname, AccessShareLock);
rt_entry_locks = rt_entry_relation->rd_rules;
- heap_close(rt_entry_relation, AccessShareLock);
if (rt_entry_locks != NULL)
{
- List *locks = matchLocks(event, rt_entry_locks, result_relation, parsetree);
+ List *locks = matchLocks(event, rt_entry_locks,
+ result_relation, parsetree);
product_queries = fireRules(parsetree,
result_relation,
qual_products);
}
+ heap_close(rt_entry_relation, AccessShareLock);
+
return product_queries;
}
/*
* to avoid infinite recursion, we restrict the number of times a query
- * can be rewritten. Detecting cycles is left for the reader as an excercise.
+ * can be rewritten. Detecting cycles is left for the reader as an exercise.
*/
#ifndef REWRITE_INVOKE_MAX
#define REWRITE_INVOKE_MAX 10
bool instead;
List *qual_products = NIL;
-
-
if (++numQueryRewriteInvoked > REWRITE_INVOKE_MAX)
{
elog(ERROR, "query rewritten %d times, may contain cycles",
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteRemove.c,v 1.37 2000/05/28 17:56:02 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteRemove.c,v 1.38 2000/06/30 07:04:23 tgl Exp $
*
*-------------------------------------------------------------------------
*/
return NameStr(((Form_pg_class) GETSTRUCT(htup))->relname);
}
-/* ----------------------------------------------------------------
- *
+/*
* RemoveRewriteRule
*
* Delete a rule given its rulename.
- *
- * There are three steps.
- * 1) Find the corresponding tuple in 'pg_rewrite' relation.
- * Find the rule Id (i.e. the Oid of the tuple) and finally delete
- * the tuple.
- * 3) Delete the locks from the 'pg_class' relation.
- *
- *
- * ----------------------------------------------------------------
*/
void
RemoveRewriteRule(char *ruleName)
{
- Relation RewriteRelation = NULL;
- HeapTuple tuple = NULL;
- Oid ruleId = (Oid) 0;
- Oid eventRelationOid = (Oid) NULL;
- Datum eventRelationOidDatum = (Datum) NULL;
- bool isNull = false;
+ Relation RewriteRelation;
+ Relation event_relation;
+ HeapTuple tuple;
+ Oid ruleId;
+ Oid eventRelationOid;
+ bool hasMoreRules;
/*
* Open the pg_rewrite relation.
RewriteRelation = heap_openr(RewriteRelationName, RowExclusiveLock);
/*
- * Scan the RuleRelation ('pg_rewrite') until we find a tuple
+ * Find the tuple for the target rule.
*/
tuple = SearchSysCacheTupleCopy(RULENAME,
PointerGetDatum(ruleName),
}
/*
- * Store the OID of the rule (i.e. the tuple's OID) and the event
+ * Save the OID of the rule (i.e. the tuple's OID) and the event
* relation's OID
*/
ruleId = tuple->t_data->t_oid;
- eventRelationOidDatum = heap_getattr(tuple,
- Anum_pg_rewrite_ev_class,
- RelationGetDescr(RewriteRelation),
- &isNull);
- if (isNull)
- {
- /* XXX strange!!! */
- heap_freetuple(tuple);
- elog(ERROR, "RemoveRewriteRule: internal error; null event target relation!");
- }
- eventRelationOid = DatumGetObjectId(eventRelationOidDatum);
+ eventRelationOid = ((Form_pg_rewrite) GETSTRUCT(tuple))->ev_class;
/*
- * Now delete the relation level locks from the updated relation.
- * (Make sure we do this before we remove the rule from pg_rewrite.
- * Otherwise, heap_openr on eventRelationOid which reads pg_rwrite for
- * the rules will fail.)
+ * We had better grab AccessExclusiveLock so that we know no other
+ * rule additions/deletions are going on for this relation. Else
+ * we cannot set relhasrules correctly. Besides, we don't want to
+ * be changing the ruleset while queries are executing on the rel.
*/
- prs2_deleteFromRelation(eventRelationOid, ruleId);
+ event_relation = heap_open(eventRelationOid, AccessExclusiveLock);
+
+ hasMoreRules = event_relation->rd_rules != NULL &&
+ event_relation->rd_rules->numLocks > 1;
/*
* Delete any comments associated with this rule
- *
*/
-
DeleteComments(ruleId);
/*
- * Now delete the tuple...
+ * Now delete the pg_rewrite tuple for the rule
*/
heap_delete(RewriteRelation, &tuple->t_self, NULL);
heap_freetuple(tuple);
+
heap_close(RewriteRelation, RowExclusiveLock);
+
+ /*
+ * Set pg_class 'relhasrules' field correctly for event relation.
+ *
+ * Important side effect: an SI notice is broadcast to force all
+ * backends (including me!) to update relcache entries with the
+ * new rule set. Therefore, must do this even if relhasrules is
+ * still true!
+ */
+ setRelhasrulesInRelation(eventRelationOid, hasMoreRules);
+
+ /* Close rel, but keep lock till commit... */
+ heap_close(event_relation, NoLock);
}
/*
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteSupport.c,v 1.42 2000/06/28 03:31:56 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteSupport.c,v 1.43 2000/06/30 07:04:23 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
-
#include "access/heapam.h"
#include "catalog/catname.h"
#include "catalog/indexing.h"
#include "utils/catcache.h"
#include "utils/syscache.h"
-/*
- * RuleIdGetActionInfo -
- * given a rule oid, look it up and return the rule-event-qual and
- * list of parsetrees for the rule (in parseTrees)
- */
-#ifdef NOT_USED
-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, AccessShareLock);
- ruleTupdesc = RelationGetDescr(ruleRelation);
- ruletuple = SearchSysCacheTuple(RULEOID,
- ObjectIdGetDatum(ruleoid),
- 0, 0, 0);
- if (ruletuple == NULL)
- elog(ERROR, "rule %u isn't in rewrite system relation", ruleoid);
-
- 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);
- *instead_flag = !!heap_getattr(ruletuple,
- Anum_pg_rewrite_is_instead,
- ruleTupdesc, &instead_is_null);
-
- if (action_is_null || instead_is_null)
- elog(ERROR, "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, AccessShareLock);
-
- *parseTrees = ruleparse;
- return rule_evqual;
-}
-
-#endif
int
IsDefinedRewriteRule(char *ruleName)
return HeapTupleIsValid(tuple);
}
-static void
+/*
+ * setRelhasrulesInRelation
+ * Set the value of the relation's relhasrules field in pg_class.
+ *
+ * NOTE: caller should be holding an appropriate lock on the relation.
+ *
+ * NOTE: an important side-effect of this operation is that an SI invalidation
+ * message is sent out to all backends --- including me --- causing relcache
+ * entries to be flushed or updated with the new set of rules for the table.
+ * Therefore, we execute the update even if relhasrules has the right value
+ * already. Possible future improvement: skip the disk update and just send
+ * an SI message in that case.
+ */
+void
setRelhasrulesInRelation(Oid relationId, bool relhasrules)
{
Relation relationRelation;
Relation idescs[Num_pg_class_indices];
/*
- * 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.
+ * Find the tuple to update in pg_class, using syscache for the lookup.
*/
relationRelation = heap_openr(RelationRelationName, RowExclusiveLock);
tuple = SearchSysCacheTupleCopy(RELOID,
0, 0, 0);
Assert(HeapTupleIsValid(tuple));
+ /* Do the update */
((Form_pg_class) GETSTRUCT(tuple))->relhasrules = relhasrules;
heap_update(relationRelation, &tuple->t_self, tuple, NULL);
- /* keep the catalog indices up to date */
+ /* Keep the catalog indices up to date */
CatalogOpenIndices(Num_pg_class_indices, Name_pg_class_indices, idescs);
CatalogIndexInsert(idescs, Num_pg_class_indices, relationRelation, tuple);
CatalogCloseIndices(Num_pg_class_indices, idescs);
heap_freetuple(tuple);
heap_close(relationRelation, RowExclusiveLock);
}
-
-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(CacheMemoryContext);
- thisRule = (RewriteRule *) palloc(sizeof(RewriteRule));
- if (qual != NULL)
- qual = copyObject(qual);
- if (actions != NIL)
- actions = copyObject(actions);
- 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, AccessShareLock);
-
- /*
- * modify or create a RuleLock cached by Relation
- */
- if (relation->rd_rules == NULL)
- {
-
- oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
- 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(CacheMemoryContext);
- rulelock->rules = (RewriteRule **) repalloc(rulelock->rules,
- sizeof(RewriteRule *) * (numlock + 1));
- MemoryContextSwitchTo(oldcxt);
- rulelock->rules[numlock] = thisRule;
- rulelock->numLocks++;
- }
-
- heap_close(relation, AccessShareLock);
-}
-
-void
-prs2_deleteFromRelation(Oid relid, Oid ruleId)
-{
- RuleLock *rulelock;
- Relation relation;
- int numlock;
- int i;
- MemoryContext oldcxt;
-
- relation = heap_open(relid, AccessShareLock);
- 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(CacheMemoryContext);
- 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, AccessShareLock);
-}
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/cache/relcache.c,v 1.104 2000/06/28 03:32:24 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/cache/relcache.c,v 1.105 2000/06/30 07:04:10 tgl Exp $
*
*-------------------------------------------------------------------------
*/
* RelationClose - close an open relation
*
* NOTES
- * This file is in the process of being cleaned up
- * before I add system attribute indexing. -cim 1/13/91
- *
* The following code contains many undocumented hacks. Please be
* careful....
*
#include "storage/smgr.h"
#include "utils/catcache.h"
#include "utils/fmgroids.h"
+#include "utils/memutils.h"
#include "utils/relcache.h"
#include "utils/temprel.h"
/* ----------------
* Hash tables that index the relation cache
*
- * Relations are cached two ways, by name and by id,
+ * Relations are looked up two ways, by name and by id,
* thus there are two hash tables for referencing them.
* ----------------
*/
*/
static List *newlyCreatedRelns = NULL;
+/*
+ * This flag is false until we have prepared the critical relcache entries
+ * that are needed to do indexscans on the tables read by relcache building.
+ */
+static bool criticalRelcachesBuilt = false;
+
/* ----------------
* RelationBuildDescInfo exists so code can be shared
static void init_irels(void);
static void write_irels(void);
-static void formrdesc(char *relationName, u_int natts,
+static void formrdesc(char *relationName, int natts,
FormData_pg_attribute *att);
static HeapTuple ScanPgRelation(RelationBuildDescInfo buildinfo);
static HeapTuple scan_pg_rel_seq(RelationBuildDescInfo buildinfo);
static HeapTuple scan_pg_rel_ind(RelationBuildDescInfo buildinfo);
-static Relation AllocateRelationDesc(Relation relation, u_int natts,
- Form_pg_class relp);
+static Relation AllocateRelationDesc(Relation relation, Form_pg_class relp);
static void RelationBuildTupleDesc(RelationBuildDescInfo buildinfo,
- Relation relation, u_int natts);
+ Relation relation);
static void build_tupdesc_seq(RelationBuildDescInfo buildinfo,
- Relation relation, u_int natts);
+ Relation relation);
static void build_tupdesc_ind(RelationBuildDescInfo buildinfo,
- Relation relation, u_int natts);
+ Relation relation);
static Relation RelationBuildDesc(RelationBuildDescInfo buildinfo,
Relation oldrelation);
static void IndexedAccessMethodInitialize(Relation relation);
static void RelCheckFetch(Relation relation);
static List *insert_ordered_oid(List *list, Oid datum);
-static bool criticalRelcacheBuild = false;
/* ----------------------------------------------------------------
* RelationIdGetRelation() and RelationNameGetRelation()
* can, and do.
*/
- if (IsIgnoringSystemIndexes() || !criticalRelcacheBuild)
+ if (IsIgnoringSystemIndexes() || !criticalRelcachesBuilt)
return scan_pg_rel_seq(buildinfo);
else
return scan_pg_rel_ind(buildinfo);
* ----------------
*/
static Relation
-AllocateRelationDesc(Relation relation, u_int natts,
- Form_pg_class relp)
+AllocateRelationDesc(Relation relation, Form_pg_class relp)
{
+ MemoryContext oldcxt;
Form_pg_class relationForm;
- /* ----------------
- * Copy the relation tuple form
- *
- * We only allocate space for the fixed fields, ie, CLASS_TUPLE_SIZE.
- * relacl is NOT stored in the relcache --- there'd be little point
- * in it, since we don't copy the tuple's nullvalues bitmap and hence
- * wouldn't know if the value is valid ... bottom line is that relacl
- * *cannot* be retrieved from the relcache. Get it from the syscache
- * if you need it.
- * ----------------
- */
- relationForm = (Form_pg_class) palloc(CLASS_TUPLE_SIZE);
-
- memcpy((char *) relationForm, (char *) relp, CLASS_TUPLE_SIZE);
+ /* Relcache entries must live in CacheMemoryContext */
+ oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
/* ----------------
* allocate space for new relation descriptor, if needed
+ * ----------------
*/
if (relation == NULL)
relation = (Relation) palloc(sizeof(RelationData));
/* ----------------
- * clear new reldesc
+ * clear all fields of reldesc
* ----------------
*/
MemSet((char *) relation, 0, sizeof(RelationData));
/* make sure relation is marked as having no open file yet */
relation->rd_fd = -1;
- /* initialize attribute tuple form */
- relation->rd_att = CreateTemplateTupleDesc(natts);
+ /* ----------------
+ * Copy the relation tuple form
+ *
+ * We only allocate space for the fixed fields, ie, CLASS_TUPLE_SIZE.
+ * relacl is NOT stored in the relcache --- there'd be little point
+ * in it, since we don't copy the tuple's nullvalues bitmap and hence
+ * wouldn't know if the value is valid ... bottom line is that relacl
+ * *cannot* be retrieved from the relcache. Get it from the syscache
+ * if you need it.
+ * ----------------
+ */
+ relationForm = (Form_pg_class) palloc(CLASS_TUPLE_SIZE);
- /* and initialize relation tuple form */
+ memcpy((char *) relationForm, (char *) relp, CLASS_TUPLE_SIZE);
+
+ /* initialize relation tuple form */
relation->rd_rel = relationForm;
+ /* and allocate attribute tuple form storage */
+ relation->rd_att = CreateTemplateTupleDesc(relationForm->relnatts);
+
+ MemoryContextSwitchTo(oldcxt);
+
return relation;
}
*/
static void
RelationBuildTupleDesc(RelationBuildDescInfo buildinfo,
- Relation relation,
- u_int natts)
+ Relation relation)
{
/*
* can, and do.
*/
- if (IsIgnoringSystemIndexes() || !criticalRelcacheBuild)
- build_tupdesc_seq(buildinfo, relation, natts);
+ if (IsIgnoringSystemIndexes() || !criticalRelcachesBuilt)
+ build_tupdesc_seq(buildinfo, relation);
else
- build_tupdesc_ind(buildinfo, relation, natts);
+ build_tupdesc_ind(buildinfo, relation);
}
static void
-SetConstrOfRelation(Relation relation, TupleConstr *constr, int ndef, AttrDefault *attrdef)
+SetConstrOfRelation(Relation relation,
+ TupleConstr *constr,
+ int ndef,
+ AttrDefault *attrdef)
{
if (constr->has_not_null || ndef > 0 || relation->rd_rel->relchecks)
{
if (relation->rd_rel->relchecks > 0) /* CHECKs */
{
constr->num_check = relation->rd_rel->relchecks;
- constr->check = (ConstrCheck *) palloc(constr->num_check *
- sizeof(ConstrCheck));
+ constr->check = (ConstrCheck *)
+ MemoryContextAlloc(CacheMemoryContext,
+ constr->num_check * sizeof(ConstrCheck));
MemSet(constr->check, 0, constr->num_check * sizeof(ConstrCheck));
RelCheckFetch(relation);
}
static void
build_tupdesc_seq(RelationBuildDescInfo buildinfo,
- Relation relation,
- u_int natts)
+ Relation relation)
{
HeapTuple pg_attribute_tuple;
Relation pg_attribute_desc;
Form_pg_attribute attp;
ScanKeyData key;
int need;
- TupleConstr *constr = (TupleConstr *) palloc(sizeof(TupleConstr));
+ TupleConstr *constr;
AttrDefault *attrdef = NULL;
int ndef = 0;
+ constr = (TupleConstr *) MemoryContextAlloc(CacheMemoryContext,
+ sizeof(TupleConstr));
constr->has_not_null = false;
+
/* ----------------
* form a scan key
* ----------------
* add attribute data to relation->rd_att
* ----------------
*/
- need = natts;
+ need = relation->rd_rel->relnatts;
pg_attribute_tuple = heap_getnext(pg_attribute_scan, 0);
while (HeapTupleIsValid(pg_attribute_tuple) && need > 0)
if (attp->attnum > 0)
{
relation->rd_att->attrs[attp->attnum - 1] =
- (Form_pg_attribute) palloc(ATTRIBUTE_TUPLE_SIZE);
+ (Form_pg_attribute) MemoryContextAlloc(CacheMemoryContext,
+ ATTRIBUTE_TUPLE_SIZE);
memcpy((char *) (relation->rd_att->attrs[attp->attnum - 1]),
(char *) attp,
ATTRIBUTE_TUPLE_SIZE);
need--;
+
/* Update if this attribute have a constraint */
if (attp->attnotnull)
constr->has_not_null = true;
{
if (attrdef == NULL)
{
- attrdef = (AttrDefault *) palloc(relation->rd_rel->relnatts *
- sizeof(AttrDefault));
+ attrdef = (AttrDefault *)
+ MemoryContextAlloc(CacheMemoryContext,
+ relation->rd_rel->relnatts *
+ sizeof(AttrDefault));
MemSet(attrdef, 0,
- relation->rd_rel->relnatts * sizeof(AttrDefault));
+ relation->rd_rel->relnatts * sizeof(AttrDefault));
}
attrdef[ndef].adnum = attp->attnum;
attrdef[ndef].adbin = NULL;
static void
build_tupdesc_ind(RelationBuildDescInfo buildinfo,
- Relation relation,
- u_int natts)
+ Relation relation)
{
Relation attrel;
HeapTuple atttup;
Form_pg_attribute attp;
- TupleConstr *constr = (TupleConstr *) palloc(sizeof(TupleConstr));
+ TupleConstr *constr;
AttrDefault *attrdef = NULL;
int ndef = 0;
int i;
+ constr = (TupleConstr *) MemoryContextAlloc(CacheMemoryContext,
+ sizeof(TupleConstr));
constr->has_not_null = false;
attrel = heap_openr(AttributeRelationName, AccessShareLock);
}
relation->rd_att->attrs[i - 1] = attp =
- (Form_pg_attribute) palloc(ATTRIBUTE_TUPLE_SIZE);
+ (Form_pg_attribute) MemoryContextAlloc(CacheMemoryContext,
+ ATTRIBUTE_TUPLE_SIZE);
memcpy((char *) attp,
(char *) (Form_pg_attribute) GETSTRUCT(atttup),
{
if (attrdef == NULL)
{
- attrdef = (AttrDefault *) palloc(relation->rd_rel->relnatts *
- sizeof(AttrDefault));
+ attrdef = (AttrDefault *)
+ MemoryContextAlloc(CacheMemoryContext,
+ relation->rd_rel->relnatts *
+ sizeof(AttrDefault));
MemSet(attrdef, 0,
relation->rd_rel->relnatts * sizeof(AttrDefault));
}
heap_close(attrel, AccessShareLock);
SetConstrOfRelation(relation, constr, ndef, attrdef);
-
}
/* --------------------------------
*
* Form the relation's rewrite rules from information in
* the pg_rewrite system catalog.
+ *
+ * Note: The rule parsetrees are potentially very complex node structures.
+ * To allow these trees to be freed when the relcache entry is flushed,
+ * we make a private memory context to hold the RuleLock information for
+ * each relcache entry that has associated rules. The context is used
+ * just for rule info, not for any other subsidiary data of the relcache
+ * entry, because that keeps the update logic in RelationClearRelation()
+ * manageable. The other subsidiary data structures are simple enough
+ * to be easy to free explicitly, anyway.
* --------------------------------
*/
static void
RelationBuildRuleLock(Relation relation)
{
+ MemoryContext rulescxt;
+ MemoryContext oldcxt;
HeapTuple pg_rewrite_tuple;
Relation pg_rewrite_desc;
TupleDesc pg_rewrite_tupdesc;
RewriteRule **rules;
int maxlocks;
+ /*
+ * Make the private context. Parameters are set on the assumption
+ * that it'll probably not contain much data.
+ */
+ rulescxt = AllocSetContextCreate(CacheMemoryContext,
+ RelationGetRelationName(relation),
+ 0, /* minsize */
+ 1024, /* initsize */
+ 1024); /* maxsize */
+ relation->rd_rulescxt = rulescxt;
+
/* ----------------
* form an array to hold the rewrite rules (the array is extended if
* necessary)
* ----------------
*/
maxlocks = 4;
- rules = (RewriteRule **) palloc(sizeof(RewriteRule *) * maxlocks);
+ rules = (RewriteRule **)
+ MemoryContextAlloc(rulescxt, sizeof(RewriteRule *) * maxlocks);
numlocks = 0;
/* ----------------
char *rule_evqual_str;
RewriteRule *rule;
- rule = (RewriteRule *) palloc(sizeof(RewriteRule));
+ rule = (RewriteRule *) MemoryContextAlloc(rulescxt,
+ sizeof(RewriteRule));
rule->ruleId = pg_rewrite_tuple->t_data->t_oid;
- rule->event = (int) heap_getattr(pg_rewrite_tuple,
- Anum_pg_rewrite_ev_type, pg_rewrite_tupdesc,
- &isnull) - 48;
- rule->attrno = (int) heap_getattr(pg_rewrite_tuple,
- Anum_pg_rewrite_ev_attr, pg_rewrite_tupdesc,
- &isnull);
- rule->isInstead = !!heap_getattr(pg_rewrite_tuple,
- Anum_pg_rewrite_is_instead, pg_rewrite_tupdesc,
- &isnull);
+ rule->event = DatumGetInt32(heap_getattr(pg_rewrite_tuple,
+ Anum_pg_rewrite_ev_type,
+ pg_rewrite_tupdesc,
+ &isnull)) - 48;
+ rule->attrno = DatumGetInt16(heap_getattr(pg_rewrite_tuple,
+ Anum_pg_rewrite_ev_attr,
+ pg_rewrite_tupdesc,
+ &isnull));
+ rule->isInstead = DatumGetBool(heap_getattr(pg_rewrite_tuple,
+ Anum_pg_rewrite_is_instead,
+ pg_rewrite_tupdesc,
+ &isnull));
ruleaction = heap_getattr(pg_rewrite_tuple,
Anum_pg_rewrite_ev_action,
pg_rewrite_tupdesc,
&isnull);
ruleaction_str = lztextout((lztext *) DatumGetPointer(ruleaction));
+ oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
rule->actions = (List *) stringToNode(ruleaction_str);
+ MemoryContextSwitchTo(oldcxt);
pfree(ruleaction_str);
rule_evqual = heap_getattr(pg_rewrite_tuple,
pg_rewrite_tupdesc,
&isnull);
rule_evqual_str = lztextout((lztext *) DatumGetPointer(rule_evqual));
+ oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
rule->qual = (Node *) stringToNode(rule_evqual_str);
+ MemoryContextSwitchTo(oldcxt);
pfree(rule_evqual_str);
if (numlocks >= maxlocks)
{
maxlocks *= 2;
- rules = (RewriteRule **) repalloc(rules, sizeof(RewriteRule *) * maxlocks);
+ rules = (RewriteRule **)
+ repalloc(rules, sizeof(RewriteRule *) * maxlocks);
}
rules[numlocks++] = rule;
}
* form a RuleLock and insert into relation
* ----------------
*/
- rulelock = (RuleLock *) palloc(sizeof(RuleLock));
+ rulelock = (RuleLock *) MemoryContextAlloc(rulescxt, sizeof(RuleLock));
rulelock->numLocks = numlocks;
rulelock->rules = rules;
relation->rd_rules = rulelock;
}
-/* --------------------------------
- * FreeRuleLock
- *
- * Release the storage used for a set of rewrite rules.
- *
- * Probably this should be in the rules code someplace...
- * --------------------------------
- */
-static void
-FreeRuleLock(RuleLock *rlock)
-{
- int i;
-
- if (rlock == NULL)
- return;
- for (i = 0; i < rlock->numLocks; i++)
- {
- RewriteRule *rule = rlock->rules[i];
-
-#if 0 /* does freefuncs.c still work? Not sure */
- freeObject(rule->actions);
- freeObject(rule->qual);
-#endif
- pfree(rule);
- }
- pfree(rlock->rules);
- pfree(rlock);
-}
-
/* --------------------------------
* equalRuleLocks
*
{
File fd;
Relation relation;
- u_int natts;
Oid relid;
Oid relam;
HeapTuple pg_class_tuple;
*/
relid = pg_class_tuple->t_data->t_oid;
relp = (Form_pg_class) GETSTRUCT(pg_class_tuple);
- natts = relp->relnatts;
/* ----------------
* allocate storage for the relation descriptor,
- * initialize relation->rd_rel and get the access method id.
- * The storage is allocated in memory context CacheMemoryContext.
+ * and copy pg_class_tuple to relation->rd_rel.
* ----------------
*/
- oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
- relation = AllocateRelationDesc(oldrelation, natts, relp);
- relam = relation->rd_rel->relam;
+ relation = AllocateRelationDesc(oldrelation, relp);
+
+ /* -------------------
+ * now we can free the memory allocated for pg_class_tuple
+ * -------------------
+ */
+ heap_freetuple(pg_class_tuple);
/* ----------------
* initialize the relation's relation id (relation->rd_id)
* initialize the access method information (relation->rd_am)
* ----------------
*/
+ relam = relation->rd_rel->relam;
if (OidIsValid(relam))
- relation->rd_am = AccessMethodObjectIdGetForm(relam);
+ relation->rd_am = AccessMethodObjectIdGetForm(relam,
+ CacheMemoryContext);
/* ----------------
* initialize the tuple descriptor (relation->rd_att).
* ----------------
*/
- RelationBuildTupleDesc(buildinfo, relation, natts);
+ RelationBuildTupleDesc(buildinfo, relation);
/* ----------------
- * initialize rules that affect this relation
+ * Fetch rules and triggers that affect this relation
* ----------------
*/
- if (relp->relhasrules)
+ if (relation->rd_rel->relhasrules)
RelationBuildRuleLock(relation);
else
+ {
relation->rd_rules = NULL;
+ relation->rd_rulescxt = NULL;
+ }
- /* Triggers */
- if (relp->reltriggers > 0)
+ if (relation->rd_rel->reltriggers > 0)
RelationBuildTriggers(relation);
else
relation->trigdesc = NULL;
Assert(fd >= -1);
if (fd == -1)
elog(NOTICE, "RelationIdBuildRelation: smgropen(%s): %m",
- NameStr(relp->relname));
+ NameStr(relation->rd_rel->relname));
relation->rd_fd = fd;
* restore memory context and return the new reldesc.
* ----------------
*/
+ oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
RelationCacheInsert(relation);
-
MemoryContextSwitchTo(oldcxt);
- /* -------------------
- * free the memory allocated for pg_class_tuple
- * and for lock data pointed to by pg_class_tuple
- * -------------------
- */
- heap_freetuple(pg_class_tuple);
-
return relation;
}
natts = relation->rd_rel->relnatts;
relamstrategies = relation->rd_am->amstrategies;
stratSize = AttributeNumberGetIndexStrategySize(natts, relamstrategies);
- strategy = (IndexStrategy) palloc(stratSize);
- relamsupport = relation->rd_am->amsupport;
+ strategy = (IndexStrategy) MemoryContextAlloc(CacheMemoryContext,
+ stratSize);
+ relamsupport = relation->rd_am->amsupport;
if (relamsupport > 0)
{
supportSize = natts * (relamsupport * sizeof(RegProcedure));
- support = (RegProcedure *) palloc(supportSize);
+ support = (RegProcedure *) MemoryContextAlloc(CacheMemoryContext,
+ supportSize);
}
else
support = (RegProcedure *) NULL;
/* --------------------------------
* formrdesc
*
- * This is a special version of RelationBuildDesc()
- * used by RelationInitialize() in initializing the
- * relcache. The system relation descriptors built
- * here are all nailed in the descriptor caches, for
- * bootstrapping.
+ * This is a special cut-down version of RelationBuildDesc()
+ * used by RelationInitialize() in initializing the relcache.
+ * The relation descriptor is built just from the supplied parameters.
+ *
+ * NOTE: we assume we are already switched into CacheMemoryContext.
* --------------------------------
*/
static void
formrdesc(char *relationName,
- u_int natts,
+ int natts,
FormData_pg_attribute *att)
{
Relation relation;
- u_int i;
+ int i;
/* ----------------
* allocate new relation desc
strcpy(RelationGetPhysicalRelationName(relation), relationName);
/* ----------------
- initialize attribute tuple form
- */
+ * initialize attribute tuple form
+ * ----------------
+ */
relation->rd_att = CreateTemplateTupleDesc(natts);
/*
relation->rd_rel->relpages = 1; /* XXX */
relation->rd_rel->reltuples = 1; /* XXX */
relation->rd_rel->relkind = RELKIND_RELATION;
- relation->rd_rel->relnatts = (uint16) natts;
+ relation->rd_rel->relnatts = (int16) natts;
relation->rd_isnailed = true;
/* ----------------
* Determining this requires a scan on pg_class, but to do the scan
* the rdesc for pg_class must already exist. Therefore we must do
* the check (and possible set) after cache insertion.
+ *
+ * XXX I believe the above comment is misguided; we should be
+ * running in bootstrap or init processing mode, and CatalogHasIndex
+ * relies on hard-wired info in those cases.
*/
relation->rd_rel->relhasindex =
CatalogHasIndex(relationName, RelationGetRelid(relation));
/* --------------------------------
* RelationIdCacheGetRelation
*
- * Lookup a reldesc by OID.
- * Only try to get the reldesc by looking up the cache
+ * Lookup an existing reldesc by OID.
+ *
+ * Only try to get the reldesc by looking in the cache,
* do not go to the disk.
*
* NB: relation ref count is incremented if successful.
* (one with refcount > 0). However, this routine just does whichever
* it's told to do; callers must determine which they want.
*
- * If we detect a change in the relation's TupleDesc or trigger data
+ * If we detect a change in the relation's TupleDesc, rules, or triggers
* while rebuilding, we complain unless refcount is 0.
* --------------------------------
*/
if (relation->rd_isnailed)
return;
- oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
-
/*
* Remove relation from hash tables
*
* visible in the hash tables until it's valid again, so don't try to
* optimize this away...
*/
+ oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
RelationCacheDelete(relation);
+ MemoryContextSwitchTo(oldcxt);
/* Clear out catcache's entries for this relation */
SystemCacheRelationFlushed(RelationGetRelid(relation));
{
/* ok to zap remaining substructure */
FreeTupleDesc(relation->rd_att);
- FreeRuleLock(relation->rd_rules);
+ if (relation->rd_rulescxt)
+ MemoryContextDelete(relation->rd_rulescxt);
FreeTriggerDesc(relation->trigdesc);
pfree(relation);
}
bool old_myxactonly = relation->rd_myxactonly;
TupleDesc old_att = relation->rd_att;
RuleLock *old_rules = relation->rd_rules;
+ MemoryContext old_rulescxt = relation->rd_rulescxt;
TriggerDesc *old_trigdesc = relation->trigdesc;
int old_nblocks = relation->rd_nblocks;
bool relDescChanged = false;
{
/* Should only get here if relation was deleted */
FreeTupleDesc(old_att);
- FreeRuleLock(old_rules);
+ if (old_rulescxt)
+ MemoryContextDelete(old_rulescxt);
FreeTriggerDesc(old_trigdesc);
pfree(relation);
elog(ERROR, "RelationClearRelation: relation %u deleted while still in use",
}
if (equalRuleLocks(old_rules, relation->rd_rules))
{
- FreeRuleLock(relation->rd_rules);
+ if (relation->rd_rulescxt)
+ MemoryContextDelete(relation->rd_rulescxt);
relation->rd_rules = old_rules;
+ relation->rd_rulescxt = old_rulescxt;
}
else
{
- FreeRuleLock(old_rules);
+ if (old_rulescxt)
+ MemoryContextDelete(old_rulescxt);
relDescChanged = true;
}
if (equalTriggerDescs(old_trigdesc, relation->trigdesc))
elog(ERROR, "RelationClearRelation: relation %u modified while in use",
buildinfo.i.info_id);
}
-
- MemoryContextSwitchTo(oldcxt);
}
/* --------------------------------
{
if (relation->rd_myxactonly)
{
- MemoryContext oldcxt;
List *curr;
List *prev = NIL;
- oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
-
foreach(curr, newlyCreatedRelns)
{
Relation reln = lfirst(curr);
else
lnext(prev) = lnext(curr);
pfree(curr);
- MemoryContextSwitchTo(oldcxt);
}
/* Unconditionally destroy the relcache entry */
{
MemoryContext oldcxt;
- oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
-
RelationInitLockInfo(relation);
+ oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
+
RelationCacheInsert(relation);
/*
void
RelationPurgeLocalRelation(bool xactCommitted)
{
- MemoryContext oldcxt;
-
if (newlyCreatedRelns == NULL)
return;
- oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
-
while (newlyCreatedRelns)
{
List *l = newlyCreatedRelns;
if (!IsBootstrapProcessingMode())
RelationClearRelation(reln, false);
}
-
- MemoryContextSwitchTo(oldcxt);
}
/* --------------------------------
elog(NOTICE, "AttrDefaultFetch: adbin IS NULL for attr %s in rel %s",
NameStr(relation->rd_att->attrs[adform->adnum - 1]->attname),
RelationGetRelationName(relation));
- attrdef[i].adbin = textout(val);
+ else
+ attrdef[i].adbin = MemoryContextStrdup(CacheMemoryContext,
+ textout(val));
break;
}
if (hasindex)
if (isnull)
elog(ERROR, "RelCheckFetch: rcname IS NULL for rel %s",
RelationGetRelationName(relation));
- check[found].ccname = pstrdup(NameStr(*rcname));
+ check[found].ccname = MemoryContextStrdup(CacheMemoryContext,
+ NameStr(*rcname));
val = (struct varlena *) fastgetattr(htup,
Anum_pg_relcheck_rcbin,
rcrel->rd_att, &isnull);
if (isnull)
elog(ERROR, "RelCheckFetch: rcbin IS NULL for rel %s",
RelationGetRelationName(relation));
- check[found].ccbin = textout(val);
+ check[found].ccbin = MemoryContextStrdup(CacheMemoryContext,
+ textout(val));
found++;
if (hasindex)
ReleaseBuffer(buffer);
RelationCacheInsert(ird);
}
- criticalRelcacheBuild = true;
+ criticalRelcachesBuilt = true;
}
static void
irel[2] = RelationBuildDesc(bi, NULL);
irel[2]->rd_isnailed = true;
- criticalRelcacheBuild = true;
+ criticalRelcachesBuilt = true;
/*
* Removed the following ProcessingMode -- inoue
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: index.h,v 1.25 2000/06/17 23:41:51 tgl Exp $
+ * $Id: index.h,v 1.26 2000/06/30 07:04:06 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "access/itup.h"
#include "nodes/execnodes.h"
-extern Form_pg_am AccessMethodObjectIdGetForm(Oid accessMethodObjectId);
+extern Form_pg_am AccessMethodObjectIdGetForm(Oid accessMethodObjectId,
+ MemoryContext resultCxt);
extern void UpdateIndexPredicate(Oid indexoid, Node *oldPred, Node *predicate);
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: rewriteSupport.h,v 1.11 2000/01/26 05:58:30 momjian Exp $
+ * $Id: rewriteSupport.h,v 1.12 2000/06/30 07:04:04 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#ifndef REWRITESUPPORT_H
#define REWRITESUPPORT_H
-#include "access/attnum.h"
-#include "nodes/pg_list.h"
-
extern int IsDefinedRewriteRule(char *ruleName);
-extern void prs2_addToRelation(Oid relid, Oid ruleId, CmdType event_type,
- AttrNumber attno, bool isInstead, Node *qual,
- List *actions);
-extern void prs2_deleteFromRelation(Oid relid, Oid ruleId);
-
+extern void setRelhasrulesInRelation(Oid relationId, bool relhasrules);
#endif /* REWRITESUPPORT_H */
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: rel.h,v 1.38 2000/06/18 22:44:34 tgl Exp $
+ * $Id: rel.h,v 1.39 2000/06/30 07:04:03 tgl Exp $
*
*-------------------------------------------------------------------------
*/
typedef struct RelationData
{
- File rd_fd; /* open file descriptor */
+ File rd_fd; /* open file descriptor, or -1 if none */
int rd_nblocks; /* number of blocks in rel */
uint16 rd_refcnt; /* reference count */
bool rd_myxactonly; /* rel uses the local buffer mgr */
LockInfoData rd_lockInfo; /* lock mgr's info for locking relation */
TupleDesc rd_att; /* tuple descriptor */
RuleLock *rd_rules; /* rewrite rules */
+ MemoryContext rd_rulescxt; /* private memory cxt for rd_rules, if any */
IndexStrategy rd_istrat; /* info needed if rel is an index */
RegProcedure *rd_support;
TriggerDesc *trigdesc; /* Trigger info, or NULL if rel has none */