Skip to content

Commit c3e2a95

Browse files
committed
Toast all the system-table columns that seem to need it. It turns out
that giving pg_proc a toast table required solving the same problems we'd have to solve for pg_class --- pg_proc is one of the relations that gets bootstrapped in relcache.c. Solution is to go back at the end of initialization and read in the *real* pg_class row to replace the phony entry created by formrdesc(). This should work as long as there's no need to touch any toasted values during initialization, which seems a reasonable assumption. Although I did not add a toast-table for every single system table with a varlena attribute, I believe that it would work to just do ALTER TABLE pg_class CREATE TOAST TABLE. So anyone who's really intent on having several thousand ACL entries for a rel could do it. NOTE: I didn't force initdb, but you must do one to see the effects of this patch.
1 parent 8ae2313 commit c3e2a95

File tree

6 files changed

+168
-78
lines changed

6 files changed

+168
-78
lines changed

src/backend/commands/analyze.c

Lines changed: 13 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $Header: /cvsroot/pgsql/src/backend/commands/analyze.c,v 1.3 2000/07/05 23:11:08 tgl Exp $
11+
* $Header: /cvsroot/pgsql/src/backend/commands/analyze.c,v 1.4 2000/08/06 04:40:08 tgl Exp $
1212
*
1313
1414
*-------------------------------------------------------------------------
@@ -106,7 +106,7 @@ analyze_rel(Oid relid, List *anal_cols2, int MESSAGE_LEVEL)
106106
elog(NOTICE, "Skipping \"%s\" --- only table owner can VACUUM it",
107107
RelationGetRelationName(onerel));
108108
*/
109-
heap_close(onerel, AccessExclusiveLock);
109+
heap_close(onerel, NoLock);
110110
CommitTransactionCommand();
111111
return;
112112
}
@@ -220,7 +220,8 @@ analyze_rel(Oid relid, List *anal_cols2, int MESSAGE_LEVEL)
220220

221221
heap_endscan(scan);
222222

223-
heap_close(onerel, AccessShareLock);
223+
/* close rel, but keep lock so it doesn't go away before commit */
224+
heap_close(onerel, NoLock);
224225

225226
/* update statistics in pg_class */
226227
update_attstats(relid, attr_cnt, vacattrstats);
@@ -388,8 +389,8 @@ bucketcpy(Form_pg_attribute attr, Datum value, Datum *bucket, int *bucket_len)
388389
/*
389390
* update_attstats() -- update attribute statistics for one relation
390391
*
391-
* Updates of pg_attribute statistics are handled by over-write.
392-
* for reasons described above.
392+
* Updates of pg_attribute statistics are handled by over-write,
393+
* for reasons described above. pg_statistic rows are added normally.
393394
*
394395
* To keep things simple, we punt for pg_statistic, and don't try
395396
* to compute or store rows for pg_statistic itself in pg_statistic.
@@ -510,7 +511,7 @@ update_attstats(Oid relid, int natts, VacAttrStats *vacattrstats)
510511
* deleted all the pg_statistic tuples for the rel, so we
511512
* just have to insert new ones here.
512513
*
513-
* Note vacuum_rel() has seen to it that we won't come here
514+
* Note analyze_rel() has seen to it that we won't come here
514515
* when vacuuming pg_statistic itself.
515516
*/
516517
if (VacAttrStatsLtGtValid(stats) && stats->initialized)
@@ -524,6 +525,7 @@ update_attstats(Oid relid, int natts, VacAttrStats *vacattrstats)
524525
nonnull_cnt_d = stats->nonnull_cnt; /* prevent overflow */
525526
Datum values[Natts_pg_statistic];
526527
char nulls[Natts_pg_statistic];
528+
Relation irelations[Num_pg_statistic_indices];
527529

528530
nullratio = null_cnt_d / (nonnull_cnt_d + null_cnt_d);
529531
bestratio = best_cnt_d / (nonnull_cnt_d + null_cnt_d);
@@ -567,31 +569,12 @@ update_attstats(Oid relid, int natts, VacAttrStats *vacattrstats)
567569

568570
stup = heap_formtuple(sd->rd_att, values, nulls);
569571

570-
/* ----------------
571-
* Watch out for oversize tuple, which can happen if
572-
* all three of the saved data values are long.
573-
* Our fallback strategy is just to not store the
574-
* pg_statistic tuple at all in that case. (We could
575-
* replace the values by NULLs and still store the
576-
* numeric stats, but presently selfuncs.c couldn't
577-
* do anything useful with that case anyway.)
578-
*
579-
* We could reduce the probability of overflow, but not
580-
* prevent it, by storing the data values as compressed
581-
* text; is that worth doing? The problem should go
582-
* away whenever long tuples get implemented...
583-
* ----------------
584-
*/
585-
if (MAXALIGN(stup->t_len) <= MaxTupleSize)
586-
{
587-
/* OK, store tuple and update indexes too */
588-
Relation irelations[Num_pg_statistic_indices];
572+
/* store tuple and update indexes too */
573+
heap_insert(sd, stup);
589574

590-
heap_insert(sd, stup);
591-
CatalogOpenIndices(Num_pg_statistic_indices, Name_pg_statistic_indices, irelations);
592-
CatalogIndexInsert(irelations, Num_pg_statistic_indices, sd, stup);
593-
CatalogCloseIndices(Num_pg_statistic_indices, irelations);
594-
}
575+
CatalogOpenIndices(Num_pg_statistic_indices, Name_pg_statistic_indices, irelations);
576+
CatalogIndexInsert(irelations, Num_pg_statistic_indices, sd, stup);
577+
CatalogCloseIndices(Num_pg_statistic_indices, irelations);
595578

596579
/* release allocated space */
597580
pfree(DatumGetPointer(values[Anum_pg_statistic_stacommonval - 1]));

src/backend/utils/cache/relcache.c

Lines changed: 110 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,14 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $Header: /cvsroot/pgsql/src/backend/utils/cache/relcache.c,v 1.108 2000/07/30 22:13:55 tgl Exp $
11+
* $Header: /cvsroot/pgsql/src/backend/utils/cache/relcache.c,v 1.109 2000/08/06 04:39:03 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
1515
/*
1616
* INTERFACE ROUTINES
17-
* RelationInitialize - initialize relcache
17+
* RelationCacheInitialize - initialize relcache
18+
* RelationCacheInitializePhase2 - finish initializing relcache
1819
* RelationIdCacheGetRelation - get a reldesc from the cache (id)
1920
* RelationNameCacheGetRelation - get a reldesc from the cache (name)
2021
* RelationIdGetRelation - get a reldesc by relation id
@@ -217,6 +218,7 @@ static void write_irels(void);
217218

218219
static void formrdesc(char *relationName, int natts,
219220
FormData_pg_attribute *att);
221+
static void fixrdesc(char *relationName);
220222

221223
static HeapTuple ScanPgRelation(RelationBuildDescInfo buildinfo);
222224
static HeapTuple scan_pg_rel_seq(RelationBuildDescInfo buildinfo);
@@ -1081,8 +1083,9 @@ IndexedAccessMethodInitialize(Relation relation)
10811083
* formrdesc
10821084
*
10831085
* This is a special cut-down version of RelationBuildDesc()
1084-
* used by RelationInitialize() in initializing the relcache.
1085-
* The relation descriptor is built just from the supplied parameters.
1086+
* used by RelationCacheInitialize() in initializing the relcache.
1087+
* The relation descriptor is built just from the supplied parameters,
1088+
* without actually looking at any system table entries.
10861089
*
10871090
* NOTE: we assume we are already switched into CacheMemoryContext.
10881091
* --------------------------------
@@ -1115,42 +1118,45 @@ formrdesc(char *relationName,
11151118
RelationSetReferenceCount(relation, 1);
11161119

11171120
/* ----------------
1118-
* initialize relation tuple form
1121+
* all entries built with this routine are nailed-in-cache
11191122
* ----------------
11201123
*/
1121-
relation->rd_rel = (Form_pg_class) palloc(CLASS_TUPLE_SIZE);
1122-
MemSet(relation->rd_rel, 0, CLASS_TUPLE_SIZE);
1123-
strcpy(RelationGetPhysicalRelationName(relation), relationName);
1124+
relation->rd_isnailed = true;
11241125

11251126
/* ----------------
1126-
* initialize attribute tuple form
1127+
* initialize relation tuple form
1128+
*
1129+
* The data we insert here is pretty incomplete/bogus, but it'll
1130+
* serve to get us launched. RelationCacheInitializePhase2() will
1131+
* read the real data from pg_class and replace what we've done here.
11271132
* ----------------
11281133
*/
1129-
relation->rd_att = CreateTemplateTupleDesc(natts);
1134+
relation->rd_rel = (Form_pg_class) palloc(CLASS_TUPLE_SIZE);
1135+
MemSet(relation->rd_rel, 0, CLASS_TUPLE_SIZE);
1136+
1137+
strcpy(RelationGetPhysicalRelationName(relation), relationName);
11301138

11311139
/*
11321140
* For debugging purposes, it's important to distinguish between
11331141
* shared and non-shared relations, even at bootstrap time. There's
11341142
* code in the buffer manager that traces allocations that has to know
11351143
* about this.
11361144
*/
1137-
11381145
if (IsSystemRelationName(relationName))
1139-
{
1140-
relation->rd_rel->relowner = 6; /* XXX use sym const */
11411146
relation->rd_rel->relisshared = IsSharedSystemRelationName(relationName);
1142-
}
11431147
else
1144-
{
1145-
relation->rd_rel->relowner = 0;
11461148
relation->rd_rel->relisshared = false;
1147-
}
11481149

1149-
relation->rd_rel->relpages = 1; /* XXX */
1150-
relation->rd_rel->reltuples = 1; /* XXX */
1150+
relation->rd_rel->relpages = 1;
1151+
relation->rd_rel->reltuples = 1;
11511152
relation->rd_rel->relkind = RELKIND_RELATION;
11521153
relation->rd_rel->relnatts = (int16) natts;
1153-
relation->rd_isnailed = true;
1154+
1155+
/* ----------------
1156+
* initialize attribute tuple form
1157+
* ----------------
1158+
*/
1159+
relation->rd_att = CreateTemplateTupleDesc(natts);
11541160

11551161
/* ----------------
11561162
* initialize tuple desc info
@@ -1187,15 +1193,65 @@ formrdesc(char *relationName,
11871193
* the rdesc for pg_class must already exist. Therefore we must do
11881194
* the check (and possible set) after cache insertion.
11891195
*
1190-
* XXX I believe the above comment is misguided; we should be
1191-
* running in bootstrap or init processing mode, and CatalogHasIndex
1196+
* XXX I believe the above comment is misguided; we should be running
1197+
* in bootstrap or init processing mode here, and CatalogHasIndex
11921198
* relies on hard-wired info in those cases.
11931199
*/
11941200
relation->rd_rel->relhasindex =
11951201
CatalogHasIndex(relationName, RelationGetRelid(relation));
11961202
}
11971203

11981204

1205+
/* --------------------------------
1206+
* fixrdesc
1207+
*
1208+
* Update the phony data inserted by formrdesc() with real info
1209+
* from pg_class.
1210+
* --------------------------------
1211+
*/
1212+
static void
1213+
fixrdesc(char *relationName)
1214+
{
1215+
RelationBuildDescInfo buildinfo;
1216+
HeapTuple pg_class_tuple;
1217+
Form_pg_class relp;
1218+
Relation relation;
1219+
1220+
/* ----------------
1221+
* find the tuple in pg_class corresponding to the given relation name
1222+
* ----------------
1223+
*/
1224+
buildinfo.infotype = INFO_RELNAME;
1225+
buildinfo.i.info_name = relationName;
1226+
1227+
pg_class_tuple = ScanPgRelation(buildinfo);
1228+
1229+
if (!HeapTupleIsValid(pg_class_tuple))
1230+
elog(FATAL, "fixrdesc: no pg_class entry for %s",
1231+
relationName);
1232+
relp = (Form_pg_class) GETSTRUCT(pg_class_tuple);
1233+
1234+
/* ----------------
1235+
* find the pre-made relcache entry (better be there!)
1236+
* ----------------
1237+
*/
1238+
relation = RelationNameCacheGetRelation(relationName);
1239+
if (!RelationIsValid(relation))
1240+
elog(FATAL, "fixrdesc: no existing relcache entry for %s",
1241+
relationName);
1242+
1243+
/* ----------------
1244+
* and copy pg_class_tuple to relation->rd_rel.
1245+
* (See notes in AllocateRelationDesc())
1246+
* ----------------
1247+
*/
1248+
Assert(relation->rd_rel != NULL);
1249+
memcpy((char *) relation->rd_rel, (char *) relp, CLASS_TUPLE_SIZE);
1250+
1251+
heap_freetuple(pg_class_tuple);
1252+
}
1253+
1254+
11991255
/* ----------------------------------------------------------------
12001256
* Relation Descriptor Lookup Interface
12011257
* ----------------------------------------------------------------
@@ -1829,7 +1885,7 @@ RelationPurgeLocalRelation(bool xactCommitted)
18291885
}
18301886

18311887
/* --------------------------------
1832-
* RelationInitialize
1888+
* RelationCacheInitialize
18331889
*
18341890
* This initializes the relation descriptor cache.
18351891
* --------------------------------
@@ -1838,7 +1894,7 @@ RelationPurgeLocalRelation(bool xactCommitted)
18381894
#define INITRELCACHESIZE 400
18391895

18401896
void
1841-
RelationInitialize(void)
1897+
RelationCacheInitialize(void)
18421898
{
18431899
MemoryContext oldcxt;
18441900
HASHCTL ctl;
@@ -1870,6 +1926,8 @@ RelationInitialize(void)
18701926
* initialize the cache with pre-made relation descriptors
18711927
* for some of the more important system relations. These
18721928
* relations should always be in the cache.
1929+
*
1930+
* NB: see also the list in RelationCacheInitializePhase2().
18731931
* ----------------
18741932
*/
18751933
formrdesc(RelationRelationName, Natts_pg_class, Desc_pg_class);
@@ -1892,6 +1950,34 @@ RelationInitialize(void)
18921950
MemoryContextSwitchTo(oldcxt);
18931951
}
18941952

1953+
/* --------------------------------
1954+
* RelationCacheInitializePhase2
1955+
*
1956+
* This completes initialization of the relcache after catcache
1957+
* is functional and we are able to actually load data from pg_class.
1958+
* --------------------------------
1959+
*/
1960+
void
1961+
RelationCacheInitializePhase2(void)
1962+
{
1963+
/*
1964+
* Get the real pg_class tuple for each nailed-in-cache relcache entry
1965+
* that was made by RelationCacheInitialize(), and replace the phony
1966+
* rd_rel entry made by formrdesc(). This is necessary so that we have,
1967+
* for example, the correct toast-table info for tables that have such.
1968+
*/
1969+
if (!IsBootstrapProcessingMode())
1970+
{
1971+
fixrdesc(RelationRelationName);
1972+
fixrdesc(AttributeRelationName);
1973+
fixrdesc(ProcedureRelationName);
1974+
fixrdesc(TypeRelationName);
1975+
/* We don't bother to update the entries for pg_variable or pg_log. */
1976+
}
1977+
}
1978+
1979+
1980+
18951981
static void
18961982
AttrDefaultFetch(Relation relation)
18971983
{

src/backend/utils/init/postinit.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $Header: /cvsroot/pgsql/src/backend/utils/init/postinit.c,v 1.63 2000/07/08 03:04:16 tgl Exp $
11+
* $Header: /cvsroot/pgsql/src/backend/utils/init/postinit.c,v 1.64 2000/08/06 04:39:10 tgl Exp $
1212
*
1313
*
1414
*-------------------------------------------------------------------------
@@ -313,7 +313,8 @@ InitPostgres(const char *dbname)
313313
* it to examine AMI transaction status, and this is never written
314314
* after initdb is done. -mer 15 June 1992
315315
*/
316-
RelationInitialize(); /* pre-allocated reldescs created here */
316+
RelationCacheInitialize(); /* pre-allocated reldescs created here */
317+
317318
InitializeTransactionSystem(); /* pg_log,etc init/crash recovery
318319
* here */
319320

@@ -362,6 +363,9 @@ InitPostgres(const char *dbname)
362363
if (!bootstrap)
363364
StartTransactionCommand();
364365

366+
/* replace faked-up relcache entries with the real info */
367+
RelationCacheInitializePhase2();
368+
365369
/*
366370
* Set ourselves to the proper user id and figure out our postgres
367371
* user id. If we ever add security so that we check for valid

src/bin/initdb/initdb.sh

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
#
2424
# Copyright (c) 1994, Regents of the University of California
2525
#
26-
# $Header: /cvsroot/pgsql/src/bin/initdb/Attic/initdb.sh,v 1.101 2000/07/06 21:33:38 petere Exp $
26+
# $Header: /cvsroot/pgsql/src/bin/initdb/Attic/initdb.sh,v 1.102 2000/08/06 04:39:22 tgl Exp $
2727
#
2828
#-------------------------------------------------------------------------
2929

@@ -519,9 +519,19 @@ if [ "$PwPrompt" ]; then
519519
fi
520520

521521

522-
echo "Enabling unlimited storage for pg_rewrite"
522+
echo "Enabling unlimited row width for system tables."
523+
echo "ALTER TABLE pg_attrdef CREATE TOAST TABLE" \
524+
| "$PGPATH"/postgres $PGSQL_OPT template1 > /dev/null || exit_nicely
525+
echo "ALTER TABLE pg_description CREATE TOAST TABLE" \
526+
| "$PGPATH"/postgres $PGSQL_OPT template1 > /dev/null || exit_nicely
527+
echo "ALTER TABLE pg_proc CREATE TOAST TABLE" \
528+
| "$PGPATH"/postgres $PGSQL_OPT template1 > /dev/null || exit_nicely
529+
echo "ALTER TABLE pg_relcheck CREATE TOAST TABLE" \
530+
| "$PGPATH"/postgres $PGSQL_OPT template1 > /dev/null || exit_nicely
523531
echo "ALTER TABLE pg_rewrite CREATE TOAST TABLE" \
524532
| "$PGPATH"/postgres $PGSQL_OPT template1 > /dev/null || exit_nicely
533+
echo "ALTER TABLE pg_statistic CREATE TOAST TABLE" \
534+
| "$PGPATH"/postgres $PGSQL_OPT template1 > /dev/null || exit_nicely
525535

526536

527537
echo "Creating view pg_user."

0 commit comments

Comments
 (0)