mirror of
				https://github.com/postgres/postgres.git
				synced 2025-11-04 00:02:52 -05:00 
			
		
		
		
	Use a private memory context to store rule information in each relcache
entry that has rules. This allows us to release the rule parsetrees on relcache flush without needing a working freeObject() routine. Formerly, the rule trees were leaked permanently at relcache flush. Also, clean up handling of rule creation and deletion --- there was not sufficient locking of the relation being modified, and there was no reliable notification of other backends that a relcache reload was needed. Also, clean up relcache.c code so that scans of system tables needed to load a relcache entry are done in the caller's memory context, not in CacheMemoryContext. This prevents any un-pfreed memory from those scans from becoming a permanent memory leak.
This commit is contained in:
		
							parent
							
								
									c9ec78a6b8
								
							
						
					
					
						commit
						b41f4ab8c4
					
				@ -8,7 +8,7 @@
 | 
			
		||||
 *
 | 
			
		||||
 *
 | 
			
		||||
 * 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
 | 
			
		||||
@ -369,16 +369,21 @@ ConstructTupleDescriptor(Oid heapoid,
 | 
			
		||||
 | 
			
		||||
/* ----------------------------------------------------------------
 | 
			
		||||
 * 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;
 | 
			
		||||
@ -415,10 +420,10 @@ AccessMethodObjectIdGetForm(Oid accessMethodObjectId)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* ----------------
 | 
			
		||||
	 *	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);
 | 
			
		||||
@ -434,22 +439,8 @@ AccessMethodObjectIdGetForm(Oid accessMethodObjectId)
 | 
			
		||||
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
 | 
			
		||||
 | 
			
		||||
@ -7,7 +7,7 @@
 | 
			
		||||
 * 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 $
 | 
			
		||||
 *
 | 
			
		||||
 *-------------------------------------------------------------------------
 | 
			
		||||
 */
 | 
			
		||||
@ -431,10 +431,17 @@ RelationRemoveTriggers(Relation rel)
 | 
			
		||||
	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;
 | 
			
		||||
@ -453,6 +460,8 @@ RelationBuildTriggers(Relation relation)
 | 
			
		||||
	int			found;
 | 
			
		||||
	bool		hasindex;
 | 
			
		||||
 | 
			
		||||
	trigdesc = (TriggerDesc *) MemoryContextAlloc(CacheMemoryContext,
 | 
			
		||||
												  sizeof(TriggerDesc));
 | 
			
		||||
	MemSet(trigdesc, 0, sizeof(TriggerDesc));
 | 
			
		||||
 | 
			
		||||
	ScanKeyEntryInitialize(&skey,
 | 
			
		||||
@ -499,13 +508,16 @@ RelationBuildTriggers(Relation relation)
 | 
			
		||||
		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;
 | 
			
		||||
@ -514,7 +526,8 @@ RelationBuildTriggers(Relation relation)
 | 
			
		||||
		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);
 | 
			
		||||
@ -533,10 +546,13 @@ RelationBuildTriggers(Relation relation)
 | 
			
		||||
				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;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
@ -611,7 +627,8 @@ DescribeTrigger(TriggerDesc *trigdesc, Trigger *trigger)
 | 
			
		||||
	{
 | 
			
		||||
		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 *));
 | 
			
		||||
@ -623,7 +640,8 @@ DescribeTrigger(TriggerDesc *trigdesc, Trigger *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 *));
 | 
			
		||||
@ -635,7 +653,8 @@ DescribeTrigger(TriggerDesc *trigdesc, Trigger *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 *));
 | 
			
		||||
@ -1023,10 +1042,9 @@ ltrmark:;
 | 
			
		||||
 | 
			
		||||
/* ----------
 | 
			
		||||
 * 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;
 | 
			
		||||
 | 
			
		||||
@ -8,7 +8,7 @@
 | 
			
		||||
 *
 | 
			
		||||
 *
 | 
			
		||||
 * 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 $
 | 
			
		||||
 *
 | 
			
		||||
 *-------------------------------------------------------------------------
 | 
			
		||||
 */
 | 
			
		||||
@ -29,27 +29,16 @@
 | 
			
		||||
 * 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];
 | 
			
		||||
@ -59,21 +48,6 @@ InsertRule(char *rulname,
 | 
			
		||||
	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);
 | 
			
		||||
@ -177,17 +151,27 @@ DefineQueryRewrite(RuleStmt *stmt)
 | 
			
		||||
	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
 | 
			
		||||
@ -209,19 +193,18 @@ DefineQueryRewrite(RuleStmt *stmt)
 | 
			
		||||
	/*
 | 
			
		||||
	 * 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");
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@ -242,8 +225,8 @@ DefineQueryRewrite(RuleStmt *stmt)
 | 
			
		||||
		 */
 | 
			
		||||
		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");
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/*
 | 
			
		||||
@ -265,8 +248,6 @@ DefineQueryRewrite(RuleStmt *stmt)
 | 
			
		||||
		 * ... 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");
 | 
			
		||||
 | 
			
		||||
@ -275,7 +256,7 @@ DefineQueryRewrite(RuleStmt *stmt)
 | 
			
		||||
			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);
 | 
			
		||||
@ -303,8 +284,6 @@ DefineQueryRewrite(RuleStmt *stmt)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		heap_close(event_relation, AccessShareLock);
 | 
			
		||||
 | 
			
		||||
		/*
 | 
			
		||||
		 * LIMIT in view is not supported
 | 
			
		||||
		 */
 | 
			
		||||
@ -337,62 +316,46 @@ DefineQueryRewrite(RuleStmt *stmt)
 | 
			
		||||
	/*
 | 
			
		||||
	 * 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);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -7,7 +7,7 @@
 | 
			
		||||
 *
 | 
			
		||||
 *
 | 
			
		||||
 * 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 $
 | 
			
		||||
 *
 | 
			
		||||
 *-------------------------------------------------------------------------
 | 
			
		||||
 */
 | 
			
		||||
@ -1332,11 +1332,11 @@ RewriteQuery(Query *parsetree, bool *instead_flag, List **qual_products)
 | 
			
		||||
	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,
 | 
			
		||||
@ -1346,13 +1346,15 @@ RewriteQuery(Query *parsetree, bool *instead_flag, List **qual_products)
 | 
			
		||||
									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
 | 
			
		||||
@ -1373,8 +1375,6 @@ deepRewriteQuery(Query *parsetree)
 | 
			
		||||
	bool		instead;
 | 
			
		||||
	List	   *qual_products = NIL;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	if (++numQueryRewriteInvoked > REWRITE_INVOKE_MAX)
 | 
			
		||||
	{
 | 
			
		||||
		elog(ERROR, "query rewritten %d times, may contain cycles",
 | 
			
		||||
 | 
			
		||||
@ -8,7 +8,7 @@
 | 
			
		||||
 *
 | 
			
		||||
 *
 | 
			
		||||
 * 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 $
 | 
			
		||||
 *
 | 
			
		||||
 *-------------------------------------------------------------------------
 | 
			
		||||
 */
 | 
			
		||||
@ -52,30 +52,20 @@ RewriteGetRuleEventRel(char *rulename)
 | 
			
		||||
	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.
 | 
			
		||||
@ -83,7 +73,7 @@ RemoveRewriteRule(char *ruleName)
 | 
			
		||||
	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),
 | 
			
		||||
@ -99,44 +89,49 @@ RemoveRewriteRule(char *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);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
@ -8,13 +8,12 @@
 | 
			
		||||
 *
 | 
			
		||||
 *
 | 
			
		||||
 * 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"
 | 
			
		||||
@ -22,60 +21,6 @@
 | 
			
		||||
#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)
 | 
			
		||||
@ -88,7 +33,20 @@ 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;
 | 
			
		||||
@ -96,9 +54,7 @@ setRelhasrulesInRelation(Oid relationId, bool relhasrules)
 | 
			
		||||
	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,
 | 
			
		||||
@ -106,10 +62,11 @@ setRelhasrulesInRelation(Oid relationId, bool relhasrules)
 | 
			
		||||
									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);
 | 
			
		||||
@ -117,120 +74,3 @@ setRelhasrulesInRelation(Oid relationId, bool relhasrules)
 | 
			
		||||
	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);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										351
									
								
								src/backend/utils/cache/relcache.c
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										351
									
								
								src/backend/utils/cache/relcache.c
									
									
									
									
										vendored
									
									
								
							@ -8,7 +8,7 @@
 | 
			
		||||
 *
 | 
			
		||||
 *
 | 
			
		||||
 * 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 $
 | 
			
		||||
 *
 | 
			
		||||
 *-------------------------------------------------------------------------
 | 
			
		||||
 */
 | 
			
		||||
@ -22,9 +22,6 @@
 | 
			
		||||
 *		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....
 | 
			
		||||
 *
 | 
			
		||||
@ -59,6 +56,7 @@
 | 
			
		||||
#include "storage/smgr.h"
 | 
			
		||||
#include "utils/catcache.h"
 | 
			
		||||
#include "utils/fmgroids.h"
 | 
			
		||||
#include "utils/memutils.h"
 | 
			
		||||
#include "utils/relcache.h"
 | 
			
		||||
#include "utils/temprel.h"
 | 
			
		||||
 | 
			
		||||
@ -77,7 +75,7 @@ static FormData_pg_attribute Desc_pg_log[Natts_pg_log] = {Schema_pg_log};
 | 
			
		||||
/* ----------------
 | 
			
		||||
 *		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.
 | 
			
		||||
 * ----------------
 | 
			
		||||
 */
 | 
			
		||||
@ -91,6 +89,12 @@ static HTAB *RelationIdCache;
 | 
			
		||||
 */
 | 
			
		||||
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
 | 
			
		||||
@ -211,20 +215,19 @@ static void RelationCacheAbortWalker(Relation *relationPtr, int dummy);
 | 
			
		||||
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);
 | 
			
		||||
@ -232,7 +235,6 @@ static void AttrDefaultFetch(Relation relation);
 | 
			
		||||
static void RelCheckFetch(Relation relation);
 | 
			
		||||
static List *insert_ordered_oid(List *list, Oid datum);
 | 
			
		||||
 | 
			
		||||
static bool criticalRelcacheBuild = false;
 | 
			
		||||
 | 
			
		||||
/* ----------------------------------------------------------------
 | 
			
		||||
 *		RelationIdGetRelation() and RelationNameGetRelation()
 | 
			
		||||
@ -262,7 +264,7 @@ ScanPgRelation(RelationBuildDescInfo buildinfo)
 | 
			
		||||
	 * can, and do.
 | 
			
		||||
	 */
 | 
			
		||||
 | 
			
		||||
	if (IsIgnoringSystemIndexes() || !criticalRelcacheBuild)
 | 
			
		||||
	if (IsIgnoringSystemIndexes() || !criticalRelcachesBuilt)
 | 
			
		||||
		return scan_pg_rel_seq(buildinfo);
 | 
			
		||||
	else
 | 
			
		||||
		return scan_pg_rel_ind(buildinfo);
 | 
			
		||||
@ -379,11 +381,30 @@ scan_pg_rel_ind(RelationBuildDescInfo 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;
 | 
			
		||||
 | 
			
		||||
	/* 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 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;
 | 
			
		||||
 | 
			
		||||
	/* ----------------
 | 
			
		||||
	 *	Copy the relation tuple form
 | 
			
		||||
	 *
 | 
			
		||||
@ -399,27 +420,14 @@ AllocateRelationDesc(Relation relation, u_int natts,
 | 
			
		||||
 | 
			
		||||
	memcpy((char *) relationForm, (char *) relp, CLASS_TUPLE_SIZE);
 | 
			
		||||
 | 
			
		||||
	/* ----------------
 | 
			
		||||
	 *	allocate space for new relation descriptor, if needed
 | 
			
		||||
	 */
 | 
			
		||||
	if (relation == NULL)
 | 
			
		||||
		relation = (Relation) palloc(sizeof(RelationData));
 | 
			
		||||
 | 
			
		||||
	/* ----------------
 | 
			
		||||
	 *	clear new 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);
 | 
			
		||||
 | 
			
		||||
	/* and initialize relation tuple form */
 | 
			
		||||
	/* initialize relation tuple form */
 | 
			
		||||
	relation->rd_rel = relationForm;
 | 
			
		||||
 | 
			
		||||
	/* and allocate attribute tuple form storage */
 | 
			
		||||
	relation->rd_att = CreateTemplateTupleDesc(relationForm->relnatts);
 | 
			
		||||
 | 
			
		||||
	MemoryContextSwitchTo(oldcxt);
 | 
			
		||||
 | 
			
		||||
	return relation;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -432,8 +440,7 @@ AllocateRelationDesc(Relation relation, u_int natts,
 | 
			
		||||
 */
 | 
			
		||||
static void
 | 
			
		||||
RelationBuildTupleDesc(RelationBuildDescInfo buildinfo,
 | 
			
		||||
					   Relation relation,
 | 
			
		||||
					   u_int natts)
 | 
			
		||||
					   Relation relation)
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
@ -442,14 +449,17 @@ RelationBuildTupleDesc(RelationBuildDescInfo buildinfo,
 | 
			
		||||
	 * 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)
 | 
			
		||||
	{
 | 
			
		||||
@ -471,8 +481,9 @@ SetConstrOfRelation(Relation relation, TupleConstr *constr, int ndef, AttrDefaul
 | 
			
		||||
		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);
 | 
			
		||||
		}
 | 
			
		||||
@ -488,8 +499,7 @@ SetConstrOfRelation(Relation relation, TupleConstr *constr, int ndef, AttrDefaul
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
build_tupdesc_seq(RelationBuildDescInfo buildinfo,
 | 
			
		||||
				  Relation relation,
 | 
			
		||||
				  u_int natts)
 | 
			
		||||
				  Relation relation)
 | 
			
		||||
{
 | 
			
		||||
	HeapTuple	pg_attribute_tuple;
 | 
			
		||||
	Relation	pg_attribute_desc;
 | 
			
		||||
@ -497,11 +507,14 @@ build_tupdesc_seq(RelationBuildDescInfo buildinfo,
 | 
			
		||||
	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
 | 
			
		||||
	 * ----------------
 | 
			
		||||
@ -522,7 +535,7 @@ build_tupdesc_seq(RelationBuildDescInfo buildinfo,
 | 
			
		||||
	 *	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)
 | 
			
		||||
@ -532,12 +545,14 @@ build_tupdesc_seq(RelationBuildDescInfo buildinfo,
 | 
			
		||||
		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;
 | 
			
		||||
@ -546,10 +561,12 @@ build_tupdesc_seq(RelationBuildDescInfo buildinfo,
 | 
			
		||||
			{
 | 
			
		||||
				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;
 | 
			
		||||
@ -575,17 +592,18 @@ build_tupdesc_seq(RelationBuildDescInfo buildinfo,
 | 
			
		||||
 | 
			
		||||
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);
 | 
			
		||||
@ -616,7 +634,8 @@ build_tupdesc_ind(RelationBuildDescInfo buildinfo,
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		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),
 | 
			
		||||
@ -638,8 +657,10 @@ build_tupdesc_ind(RelationBuildDescInfo buildinfo,
 | 
			
		||||
		{
 | 
			
		||||
			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));
 | 
			
		||||
			}
 | 
			
		||||
@ -652,7 +673,6 @@ build_tupdesc_ind(RelationBuildDescInfo buildinfo,
 | 
			
		||||
	heap_close(attrel, AccessShareLock);
 | 
			
		||||
 | 
			
		||||
	SetConstrOfRelation(relation, constr, ndef, attrdef);
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* --------------------------------
 | 
			
		||||
@ -660,11 +680,22 @@ build_tupdesc_ind(RelationBuildDescInfo buildinfo,
 | 
			
		||||
 *
 | 
			
		||||
 *		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;
 | 
			
		||||
@ -675,13 +706,25 @@ RelationBuildRuleLock(Relation relation)
 | 
			
		||||
	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;
 | 
			
		||||
 | 
			
		||||
	/* ----------------
 | 
			
		||||
@ -710,26 +753,32 @@ RelationBuildRuleLock(Relation relation)
 | 
			
		||||
		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,
 | 
			
		||||
@ -737,13 +786,16 @@ RelationBuildRuleLock(Relation relation)
 | 
			
		||||
								   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;
 | 
			
		||||
	}
 | 
			
		||||
@ -759,42 +811,13 @@ RelationBuildRuleLock(Relation relation)
 | 
			
		||||
	 *	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
 | 
			
		||||
 *
 | 
			
		||||
@ -886,7 +909,6 @@ RelationBuildDesc(RelationBuildDescInfo buildinfo,
 | 
			
		||||
{
 | 
			
		||||
	File		fd;
 | 
			
		||||
	Relation	relation;
 | 
			
		||||
	u_int		natts;
 | 
			
		||||
	Oid			relid;
 | 
			
		||||
	Oid			relam;
 | 
			
		||||
	HeapTuple	pg_class_tuple;
 | 
			
		||||
@ -912,17 +934,19 @@ RelationBuildDesc(RelationBuildDescInfo buildinfo,
 | 
			
		||||
	 */
 | 
			
		||||
	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)
 | 
			
		||||
@ -946,26 +970,30 @@ RelationBuildDesc(RelationBuildDescInfo buildinfo,
 | 
			
		||||
	 *	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;
 | 
			
		||||
@ -993,7 +1021,7 @@ RelationBuildDesc(RelationBuildDescInfo buildinfo,
 | 
			
		||||
	Assert(fd >= -1);
 | 
			
		||||
	if (fd == -1)
 | 
			
		||||
		elog(NOTICE, "RelationIdBuildRelation: smgropen(%s): %m",
 | 
			
		||||
			 NameStr(relp->relname));
 | 
			
		||||
			 NameStr(relation->rd_rel->relname));
 | 
			
		||||
 | 
			
		||||
	relation->rd_fd = fd;
 | 
			
		||||
 | 
			
		||||
@ -1002,17 +1030,10 @@ RelationBuildDesc(RelationBuildDescInfo buildinfo,
 | 
			
		||||
	 *	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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1030,13 +1051,15 @@ IndexedAccessMethodInitialize(Relation 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;
 | 
			
		||||
@ -1052,20 +1075,20 @@ IndexedAccessMethodInitialize(Relation relation)
 | 
			
		||||
/* --------------------------------
 | 
			
		||||
 *		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
 | 
			
		||||
@ -1095,8 +1118,9 @@ formrdesc(char *relationName,
 | 
			
		||||
	strcpy(RelationGetPhysicalRelationName(relation), relationName);
 | 
			
		||||
 | 
			
		||||
	/* ----------------
 | 
			
		||||
	   initialize attribute tuple form
 | 
			
		||||
	*/
 | 
			
		||||
	 *	initialize attribute tuple form
 | 
			
		||||
	 * ----------------
 | 
			
		||||
	 */
 | 
			
		||||
	relation->rd_att = CreateTemplateTupleDesc(natts);
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
@ -1120,7 +1144,7 @@ formrdesc(char *relationName,
 | 
			
		||||
	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;
 | 
			
		||||
 | 
			
		||||
	/* ----------------
 | 
			
		||||
@ -1157,6 +1181,10 @@ formrdesc(char *relationName,
 | 
			
		||||
	 * 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));
 | 
			
		||||
@ -1171,8 +1199,9 @@ formrdesc(char *relationName,
 | 
			
		||||
/* --------------------------------
 | 
			
		||||
 *		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.
 | 
			
		||||
@ -1355,7 +1384,7 @@ RelationClose(Relation relation)
 | 
			
		||||
 *	 (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.
 | 
			
		||||
 * --------------------------------
 | 
			
		||||
 */
 | 
			
		||||
@ -1383,8 +1412,6 @@ RelationClearRelation(Relation relation, bool rebuildIt)
 | 
			
		||||
	if (relation->rd_isnailed)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Remove relation from hash tables
 | 
			
		||||
	 *
 | 
			
		||||
@ -1392,7 +1419,9 @@ RelationClearRelation(Relation relation, bool rebuildIt)
 | 
			
		||||
	 * 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));
 | 
			
		||||
@ -1425,7 +1454,8 @@ RelationClearRelation(Relation relation, bool rebuildIt)
 | 
			
		||||
	{
 | 
			
		||||
		/* 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);
 | 
			
		||||
	}
 | 
			
		||||
@ -1443,6 +1473,7 @@ RelationClearRelation(Relation relation, bool rebuildIt)
 | 
			
		||||
		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;
 | 
			
		||||
@ -1455,7 +1486,8 @@ RelationClearRelation(Relation relation, bool rebuildIt)
 | 
			
		||||
		{
 | 
			
		||||
			/* 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",
 | 
			
		||||
@ -1475,12 +1507,15 @@ RelationClearRelation(Relation relation, bool rebuildIt)
 | 
			
		||||
		}
 | 
			
		||||
		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))
 | 
			
		||||
@ -1505,8 +1540,6 @@ RelationClearRelation(Relation relation, bool rebuildIt)
 | 
			
		||||
			elog(ERROR, "RelationClearRelation: relation %u modified while in use",
 | 
			
		||||
				 buildinfo.i.info_id);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	MemoryContextSwitchTo(oldcxt);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* --------------------------------
 | 
			
		||||
@ -1570,12 +1603,9 @@ RelationForgetRelation(Oid rid)
 | 
			
		||||
	{
 | 
			
		||||
		if (relation->rd_myxactonly)
 | 
			
		||||
		{
 | 
			
		||||
			MemoryContext oldcxt;
 | 
			
		||||
			List	   *curr;
 | 
			
		||||
			List	   *prev = NIL;
 | 
			
		||||
 | 
			
		||||
			oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
 | 
			
		||||
 | 
			
		||||
			foreach(curr, newlyCreatedRelns)
 | 
			
		||||
			{
 | 
			
		||||
				Relation	reln = lfirst(curr);
 | 
			
		||||
@ -1593,7 +1623,6 @@ RelationForgetRelation(Oid rid)
 | 
			
		||||
			else
 | 
			
		||||
				lnext(prev) = lnext(curr);
 | 
			
		||||
			pfree(curr);
 | 
			
		||||
			MemoryContextSwitchTo(oldcxt);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/* Unconditionally destroy the relcache entry */
 | 
			
		||||
@ -1731,10 +1760,10 @@ RelationRegisterRelation(Relation relation)
 | 
			
		||||
{
 | 
			
		||||
	MemoryContext oldcxt;
 | 
			
		||||
 | 
			
		||||
	oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
 | 
			
		||||
 | 
			
		||||
	RelationInitLockInfo(relation);
 | 
			
		||||
 | 
			
		||||
	oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
 | 
			
		||||
 | 
			
		||||
	RelationCacheInsert(relation);
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
@ -1761,13 +1790,9 @@ RelationRegisterRelation(Relation relation)
 | 
			
		||||
void
 | 
			
		||||
RelationPurgeLocalRelation(bool xactCommitted)
 | 
			
		||||
{
 | 
			
		||||
	MemoryContext oldcxt;
 | 
			
		||||
 | 
			
		||||
	if (newlyCreatedRelns == NULL)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
 | 
			
		||||
 | 
			
		||||
	while (newlyCreatedRelns)
 | 
			
		||||
	{
 | 
			
		||||
		List	   *l = newlyCreatedRelns;
 | 
			
		||||
@ -1796,8 +1821,6 @@ RelationPurgeLocalRelation(bool xactCommitted)
 | 
			
		||||
		if (!IsBootstrapProcessingMode())
 | 
			
		||||
			RelationClearRelation(reln, false);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	MemoryContextSwitchTo(oldcxt);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* --------------------------------
 | 
			
		||||
@ -1943,7 +1966,9 @@ AttrDefaultFetch(Relation relation)
 | 
			
		||||
				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)
 | 
			
		||||
@ -2039,14 +2064,16 @@ RelCheckFetch(Relation relation)
 | 
			
		||||
		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);
 | 
			
		||||
@ -2416,7 +2443,7 @@ init_irels(void)
 | 
			
		||||
 | 
			
		||||
		RelationCacheInsert(ird);
 | 
			
		||||
	}
 | 
			
		||||
	criticalRelcacheBuild = true;
 | 
			
		||||
	criticalRelcachesBuilt = true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
@ -2489,7 +2516,7 @@ write_irels(void)
 | 
			
		||||
	irel[2] = RelationBuildDesc(bi, NULL);
 | 
			
		||||
	irel[2]->rd_isnailed = true;
 | 
			
		||||
 | 
			
		||||
	criticalRelcacheBuild = true;
 | 
			
		||||
	criticalRelcachesBuilt = true;
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Removed the following ProcessingMode -- inoue
 | 
			
		||||
 | 
			
		||||
@ -7,7 +7,7 @@
 | 
			
		||||
 * 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 $
 | 
			
		||||
 *
 | 
			
		||||
 *-------------------------------------------------------------------------
 | 
			
		||||
 */
 | 
			
		||||
@ -17,7 +17,8 @@
 | 
			
		||||
#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);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -7,22 +7,15 @@
 | 
			
		||||
 * 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 */
 | 
			
		||||
 | 
			
		||||
@ -7,7 +7,7 @@
 | 
			
		||||
 * 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 $
 | 
			
		||||
 *
 | 
			
		||||
 *-------------------------------------------------------------------------
 | 
			
		||||
 */
 | 
			
		||||
@ -85,7 +85,7 @@ typedef struct TriggerDesc
 | 
			
		||||
 | 
			
		||||
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 */
 | 
			
		||||
@ -99,6 +99,7 @@ typedef struct RelationData
 | 
			
		||||
	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 */
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user