aboutsummaryrefslogtreecommitdiff
path: root/src/backend/utils/cache/relcache.c
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>1999-10-03 23:55:40 +0000
committerTom Lane <tgl@sss.pgh.pa.us>1999-10-03 23:55:40 +0000
commiteabc714a916b772650c97b065ef27767dc5942e4 (patch)
tree9271817f0a846e303ae8d32338b1d58a5c2754d5 /src/backend/utils/cache/relcache.c
parentf29ccc827006d13be0f4bf0255b06f3c4e921709 (diff)
downloadpostgresql-eabc714a916b772650c97b065ef27767dc5942e4.tar.gz
postgresql-eabc714a916b772650c97b065ef27767dc5942e4.zip
Reimplement parsing and storage of default expressions and constraint
expressions in CREATE TABLE. There is no longer an emasculated expression syntax for these things; it's full a_expr for constraints, and b_expr for defaults (unfortunately the fact that NOT NULL is a part of the column constraint syntax causes a shift/reduce conflict if you try a_expr. Oh well --- at least parenthesized boolean expressions work now). Also, stored expression for a column default is not pre-coerced to the column type; we rely on transformInsertStatement to do that when the default is actually used. This means "f1 datetime default 'now'" behaves the way people usually expect it to. BTW, all the support code is now there to implement ALTER TABLE ADD CONSTRAINT and ALTER TABLE ADD COLUMN with a default value. I didn't actually teach ALTER TABLE to call it, but it wouldn't be much work.
Diffstat (limited to 'src/backend/utils/cache/relcache.c')
-rw-r--r--src/backend/utils/cache/relcache.c171
1 files changed, 91 insertions, 80 deletions
diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c
index afba41db108..fab04036d2e 100644
--- a/src/backend/utils/cache/relcache.c
+++ b/src/backend/utils/cache/relcache.c
@@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/cache/relcache.c,v 1.73 1999/09/18 19:07:55 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/cache/relcache.c,v 1.74 1999/10/03 23:55:33 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -19,7 +19,7 @@
* RelationIdGetRelation - get a reldesc by relation id
* RelationNameGetRelation - get a reldesc by relation name
* RelationClose - close an open relation
- * RelationFlushRelation - flush relation information
+ * RelationRebuildRelation - rebuild relation information
*
* NOTES
* This file is in the process of being cleaned up
@@ -59,8 +59,9 @@
#include "utils/temprel.h"
+static void RelationClearRelation(Relation relation, bool rebuildIt);
static void RelationFlushRelation(Relation *relationPtr,
- bool onlyFlushReferenceCountZero);
+ bool onlyFlushReferenceCountZero);
static Relation RelationNameCacheGetRelation(char *relationName);
static void RelationCacheAbortWalker(Relation *relationPtr,
int dummy);
@@ -247,34 +248,6 @@ static List *newlyCreatedRelns = NULL;
*/
-#if NOT_USED /* XXX This doesn't seem to be used
- * anywhere */
-/* --------------------------------
- * BuildDescInfoError returns a string appropriate to
- * the buildinfo passed to it
- * --------------------------------
- */
-static char *
-BuildDescInfoError(RelationBuildDescInfo buildinfo)
-{
- static char errBuf[64];
-
- MemSet(errBuf, 0, (int) sizeof(errBuf));
- switch (buildinfo.infotype)
- {
- case INFO_RELID:
- sprintf(errBuf, "(relation id %u)", buildinfo.i.info_id);
- break;
- case INFO_RELNAME:
- sprintf(errBuf, "(relation name %s)", buildinfo.i.info_name);
- break;
- }
-
- return errBuf;
-}
-
-#endif
-
/* --------------------------------
* ScanPgRelation
*
@@ -403,7 +376,7 @@ scan_pg_rel_ind(RelationBuildDescInfo buildinfo)
*
* If 'relation' is NULL, allocate a new RelationData object.
* If not, reuse the given object (that path is taken only when
- * we have to rebuild a relcache entry during RelationFlushRelation).
+ * we have to rebuild a relcache entry during RelationClearRelation).
* ----------------
*/
static Relation
@@ -578,11 +551,14 @@ build_tupdesc_ind(RelationBuildDescInfo buildinfo,
if (attp->atthasdef)
{
if (attrdef == NULL)
+ {
attrdef = (AttrDefault *) palloc(relation->rd_rel->relnatts *
sizeof(AttrDefault));
+ MemSet(attrdef, 0,
+ relation->rd_rel->relnatts * sizeof(AttrDefault));
+ }
attrdef[ndef].adnum = i;
attrdef[ndef].adbin = NULL;
- attrdef[ndef].adsrc = NULL;
ndef++;
}
}
@@ -1231,7 +1207,9 @@ RelationNameGetRelation(char *relationName)
*/
/* --------------------------------
- * RelationClose - close an open relation
+ * RelationClose - close an open relation
+ *
+ * Actually, we just decrement the refcount.
* --------------------------------
*/
void
@@ -1242,17 +1220,18 @@ RelationClose(Relation relation)
}
/* --------------------------------
- * RelationFlushRelation
+ * RelationClearRelation
*
- * Actually blows away a relation cache entry... RelationFree doesn't do
- * anything anymore.
+ * Physically blow away a relation cache entry, or reset it and rebuild
+ * it from scratch (that is, from catalog entries). The latter path is
+ * usually used when we are notified of a change to an open relation
+ * (one with refcount > 0). However, this routine just does whichever
+ * it's told to do; callers must determine which they want.
* --------------------------------
*/
static void
-RelationFlushRelation(Relation *relationPtr,
- bool onlyFlushReferenceCountZero)
+RelationClearRelation(Relation relation, bool rebuildIt)
{
- Relation relation = *relationPtr;
MemoryContext oldcxt;
/*
@@ -1261,19 +1240,18 @@ RelationFlushRelation(Relation *relationPtr,
* if the relation is not deleted, the next smgr access should
* reopen the files automatically. This ensures that the low-level
* file access state is updated after, say, a vacuum truncation.
+ *
* NOTE: this call is a no-op if the relation's smgr file is already
* closed or unlinked.
*/
smgrclose(DEFAULT_SMGR, relation);
- if (relation->rd_isnailed || relation->rd_myxactonly)
- {
- /* Do not flush relation cache entry if it is a nailed-in system
- * relation or it is marked transaction-local.
- * (To delete a local relation, caller must clear rd_myxactonly!)
- */
+ /*
+ * Never, never ever blow away a nailed-in system relation,
+ * because we'd be unable to recover.
+ */
+ if (relation->rd_isnailed)
return;
- }
oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
@@ -1293,19 +1271,21 @@ RelationFlushRelation(Relation *relationPtr,
FreeTriggerDesc(relation);
pfree(RelationGetForm(relation));
- /* If we're really done with the relcache entry, blow it away.
+ /*
+ * If we're really done with the relcache entry, blow it away.
* But if someone is still using it, reconstruct the whole deal
* without moving the physical RelationData record (so that the
- * someone's pointer is still valid). Preserve ref count, too.
+ * someone's pointer is still valid). Must preserve ref count
+ * and myxactonly flag, too.
*/
- if (!onlyFlushReferenceCountZero ||
- RelationHasReferenceCountZero(relation))
+ if (! rebuildIt)
{
pfree(relation);
}
else
{
uint16 old_refcnt = relation->rd_refcnt;
+ bool old_myxactonly = relation->rd_myxactonly;
RelationBuildDescInfo buildinfo;
buildinfo.infotype = INFO_RELID;
@@ -1315,19 +1295,53 @@ RelationFlushRelation(Relation *relationPtr,
{
/* Should only get here if relation was deleted */
pfree(relation);
- elog(ERROR, "RelationFlushRelation: relation %u deleted while still in use",
+ elog(ERROR, "RelationClearRelation: relation %u deleted while still in use",
buildinfo.i.info_id);
}
RelationSetReferenceCount(relation, old_refcnt);
+ relation->rd_myxactonly = old_myxactonly;
}
MemoryContextSwitchTo(oldcxt);
}
/* --------------------------------
- * RelationForgetRelation -
- * RelationFlushRelation + if the relation is myxactonly then
- * get rid of the relation descriptor from the newly created
+ * RelationFlushRelation
+ *
+ * Rebuild the relation if it is open (refcount > 0), else blow it away.
+ * Setting onlyFlushReferenceCountZero to FALSE overrides refcount check.
+ * This is currently only used to process SI invalidation notifications.
+ * The peculiar calling convention (pointer to pointer to relation)
+ * is needed so that we can use this routine as a hash table walker.
+ * --------------------------------
+ */
+static void
+RelationFlushRelation(Relation *relationPtr,
+ bool onlyFlushReferenceCountZero)
+{
+ Relation relation = *relationPtr;
+
+ /*
+ * Do nothing to transaction-local relations, since they cannot be
+ * subjects of SI notifications from other backends.
+ */
+ if (relation->rd_myxactonly)
+ return;
+
+ /*
+ * Zap it. Rebuild if it has nonzero ref count and we did not get
+ * the override flag.
+ */
+ RelationClearRelation(relation,
+ (onlyFlushReferenceCountZero &&
+ ! RelationHasReferenceCountZero(relation)));
+}
+
+/* --------------------------------
+ * RelationForgetRelation -
+ *
+ * RelationClearRelation + if the relation is myxactonly then
+ * remove the relation descriptor from the newly created
* relation list.
* --------------------------------
*/
@@ -1368,13 +1382,25 @@ RelationForgetRelation(Oid rid)
MemoryContextSwitchTo(oldcxt);
}
- relation->rd_myxactonly = false; /* so it can be flushed */
-
- RelationFlushRelation(&relation, false);
+ /* Unconditionally destroy the relcache entry */
+ RelationClearRelation(relation, false);
}
}
/* --------------------------------
+ * RelationRebuildRelation -
+ *
+ * Force a relcache entry to be rebuilt from catalog entries.
+ * This is needed, eg, after modifying an attribute of the rel.
+ * --------------------------------
+ */
+void
+RelationRebuildRelation(Relation relation)
+{
+ RelationClearRelation(relation, true);
+}
+
+/* --------------------------------
* RelationIdInvalidateRelationCacheByRelationId
* --------------------------------
*/
@@ -1573,6 +1599,11 @@ RelationPurgeLocalRelation(bool xactCommitted)
Assert(reln != NULL && reln->rd_myxactonly);
+ reln->rd_myxactonly = false; /* mark it not on list anymore */
+
+ newlyCreatedRelns = lnext(newlyCreatedRelns);
+ pfree(l);
+
if (!xactCommitted)
{
@@ -1592,13 +1623,8 @@ RelationPurgeLocalRelation(bool xactCommitted)
smgrunlink(DEFAULT_SMGR, reln);
}
- reln->rd_myxactonly = false; /* so it can be flushed */
-
if (!IsBootstrapProcessingMode())
- RelationFlushRelation(&reln, false);
-
- newlyCreatedRelns = lnext(newlyCreatedRelns);
- pfree(l);
+ RelationClearRelation(reln, false);
}
MemoryContextSwitchTo(oldcxt);
@@ -1717,7 +1743,7 @@ AttrDefaultFetch(Relation relation)
{
if (adform->adnum != attrdef[i].adnum)
continue;
- if (attrdef[i].adsrc != NULL)
+ if (attrdef[i].adbin != NULL)
elog(ERROR, "AttrDefaultFetch: second record found for attr %s in rel %s",
relation->rd_att->attrs[adform->adnum - 1]->attname.data,
relation->rd_rel->relname.data);
@@ -1730,14 +1756,6 @@ AttrDefaultFetch(Relation relation)
relation->rd_att->attrs[adform->adnum - 1]->attname.data,
relation->rd_rel->relname.data);
attrdef[i].adbin = textout(val);
- val = (struct varlena *) fastgetattr(&tuple,
- Anum_pg_attrdef_adsrc,
- adrel->rd_att, &isnull);
- if (isnull)
- elog(ERROR, "AttrDefaultFetch: adsrc IS NULL for attr %s in rel %s",
- relation->rd_att->attrs[adform->adnum - 1]->attname.data,
- relation->rd_rel->relname.data);
- attrdef[i].adsrc = textout(val);
break;
}
ReleaseBuffer(buffer);
@@ -1816,13 +1834,6 @@ RelCheckFetch(Relation relation)
elog(ERROR, "RelCheckFetch: rcbin IS NULL for rel %s",
relation->rd_rel->relname.data);
check[found].ccbin = textout(val);
- val = (struct varlena *) fastgetattr(&tuple,
- Anum_pg_relcheck_rcsrc,
- rcrel->rd_att, &isnull);
- if (isnull)
- elog(ERROR, "RelCheckFetch: rcsrc IS NULL for rel %s",
- relation->rd_rel->relname.data);
- check[found].ccsrc = textout(val);
found++;
ReleaseBuffer(buffer);
}