1 /*-------------------------------------------------------------------------
4 * POSTGRES relation descriptor cache code
6 * Copyright (c) 1994, Regents of the University of California
10 * $Header: /cvsroot/pgsql/src/backend/utils/cache/relcache.c,v 1.60 1999/05/01 19:09:44 tgl Exp $
12 *-------------------------------------------------------------------------
16 * RelationInitialize - initialize relcache
17 * RelationIdCacheGetRelation - get a reldesc from the cache (id)
18 * RelationNameCacheGetRelation - get a reldesc from the cache (name)
19 * RelationIdGetRelation - get a reldesc by relation id
20 * RelationNameGetRelation - get a reldesc by relation name
21 * RelationClose - close an open relation
22 * RelationFlushRelation - flush relation information
25 * This file is in the process of being cleaned up
26 * before I add system attribute indexing. -cim 1/13/91
28 * The following code contains many undocumented hacks. Please be
32 #include <sys/types.h>
33 #include <stdio.h> /* for sprintf() */
41 #include "access/genam.h"
42 #include "access/heapam.h"
43 #include "access/htup.h"
44 #include "access/istrat.h"
45 #include "access/itup.h"
46 #include "access/skey.h"
47 #include "access/tupdesc.h"
48 #include "access/tupmacs.h"
49 #include "access/xact.h"
50 #include "catalog/catalog.h"
51 #include "catalog/catname.h"
52 #include "catalog/index.h"
53 #include "catalog/indexing.h"
54 #include "catalog/pg_aggregate.h"
55 #include "catalog/pg_attrdef.h"
56 #include "catalog/pg_attribute.h"
57 #include "catalog/pg_index.h"
58 #include "catalog/pg_proc.h"
59 #include "catalog/pg_class.h"
60 #include "catalog/pg_log.h"
61 #include "catalog/pg_relcheck.h"
62 #include "catalog/pg_rewrite.h"
63 #include "catalog/pg_type.h"
64 #include "catalog/pg_variable.h"
66 #include "lib/hasht.h"
67 #include "miscadmin.h"
68 #include "storage/buf.h"
69 #include "storage/bufmgr.h"
70 #include "storage/fd.h" /* for SEEK_ */
71 #include "storage/lmgr.h"
72 #include "storage/smgr.h"
73 #include "utils/builtins.h"
74 #include "utils/catcache.h"
75 #include "utils/hsearch.h"
76 #include "utils/mcxt.h"
77 #include "utils/memutils.h"
78 #include "utils/rel.h"
79 #include "utils/relcache.h"
80 #include "utils/syscache.h"
83 static void RelationFlushRelation(Relation *relationPtr,
84 bool onlyFlushReferenceCountZero);
85 static Relation RelationNameCacheGetRelation(char *relationName);
86 static void init_irels(void);
87 static void write_irels(void);
93 extern bool AMI_OVERRIDE; /* XXX style */
94 extern GlobalMemory CacheCxt; /* from utils/cache/catcache.c */
97 * hardcoded tuple descriptors. see lib/backend/catalog/pg_attribute.h
100 FormData_pg_attribute Desc_pg_class[Natts_pg_class] = {Schema_pg_class};
101 FormData_pg_attribute Desc_pg_attribute[Natts_pg_attribute] = {Schema_pg_attribute};
102 FormData_pg_attribute Desc_pg_proc[Natts_pg_proc] = {Schema_pg_proc};
103 FormData_pg_attribute Desc_pg_type[Natts_pg_type] = {Schema_pg_type};
104 FormData_pg_attribute Desc_pg_variable[Natts_pg_variable] = {Schema_pg_variable};
105 FormData_pg_attribute Desc_pg_log[Natts_pg_log] = {Schema_pg_log};
110 * Relations are cached two ways, by name and by id,
111 * thus there are two hash tables for referencing them.
114 HTAB *RelationNameCache;
115 HTAB *RelationIdCache;
118 * RelationBuildDescInfo exists so code can be shared
119 * between RelationIdGetRelation() and RelationNameGetRelation()
122 typedef struct RelationBuildDescInfo
124 int infotype; /* lookup by id or by name */
126 #define INFO_RELNAME 2
129 Oid info_id; /* relation object id */
130 char *info_name; /* relation name */
132 } RelationBuildDescInfo;
134 typedef struct relidcacheent
140 typedef struct relnamecacheent
147 * macros to manipulate name cache and id cache
150 #define RelationCacheInsert(RELATION) \
152 RelIdCacheEnt *idhentry; RelNameCacheEnt *namehentry; \
153 char *relname; Oid reloid; bool found; \
154 relname = (RELATION->rd_rel->relname).data; \
155 namehentry = (RelNameCacheEnt*)hash_search(RelationNameCache, \
159 if (namehentry == NULL) \
160 elog(FATAL, "can't insert into relation descriptor cache"); \
161 if (found && !IsBootstrapProcessingMode()) \
162 /* used to give notice -- now just keep quiet */ ; \
163 namehentry->reldesc = RELATION; \
164 reloid = RELATION->rd_id; \
165 idhentry = (RelIdCacheEnt*)hash_search(RelationIdCache, \
169 if (idhentry == NULL) \
170 elog(FATAL, "can't insert into relation descriptor cache"); \
171 if (found && !IsBootstrapProcessingMode()) \
172 /* used to give notice -- now just keep quiet */ ; \
173 idhentry->reldesc = RELATION; \
176 #define RelationNameCacheLookup(NAME, RELATION) \
178 RelNameCacheEnt *hentry; bool found; \
179 hentry = (RelNameCacheEnt*)hash_search(RelationNameCache, \
180 (char *)NAME,HASH_FIND,&found); \
181 if (hentry == NULL) \
182 elog(FATAL, "error in CACHE"); \
184 RELATION = hentry->reldesc; \
189 #define RelationIdCacheLookup(ID, RELATION) \
191 RelIdCacheEnt *hentry; \
193 hentry = (RelIdCacheEnt*)hash_search(RelationIdCache, \
194 (char *)&(ID),HASH_FIND, &found); \
195 if (hentry == NULL) \
196 elog(FATAL, "error in CACHE"); \
198 RELATION = hentry->reldesc; \
203 #define RelationCacheDelete(RELATION) \
205 RelNameCacheEnt *namehentry; RelIdCacheEnt *idhentry; \
206 char *relname; Oid reloid; bool found; \
207 relname = (RELATION->rd_rel->relname).data; \
208 namehentry = (RelNameCacheEnt*)hash_search(RelationNameCache, \
212 if (namehentry == NULL) \
213 elog(FATAL, "can't delete from relation descriptor cache"); \
215 elog(NOTICE, "trying to delete a reldesc that does not exist."); \
216 reloid = RELATION->rd_id; \
217 idhentry = (RelIdCacheEnt*)hash_search(RelationIdCache, \
219 HASH_REMOVE, &found); \
220 if (idhentry == NULL) \
221 elog(FATAL, "can't delete from relation descriptor cache"); \
223 elog(NOTICE, "trying to delete a reldesc that does not exist."); \
226 /* non-export function prototypes */
227 static void formrdesc(char *relationName, u_int natts,
228 FormData_pg_attribute *att);
230 #ifdef NOT_USED /* See comments at line 1304 */
231 static void RelationFlushIndexes(Relation *r, Oid accessMethodId);
235 static HeapTuple ScanPgRelation(RelationBuildDescInfo buildinfo);
236 static HeapTuple scan_pg_rel_seq(RelationBuildDescInfo buildinfo);
237 static HeapTuple scan_pg_rel_ind(RelationBuildDescInfo buildinfo);
238 static Relation AllocateRelationDesc(u_int natts, Form_pg_class relp);
239 static void RelationBuildTupleDesc(RelationBuildDescInfo buildinfo,
240 Relation relation, u_int natts);
241 static void build_tupdesc_seq(RelationBuildDescInfo buildinfo,
242 Relation relation, u_int natts);
243 static void build_tupdesc_ind(RelationBuildDescInfo buildinfo,
244 Relation relation, u_int natts);
245 static Relation RelationBuildDesc(RelationBuildDescInfo buildinfo);
246 static void IndexedAccessMethodInitialize(Relation relation);
247 static void AttrDefaultFetch(Relation relation);
248 static void RelCheckFetch(Relation relation);
250 extern void RelationBuildTriggers(Relation relation);
251 extern void FreeTriggerDesc(Relation relation);
254 * newlyCreatedRelns -
255 * relations created during this transaction. We need to keep track of
258 static List *newlyCreatedRelns = NULL;
260 /* ----------------------------------------------------------------
261 * RelationIdGetRelation() and RelationNameGetRelation()
263 * ----------------------------------------------------------------
267 #if NOT_USED /* XXX This doesn't seem to be used
269 /* --------------------------------
270 * BuildDescInfoError returns a string appropriate to
271 * the buildinfo passed to it
272 * --------------------------------
275 BuildDescInfoError(RelationBuildDescInfo buildinfo)
277 static char errBuf[64];
279 MemSet(errBuf, 0, (int) sizeof(errBuf));
280 switch (buildinfo.infotype)
283 sprintf(errBuf, "(relation id %d)", buildinfo.i.info_id);
286 sprintf(errBuf, "(relation name %s)", buildinfo.i.info_name);
295 /* --------------------------------
298 * this is used by RelationBuildDesc to find a pg_class
299 * tuple matching either a relation name or a relation id
300 * as specified in buildinfo.
301 * --------------------------------
304 ScanPgRelation(RelationBuildDescInfo buildinfo)
308 * If this is bootstrap time (initdb), then we can't use the system
309 * catalog indices, because they may not exist yet. Otherwise, we
313 if (IsBootstrapProcessingMode())
314 return scan_pg_rel_seq(buildinfo);
316 return scan_pg_rel_ind(buildinfo);
320 scan_pg_rel_seq(RelationBuildDescInfo buildinfo)
322 HeapTuple pg_class_tuple;
323 HeapTuple return_tuple;
324 Relation pg_class_desc;
325 HeapScanDesc pg_class_scan;
332 switch (buildinfo.infotype)
335 ScanKeyEntryInitialize(&key, 0,
336 ObjectIdAttributeNumber,
338 ObjectIdGetDatum(buildinfo.i.info_id));
342 ScanKeyEntryInitialize(&key, 0,
343 Anum_pg_class_relname,
345 NameGetDatum(buildinfo.i.info_name));
349 elog(ERROR, "ScanPgRelation: bad buildinfo");
354 * open pg_class and fetch a tuple
357 pg_class_desc = heap_openr(RelationRelationName);
358 pg_class_scan = heap_beginscan(pg_class_desc, 0, SnapshotNow, 1, &key);
359 pg_class_tuple = heap_getnext(pg_class_scan, 0);
362 * get set to return tuple
365 if (!HeapTupleIsValid(pg_class_tuple))
366 return_tuple = pg_class_tuple;
369 /* ------------------
370 * a satanic bug used to live here: pg_class_tuple used to be
371 * returned here without having the corresponding buffer pinned.
372 * so when the buffer gets replaced, all hell breaks loose.
373 * this bug is discovered and killed by wei on 9/27/91.
374 * -------------------
376 return_tuple = heap_copytuple(pg_class_tuple);
380 heap_endscan(pg_class_scan);
381 heap_close(pg_class_desc);
387 scan_pg_rel_ind(RelationBuildDescInfo buildinfo)
389 Relation pg_class_desc;
390 HeapTuple return_tuple;
392 pg_class_desc = heap_openr(RelationRelationName);
393 if (!IsInitProcessingMode())
394 LockRelation(pg_class_desc, AccessShareLock);
396 switch (buildinfo.infotype)
399 return_tuple = ClassOidIndexScan(pg_class_desc,buildinfo.i.info_id);
403 return_tuple = ClassNameIndexScan(pg_class_desc,
404 buildinfo.i.info_name);
408 elog(ERROR, "ScanPgRelation: bad buildinfo");
411 * XXX I hope this is right. It seems better than returning
412 * an uninitialized value
418 if (!IsInitProcessingMode())
419 UnlockRelation(pg_class_desc, AccessShareLock);
420 heap_close(pg_class_desc);
426 * AllocateRelationDesc
428 * This is used to allocate memory for a new relation descriptor
429 * and initialize the rd_rel field.
433 AllocateRelationDesc(u_int natts, Form_pg_class relp)
437 Form_pg_class relationForm;
440 * allocate space for the relation tuple form
443 relationForm = (Form_pg_class)
444 palloc((Size) (sizeof(FormData_pg_class)));
446 memmove((char *) relationForm, (char *) relp, CLASS_TUPLE_SIZE);
449 * allocate space for new relation descriptor
451 len = sizeof(RelationData) + 10; /* + 10 is voodoo XXX mao */
453 relation = (Relation) palloc(len);
459 MemSet((char *) relation, 0, len);
461 /* initialize attribute tuple form */
462 relation->rd_att = CreateTemplateTupleDesc(natts);
464 /* and initialize relation tuple form */
465 relation->rd_rel = relationForm;
470 /* --------------------------------
471 * RelationBuildTupleDesc
473 * Form the relation's tuple descriptor from information in
474 * the pg_attribute, pg_attrdef & pg_relcheck system cataloges.
475 * --------------------------------
478 RelationBuildTupleDesc(RelationBuildDescInfo buildinfo,
484 * If this is bootstrap time (initdb), then we can't use the system
485 * catalog indices, because they may not exist yet. Otherwise, we
489 if (IsBootstrapProcessingMode())
490 build_tupdesc_seq(buildinfo, relation, natts);
492 build_tupdesc_ind(buildinfo, relation, natts);
496 build_tupdesc_seq(RelationBuildDescInfo buildinfo,
500 HeapTuple pg_attribute_tuple;
501 Relation pg_attribute_desc;
502 HeapScanDesc pg_attribute_scan;
503 Form_pg_attribute attp;
511 ScanKeyEntryInitialize(&key, 0,
512 Anum_pg_attribute_attrelid,
514 ObjectIdGetDatum(RelationGetRelid(relation)));
517 * open pg_attribute and begin a scan
520 pg_attribute_desc = heap_openr(AttributeRelationName);
521 pg_attribute_scan = heap_beginscan(pg_attribute_desc, 0, SnapshotNow, 1, &key);
524 * add attribute data to relation->rd_att
529 pg_attribute_tuple = heap_getnext(pg_attribute_scan, 0);
530 while (HeapTupleIsValid(pg_attribute_tuple) && need > 0)
532 attp = (Form_pg_attribute) GETSTRUCT(pg_attribute_tuple);
534 if (attp->attnum > 0)
536 relation->rd_att->attrs[attp->attnum - 1] =
537 (Form_pg_attribute) palloc(ATTRIBUTE_TUPLE_SIZE);
539 memmove((char *) (relation->rd_att->attrs[attp->attnum - 1]),
541 ATTRIBUTE_TUPLE_SIZE);
544 pg_attribute_tuple = heap_getnext(pg_attribute_scan, 0);
548 elog(ERROR, "catalog is missing %d attribute%s for relid %d",
549 need, (need == 1 ? "" : "s"), RelationGetRelid(relation));
552 * end the scan and close the attribute relation
555 heap_endscan(pg_attribute_scan);
556 heap_close(pg_attribute_desc);
560 build_tupdesc_ind(RelationBuildDescInfo buildinfo,
566 Form_pg_attribute attp;
567 TupleConstr *constr = (TupleConstr *) palloc(sizeof(TupleConstr));
568 AttrDefault *attrdef = NULL;
572 constr->has_not_null = false;
574 attrel = heap_openr(AttributeRelationName);
576 for (i = 1; i <= relation->rd_rel->relnatts; i++)
578 atttup = (HeapTuple) AttributeNumIndexScan(attrel,
579 RelationGetRelid(relation), i);
581 if (!HeapTupleIsValid(atttup))
582 elog(ERROR, "cannot find attribute %d of relation %s", i,
583 relation->rd_rel->relname.data);
584 attp = (Form_pg_attribute) GETSTRUCT(atttup);
586 relation->rd_att->attrs[i - 1] =
587 (Form_pg_attribute) palloc(ATTRIBUTE_TUPLE_SIZE);
589 memmove((char *) (relation->rd_att->attrs[i - 1]),
591 ATTRIBUTE_TUPLE_SIZE);
593 /* Update if this attribute have a constraint */
594 if (attp->attnotnull)
595 constr->has_not_null = true;
600 attrdef = (AttrDefault *) palloc(relation->rd_rel->relnatts *
601 sizeof(AttrDefault));
602 attrdef[ndef].adnum = i;
603 attrdef[ndef].adbin = NULL;
604 attrdef[ndef].adsrc = NULL;
611 if (constr->has_not_null || ndef > 0 || relation->rd_rel->relchecks)
613 relation->rd_att->constr = constr;
615 if (ndef > 0) /* DEFAULTs */
617 if (ndef < relation->rd_rel->relnatts)
618 constr->defval = (AttrDefault *)
619 repalloc(attrdef, ndef * sizeof(AttrDefault));
621 constr->defval = attrdef;
622 constr->num_defval = ndef;
623 AttrDefaultFetch(relation);
626 constr->num_defval = 0;
628 if (relation->rd_rel->relchecks > 0) /* CHECKs */
630 constr->num_check = relation->rd_rel->relchecks;
631 constr->check = (ConstrCheck *) palloc(constr->num_check *
632 sizeof(ConstrCheck));
633 MemSet(constr->check, 0, constr->num_check * sizeof(ConstrCheck));
634 RelCheckFetch(relation);
637 constr->num_check = 0;
642 relation->rd_att->constr = NULL;
647 /* --------------------------------
648 * RelationBuildRuleLock
650 * Form the relation's rewrite rules from information in
651 * the pg_rewrite system catalog.
652 * --------------------------------
655 RelationBuildRuleLock(Relation relation)
657 HeapTuple pg_rewrite_tuple;
658 Relation pg_rewrite_desc;
659 TupleDesc pg_rewrite_tupdesc;
660 HeapScanDesc pg_rewrite_scan;
668 * form an array to hold the rewrite rules (the array is extended if
673 rules = (RewriteRule **) palloc(sizeof(RewriteRule *) * maxlocks);
680 ScanKeyEntryInitialize(&key, 0,
681 Anum_pg_rewrite_ev_class,
683 ObjectIdGetDatum(RelationGetRelid(relation)));
686 * open pg_attribute and begin a scan
689 pg_rewrite_desc = heap_openr(RewriteRelationName);
690 pg_rewrite_scan = heap_beginscan(pg_rewrite_desc, 0, SnapshotNow, 1, &key);
691 pg_rewrite_tupdesc = RelationGetDescr(pg_rewrite_desc);
694 * add attribute data to relation->rd_att
697 while (HeapTupleIsValid(pg_rewrite_tuple = heap_getnext(pg_rewrite_scan, 0)))
701 Datum rule_evqual_string;
704 rule = (RewriteRule *) palloc(sizeof(RewriteRule));
706 rule->ruleId = pg_rewrite_tuple->t_data->t_oid;
708 rule->event = (int) heap_getattr(pg_rewrite_tuple,
709 Anum_pg_rewrite_ev_type, pg_rewrite_tupdesc,
711 rule->attrno = (int) heap_getattr(pg_rewrite_tuple,
712 Anum_pg_rewrite_ev_attr, pg_rewrite_tupdesc,
714 rule->isInstead = !!heap_getattr(pg_rewrite_tuple,
715 Anum_pg_rewrite_is_instead, pg_rewrite_tupdesc,
718 ruleaction = heap_getattr(pg_rewrite_tuple,
719 Anum_pg_rewrite_ev_action, pg_rewrite_tupdesc,
721 rule_evqual_string = heap_getattr(pg_rewrite_tuple,
722 Anum_pg_rewrite_ev_qual, pg_rewrite_tupdesc,
725 ruleaction = PointerGetDatum(textout((struct varlena *) DatumGetPointer(ruleaction)));
726 rule_evqual_string = PointerGetDatum(textout((struct varlena *) DatumGetPointer(rule_evqual_string)));
728 rule->actions = (List *) stringToNode(DatumGetPointer(ruleaction));
729 rule->qual = (Node *) stringToNode(DatumGetPointer(rule_evqual_string));
731 rules[numlocks++] = rule;
732 if (numlocks == maxlocks)
735 rules = (RewriteRule **) repalloc(rules, sizeof(RewriteRule *) * maxlocks);
740 * end the scan and close the attribute relation
743 heap_endscan(pg_rewrite_scan);
744 heap_close(pg_rewrite_desc);
747 * form a RuleLock and insert into relation
750 rulelock = (RuleLock *) palloc(sizeof(RuleLock));
751 rulelock->numLocks = numlocks;
752 rulelock->rules = rules;
754 relation->rd_rules = rulelock;
759 /* --------------------------------
762 * To build a relation descriptor, we have to allocate space,
763 * open the underlying unix file and initialize the following
766 * File rd_fd; open file descriptor
767 * int rd_nblocks; number of blocks in rel
768 * it will be set in ambeginscan()
769 * uint16 rd_refcnt; reference count
770 * Form_pg_am rd_am; AM tuple
771 * Form_pg_class rd_rel; RELATION tuple
772 * Oid rd_id; relations's object id
773 * Pointer lockInfo; ptr. to misc. info.
774 * TupleDesc rd_att; tuple desciptor
776 * Note: rd_ismem (rel is in-memory only) is currently unused
777 * by any part of the system. someday this will indicate that
778 * the relation lives only in the main-memory buffer pool
780 * --------------------------------
783 RelationBuildDesc(RelationBuildDescInfo buildinfo)
792 MemoryContext oldcxt;
794 HeapTuple pg_class_tuple;
796 oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
799 * find the tuple in pg_class corresponding to the given relation id
802 pg_class_tuple = ScanPgRelation(buildinfo);
805 * if no such tuple exists, return NULL
808 if (!HeapTupleIsValid(pg_class_tuple))
810 MemoryContextSwitchTo(oldcxt);
816 * get information from the pg_class_tuple
819 relid = pg_class_tuple->t_data->t_oid;
820 relp = (Form_pg_class) GETSTRUCT(pg_class_tuple);
821 natts = relp->relnatts;
824 * allocate storage for the relation descriptor,
825 * initialize relation->rd_rel and get the access method id.
828 relation = AllocateRelationDesc(natts, relp);
829 relam = relation->rd_rel->relam;
832 * initialize the relation's relation id (relation->rd_id)
835 RelationGetRelid(relation) = relid;
838 * initialize relation->rd_refcnt
841 RelationSetReferenceCount(relation, 1);
844 * normal relations are not nailed into the cache
847 relation->rd_isnailed = false;
850 * initialize the access method information (relation->rd_am)
853 if (OidIsValid(relam))
855 relation->rd_am = (Form_pg_am) AccessMethodObjectIdGetForm(relam);
859 * initialize the tuple descriptor (relation->rd_att).
860 * remember, rd_att is an array of attribute pointers that lives
861 * off the end of the relation descriptor structure so space was
862 * already allocated for it by AllocateRelationDesc.
865 RelationBuildTupleDesc(buildinfo, relation, natts);
868 * initialize rules that affect this relation
871 if (relp->relhasrules)
872 RelationBuildRuleLock(relation);
874 relation->rd_rules = NULL;
877 if (relp->reltriggers > 0)
878 RelationBuildTriggers(relation);
880 relation->trigdesc = NULL;
883 * initialize index strategy and support information for this relation
886 if (OidIsValid(relam))
887 IndexedAccessMethodInitialize(relation);
890 * initialize the relation lock manager information
893 RelationInitLockInfo(relation); /* see lmgr.c */
896 * open the relation and assign the file descriptor returned
897 * by the storage manager code to rd_fd.
900 fd = smgropen(DEFAULT_SMGR, relation);
904 elog(NOTICE, "RelationIdBuildRelation: smgropen(%s): %m",
907 relation->rd_fd = fd;
910 * insert newly created relation into proper relcaches,
911 * restore memory context and return the new reldesc.
914 RelationCacheInsert(relation);
916 /* -------------------
917 * free the memory allocated for pg_class_tuple
918 * and for lock data pointed to by pg_class_tuple
919 * -------------------
921 pfree(pg_class_tuple);
923 MemoryContextSwitchTo(oldcxt);
929 IndexedAccessMethodInitialize(Relation relation)
931 IndexStrategy strategy;
932 RegProcedure *support;
936 uint16 relamstrategies;
939 natts = relation->rd_rel->relnatts;
940 relamstrategies = relation->rd_am->amstrategies;
941 stratSize = AttributeNumberGetIndexStrategySize(natts, relamstrategies);
942 strategy = (IndexStrategy) palloc(stratSize);
943 relamsupport = relation->rd_am->amsupport;
945 if (relamsupport > 0)
947 supportSize = natts * (relamsupport * sizeof(RegProcedure));
948 support = (RegProcedure *) palloc(supportSize);
951 support = (RegProcedure *) NULL;
953 IndexSupportInitialize(strategy, support,
954 relation->rd_att->attrs[0]->attrelid,
955 relation->rd_rel->relam,
956 relamstrategies, relamsupport, natts);
958 RelationSetIndexSupport(relation, strategy, support);
961 /* --------------------------------
964 * This is a special version of RelationBuildDesc()
965 * used by RelationInitialize() in initializing the
966 * relcache. The system relation descriptors built
967 * here are all nailed in the descriptor caches, for
969 * --------------------------------
972 formrdesc(char *relationName,
974 FormData_pg_attribute *att)
981 * allocate new relation desc
984 len = sizeof(RelationData);
985 relation = (Relation) palloc(len);
986 MemSet((char *) relation, 0, len);
989 * don't open the unix file yet..
992 relation->rd_fd = -1;
995 * initialize reference count
998 RelationSetReferenceCount(relation, 1);
1001 * initialize relation tuple form
1004 relation->rd_rel = (Form_pg_class)
1005 palloc((Size) (sizeof(*relation->rd_rel)));
1006 MemSet(relation->rd_rel, 0, sizeof(FormData_pg_class));
1007 namestrcpy(&relation->rd_rel->relname, relationName);
1010 initialize attribute tuple form
1012 relation->rd_att = CreateTemplateTupleDesc(natts);
1015 * For debugging purposes, it's important to distinguish between
1016 * shared and non-shared relations, even at bootstrap time. There's
1017 * code in the buffer manager that traces allocations that has to know
1021 if (IsSystemRelationName(relationName))
1023 relation->rd_rel->relowner = 6; /* XXX use sym const */
1024 relation->rd_rel->relisshared = IsSharedSystemRelationName(relationName);
1028 relation->rd_rel->relowner = 0;
1029 relation->rd_rel->relisshared = false;
1032 relation->rd_rel->relpages = 1; /* XXX */
1033 relation->rd_rel->reltuples = 1; /* XXX */
1034 relation->rd_rel->relkind = RELKIND_RELATION;
1035 relation->rd_rel->relnatts = (uint16) natts;
1036 relation->rd_isnailed = true;
1039 * initialize tuple desc info
1042 for (i = 0; i < natts; i++)
1044 relation->rd_att->attrs[i] = (Form_pg_attribute) palloc(ATTRIBUTE_TUPLE_SIZE);
1046 MemSet((char *) relation->rd_att->attrs[i], 0,
1047 ATTRIBUTE_TUPLE_SIZE);
1048 memmove((char *) relation->rd_att->attrs[i],
1050 ATTRIBUTE_TUPLE_SIZE);
1054 * initialize relation id
1057 RelationGetRelid(relation) = relation->rd_att->attrs[0]->attrelid;
1060 * add new reldesc to relcache
1063 RelationCacheInsert(relation);
1065 RelationInitLockInfo(relation);
1068 * Determining this requires a scan on pg_class, but to do the scan
1069 * the rdesc for pg_class must already exist. Therefore we must do
1070 * the check (and possible set) after cache insertion.
1072 relation->rd_rel->relhasindex =
1073 CatalogHasIndex(relationName, RelationGetRelid(relation));
1077 /* ----------------------------------------------------------------
1078 * Relation Descriptor Lookup Interface
1079 * ----------------------------------------------------------------
1082 /* --------------------------------
1083 * RelationIdCacheGetRelation
1085 * only try to get the reldesc by looking up the cache
1086 * do not go to the disk. this is used by BlockPrepareFile()
1087 * and RelationIdGetRelation below.
1088 * --------------------------------
1091 RelationIdCacheGetRelation(Oid relationId)
1095 RelationIdCacheLookup(relationId, rd);
1097 if (RelationIsValid(rd))
1099 if (rd->rd_fd == -1)
1101 rd->rd_fd = smgropen(DEFAULT_SMGR, rd);
1102 Assert(rd->rd_fd != -1);
1105 RelationIncrementReferenceCount(rd);
1112 /* --------------------------------
1113 * RelationNameCacheGetRelation
1114 * --------------------------------
1117 RelationNameCacheGetRelation(char *relationName)
1123 * make sure that the name key used for hash lookup is properly
1126 namestrcpy(&name, relationName);
1127 RelationNameCacheLookup(name.data, rd);
1129 if (RelationIsValid(rd))
1131 if (rd->rd_fd == -1)
1133 rd->rd_fd = smgropen(DEFAULT_SMGR, rd);
1134 Assert(rd->rd_fd != -1);
1137 RelationIncrementReferenceCount(rd);
1144 /* --------------------------------
1145 * RelationIdGetRelation
1147 * return a relation descriptor based on its id.
1148 * return a cached value if possible
1149 * --------------------------------
1152 RelationIdGetRelation(Oid relationId)
1155 RelationBuildDescInfo buildinfo;
1158 * increment access statistics
1161 IncrHeapAccessStat(local_RelationIdGetRelation);
1162 IncrHeapAccessStat(global_RelationIdGetRelation);
1165 * first try and get a reldesc from the cache
1168 rd = RelationIdCacheGetRelation(relationId);
1169 if (RelationIsValid(rd))
1173 * no reldesc in the cache, so have RelationBuildDesc()
1174 * build one and add it.
1177 buildinfo.infotype = INFO_RELID;
1178 buildinfo.i.info_id = relationId;
1180 rd = RelationBuildDesc(buildinfo);
1184 /* --------------------------------
1185 * RelationNameGetRelation
1187 * return a relation descriptor based on its name.
1188 * return a cached value if possible
1189 * --------------------------------
1192 RelationNameGetRelation(char *relationName)
1195 RelationBuildDescInfo buildinfo;
1198 * increment access statistics
1201 IncrHeapAccessStat(local_RelationNameGetRelation);
1202 IncrHeapAccessStat(global_RelationNameGetRelation);
1205 * first try and get a reldesc from the cache
1208 rd = RelationNameCacheGetRelation(relationName);
1209 if (RelationIsValid(rd))
1213 * no reldesc in the cache, so have RelationBuildDesc()
1214 * build one and add it.
1217 buildinfo.infotype = INFO_RELNAME;
1218 buildinfo.i.info_name = relationName;
1220 rd = RelationBuildDesc(buildinfo);
1225 * old "getreldesc" interface.
1230 getreldesc(char *relationName)
1233 * increment access statistics
1236 IncrHeapAccessStat(local_getreldesc);
1237 IncrHeapAccessStat(global_getreldesc);
1239 return RelationNameGetRelation(relationName);
1244 /* ----------------------------------------------------------------
1245 * cache invalidation support routines
1246 * ----------------------------------------------------------------
1249 /* --------------------------------
1250 * RelationClose - close an open relation
1251 * --------------------------------
1254 RelationClose(Relation relation)
1256 /* Note: no locking manipulations needed */
1257 RelationDecrementReferenceCount(relation);
1260 /* --------------------------------
1261 * RelationFlushRelation
1263 * Actually blows away a relation... RelationFree doesn't do
1265 * --------------------------------
1268 RelationFlushRelation(Relation *relationPtr,
1269 bool onlyFlushReferenceCountZero)
1271 MemoryContext oldcxt;
1272 Relation relation = *relationPtr;
1274 if (relation->rd_isnailed)
1276 /* this is a nailed special relation for bootstraping */
1280 if (!onlyFlushReferenceCountZero ||
1281 RelationHasReferenceCountZero(relation))
1284 oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
1286 RelationCacheDelete(relation);
1288 FreeTupleDesc(relation->rd_att);
1289 SystemCacheRelationFlushed(RelationGetRelid(relation));
1291 FreeTriggerDesc(relation);
1294 if (relation->rd_rules)
1298 for (j = 0; j < relation->rd_rules->numLocks; j++)
1299 pfree(relation->rd_rules->rules[j]);
1300 pfree(relation->rd_rules->rules);
1301 pfree(relation->rd_rules);
1305 pfree(RelationGetLockInfo(relation));
1306 pfree(RelationGetForm(relation));
1309 MemoryContextSwitchTo(oldcxt);
1313 /* --------------------------------
1314 * RelationForgetRelation -
1315 * RelationFlushRelation + if the relation is myxactonly then
1316 * get rid of the relation descriptor from the newly created
1318 * --------------------------------
1321 RelationForgetRelation(Oid rid)
1325 RelationIdCacheLookup(rid, relation);
1327 if (PointerIsValid(relation))
1329 if (relation->rd_myxactonly)
1331 MemoryContext oldcxt;
1335 oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
1337 foreach(curr, newlyCreatedRelns)
1339 Relation reln = lfirst(curr);
1341 Assert(reln != NULL && reln->rd_myxactonly);
1342 if (RelationGetRelid(reln) == rid)
1347 elog(FATAL, "Local relation %s not found in list",
1348 (RelationGetRelationName(relation))->data);
1350 newlyCreatedRelns = lnext(newlyCreatedRelns);
1352 lnext(prev) = lnext(curr);
1354 MemoryContextSwitchTo(oldcxt);
1357 RelationFlushRelation(&relation, false);
1361 /* --------------------------------
1362 * RelationIdInvalidateRelationCacheByRelationId
1363 * --------------------------------
1366 RelationIdInvalidateRelationCacheByRelationId(Oid relationId)
1370 RelationIdCacheLookup(relationId, relation);
1373 * "local" relations are invalidated by RelationPurgeLocalRelation.
1374 * (This is to make LocalBufferSync's life easier: want the descriptor
1375 * to hang around for a while. In fact, won't we want this for
1376 * BufferSync also? But I'll leave it for now since I don't want to
1377 * break anything.) - ay 3/95
1379 if (PointerIsValid(relation) && !relation->rd_myxactonly)
1382 * The boolean onlyFlushReferenceCountZero in RelationFlushReln()
1383 * should be set to true when we are incrementing the command
1384 * counter and to false when we are starting a new xaction. This
1385 * can be determined by checking the current xaction status.
1387 RelationFlushRelation(&relation, CurrentXactInProgress());
1391 #if NOT_USED /* See comments at line 1304 */
1392 /* --------------------------------
1393 * RelationIdInvalidateRelationCacheByAccessMethodId
1395 * RelationFlushIndexes is needed for use with HashTableWalk..
1396 * --------------------------------
1399 RelationFlushIndexes(Relation *r,
1402 Relation relation = *r;
1404 if (!RelationIsValid(relation))
1406 elog(NOTICE, "inval call to RFI");
1410 if (relation->rd_rel->relkind == RELKIND_INDEX && /* XXX style */
1411 (!OidIsValid(accessMethodId) ||
1412 relation->rd_rel->relam == accessMethodId))
1413 RelationFlushRelation(&relation, false);
1420 RelationIdInvalidateRelationCacheByAccessMethodId(Oid accessMethodId)
1425 * 25 aug 1992: mao commented out the ht walk below. it should be
1426 * doing the right thing, in theory, but flushing reldescs for index
1427 * relations apparently doesn't work. we want to cut 4.0.1, and i
1428 * don't want to introduce new bugs. this code never executed before,
1429 * so i'm turning it off for now. after the release is cut, i'll fix
1433 HashTableWalk(RelationNameCache, (HashtFunc) RelationFlushIndexes,
1441 * RelationCacheInvalidate
1443 * Will blow away either all the cached relation descriptors or
1444 * those that have a zero reference count.
1448 RelationCacheInvalidate(bool onlyFlushReferenceCountZero)
1450 HashTableWalk(RelationNameCache, (HashtFunc) RelationFlushRelation,
1451 onlyFlushReferenceCountZero);
1454 * nailed-in reldescs will still be in the cache... 7 hardwired heaps
1455 * + 3 hardwired indices == 10 total.
1457 if (!onlyFlushReferenceCountZero)
1459 Assert(RelationNameCache->hctl->nkeys == 10);
1460 Assert(RelationIdCache->hctl->nkeys == 10);
1465 /* --------------------------------
1466 * RelationRegisterRelation -
1467 * register the Relation descriptor of a newly created relation
1468 * with the relation descriptor Cache.
1469 * --------------------------------
1472 RelationRegisterRelation(Relation relation)
1474 MemoryContext oldcxt;
1476 oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
1478 if (oldcxt != (MemoryContext) CacheCxt)
1479 elog(NOIND, "RelationRegisterRelation: WARNING: Context != CacheCxt");
1481 RelationCacheInsert(relation);
1483 RelationInitLockInfo(relation);
1486 * we've just created the relation. It is invisible to anyone else
1487 * before the transaction is committed. Setting rd_myxactonly allows us
1488 * to use the local buffer manager for select/insert/etc before the
1489 * end of transaction. (We also need to keep track of relations
1490 * created during a transaction and does the necessary clean up at the
1491 * end of the transaction.) - ay 3/95
1493 relation->rd_myxactonly = TRUE;
1494 newlyCreatedRelns = lcons(relation, newlyCreatedRelns);
1496 MemoryContextSwitchTo(oldcxt);
1500 * RelationPurgeLocalRelation -
1501 * find all the Relation descriptors marked rd_myxactonly and reset them.
1502 * This should be called at the end of a transaction (commit/abort) when
1503 * the "local" relations will become visible to others and the multi-user
1504 * buffer pool should be used.
1507 RelationPurgeLocalRelation(bool xactCommitted)
1509 MemoryContext oldcxt;
1511 if (newlyCreatedRelns == NULL)
1514 oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
1516 while (newlyCreatedRelns)
1518 List *l = newlyCreatedRelns;
1519 Relation reln = lfirst(l);
1521 Assert(reln != NULL && reln->rd_myxactonly);
1527 * remove the file if we abort. This is so that files for
1528 * tables created inside a transaction block get removed.
1530 if (reln->rd_isnoname)
1532 if (!(reln->rd_nonameunlinked))
1534 smgrunlink(DEFAULT_SMGR, reln);
1535 reln->rd_nonameunlinked = TRUE;
1539 smgrunlink(DEFAULT_SMGR, reln);
1541 else if (!IsBootstrapProcessingMode() && !(reln->rd_isnoname))
1544 * RelationFlushRelation () below will flush relation
1545 * information from the cache. We must call smgrclose to flush
1546 * relation information from SMGR & FMGR, too. We assume that
1547 * for temp relations smgrunlink is already called by
1548 * heap_destroyr and we skip smgrclose for them. -
1551 smgrclose(DEFAULT_SMGR, reln);
1553 reln->rd_myxactonly = FALSE;
1555 if (!IsBootstrapProcessingMode())
1556 RelationFlushRelation(&reln, FALSE);
1558 newlyCreatedRelns = lnext(newlyCreatedRelns);
1562 MemoryContextSwitchTo(oldcxt);
1565 /* --------------------------------
1566 * RelationInitialize
1568 * This initializes the relation descriptor cache.
1569 * --------------------------------
1572 #define INITRELCACHESIZE 400
1575 RelationInitialize(void)
1577 MemoryContext oldcxt;
1581 * switch to cache memory context
1585 CacheCxt = CreateGlobalMemory("Cache");
1587 oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
1590 * create global caches
1593 MemSet(&ctl, 0, (int) sizeof(ctl));
1594 ctl.keysize = sizeof(NameData);
1595 ctl.datasize = sizeof(Relation);
1596 RelationNameCache = hash_create(INITRELCACHESIZE, &ctl, HASH_ELEM);
1598 ctl.keysize = sizeof(Oid);
1599 ctl.hash = tag_hash;
1600 RelationIdCache = hash_create(INITRELCACHESIZE, &ctl,
1601 HASH_ELEM | HASH_FUNCTION);
1604 * initialize the cache with pre-made relation descriptors
1605 * for some of the more important system relations. These
1606 * relations should always be in the cache.
1609 formrdesc(RelationRelationName, Natts_pg_class, Desc_pg_class);
1610 formrdesc(AttributeRelationName, Natts_pg_attribute, Desc_pg_attribute);
1611 formrdesc(ProcedureRelationName, Natts_pg_proc, Desc_pg_proc);
1612 formrdesc(TypeRelationName, Natts_pg_type, Desc_pg_type);
1613 formrdesc(VariableRelationName, Natts_pg_variable, Desc_pg_variable);
1614 formrdesc(LogRelationName, Natts_pg_log, Desc_pg_log);
1617 * If this isn't initdb time, then we want to initialize some index
1618 * relation descriptors, as well. The descriptors are for
1619 * pg_attnumind (to make building relation descriptors fast) and
1620 * possibly others, as they're added.
1623 if (!IsBootstrapProcessingMode())
1626 MemoryContextSwitchTo(oldcxt);
1630 AttrDefaultFetch(Relation relation)
1632 AttrDefault *attrdef = relation->rd_att->constr->defval;
1633 int ndef = relation->rd_att->constr->num_defval;
1637 HeapTupleData tuple;
1638 Form_pg_attrdef adform;
1640 RetrieveIndexResult indexRes;
1641 struct varlena *val;
1646 ScanKeyEntryInitialize(&skey,
1649 (RegProcedure) F_OIDEQ,
1650 ObjectIdGetDatum(RelationGetRelid(relation)));
1652 adrel = heap_openr(AttrDefaultRelationName);
1653 irel = index_openr(AttrDefaultIndex);
1654 sd = index_beginscan(irel, false, 1, &skey);
1655 tuple.t_data = NULL;
1661 indexRes = index_getnext(sd, ForwardScanDirection);
1665 tuple.t_self = indexRes->heap_iptr;
1666 heap_fetch(adrel, SnapshotNow, &tuple, &buffer);
1668 if (tuple.t_data == NULL)
1671 adform = (Form_pg_attrdef) GETSTRUCT(&tuple);
1672 for (i = 0; i < ndef; i++)
1674 if (adform->adnum != attrdef[i].adnum)
1676 if (attrdef[i].adsrc != NULL)
1677 elog(ERROR, "AttrDefaultFetch: second record found for attr %s in rel %s",
1678 relation->rd_att->attrs[adform->adnum - 1]->attname.data,
1679 relation->rd_rel->relname.data);
1681 val = (struct varlena *) fastgetattr(&tuple,
1682 Anum_pg_attrdef_adbin,
1683 adrel->rd_att, &isnull);
1685 elog(ERROR, "AttrDefaultFetch: adbin IS NULL for attr %s in rel %s",
1686 relation->rd_att->attrs[adform->adnum - 1]->attname.data,
1687 relation->rd_rel->relname.data);
1688 attrdef[i].adbin = textout(val);
1689 val = (struct varlena *) fastgetattr(&tuple,
1690 Anum_pg_attrdef_adsrc,
1691 adrel->rd_att, &isnull);
1693 elog(ERROR, "AttrDefaultFetch: adsrc IS NULL for attr %s in rel %s",
1694 relation->rd_att->attrs[adform->adnum - 1]->attname.data,
1695 relation->rd_rel->relname.data);
1696 attrdef[i].adsrc = textout(val);
1699 ReleaseBuffer(buffer);
1702 elog(ERROR, "AttrDefaultFetch: unexpected record found for attr %d in rel %s",
1704 relation->rd_rel->relname.data);
1708 elog(ERROR, "AttrDefaultFetch: %d record not found for rel %s",
1709 ndef - found, relation->rd_rel->relname.data);
1718 RelCheckFetch(Relation relation)
1720 ConstrCheck *check = relation->rd_att->constr->check;
1721 int ncheck = relation->rd_att->constr->num_check;
1725 HeapTupleData tuple;
1727 RetrieveIndexResult indexRes;
1729 struct varlena *val;
1733 ScanKeyEntryInitialize(&skey,
1736 (RegProcedure) F_OIDEQ,
1737 ObjectIdGetDatum(RelationGetRelid(relation)));
1739 rcrel = heap_openr(RelCheckRelationName);
1740 irel = index_openr(RelCheckIndex);
1741 sd = index_beginscan(irel, false, 1, &skey);
1742 tuple.t_data = NULL;
1748 indexRes = index_getnext(sd, ForwardScanDirection);
1752 tuple.t_self = indexRes->heap_iptr;
1753 heap_fetch(rcrel, SnapshotNow, &tuple, &buffer);
1755 if (tuple.t_data == NULL)
1757 if (found == ncheck)
1758 elog(ERROR, "RelCheckFetch: unexpected record found for rel %s",
1759 relation->rd_rel->relname.data);
1761 rcname = (Name) fastgetattr(&tuple,
1762 Anum_pg_relcheck_rcname,
1763 rcrel->rd_att, &isnull);
1765 elog(ERROR, "RelCheckFetch: rcname IS NULL for rel %s",
1766 relation->rd_rel->relname.data);
1767 check[found].ccname = nameout(rcname);
1768 val = (struct varlena *) fastgetattr(&tuple,
1769 Anum_pg_relcheck_rcbin,
1770 rcrel->rd_att, &isnull);
1772 elog(ERROR, "RelCheckFetch: rcbin IS NULL for rel %s",
1773 relation->rd_rel->relname.data);
1774 check[found].ccbin = textout(val);
1775 val = (struct varlena *) fastgetattr(&tuple,
1776 Anum_pg_relcheck_rcsrc,
1777 rcrel->rd_att, &isnull);
1779 elog(ERROR, "RelCheckFetch: rcsrc IS NULL for rel %s",
1780 relation->rd_rel->relname.data);
1781 check[found].ccsrc = textout(val);
1783 ReleaseBuffer(buffer);
1787 elog(ERROR, "RelCheckFetch: %d record not found for rel %s",
1789 relation->rd_rel->relname.data);
1799 * init_irels(), write_irels() -- handle special-case initialization of
1800 * index relation descriptors.
1802 * In late 1992, we started regularly having databases with more than
1803 * a thousand classes in them. With this number of classes, it became
1804 * critical to do indexed lookups on the system catalogs.
1806 * Bootstrapping these lookups is very hard. We want to be able to
1807 * use an index on pg_attribute, for example, but in order to do so,
1808 * we must have read pg_attribute for the attributes in the index,
1809 * which implies that we need to use the index.
1811 * In order to get around the problem, we do the following:
1813 * + When the database system is initialized (at initdb time), we
1814 * don't use indices on pg_attribute. We do sequential scans.
1816 * + When the backend is started up in normal mode, we load an image
1817 * of the appropriate relation descriptors, in internal format,
1818 * from an initialization file in the data/base/... directory.
1820 * + If the initialization file isn't there, then we create the
1821 * relation descriptors using sequential scans and write 'em to
1822 * the initialization file for use by subsequent backends.
1824 * We could dispense with the initialization file and just build the
1825 * critical reldescs the hard way on every backend startup, but that
1826 * slows down backend startup noticeably if pg_class is large.
1828 * As of v6.5, vacuum.c deletes the initialization file at completion
1829 * of a VACUUM, so that it will be rebuilt at the next backend startup.
1830 * This ensures that vacuum-collected stats for the system indexes
1831 * will eventually get used by the optimizer --- otherwise the relcache
1832 * entries for these indexes will show zero sizes forever, since the
1833 * relcache entries are pinned in memory and will never be reloaded
1837 /* pg_attnumind, pg_classnameind, pg_classoidind */
1838 #define Num_indices_bootstrap 3
1846 Relation irel[Num_indices_bootstrap];
1849 Form_pg_class relform;
1850 IndexStrategy strat;
1851 RegProcedure *support;
1855 #ifndef __CYGWIN32__
1856 if ((fd = FileNameOpenFile(RELCACHE_INIT_FILENAME, O_RDONLY, 0600)) < 0)
1858 if ((fd = FileNameOpenFile(RELCACHE_INIT_FILENAME, O_RDONLY | O_BINARY, 0600)) < 0)
1865 FileSeek(fd, 0L, SEEK_SET);
1867 for (relno = 0; relno < Num_indices_bootstrap; relno++)
1869 /* first read the relation descriptor length */
1870 if ((nread = FileRead(fd, (char *) &len, sizeof(len))) != sizeof(len))
1876 ird = irel[relno] = (Relation) palloc(len);
1877 MemSet(ird, 0, len);
1879 /* then, read the Relation structure */
1880 if ((nread = FileRead(fd, (char *) ird, len)) != len)
1886 /* the file descriptor is not yet opened */
1889 /* lock info is not initialized */
1890 ird->lockInfo = (char *) NULL;
1892 /* next, read the access method tuple form */
1893 if ((nread = FileRead(fd, (char *) &len, sizeof(len))) != sizeof(len))
1899 am = (Form_pg_am) palloc(len);
1900 if ((nread = FileRead(fd, (char *) am, len)) != len)
1908 /* next read the relation tuple form */
1909 if ((nread = FileRead(fd, (char *) &len, sizeof(len))) != sizeof(len))
1915 relform = (Form_pg_class) palloc(len);
1916 if ((nread = FileRead(fd, (char *) relform, len)) != len)
1922 ird->rd_rel = relform;
1924 /* initialize attribute tuple forms */
1925 ird->rd_att = CreateTemplateTupleDesc(relform->relnatts);
1927 /* next read all the attribute tuple form data entries */
1928 len = ATTRIBUTE_TUPLE_SIZE;
1929 for (i = 0; i < relform->relnatts; i++)
1931 if ((nread = FileRead(fd, (char *) &len, sizeof(len))) != sizeof(len))
1937 ird->rd_att->attrs[i] = (Form_pg_attribute) palloc(len);
1939 if ((nread = FileRead(fd, (char *) ird->rd_att->attrs[i], len)) != len)
1946 /* next, read the index strategy map */
1947 if ((nread = FileRead(fd, (char *) &len, sizeof(len))) != sizeof(len))
1953 strat = (IndexStrategy) palloc(len);
1954 if ((nread = FileRead(fd, (char *) strat, len)) != len)
1960 /* oh, for god's sake... */
1961 #define SMD(i) strat[0].strategyMapData[i].entry[0]
1963 /* have to reinit the function pointers in the strategy maps */
1964 for (i = 0; i < am->amstrategies * relform->relnatts; i++)
1966 fmgr_info(SMD(i).sk_procedure,
1968 SMD(i).sk_nargs = SMD(i).sk_func.fn_nargs;
1973 * use a real field called rd_istrat instead of the bogosity of
1974 * hanging invisible fields off the end of a structure - jolly
1976 ird->rd_istrat = strat;
1978 /* finally, read the vector of support procedures */
1979 if ((nread = FileRead(fd, (char *) &len, sizeof(len))) != sizeof(len))
1985 support = (RegProcedure *) palloc(len);
1986 if ((nread = FileRead(fd, (char *) support, len)) != len)
1993 * p += sizeof(IndexStrategy); ((RegProcedure **) p) = support;
1996 ird->rd_support = support;
1998 RelationCacheInsert(ird);
1999 RelationInitLockInfo(ird);
2009 Relation irel[Num_indices_bootstrap];
2012 Form_pg_class relform;
2013 IndexStrategy strat;
2014 RegProcedure *support;
2015 ProcessingMode oldmode;
2018 RelationBuildDescInfo bi;
2020 #ifndef __CYGWIN32__
2021 fd = FileNameOpenFile(RELCACHE_INIT_FILENAME, O_WRONLY | O_CREAT | O_TRUNC, 0600);
2023 fd = FileNameOpenFile(RELCACHE_INIT_FILENAME, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0600);
2026 elog(FATAL, "cannot create init file %s", RELCACHE_INIT_FILENAME);
2028 FileSeek(fd, 0L, SEEK_SET);
2031 * Build a relation descriptor for pg_attnumind without resort to the
2032 * descriptor cache. In order to do this, we set ProcessingMode to
2033 * Bootstrap. The effect of this is to disable indexed relation
2034 * searches -- a necessary step, since we're trying to instantiate the
2035 * index relation descriptors here.
2038 oldmode = GetProcessingMode();
2039 SetProcessingMode(BootstrapProcessing);
2041 bi.infotype = INFO_RELNAME;
2042 bi.i.info_name = AttributeNumIndex;
2043 irel[0] = RelationBuildDesc(bi);
2044 irel[0]->rd_isnailed = true;
2046 bi.i.info_name = ClassNameIndex;
2047 irel[1] = RelationBuildDesc(bi);
2048 irel[1]->rd_isnailed = true;
2050 bi.i.info_name = ClassOidIndex;
2051 irel[2] = RelationBuildDesc(bi);
2052 irel[2]->rd_isnailed = true;
2054 SetProcessingMode(oldmode);
2056 /* nail the descriptor in the cache */
2057 for (relno = 0; relno < Num_indices_bootstrap; relno++)
2061 /* save the volatile fields in the relation descriptor */
2063 ird->rd_am = (Form_pg_am) NULL;
2064 relform = ird->rd_rel;
2065 ird->rd_rel = (Form_pg_class) NULL;
2066 strat = ird->rd_istrat;
2067 support = ird->rd_support;
2070 * first write the relation descriptor , excluding strategy and
2073 len = sizeof(RelationData);
2075 /* first, write the relation descriptor length */
2076 if ((nwritten = FileWrite(fd, (char *) &len, sizeof(len)))
2078 elog(FATAL, "cannot write init file -- descriptor length");
2080 /* next, write out the Relation structure */
2081 if ((nwritten = FileWrite(fd, (char *) ird, len)) != len)
2082 elog(FATAL, "cannot write init file -- reldesc");
2084 /* next, write the access method tuple form */
2085 len = sizeof(FormData_pg_am);
2086 if ((nwritten = FileWrite(fd, (char *) &len, sizeof(len)))
2088 elog(FATAL, "cannot write init file -- am tuple form length");
2090 if ((nwritten = FileWrite(fd, (char *) am, len)) != len)
2091 elog(FATAL, "cannot write init file -- am tuple form");
2093 /* next write the relation tuple form */
2094 len = sizeof(FormData_pg_class);
2095 if ((nwritten = FileWrite(fd, (char *) &len, sizeof(len)))
2097 elog(FATAL, "cannot write init file -- relation tuple form length");
2099 if ((nwritten = FileWrite(fd, (char *) relform, len)) != len)
2100 elog(FATAL, "cannot write init file -- relation tuple form");
2102 /* next, do all the attribute tuple form data entries */
2103 len = ATTRIBUTE_TUPLE_SIZE;
2104 for (i = 0; i < relform->relnatts; i++)
2106 if ((nwritten = FileWrite(fd, (char *) &len, sizeof(len)))
2108 elog(FATAL, "cannot write init file -- length of attdesc %d", i);
2109 if ((nwritten = FileWrite(fd, (char *) ird->rd_att->attrs[i], len))
2111 elog(FATAL, "cannot write init file -- attdesc %d", i);
2114 /* next, write the index strategy map */
2115 len = AttributeNumberGetIndexStrategySize(relform->relnatts,
2117 if ((nwritten = FileWrite(fd, (char *) &len, sizeof(len)))
2119 elog(FATAL, "cannot write init file -- strategy map length");
2121 if ((nwritten = FileWrite(fd, (char *) strat, len)) != len)
2122 elog(FATAL, "cannot write init file -- strategy map");
2124 /* finally, write the vector of support procedures */
2125 len = relform->relnatts * (am->amsupport * sizeof(RegProcedure));
2126 if ((nwritten = FileWrite(fd, (char *) &len, sizeof(len)))
2128 elog(FATAL, "cannot write init file -- support vector length");
2130 if ((nwritten = FileWrite(fd, (char *) support, len)) != len)
2131 elog(FATAL, "cannot write init file -- support vector");
2133 /* restore volatile fields */
2135 ird->rd_rel = relform;