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
src
backend
catalog
commands
rewrite
utils/cache
include
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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
|
* INTERFACE ROUTINES
|
||||||
@ -369,16 +369,21 @@ ConstructTupleDescriptor(Oid heapoid,
|
|||||||
|
|
||||||
/* ----------------------------------------------------------------
|
/* ----------------------------------------------------------------
|
||||||
* AccessMethodObjectIdGetForm
|
* 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:
|
* There was a note here about adding indexing, but I don't see a need
|
||||||
* Assumes object identifier is valid.
|
* for it. There are so few tuples in pg_am that an indexscan would
|
||||||
|
* surely be slower.
|
||||||
* ----------------------------------------------------------------
|
* ----------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
Form_pg_am
|
Form_pg_am
|
||||||
AccessMethodObjectIdGetForm(Oid accessMethodObjectId)
|
AccessMethodObjectIdGetForm(Oid accessMethodObjectId,
|
||||||
|
MemoryContext resultCxt)
|
||||||
{
|
{
|
||||||
Relation pg_am_desc;
|
Relation pg_am_desc;
|
||||||
HeapScanDesc pg_am_scan;
|
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);
|
memcpy(aform, GETSTRUCT(pg_am_tuple), sizeof *aform);
|
||||||
|
|
||||||
heap_endscan(pg_am_scan);
|
heap_endscan(pg_am_scan);
|
||||||
@ -434,22 +439,8 @@ AccessMethodObjectIdGetForm(Oid accessMethodObjectId)
|
|||||||
static void
|
static void
|
||||||
ConstructIndexReldesc(Relation indexRelation, Oid amoid)
|
ConstructIndexReldesc(Relation indexRelation, Oid amoid)
|
||||||
{
|
{
|
||||||
MemoryContext oldcxt;
|
indexRelation->rd_am = AccessMethodObjectIdGetForm(amoid,
|
||||||
|
CacheMemoryContext);
|
||||||
/* ----------------
|
|
||||||
* 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);
|
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
* XXX missing the initialization of some other fields
|
* XXX missing the initialization of some other fields
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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);
|
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
|
void
|
||||||
RelationBuildTriggers(Relation relation)
|
RelationBuildTriggers(Relation relation)
|
||||||
{
|
{
|
||||||
TriggerDesc *trigdesc = (TriggerDesc *) palloc(sizeof(TriggerDesc));
|
TriggerDesc *trigdesc;
|
||||||
int ntrigs = relation->rd_rel->reltriggers;
|
int ntrigs = relation->rd_rel->reltriggers;
|
||||||
Trigger *triggers = NULL;
|
Trigger *triggers = NULL;
|
||||||
Trigger *build;
|
Trigger *build;
|
||||||
@ -453,6 +460,8 @@ RelationBuildTriggers(Relation relation)
|
|||||||
int found;
|
int found;
|
||||||
bool hasindex;
|
bool hasindex;
|
||||||
|
|
||||||
|
trigdesc = (TriggerDesc *) MemoryContextAlloc(CacheMemoryContext,
|
||||||
|
sizeof(TriggerDesc));
|
||||||
MemSet(trigdesc, 0, sizeof(TriggerDesc));
|
MemSet(trigdesc, 0, sizeof(TriggerDesc));
|
||||||
|
|
||||||
ScanKeyEntryInitialize(&skey,
|
ScanKeyEntryInitialize(&skey,
|
||||||
@ -499,13 +508,16 @@ RelationBuildTriggers(Relation relation)
|
|||||||
pg_trigger = (Form_pg_trigger) GETSTRUCT(htup);
|
pg_trigger = (Form_pg_trigger) GETSTRUCT(htup);
|
||||||
|
|
||||||
if (triggers == NULL)
|
if (triggers == NULL)
|
||||||
triggers = (Trigger *) palloc(sizeof(Trigger));
|
triggers = (Trigger *) MemoryContextAlloc(CacheMemoryContext,
|
||||||
|
sizeof(Trigger));
|
||||||
else
|
else
|
||||||
triggers = (Trigger *) repalloc(triggers, (found + 1) * sizeof(Trigger));
|
triggers = (Trigger *) repalloc(triggers,
|
||||||
|
(found + 1) * sizeof(Trigger));
|
||||||
build = &(triggers[found]);
|
build = &(triggers[found]);
|
||||||
|
|
||||||
build->tgoid = htup->t_data->t_oid;
|
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->tgfoid = pg_trigger->tgfoid;
|
||||||
build->tgfunc.fn_oid = InvalidOid; /* mark FmgrInfo as uninitialized */
|
build->tgfunc.fn_oid = InvalidOid; /* mark FmgrInfo as uninitialized */
|
||||||
build->tgtype = pg_trigger->tgtype;
|
build->tgtype = pg_trigger->tgtype;
|
||||||
@ -514,7 +526,8 @@ RelationBuildTriggers(Relation relation)
|
|||||||
build->tgdeferrable = pg_trigger->tgdeferrable;
|
build->tgdeferrable = pg_trigger->tgdeferrable;
|
||||||
build->tginitdeferred = pg_trigger->tginitdeferred;
|
build->tginitdeferred = pg_trigger->tginitdeferred;
|
||||||
build->tgnargs = pg_trigger->tgnargs;
|
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,
|
val = (struct varlena *) fastgetattr(htup,
|
||||||
Anum_pg_trigger_tgargs,
|
Anum_pg_trigger_tgargs,
|
||||||
tgrel->rd_att, &isnull);
|
tgrel->rd_att, &isnull);
|
||||||
@ -533,10 +546,13 @@ RelationBuildTriggers(Relation relation)
|
|||||||
elog(ERROR, "RelationBuildTriggers: tgargs IS NULL for rel %s",
|
elog(ERROR, "RelationBuildTriggers: tgargs IS NULL for rel %s",
|
||||||
RelationGetRelationName(relation));
|
RelationGetRelationName(relation));
|
||||||
p = (char *) VARDATA(val);
|
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++)
|
for (i = 0; i < build->tgnargs; i++)
|
||||||
{
|
{
|
||||||
build->tgargs[i] = pstrdup(p);
|
build->tgargs[i] = MemoryContextStrdup(CacheMemoryContext,
|
||||||
|
p);
|
||||||
p += strlen(p) + 1;
|
p += strlen(p) + 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -611,7 +627,8 @@ DescribeTrigger(TriggerDesc *trigdesc, Trigger *trigger)
|
|||||||
{
|
{
|
||||||
tp = &(t[TRIGGER_EVENT_INSERT]);
|
tp = &(t[TRIGGER_EVENT_INSERT]);
|
||||||
if (*tp == NULL)
|
if (*tp == NULL)
|
||||||
*tp = (Trigger **) palloc(sizeof(Trigger *));
|
*tp = (Trigger **) MemoryContextAlloc(CacheMemoryContext,
|
||||||
|
sizeof(Trigger *));
|
||||||
else
|
else
|
||||||
*tp = (Trigger **) repalloc(*tp, (n[TRIGGER_EVENT_INSERT] + 1) *
|
*tp = (Trigger **) repalloc(*tp, (n[TRIGGER_EVENT_INSERT] + 1) *
|
||||||
sizeof(Trigger *));
|
sizeof(Trigger *));
|
||||||
@ -623,7 +640,8 @@ DescribeTrigger(TriggerDesc *trigdesc, Trigger *trigger)
|
|||||||
{
|
{
|
||||||
tp = &(t[TRIGGER_EVENT_DELETE]);
|
tp = &(t[TRIGGER_EVENT_DELETE]);
|
||||||
if (*tp == NULL)
|
if (*tp == NULL)
|
||||||
*tp = (Trigger **) palloc(sizeof(Trigger *));
|
*tp = (Trigger **) MemoryContextAlloc(CacheMemoryContext,
|
||||||
|
sizeof(Trigger *));
|
||||||
else
|
else
|
||||||
*tp = (Trigger **) repalloc(*tp, (n[TRIGGER_EVENT_DELETE] + 1) *
|
*tp = (Trigger **) repalloc(*tp, (n[TRIGGER_EVENT_DELETE] + 1) *
|
||||||
sizeof(Trigger *));
|
sizeof(Trigger *));
|
||||||
@ -635,7 +653,8 @@ DescribeTrigger(TriggerDesc *trigdesc, Trigger *trigger)
|
|||||||
{
|
{
|
||||||
tp = &(t[TRIGGER_EVENT_UPDATE]);
|
tp = &(t[TRIGGER_EVENT_UPDATE]);
|
||||||
if (*tp == NULL)
|
if (*tp == NULL)
|
||||||
*tp = (Trigger **) palloc(sizeof(Trigger *));
|
*tp = (Trigger **) MemoryContextAlloc(CacheMemoryContext,
|
||||||
|
sizeof(Trigger *));
|
||||||
else
|
else
|
||||||
*tp = (Trigger **) repalloc(*tp, (n[TRIGGER_EVENT_UPDATE] + 1) *
|
*tp = (Trigger **) repalloc(*tp, (n[TRIGGER_EVENT_UPDATE] + 1) *
|
||||||
sizeof(Trigger *));
|
sizeof(Trigger *));
|
||||||
@ -1023,10 +1042,9 @@ ltrmark:;
|
|||||||
|
|
||||||
/* ----------
|
/* ----------
|
||||||
* Internal data to the deferred trigger mechanism is held
|
* Internal data to the deferred trigger mechanism is held
|
||||||
* during entire session in a global memor created at startup and
|
* during entire session in a global context created at startup and
|
||||||
* over statements/commands in a separate global memory which
|
* over statements/commands in a separate context which
|
||||||
* is created at transaction start and destroyed at transaction
|
* is created at transaction start and destroyed at transaction end.
|
||||||
* end.
|
|
||||||
* ----------
|
* ----------
|
||||||
*/
|
*/
|
||||||
static MemoryContext deftrig_gcxt = NULL;
|
static MemoryContext deftrig_gcxt = NULL;
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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 -
|
* InsertRule -
|
||||||
* takes the arguments and inserts them as attributes into the system
|
* takes the arguments and inserts them as attributes into the system
|
||||||
* relation "pg_rewrite"
|
* 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
|
static Oid
|
||||||
InsertRule(char *rulname,
|
InsertRule(char *rulname,
|
||||||
int evtype,
|
int evtype,
|
||||||
char *evobj,
|
Oid eventrel_oid,
|
||||||
char *evslot,
|
AttrNumber evslot_index,
|
||||||
char *evqual,
|
|
||||||
bool evinstead,
|
bool evinstead,
|
||||||
|
char *evqual,
|
||||||
char *actiontree)
|
char *actiontree)
|
||||||
{
|
{
|
||||||
Relation eventrel;
|
|
||||||
Oid eventrel_oid;
|
|
||||||
AttrNumber evslot_index;
|
|
||||||
int i;
|
int i;
|
||||||
Datum values[Natts_pg_rewrite];
|
Datum values[Natts_pg_rewrite];
|
||||||
char nulls[Natts_pg_rewrite];
|
char nulls[Natts_pg_rewrite];
|
||||||
@ -59,21 +48,6 @@ InsertRule(char *rulname,
|
|||||||
HeapTuple tup;
|
HeapTuple tup;
|
||||||
Oid rewriteObjectId;
|
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))
|
if (IsDefinedRewriteRule(rulname))
|
||||||
elog(ERROR, "Attempt to insert rule '%s' failed: already exists",
|
elog(ERROR, "Attempt to insert rule '%s' failed: already exists",
|
||||||
rulname);
|
rulname);
|
||||||
@ -177,17 +151,27 @@ DefineQueryRewrite(RuleStmt *stmt)
|
|||||||
Node *event_qual = stmt->whereClause;
|
Node *event_qual = stmt->whereClause;
|
||||||
bool is_instead = stmt->instead;
|
bool is_instead = stmt->instead;
|
||||||
List *action = stmt->actions;
|
List *action = stmt->actions;
|
||||||
Relation event_relation = NULL;
|
Relation event_relation;
|
||||||
|
Oid ev_relid;
|
||||||
Oid ruleId;
|
Oid ruleId;
|
||||||
Oid ev_relid = 0;
|
|
||||||
char *eslot_string = NULL;
|
char *eslot_string = NULL;
|
||||||
int event_attno = 0;
|
int event_attno;
|
||||||
Oid event_attype = 0;
|
Oid event_attype;
|
||||||
char *actionP,
|
char *actionP,
|
||||||
*event_qualP;
|
*event_qualP;
|
||||||
List *l;
|
List *l;
|
||||||
Query *query;
|
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
|
* The current rewrite handler is known to work on relation level
|
||||||
* rules only. And for SELECT events, it expects one non-nothing
|
* 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
|
* No rule actions that modify OLD or NEW
|
||||||
*/
|
*/
|
||||||
if (action != NIL)
|
foreach(l, action)
|
||||||
foreach(l, action)
|
|
||||||
{
|
{
|
||||||
query = (Query *) lfirst(l);
|
query = (Query *) lfirst(l);
|
||||||
if (query->resultRelation == 1)
|
if (query->resultRelation == 1)
|
||||||
{
|
{
|
||||||
elog(NOTICE, "rule actions on OLD currently not supported");
|
elog(ERROR, "rule actions on OLD currently not supported"
|
||||||
elog(ERROR, " use views or triggers instead");
|
"\n\tuse views or triggers instead");
|
||||||
}
|
}
|
||||||
if (query->resultRelation == 2)
|
if (query->resultRelation == 2)
|
||||||
{
|
{
|
||||||
elog(NOTICE, "rule actions on NEW currently not supported");
|
elog(ERROR, "rule actions on NEW currently not supported"
|
||||||
elog(ERROR, " use triggers instead");
|
"\n\tuse triggers instead");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -242,8 +225,8 @@ DefineQueryRewrite(RuleStmt *stmt)
|
|||||||
*/
|
*/
|
||||||
if (length(action) == 0)
|
if (length(action) == 0)
|
||||||
{
|
{
|
||||||
elog(NOTICE, "instead nothing rules on select currently not supported");
|
elog(ERROR, "instead nothing rules on select currently not supported"
|
||||||
elog(ERROR, " use views instead");
|
"\n\tuse views instead");
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -265,8 +248,6 @@ DefineQueryRewrite(RuleStmt *stmt)
|
|||||||
* ... the targetlist of the SELECT action must exactly match the
|
* ... the targetlist of the SELECT action must exactly match the
|
||||||
* event relation, ...
|
* event relation, ...
|
||||||
*/
|
*/
|
||||||
event_relation = heap_openr(event_obj->relname, AccessShareLock);
|
|
||||||
|
|
||||||
if (event_relation->rd_att->natts != length(query->targetList))
|
if (event_relation->rd_att->natts != length(query->targetList))
|
||||||
elog(ERROR, "select rules target list must match event relations structure");
|
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);
|
tle = (TargetEntry *) nth(i - 1, query->targetList);
|
||||||
resdom = tle->resdom;
|
resdom = tle->resdom;
|
||||||
attr = event_relation->rd_att->attrs[i - 1];
|
attr = event_relation->rd_att->attrs[i - 1];
|
||||||
attname = pstrdup(NameStr(attr->attname));
|
attname = NameStr(attr->attname);
|
||||||
|
|
||||||
if (strcmp(resdom->resname, attname) != 0)
|
if (strcmp(resdom->resname, attname) != 0)
|
||||||
elog(ERROR, "select rules target entry %d has different column name from %s", i, attname);
|
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
|
* LIMIT in view is not supported
|
||||||
*/
|
*/
|
||||||
@ -337,62 +316,46 @@ DefineQueryRewrite(RuleStmt *stmt)
|
|||||||
/*
|
/*
|
||||||
* This rule is allowed - install it.
|
* This rule is allowed - install it.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
event_relation = heap_openr(event_obj->relname, AccessShareLock);
|
|
||||||
ev_relid = RelationGetRelid(event_relation);
|
|
||||||
|
|
||||||
if (eslot_string == NULL)
|
if (eslot_string == NULL)
|
||||||
{
|
{
|
||||||
event_attno = -1;
|
event_attno = -1;
|
||||||
event_attype = -1; /* XXX - don't care */
|
event_attype = InvalidOid;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
event_attno = attnameAttNum(event_relation, eslot_string);
|
event_attno = attnameAttNum(event_relation, eslot_string);
|
||||||
event_attype = attnumTypeId(event_relation, event_attno);
|
event_attype = attnumTypeId(event_relation, event_attno);
|
||||||
}
|
}
|
||||||
heap_close(event_relation, AccessShareLock);
|
|
||||||
|
|
||||||
/* fix bug about instead nothing */
|
/* fix bug about instead nothing */
|
||||||
ValidateRule(event_type, event_obj->relname,
|
ValidateRule(event_type, event_obj->relname,
|
||||||
eslot_string, event_qual, &action,
|
eslot_string, event_qual, &action,
|
||||||
is_instead, event_attype);
|
is_instead, event_attype);
|
||||||
|
|
||||||
if (action == NULL)
|
/* discard rule if it's null action and not INSTEAD; it's a no-op */
|
||||||
{
|
if (action != NULL || is_instead)
|
||||||
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
|
|
||||||
{
|
{
|
||||||
event_qualP = nodeToString(event_qual);
|
event_qualP = nodeToString(event_qual);
|
||||||
actionP = nodeToString(action);
|
actionP = nodeToString(action);
|
||||||
|
|
||||||
ruleId = InsertRule(stmt->rulename,
|
ruleId = InsertRule(stmt->rulename,
|
||||||
event_type,
|
event_type,
|
||||||
event_obj->relname,
|
ev_relid,
|
||||||
eslot_string,
|
event_attno,
|
||||||
event_qualP,
|
|
||||||
is_instead,
|
is_instead,
|
||||||
|
event_qualP,
|
||||||
actionP);
|
actionP);
|
||||||
|
|
||||||
/* what is the max size of type text? XXX -- glass */
|
/*
|
||||||
if (length(action) > 15)
|
* Set pg_class 'relhasrules' field TRUE for event relation.
|
||||||
elog(ERROR, "max # of actions exceeded");
|
*
|
||||||
prs2_addToRelation(ev_relid, ruleId, event_type, event_attno,
|
* Important side effect: an SI notice is broadcast to force all
|
||||||
is_instead, event_qual, action);
|
* 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
|
* 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 = rt_fetch(result_relation, parsetree->rtable);
|
||||||
rt_entry_relation = heap_openr(rt_entry->relname, AccessShareLock);
|
rt_entry_relation = heap_openr(rt_entry->relname, AccessShareLock);
|
||||||
rt_entry_locks = rt_entry_relation->rd_rules;
|
rt_entry_locks = rt_entry_relation->rd_rules;
|
||||||
heap_close(rt_entry_relation, AccessShareLock);
|
|
||||||
|
|
||||||
if (rt_entry_locks != NULL)
|
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,
|
product_queries = fireRules(parsetree,
|
||||||
result_relation,
|
result_relation,
|
||||||
@ -1346,13 +1346,15 @@ RewriteQuery(Query *parsetree, bool *instead_flag, List **qual_products)
|
|||||||
qual_products);
|
qual_products);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
heap_close(rt_entry_relation, AccessShareLock);
|
||||||
|
|
||||||
return product_queries;
|
return product_queries;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* to avoid infinite recursion, we restrict the number of times a query
|
* 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
|
#ifndef REWRITE_INVOKE_MAX
|
||||||
#define REWRITE_INVOKE_MAX 10
|
#define REWRITE_INVOKE_MAX 10
|
||||||
@ -1373,8 +1375,6 @@ deepRewriteQuery(Query *parsetree)
|
|||||||
bool instead;
|
bool instead;
|
||||||
List *qual_products = NIL;
|
List *qual_products = NIL;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (++numQueryRewriteInvoked > REWRITE_INVOKE_MAX)
|
if (++numQueryRewriteInvoked > REWRITE_INVOKE_MAX)
|
||||||
{
|
{
|
||||||
elog(ERROR, "query rewritten %d times, may contain cycles",
|
elog(ERROR, "query rewritten %d times, may contain cycles",
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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);
|
return NameStr(((Form_pg_class) GETSTRUCT(htup))->relname);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------------------------------------------------------
|
/*
|
||||||
*
|
|
||||||
* RemoveRewriteRule
|
* RemoveRewriteRule
|
||||||
*
|
*
|
||||||
* Delete a rule given its rulename.
|
* 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
|
void
|
||||||
RemoveRewriteRule(char *ruleName)
|
RemoveRewriteRule(char *ruleName)
|
||||||
{
|
{
|
||||||
Relation RewriteRelation = NULL;
|
Relation RewriteRelation;
|
||||||
HeapTuple tuple = NULL;
|
Relation event_relation;
|
||||||
Oid ruleId = (Oid) 0;
|
HeapTuple tuple;
|
||||||
Oid eventRelationOid = (Oid) NULL;
|
Oid ruleId;
|
||||||
Datum eventRelationOidDatum = (Datum) NULL;
|
Oid eventRelationOid;
|
||||||
bool isNull = false;
|
bool hasMoreRules;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Open the pg_rewrite relation.
|
* Open the pg_rewrite relation.
|
||||||
@ -83,7 +73,7 @@ RemoveRewriteRule(char *ruleName)
|
|||||||
RewriteRelation = heap_openr(RewriteRelationName, RowExclusiveLock);
|
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,
|
tuple = SearchSysCacheTupleCopy(RULENAME,
|
||||||
PointerGetDatum(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
|
* relation's OID
|
||||||
*/
|
*/
|
||||||
ruleId = tuple->t_data->t_oid;
|
ruleId = tuple->t_data->t_oid;
|
||||||
eventRelationOidDatum = heap_getattr(tuple,
|
eventRelationOid = ((Form_pg_rewrite) GETSTRUCT(tuple))->ev_class;
|
||||||
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);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Now delete the relation level locks from the updated relation.
|
* We had better grab AccessExclusiveLock so that we know no other
|
||||||
* (Make sure we do this before we remove the rule from pg_rewrite.
|
* rule additions/deletions are going on for this relation. Else
|
||||||
* Otherwise, heap_openr on eventRelationOid which reads pg_rwrite for
|
* we cannot set relhasrules correctly. Besides, we don't want to
|
||||||
* the rules will fail.)
|
* 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
|
* Delete any comments associated with this rule
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
DeleteComments(ruleId);
|
DeleteComments(ruleId);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Now delete the tuple...
|
* Now delete the pg_rewrite tuple for the rule
|
||||||
*/
|
*/
|
||||||
heap_delete(RewriteRelation, &tuple->t_self, NULL);
|
heap_delete(RewriteRelation, &tuple->t_self, NULL);
|
||||||
|
|
||||||
heap_freetuple(tuple);
|
heap_freetuple(tuple);
|
||||||
|
|
||||||
heap_close(RewriteRelation, RowExclusiveLock);
|
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
|
* 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 "postgres.h"
|
||||||
|
|
||||||
|
|
||||||
#include "access/heapam.h"
|
#include "access/heapam.h"
|
||||||
#include "catalog/catname.h"
|
#include "catalog/catname.h"
|
||||||
#include "catalog/indexing.h"
|
#include "catalog/indexing.h"
|
||||||
@ -22,60 +21,6 @@
|
|||||||
#include "utils/catcache.h"
|
#include "utils/catcache.h"
|
||||||
#include "utils/syscache.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
|
int
|
||||||
IsDefinedRewriteRule(char *ruleName)
|
IsDefinedRewriteRule(char *ruleName)
|
||||||
@ -88,7 +33,20 @@ IsDefinedRewriteRule(char *ruleName)
|
|||||||
return HeapTupleIsValid(tuple);
|
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)
|
setRelhasrulesInRelation(Oid relationId, bool relhasrules)
|
||||||
{
|
{
|
||||||
Relation relationRelation;
|
Relation relationRelation;
|
||||||
@ -96,9 +54,7 @@ setRelhasrulesInRelation(Oid relationId, bool relhasrules)
|
|||||||
Relation idescs[Num_pg_class_indices];
|
Relation idescs[Num_pg_class_indices];
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Lock a relation given its Oid. Go to the RelationRelation (i.e.
|
* Find the tuple to update in pg_class, using syscache for the lookup.
|
||||||
* pg_relation), find the appropriate tuple, and add the specified
|
|
||||||
* lock to it.
|
|
||||||
*/
|
*/
|
||||||
relationRelation = heap_openr(RelationRelationName, RowExclusiveLock);
|
relationRelation = heap_openr(RelationRelationName, RowExclusiveLock);
|
||||||
tuple = SearchSysCacheTupleCopy(RELOID,
|
tuple = SearchSysCacheTupleCopy(RELOID,
|
||||||
@ -106,10 +62,11 @@ setRelhasrulesInRelation(Oid relationId, bool relhasrules)
|
|||||||
0, 0, 0);
|
0, 0, 0);
|
||||||
Assert(HeapTupleIsValid(tuple));
|
Assert(HeapTupleIsValid(tuple));
|
||||||
|
|
||||||
|
/* Do the update */
|
||||||
((Form_pg_class) GETSTRUCT(tuple))->relhasrules = relhasrules;
|
((Form_pg_class) GETSTRUCT(tuple))->relhasrules = relhasrules;
|
||||||
heap_update(relationRelation, &tuple->t_self, tuple, NULL);
|
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);
|
CatalogOpenIndices(Num_pg_class_indices, Name_pg_class_indices, idescs);
|
||||||
CatalogIndexInsert(idescs, Num_pg_class_indices, relationRelation, tuple);
|
CatalogIndexInsert(idescs, Num_pg_class_indices, relationRelation, tuple);
|
||||||
CatalogCloseIndices(Num_pg_class_indices, idescs);
|
CatalogCloseIndices(Num_pg_class_indices, idescs);
|
||||||
@ -117,120 +74,3 @@ setRelhasrulesInRelation(Oid relationId, bool relhasrules)
|
|||||||
heap_freetuple(tuple);
|
heap_freetuple(tuple);
|
||||||
heap_close(relationRelation, RowExclusiveLock);
|
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
|
* 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
|
* RelationClose - close an open relation
|
||||||
*
|
*
|
||||||
* NOTES
|
* 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
|
* The following code contains many undocumented hacks. Please be
|
||||||
* careful....
|
* careful....
|
||||||
*
|
*
|
||||||
@ -59,6 +56,7 @@
|
|||||||
#include "storage/smgr.h"
|
#include "storage/smgr.h"
|
||||||
#include "utils/catcache.h"
|
#include "utils/catcache.h"
|
||||||
#include "utils/fmgroids.h"
|
#include "utils/fmgroids.h"
|
||||||
|
#include "utils/memutils.h"
|
||||||
#include "utils/relcache.h"
|
#include "utils/relcache.h"
|
||||||
#include "utils/temprel.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
|
* 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.
|
* thus there are two hash tables for referencing them.
|
||||||
* ----------------
|
* ----------------
|
||||||
*/
|
*/
|
||||||
@ -91,6 +89,12 @@ static HTAB *RelationIdCache;
|
|||||||
*/
|
*/
|
||||||
static List *newlyCreatedRelns = NULL;
|
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
|
* 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 init_irels(void);
|
||||||
static void write_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);
|
FormData_pg_attribute *att);
|
||||||
|
|
||||||
static HeapTuple ScanPgRelation(RelationBuildDescInfo buildinfo);
|
static HeapTuple ScanPgRelation(RelationBuildDescInfo buildinfo);
|
||||||
static HeapTuple scan_pg_rel_seq(RelationBuildDescInfo buildinfo);
|
static HeapTuple scan_pg_rel_seq(RelationBuildDescInfo buildinfo);
|
||||||
static HeapTuple scan_pg_rel_ind(RelationBuildDescInfo buildinfo);
|
static HeapTuple scan_pg_rel_ind(RelationBuildDescInfo buildinfo);
|
||||||
static Relation AllocateRelationDesc(Relation relation, u_int natts,
|
static Relation AllocateRelationDesc(Relation relation, Form_pg_class relp);
|
||||||
Form_pg_class relp);
|
|
||||||
static void RelationBuildTupleDesc(RelationBuildDescInfo buildinfo,
|
static void RelationBuildTupleDesc(RelationBuildDescInfo buildinfo,
|
||||||
Relation relation, u_int natts);
|
Relation relation);
|
||||||
static void build_tupdesc_seq(RelationBuildDescInfo buildinfo,
|
static void build_tupdesc_seq(RelationBuildDescInfo buildinfo,
|
||||||
Relation relation, u_int natts);
|
Relation relation);
|
||||||
static void build_tupdesc_ind(RelationBuildDescInfo buildinfo,
|
static void build_tupdesc_ind(RelationBuildDescInfo buildinfo,
|
||||||
Relation relation, u_int natts);
|
Relation relation);
|
||||||
static Relation RelationBuildDesc(RelationBuildDescInfo buildinfo,
|
static Relation RelationBuildDesc(RelationBuildDescInfo buildinfo,
|
||||||
Relation oldrelation);
|
Relation oldrelation);
|
||||||
static void IndexedAccessMethodInitialize(Relation relation);
|
static void IndexedAccessMethodInitialize(Relation relation);
|
||||||
@ -232,7 +235,6 @@ static void AttrDefaultFetch(Relation relation);
|
|||||||
static void RelCheckFetch(Relation relation);
|
static void RelCheckFetch(Relation relation);
|
||||||
static List *insert_ordered_oid(List *list, Oid datum);
|
static List *insert_ordered_oid(List *list, Oid datum);
|
||||||
|
|
||||||
static bool criticalRelcacheBuild = false;
|
|
||||||
|
|
||||||
/* ----------------------------------------------------------------
|
/* ----------------------------------------------------------------
|
||||||
* RelationIdGetRelation() and RelationNameGetRelation()
|
* RelationIdGetRelation() and RelationNameGetRelation()
|
||||||
@ -262,7 +264,7 @@ ScanPgRelation(RelationBuildDescInfo buildinfo)
|
|||||||
* can, and do.
|
* can, and do.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (IsIgnoringSystemIndexes() || !criticalRelcacheBuild)
|
if (IsIgnoringSystemIndexes() || !criticalRelcachesBuilt)
|
||||||
return scan_pg_rel_seq(buildinfo);
|
return scan_pg_rel_seq(buildinfo);
|
||||||
else
|
else
|
||||||
return scan_pg_rel_ind(buildinfo);
|
return scan_pg_rel_ind(buildinfo);
|
||||||
@ -379,11 +381,30 @@ scan_pg_rel_ind(RelationBuildDescInfo buildinfo)
|
|||||||
* ----------------
|
* ----------------
|
||||||
*/
|
*/
|
||||||
static Relation
|
static Relation
|
||||||
AllocateRelationDesc(Relation relation, u_int natts,
|
AllocateRelationDesc(Relation relation, Form_pg_class relp)
|
||||||
Form_pg_class relp)
|
|
||||||
{
|
{
|
||||||
|
MemoryContext oldcxt;
|
||||||
Form_pg_class relationForm;
|
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
|
* Copy the relation tuple form
|
||||||
*
|
*
|
||||||
@ -399,27 +420,14 @@ AllocateRelationDesc(Relation relation, u_int natts,
|
|||||||
|
|
||||||
memcpy((char *) relationForm, (char *) relp, CLASS_TUPLE_SIZE);
|
memcpy((char *) relationForm, (char *) relp, CLASS_TUPLE_SIZE);
|
||||||
|
|
||||||
/* ----------------
|
/* initialize relation tuple form */
|
||||||
* 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 */
|
|
||||||
relation->rd_rel = relationForm;
|
relation->rd_rel = relationForm;
|
||||||
|
|
||||||
|
/* and allocate attribute tuple form storage */
|
||||||
|
relation->rd_att = CreateTemplateTupleDesc(relationForm->relnatts);
|
||||||
|
|
||||||
|
MemoryContextSwitchTo(oldcxt);
|
||||||
|
|
||||||
return relation;
|
return relation;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -432,8 +440,7 @@ AllocateRelationDesc(Relation relation, u_int natts,
|
|||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
RelationBuildTupleDesc(RelationBuildDescInfo buildinfo,
|
RelationBuildTupleDesc(RelationBuildDescInfo buildinfo,
|
||||||
Relation relation,
|
Relation relation)
|
||||||
u_int natts)
|
|
||||||
{
|
{
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -442,14 +449,17 @@ RelationBuildTupleDesc(RelationBuildDescInfo buildinfo,
|
|||||||
* can, and do.
|
* can, and do.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (IsIgnoringSystemIndexes() || !criticalRelcacheBuild)
|
if (IsIgnoringSystemIndexes() || !criticalRelcachesBuilt)
|
||||||
build_tupdesc_seq(buildinfo, relation, natts);
|
build_tupdesc_seq(buildinfo, relation);
|
||||||
else
|
else
|
||||||
build_tupdesc_ind(buildinfo, relation, natts);
|
build_tupdesc_ind(buildinfo, relation);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
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 (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 */
|
if (relation->rd_rel->relchecks > 0) /* CHECKs */
|
||||||
{
|
{
|
||||||
constr->num_check = relation->rd_rel->relchecks;
|
constr->num_check = relation->rd_rel->relchecks;
|
||||||
constr->check = (ConstrCheck *) palloc(constr->num_check *
|
constr->check = (ConstrCheck *)
|
||||||
sizeof(ConstrCheck));
|
MemoryContextAlloc(CacheMemoryContext,
|
||||||
|
constr->num_check * sizeof(ConstrCheck));
|
||||||
MemSet(constr->check, 0, constr->num_check * sizeof(ConstrCheck));
|
MemSet(constr->check, 0, constr->num_check * sizeof(ConstrCheck));
|
||||||
RelCheckFetch(relation);
|
RelCheckFetch(relation);
|
||||||
}
|
}
|
||||||
@ -488,8 +499,7 @@ SetConstrOfRelation(Relation relation, TupleConstr *constr, int ndef, AttrDefaul
|
|||||||
|
|
||||||
static void
|
static void
|
||||||
build_tupdesc_seq(RelationBuildDescInfo buildinfo,
|
build_tupdesc_seq(RelationBuildDescInfo buildinfo,
|
||||||
Relation relation,
|
Relation relation)
|
||||||
u_int natts)
|
|
||||||
{
|
{
|
||||||
HeapTuple pg_attribute_tuple;
|
HeapTuple pg_attribute_tuple;
|
||||||
Relation pg_attribute_desc;
|
Relation pg_attribute_desc;
|
||||||
@ -497,11 +507,14 @@ build_tupdesc_seq(RelationBuildDescInfo buildinfo,
|
|||||||
Form_pg_attribute attp;
|
Form_pg_attribute attp;
|
||||||
ScanKeyData key;
|
ScanKeyData key;
|
||||||
int need;
|
int need;
|
||||||
TupleConstr *constr = (TupleConstr *) palloc(sizeof(TupleConstr));
|
TupleConstr *constr;
|
||||||
AttrDefault *attrdef = NULL;
|
AttrDefault *attrdef = NULL;
|
||||||
int ndef = 0;
|
int ndef = 0;
|
||||||
|
|
||||||
|
constr = (TupleConstr *) MemoryContextAlloc(CacheMemoryContext,
|
||||||
|
sizeof(TupleConstr));
|
||||||
constr->has_not_null = false;
|
constr->has_not_null = false;
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
* form a scan key
|
* form a scan key
|
||||||
* ----------------
|
* ----------------
|
||||||
@ -522,7 +535,7 @@ build_tupdesc_seq(RelationBuildDescInfo buildinfo,
|
|||||||
* add attribute data to relation->rd_att
|
* add attribute data to relation->rd_att
|
||||||
* ----------------
|
* ----------------
|
||||||
*/
|
*/
|
||||||
need = natts;
|
need = relation->rd_rel->relnatts;
|
||||||
|
|
||||||
pg_attribute_tuple = heap_getnext(pg_attribute_scan, 0);
|
pg_attribute_tuple = heap_getnext(pg_attribute_scan, 0);
|
||||||
while (HeapTupleIsValid(pg_attribute_tuple) && need > 0)
|
while (HeapTupleIsValid(pg_attribute_tuple) && need > 0)
|
||||||
@ -532,12 +545,14 @@ build_tupdesc_seq(RelationBuildDescInfo buildinfo,
|
|||||||
if (attp->attnum > 0)
|
if (attp->attnum > 0)
|
||||||
{
|
{
|
||||||
relation->rd_att->attrs[attp->attnum - 1] =
|
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]),
|
memcpy((char *) (relation->rd_att->attrs[attp->attnum - 1]),
|
||||||
(char *) attp,
|
(char *) attp,
|
||||||
ATTRIBUTE_TUPLE_SIZE);
|
ATTRIBUTE_TUPLE_SIZE);
|
||||||
need--;
|
need--;
|
||||||
|
|
||||||
/* Update if this attribute have a constraint */
|
/* Update if this attribute have a constraint */
|
||||||
if (attp->attnotnull)
|
if (attp->attnotnull)
|
||||||
constr->has_not_null = true;
|
constr->has_not_null = true;
|
||||||
@ -546,10 +561,12 @@ build_tupdesc_seq(RelationBuildDescInfo buildinfo,
|
|||||||
{
|
{
|
||||||
if (attrdef == NULL)
|
if (attrdef == NULL)
|
||||||
{
|
{
|
||||||
attrdef = (AttrDefault *) palloc(relation->rd_rel->relnatts *
|
attrdef = (AttrDefault *)
|
||||||
sizeof(AttrDefault));
|
MemoryContextAlloc(CacheMemoryContext,
|
||||||
|
relation->rd_rel->relnatts *
|
||||||
|
sizeof(AttrDefault));
|
||||||
MemSet(attrdef, 0,
|
MemSet(attrdef, 0,
|
||||||
relation->rd_rel->relnatts * sizeof(AttrDefault));
|
relation->rd_rel->relnatts * sizeof(AttrDefault));
|
||||||
}
|
}
|
||||||
attrdef[ndef].adnum = attp->attnum;
|
attrdef[ndef].adnum = attp->attnum;
|
||||||
attrdef[ndef].adbin = NULL;
|
attrdef[ndef].adbin = NULL;
|
||||||
@ -575,17 +592,18 @@ build_tupdesc_seq(RelationBuildDescInfo buildinfo,
|
|||||||
|
|
||||||
static void
|
static void
|
||||||
build_tupdesc_ind(RelationBuildDescInfo buildinfo,
|
build_tupdesc_ind(RelationBuildDescInfo buildinfo,
|
||||||
Relation relation,
|
Relation relation)
|
||||||
u_int natts)
|
|
||||||
{
|
{
|
||||||
Relation attrel;
|
Relation attrel;
|
||||||
HeapTuple atttup;
|
HeapTuple atttup;
|
||||||
Form_pg_attribute attp;
|
Form_pg_attribute attp;
|
||||||
TupleConstr *constr = (TupleConstr *) palloc(sizeof(TupleConstr));
|
TupleConstr *constr;
|
||||||
AttrDefault *attrdef = NULL;
|
AttrDefault *attrdef = NULL;
|
||||||
int ndef = 0;
|
int ndef = 0;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
constr = (TupleConstr *) MemoryContextAlloc(CacheMemoryContext,
|
||||||
|
sizeof(TupleConstr));
|
||||||
constr->has_not_null = false;
|
constr->has_not_null = false;
|
||||||
|
|
||||||
attrel = heap_openr(AttributeRelationName, AccessShareLock);
|
attrel = heap_openr(AttributeRelationName, AccessShareLock);
|
||||||
@ -616,7 +634,8 @@ build_tupdesc_ind(RelationBuildDescInfo buildinfo,
|
|||||||
}
|
}
|
||||||
|
|
||||||
relation->rd_att->attrs[i - 1] = attp =
|
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,
|
memcpy((char *) attp,
|
||||||
(char *) (Form_pg_attribute) GETSTRUCT(atttup),
|
(char *) (Form_pg_attribute) GETSTRUCT(atttup),
|
||||||
@ -638,8 +657,10 @@ build_tupdesc_ind(RelationBuildDescInfo buildinfo,
|
|||||||
{
|
{
|
||||||
if (attrdef == NULL)
|
if (attrdef == NULL)
|
||||||
{
|
{
|
||||||
attrdef = (AttrDefault *) palloc(relation->rd_rel->relnatts *
|
attrdef = (AttrDefault *)
|
||||||
sizeof(AttrDefault));
|
MemoryContextAlloc(CacheMemoryContext,
|
||||||
|
relation->rd_rel->relnatts *
|
||||||
|
sizeof(AttrDefault));
|
||||||
MemSet(attrdef, 0,
|
MemSet(attrdef, 0,
|
||||||
relation->rd_rel->relnatts * sizeof(AttrDefault));
|
relation->rd_rel->relnatts * sizeof(AttrDefault));
|
||||||
}
|
}
|
||||||
@ -652,7 +673,6 @@ build_tupdesc_ind(RelationBuildDescInfo buildinfo,
|
|||||||
heap_close(attrel, AccessShareLock);
|
heap_close(attrel, AccessShareLock);
|
||||||
|
|
||||||
SetConstrOfRelation(relation, constr, ndef, attrdef);
|
SetConstrOfRelation(relation, constr, ndef, attrdef);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* --------------------------------
|
/* --------------------------------
|
||||||
@ -660,11 +680,22 @@ build_tupdesc_ind(RelationBuildDescInfo buildinfo,
|
|||||||
*
|
*
|
||||||
* Form the relation's rewrite rules from information in
|
* Form the relation's rewrite rules from information in
|
||||||
* the pg_rewrite system catalog.
|
* 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
|
static void
|
||||||
RelationBuildRuleLock(Relation relation)
|
RelationBuildRuleLock(Relation relation)
|
||||||
{
|
{
|
||||||
|
MemoryContext rulescxt;
|
||||||
|
MemoryContext oldcxt;
|
||||||
HeapTuple pg_rewrite_tuple;
|
HeapTuple pg_rewrite_tuple;
|
||||||
Relation pg_rewrite_desc;
|
Relation pg_rewrite_desc;
|
||||||
TupleDesc pg_rewrite_tupdesc;
|
TupleDesc pg_rewrite_tupdesc;
|
||||||
@ -675,13 +706,25 @@ RelationBuildRuleLock(Relation relation)
|
|||||||
RewriteRule **rules;
|
RewriteRule **rules;
|
||||||
int maxlocks;
|
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
|
* form an array to hold the rewrite rules (the array is extended if
|
||||||
* necessary)
|
* necessary)
|
||||||
* ----------------
|
* ----------------
|
||||||
*/
|
*/
|
||||||
maxlocks = 4;
|
maxlocks = 4;
|
||||||
rules = (RewriteRule **) palloc(sizeof(RewriteRule *) * maxlocks);
|
rules = (RewriteRule **)
|
||||||
|
MemoryContextAlloc(rulescxt, sizeof(RewriteRule *) * maxlocks);
|
||||||
numlocks = 0;
|
numlocks = 0;
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
@ -710,26 +753,32 @@ RelationBuildRuleLock(Relation relation)
|
|||||||
char *rule_evqual_str;
|
char *rule_evqual_str;
|
||||||
RewriteRule *rule;
|
RewriteRule *rule;
|
||||||
|
|
||||||
rule = (RewriteRule *) palloc(sizeof(RewriteRule));
|
rule = (RewriteRule *) MemoryContextAlloc(rulescxt,
|
||||||
|
sizeof(RewriteRule));
|
||||||
|
|
||||||
rule->ruleId = pg_rewrite_tuple->t_data->t_oid;
|
rule->ruleId = pg_rewrite_tuple->t_data->t_oid;
|
||||||
|
|
||||||
rule->event = (int) heap_getattr(pg_rewrite_tuple,
|
rule->event = DatumGetInt32(heap_getattr(pg_rewrite_tuple,
|
||||||
Anum_pg_rewrite_ev_type, pg_rewrite_tupdesc,
|
Anum_pg_rewrite_ev_type,
|
||||||
&isnull) - 48;
|
pg_rewrite_tupdesc,
|
||||||
rule->attrno = (int) heap_getattr(pg_rewrite_tuple,
|
&isnull)) - 48;
|
||||||
Anum_pg_rewrite_ev_attr, pg_rewrite_tupdesc,
|
rule->attrno = DatumGetInt16(heap_getattr(pg_rewrite_tuple,
|
||||||
&isnull);
|
Anum_pg_rewrite_ev_attr,
|
||||||
rule->isInstead = !!heap_getattr(pg_rewrite_tuple,
|
pg_rewrite_tupdesc,
|
||||||
Anum_pg_rewrite_is_instead, pg_rewrite_tupdesc,
|
&isnull));
|
||||||
&isnull);
|
rule->isInstead = DatumGetBool(heap_getattr(pg_rewrite_tuple,
|
||||||
|
Anum_pg_rewrite_is_instead,
|
||||||
|
pg_rewrite_tupdesc,
|
||||||
|
&isnull));
|
||||||
|
|
||||||
ruleaction = heap_getattr(pg_rewrite_tuple,
|
ruleaction = heap_getattr(pg_rewrite_tuple,
|
||||||
Anum_pg_rewrite_ev_action,
|
Anum_pg_rewrite_ev_action,
|
||||||
pg_rewrite_tupdesc,
|
pg_rewrite_tupdesc,
|
||||||
&isnull);
|
&isnull);
|
||||||
ruleaction_str = lztextout((lztext *) DatumGetPointer(ruleaction));
|
ruleaction_str = lztextout((lztext *) DatumGetPointer(ruleaction));
|
||||||
|
oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
|
||||||
rule->actions = (List *) stringToNode(ruleaction_str);
|
rule->actions = (List *) stringToNode(ruleaction_str);
|
||||||
|
MemoryContextSwitchTo(oldcxt);
|
||||||
pfree(ruleaction_str);
|
pfree(ruleaction_str);
|
||||||
|
|
||||||
rule_evqual = heap_getattr(pg_rewrite_tuple,
|
rule_evqual = heap_getattr(pg_rewrite_tuple,
|
||||||
@ -737,13 +786,16 @@ RelationBuildRuleLock(Relation relation)
|
|||||||
pg_rewrite_tupdesc,
|
pg_rewrite_tupdesc,
|
||||||
&isnull);
|
&isnull);
|
||||||
rule_evqual_str = lztextout((lztext *) DatumGetPointer(rule_evqual));
|
rule_evqual_str = lztextout((lztext *) DatumGetPointer(rule_evqual));
|
||||||
|
oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
|
||||||
rule->qual = (Node *) stringToNode(rule_evqual_str);
|
rule->qual = (Node *) stringToNode(rule_evqual_str);
|
||||||
|
MemoryContextSwitchTo(oldcxt);
|
||||||
pfree(rule_evqual_str);
|
pfree(rule_evqual_str);
|
||||||
|
|
||||||
if (numlocks >= maxlocks)
|
if (numlocks >= maxlocks)
|
||||||
{
|
{
|
||||||
maxlocks *= 2;
|
maxlocks *= 2;
|
||||||
rules = (RewriteRule **) repalloc(rules, sizeof(RewriteRule *) * maxlocks);
|
rules = (RewriteRule **)
|
||||||
|
repalloc(rules, sizeof(RewriteRule *) * maxlocks);
|
||||||
}
|
}
|
||||||
rules[numlocks++] = rule;
|
rules[numlocks++] = rule;
|
||||||
}
|
}
|
||||||
@ -759,42 +811,13 @@ RelationBuildRuleLock(Relation relation)
|
|||||||
* form a RuleLock and insert into relation
|
* form a RuleLock and insert into relation
|
||||||
* ----------------
|
* ----------------
|
||||||
*/
|
*/
|
||||||
rulelock = (RuleLock *) palloc(sizeof(RuleLock));
|
rulelock = (RuleLock *) MemoryContextAlloc(rulescxt, sizeof(RuleLock));
|
||||||
rulelock->numLocks = numlocks;
|
rulelock->numLocks = numlocks;
|
||||||
rulelock->rules = rules;
|
rulelock->rules = rules;
|
||||||
|
|
||||||
relation->rd_rules = rulelock;
|
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
|
* equalRuleLocks
|
||||||
*
|
*
|
||||||
@ -886,7 +909,6 @@ RelationBuildDesc(RelationBuildDescInfo buildinfo,
|
|||||||
{
|
{
|
||||||
File fd;
|
File fd;
|
||||||
Relation relation;
|
Relation relation;
|
||||||
u_int natts;
|
|
||||||
Oid relid;
|
Oid relid;
|
||||||
Oid relam;
|
Oid relam;
|
||||||
HeapTuple pg_class_tuple;
|
HeapTuple pg_class_tuple;
|
||||||
@ -912,17 +934,19 @@ RelationBuildDesc(RelationBuildDescInfo buildinfo,
|
|||||||
*/
|
*/
|
||||||
relid = pg_class_tuple->t_data->t_oid;
|
relid = pg_class_tuple->t_data->t_oid;
|
||||||
relp = (Form_pg_class) GETSTRUCT(pg_class_tuple);
|
relp = (Form_pg_class) GETSTRUCT(pg_class_tuple);
|
||||||
natts = relp->relnatts;
|
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
* allocate storage for the relation descriptor,
|
* allocate storage for the relation descriptor,
|
||||||
* initialize relation->rd_rel and get the access method id.
|
* and copy pg_class_tuple to relation->rd_rel.
|
||||||
* The storage is allocated in memory context CacheMemoryContext.
|
|
||||||
* ----------------
|
* ----------------
|
||||||
*/
|
*/
|
||||||
oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
|
relation = AllocateRelationDesc(oldrelation, relp);
|
||||||
relation = AllocateRelationDesc(oldrelation, natts, relp);
|
|
||||||
relam = relation->rd_rel->relam;
|
/* -------------------
|
||||||
|
* 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 relation's relation id (relation->rd_id)
|
||||||
@ -946,26 +970,30 @@ RelationBuildDesc(RelationBuildDescInfo buildinfo,
|
|||||||
* initialize the access method information (relation->rd_am)
|
* initialize the access method information (relation->rd_am)
|
||||||
* ----------------
|
* ----------------
|
||||||
*/
|
*/
|
||||||
|
relam = relation->rd_rel->relam;
|
||||||
if (OidIsValid(relam))
|
if (OidIsValid(relam))
|
||||||
relation->rd_am = AccessMethodObjectIdGetForm(relam);
|
relation->rd_am = AccessMethodObjectIdGetForm(relam,
|
||||||
|
CacheMemoryContext);
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
* initialize the tuple descriptor (relation->rd_att).
|
* 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);
|
RelationBuildRuleLock(relation);
|
||||||
else
|
else
|
||||||
|
{
|
||||||
relation->rd_rules = NULL;
|
relation->rd_rules = NULL;
|
||||||
|
relation->rd_rulescxt = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
/* Triggers */
|
if (relation->rd_rel->reltriggers > 0)
|
||||||
if (relp->reltriggers > 0)
|
|
||||||
RelationBuildTriggers(relation);
|
RelationBuildTriggers(relation);
|
||||||
else
|
else
|
||||||
relation->trigdesc = NULL;
|
relation->trigdesc = NULL;
|
||||||
@ -993,7 +1021,7 @@ RelationBuildDesc(RelationBuildDescInfo buildinfo,
|
|||||||
Assert(fd >= -1);
|
Assert(fd >= -1);
|
||||||
if (fd == -1)
|
if (fd == -1)
|
||||||
elog(NOTICE, "RelationIdBuildRelation: smgropen(%s): %m",
|
elog(NOTICE, "RelationIdBuildRelation: smgropen(%s): %m",
|
||||||
NameStr(relp->relname));
|
NameStr(relation->rd_rel->relname));
|
||||||
|
|
||||||
relation->rd_fd = fd;
|
relation->rd_fd = fd;
|
||||||
|
|
||||||
@ -1002,17 +1030,10 @@ RelationBuildDesc(RelationBuildDescInfo buildinfo,
|
|||||||
* restore memory context and return the new reldesc.
|
* restore memory context and return the new reldesc.
|
||||||
* ----------------
|
* ----------------
|
||||||
*/
|
*/
|
||||||
|
oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
|
||||||
RelationCacheInsert(relation);
|
RelationCacheInsert(relation);
|
||||||
|
|
||||||
MemoryContextSwitchTo(oldcxt);
|
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;
|
return relation;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1030,13 +1051,15 @@ IndexedAccessMethodInitialize(Relation relation)
|
|||||||
natts = relation->rd_rel->relnatts;
|
natts = relation->rd_rel->relnatts;
|
||||||
relamstrategies = relation->rd_am->amstrategies;
|
relamstrategies = relation->rd_am->amstrategies;
|
||||||
stratSize = AttributeNumberGetIndexStrategySize(natts, relamstrategies);
|
stratSize = AttributeNumberGetIndexStrategySize(natts, relamstrategies);
|
||||||
strategy = (IndexStrategy) palloc(stratSize);
|
strategy = (IndexStrategy) MemoryContextAlloc(CacheMemoryContext,
|
||||||
relamsupport = relation->rd_am->amsupport;
|
stratSize);
|
||||||
|
|
||||||
|
relamsupport = relation->rd_am->amsupport;
|
||||||
if (relamsupport > 0)
|
if (relamsupport > 0)
|
||||||
{
|
{
|
||||||
supportSize = natts * (relamsupport * sizeof(RegProcedure));
|
supportSize = natts * (relamsupport * sizeof(RegProcedure));
|
||||||
support = (RegProcedure *) palloc(supportSize);
|
support = (RegProcedure *) MemoryContextAlloc(CacheMemoryContext,
|
||||||
|
supportSize);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
support = (RegProcedure *) NULL;
|
support = (RegProcedure *) NULL;
|
||||||
@ -1052,20 +1075,20 @@ IndexedAccessMethodInitialize(Relation relation)
|
|||||||
/* --------------------------------
|
/* --------------------------------
|
||||||
* formrdesc
|
* formrdesc
|
||||||
*
|
*
|
||||||
* This is a special version of RelationBuildDesc()
|
* This is a special cut-down version of RelationBuildDesc()
|
||||||
* used by RelationInitialize() in initializing the
|
* used by RelationInitialize() in initializing the relcache.
|
||||||
* relcache. The system relation descriptors built
|
* The relation descriptor is built just from the supplied parameters.
|
||||||
* here are all nailed in the descriptor caches, for
|
*
|
||||||
* bootstrapping.
|
* NOTE: we assume we are already switched into CacheMemoryContext.
|
||||||
* --------------------------------
|
* --------------------------------
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
formrdesc(char *relationName,
|
formrdesc(char *relationName,
|
||||||
u_int natts,
|
int natts,
|
||||||
FormData_pg_attribute *att)
|
FormData_pg_attribute *att)
|
||||||
{
|
{
|
||||||
Relation relation;
|
Relation relation;
|
||||||
u_int i;
|
int i;
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
* allocate new relation desc
|
* allocate new relation desc
|
||||||
@ -1095,8 +1118,9 @@ formrdesc(char *relationName,
|
|||||||
strcpy(RelationGetPhysicalRelationName(relation), relationName);
|
strcpy(RelationGetPhysicalRelationName(relation), relationName);
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
initialize attribute tuple form
|
* initialize attribute tuple form
|
||||||
*/
|
* ----------------
|
||||||
|
*/
|
||||||
relation->rd_att = CreateTemplateTupleDesc(natts);
|
relation->rd_att = CreateTemplateTupleDesc(natts);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1120,7 +1144,7 @@ formrdesc(char *relationName,
|
|||||||
relation->rd_rel->relpages = 1; /* XXX */
|
relation->rd_rel->relpages = 1; /* XXX */
|
||||||
relation->rd_rel->reltuples = 1; /* XXX */
|
relation->rd_rel->reltuples = 1; /* XXX */
|
||||||
relation->rd_rel->relkind = RELKIND_RELATION;
|
relation->rd_rel->relkind = RELKIND_RELATION;
|
||||||
relation->rd_rel->relnatts = (uint16) natts;
|
relation->rd_rel->relnatts = (int16) natts;
|
||||||
relation->rd_isnailed = true;
|
relation->rd_isnailed = true;
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
@ -1157,6 +1181,10 @@ formrdesc(char *relationName,
|
|||||||
* Determining this requires a scan on pg_class, but to do the scan
|
* 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 rdesc for pg_class must already exist. Therefore we must do
|
||||||
* the check (and possible set) after cache insertion.
|
* 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 =
|
relation->rd_rel->relhasindex =
|
||||||
CatalogHasIndex(relationName, RelationGetRelid(relation));
|
CatalogHasIndex(relationName, RelationGetRelid(relation));
|
||||||
@ -1171,8 +1199,9 @@ formrdesc(char *relationName,
|
|||||||
/* --------------------------------
|
/* --------------------------------
|
||||||
* RelationIdCacheGetRelation
|
* RelationIdCacheGetRelation
|
||||||
*
|
*
|
||||||
* Lookup a reldesc by OID.
|
* Lookup an existing reldesc by OID.
|
||||||
* Only try to get the reldesc by looking up the cache
|
*
|
||||||
|
* Only try to get the reldesc by looking in the cache,
|
||||||
* do not go to the disk.
|
* do not go to the disk.
|
||||||
*
|
*
|
||||||
* NB: relation ref count is incremented if successful.
|
* 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
|
* (one with refcount > 0). However, this routine just does whichever
|
||||||
* it's told to do; callers must determine which they want.
|
* 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.
|
* while rebuilding, we complain unless refcount is 0.
|
||||||
* --------------------------------
|
* --------------------------------
|
||||||
*/
|
*/
|
||||||
@ -1383,8 +1412,6 @@ RelationClearRelation(Relation relation, bool rebuildIt)
|
|||||||
if (relation->rd_isnailed)
|
if (relation->rd_isnailed)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Remove relation from hash tables
|
* 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
|
* visible in the hash tables until it's valid again, so don't try to
|
||||||
* optimize this away...
|
* optimize this away...
|
||||||
*/
|
*/
|
||||||
|
oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
|
||||||
RelationCacheDelete(relation);
|
RelationCacheDelete(relation);
|
||||||
|
MemoryContextSwitchTo(oldcxt);
|
||||||
|
|
||||||
/* Clear out catcache's entries for this relation */
|
/* Clear out catcache's entries for this relation */
|
||||||
SystemCacheRelationFlushed(RelationGetRelid(relation));
|
SystemCacheRelationFlushed(RelationGetRelid(relation));
|
||||||
@ -1425,7 +1454,8 @@ RelationClearRelation(Relation relation, bool rebuildIt)
|
|||||||
{
|
{
|
||||||
/* ok to zap remaining substructure */
|
/* ok to zap remaining substructure */
|
||||||
FreeTupleDesc(relation->rd_att);
|
FreeTupleDesc(relation->rd_att);
|
||||||
FreeRuleLock(relation->rd_rules);
|
if (relation->rd_rulescxt)
|
||||||
|
MemoryContextDelete(relation->rd_rulescxt);
|
||||||
FreeTriggerDesc(relation->trigdesc);
|
FreeTriggerDesc(relation->trigdesc);
|
||||||
pfree(relation);
|
pfree(relation);
|
||||||
}
|
}
|
||||||
@ -1443,6 +1473,7 @@ RelationClearRelation(Relation relation, bool rebuildIt)
|
|||||||
bool old_myxactonly = relation->rd_myxactonly;
|
bool old_myxactonly = relation->rd_myxactonly;
|
||||||
TupleDesc old_att = relation->rd_att;
|
TupleDesc old_att = relation->rd_att;
|
||||||
RuleLock *old_rules = relation->rd_rules;
|
RuleLock *old_rules = relation->rd_rules;
|
||||||
|
MemoryContext old_rulescxt = relation->rd_rulescxt;
|
||||||
TriggerDesc *old_trigdesc = relation->trigdesc;
|
TriggerDesc *old_trigdesc = relation->trigdesc;
|
||||||
int old_nblocks = relation->rd_nblocks;
|
int old_nblocks = relation->rd_nblocks;
|
||||||
bool relDescChanged = false;
|
bool relDescChanged = false;
|
||||||
@ -1455,7 +1486,8 @@ RelationClearRelation(Relation relation, bool rebuildIt)
|
|||||||
{
|
{
|
||||||
/* Should only get here if relation was deleted */
|
/* Should only get here if relation was deleted */
|
||||||
FreeTupleDesc(old_att);
|
FreeTupleDesc(old_att);
|
||||||
FreeRuleLock(old_rules);
|
if (old_rulescxt)
|
||||||
|
MemoryContextDelete(old_rulescxt);
|
||||||
FreeTriggerDesc(old_trigdesc);
|
FreeTriggerDesc(old_trigdesc);
|
||||||
pfree(relation);
|
pfree(relation);
|
||||||
elog(ERROR, "RelationClearRelation: relation %u deleted while still in use",
|
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))
|
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_rules = old_rules;
|
||||||
|
relation->rd_rulescxt = old_rulescxt;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
FreeRuleLock(old_rules);
|
if (old_rulescxt)
|
||||||
|
MemoryContextDelete(old_rulescxt);
|
||||||
relDescChanged = true;
|
relDescChanged = true;
|
||||||
}
|
}
|
||||||
if (equalTriggerDescs(old_trigdesc, relation->trigdesc))
|
if (equalTriggerDescs(old_trigdesc, relation->trigdesc))
|
||||||
@ -1505,8 +1540,6 @@ RelationClearRelation(Relation relation, bool rebuildIt)
|
|||||||
elog(ERROR, "RelationClearRelation: relation %u modified while in use",
|
elog(ERROR, "RelationClearRelation: relation %u modified while in use",
|
||||||
buildinfo.i.info_id);
|
buildinfo.i.info_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
MemoryContextSwitchTo(oldcxt);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* --------------------------------
|
/* --------------------------------
|
||||||
@ -1570,12 +1603,9 @@ RelationForgetRelation(Oid rid)
|
|||||||
{
|
{
|
||||||
if (relation->rd_myxactonly)
|
if (relation->rd_myxactonly)
|
||||||
{
|
{
|
||||||
MemoryContext oldcxt;
|
|
||||||
List *curr;
|
List *curr;
|
||||||
List *prev = NIL;
|
List *prev = NIL;
|
||||||
|
|
||||||
oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
|
|
||||||
|
|
||||||
foreach(curr, newlyCreatedRelns)
|
foreach(curr, newlyCreatedRelns)
|
||||||
{
|
{
|
||||||
Relation reln = lfirst(curr);
|
Relation reln = lfirst(curr);
|
||||||
@ -1593,7 +1623,6 @@ RelationForgetRelation(Oid rid)
|
|||||||
else
|
else
|
||||||
lnext(prev) = lnext(curr);
|
lnext(prev) = lnext(curr);
|
||||||
pfree(curr);
|
pfree(curr);
|
||||||
MemoryContextSwitchTo(oldcxt);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Unconditionally destroy the relcache entry */
|
/* Unconditionally destroy the relcache entry */
|
||||||
@ -1731,10 +1760,10 @@ RelationRegisterRelation(Relation relation)
|
|||||||
{
|
{
|
||||||
MemoryContext oldcxt;
|
MemoryContext oldcxt;
|
||||||
|
|
||||||
oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
|
|
||||||
|
|
||||||
RelationInitLockInfo(relation);
|
RelationInitLockInfo(relation);
|
||||||
|
|
||||||
|
oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
|
||||||
|
|
||||||
RelationCacheInsert(relation);
|
RelationCacheInsert(relation);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1761,13 +1790,9 @@ RelationRegisterRelation(Relation relation)
|
|||||||
void
|
void
|
||||||
RelationPurgeLocalRelation(bool xactCommitted)
|
RelationPurgeLocalRelation(bool xactCommitted)
|
||||||
{
|
{
|
||||||
MemoryContext oldcxt;
|
|
||||||
|
|
||||||
if (newlyCreatedRelns == NULL)
|
if (newlyCreatedRelns == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
|
|
||||||
|
|
||||||
while (newlyCreatedRelns)
|
while (newlyCreatedRelns)
|
||||||
{
|
{
|
||||||
List *l = newlyCreatedRelns;
|
List *l = newlyCreatedRelns;
|
||||||
@ -1796,8 +1821,6 @@ RelationPurgeLocalRelation(bool xactCommitted)
|
|||||||
if (!IsBootstrapProcessingMode())
|
if (!IsBootstrapProcessingMode())
|
||||||
RelationClearRelation(reln, false);
|
RelationClearRelation(reln, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
MemoryContextSwitchTo(oldcxt);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* --------------------------------
|
/* --------------------------------
|
||||||
@ -1943,7 +1966,9 @@ AttrDefaultFetch(Relation relation)
|
|||||||
elog(NOTICE, "AttrDefaultFetch: adbin IS NULL for attr %s in rel %s",
|
elog(NOTICE, "AttrDefaultFetch: adbin IS NULL for attr %s in rel %s",
|
||||||
NameStr(relation->rd_att->attrs[adform->adnum - 1]->attname),
|
NameStr(relation->rd_att->attrs[adform->adnum - 1]->attname),
|
||||||
RelationGetRelationName(relation));
|
RelationGetRelationName(relation));
|
||||||
attrdef[i].adbin = textout(val);
|
else
|
||||||
|
attrdef[i].adbin = MemoryContextStrdup(CacheMemoryContext,
|
||||||
|
textout(val));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (hasindex)
|
if (hasindex)
|
||||||
@ -2039,14 +2064,16 @@ RelCheckFetch(Relation relation)
|
|||||||
if (isnull)
|
if (isnull)
|
||||||
elog(ERROR, "RelCheckFetch: rcname IS NULL for rel %s",
|
elog(ERROR, "RelCheckFetch: rcname IS NULL for rel %s",
|
||||||
RelationGetRelationName(relation));
|
RelationGetRelationName(relation));
|
||||||
check[found].ccname = pstrdup(NameStr(*rcname));
|
check[found].ccname = MemoryContextStrdup(CacheMemoryContext,
|
||||||
|
NameStr(*rcname));
|
||||||
val = (struct varlena *) fastgetattr(htup,
|
val = (struct varlena *) fastgetattr(htup,
|
||||||
Anum_pg_relcheck_rcbin,
|
Anum_pg_relcheck_rcbin,
|
||||||
rcrel->rd_att, &isnull);
|
rcrel->rd_att, &isnull);
|
||||||
if (isnull)
|
if (isnull)
|
||||||
elog(ERROR, "RelCheckFetch: rcbin IS NULL for rel %s",
|
elog(ERROR, "RelCheckFetch: rcbin IS NULL for rel %s",
|
||||||
RelationGetRelationName(relation));
|
RelationGetRelationName(relation));
|
||||||
check[found].ccbin = textout(val);
|
check[found].ccbin = MemoryContextStrdup(CacheMemoryContext,
|
||||||
|
textout(val));
|
||||||
found++;
|
found++;
|
||||||
if (hasindex)
|
if (hasindex)
|
||||||
ReleaseBuffer(buffer);
|
ReleaseBuffer(buffer);
|
||||||
@ -2416,7 +2443,7 @@ init_irels(void)
|
|||||||
|
|
||||||
RelationCacheInsert(ird);
|
RelationCacheInsert(ird);
|
||||||
}
|
}
|
||||||
criticalRelcacheBuild = true;
|
criticalRelcachesBuilt = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -2489,7 +2516,7 @@ write_irels(void)
|
|||||||
irel[2] = RelationBuildDesc(bi, NULL);
|
irel[2] = RelationBuildDesc(bi, NULL);
|
||||||
irel[2]->rd_isnailed = true;
|
irel[2]->rd_isnailed = true;
|
||||||
|
|
||||||
criticalRelcacheBuild = true;
|
criticalRelcachesBuilt = true;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Removed the following ProcessingMode -- inoue
|
* Removed the following ProcessingMode -- inoue
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* 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 "access/itup.h"
|
||||||
#include "nodes/execnodes.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);
|
extern void UpdateIndexPredicate(Oid indexoid, Node *oldPred, Node *predicate);
|
||||||
|
|
||||||
|
@ -7,22 +7,15 @@
|
|||||||
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* 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
|
#ifndef REWRITESUPPORT_H
|
||||||
#define REWRITESUPPORT_H
|
#define REWRITESUPPORT_H
|
||||||
|
|
||||||
#include "access/attnum.h"
|
|
||||||
#include "nodes/pg_list.h"
|
|
||||||
|
|
||||||
extern int IsDefinedRewriteRule(char *ruleName);
|
extern int IsDefinedRewriteRule(char *ruleName);
|
||||||
|
|
||||||
extern void prs2_addToRelation(Oid relid, Oid ruleId, CmdType event_type,
|
extern void setRelhasrulesInRelation(Oid relationId, bool relhasrules);
|
||||||
AttrNumber attno, bool isInstead, Node *qual,
|
|
||||||
List *actions);
|
|
||||||
extern void prs2_deleteFromRelation(Oid relid, Oid ruleId);
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* REWRITESUPPORT_H */
|
#endif /* REWRITESUPPORT_H */
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* 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
|
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 */
|
int rd_nblocks; /* number of blocks in rel */
|
||||||
uint16 rd_refcnt; /* reference count */
|
uint16 rd_refcnt; /* reference count */
|
||||||
bool rd_myxactonly; /* rel uses the local buffer mgr */
|
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 */
|
LockInfoData rd_lockInfo; /* lock mgr's info for locking relation */
|
||||||
TupleDesc rd_att; /* tuple descriptor */
|
TupleDesc rd_att; /* tuple descriptor */
|
||||||
RuleLock *rd_rules; /* rewrite rules */
|
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 */
|
IndexStrategy rd_istrat; /* info needed if rel is an index */
|
||||||
RegProcedure *rd_support;
|
RegProcedure *rd_support;
|
||||||
TriggerDesc *trigdesc; /* Trigger info, or NULL if rel has none */
|
TriggerDesc *trigdesc; /* Trigger info, or NULL if rel has none */
|
||||||
|
Loading…
x
Reference in New Issue
Block a user