OSDN Git Service

38edc3a790a69d118d7d961781d427af50098026
[pg-rex/syncrep.git] / src / backend / utils / cache / relcache.c
1 /*-------------------------------------------------------------------------
2  *
3  * relcache.c
4  *        POSTGRES relation descriptor cache code
5  *
6  * Copyright (c) 1994, Regents of the University of California
7  *
8  *
9  * IDENTIFICATION
10  *        $Header: /cvsroot/pgsql/src/backend/utils/cache/relcache.c,v 1.60 1999/05/01 19:09:44 tgl Exp $
11  *
12  *-------------------------------------------------------------------------
13  */
14 /*
15  * INTERFACE ROUTINES
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
23  *
24  * NOTES
25  *              This file is in the process of being cleaned up
26  *              before I add system attribute indexing.  -cim 1/13/91
27  *
28  *              The following code contains many undocumented hacks.  Please be
29  *              careful....
30  *
31  */
32 #include <sys/types.h>
33 #include <stdio.h>                              /* for sprintf() */
34 #include <errno.h>
35 #include <sys/file.h>
36 #include <fcntl.h>
37 #include <string.h>
38
39 #include "postgres.h"
40
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"
65 #include "fmgr.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"
81
82
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);
88
89 /* ----------------
90  *              externs
91  * ----------------
92  */
93 extern bool AMI_OVERRIDE;               /* XXX style */
94 extern GlobalMemory CacheCxt;   /* from utils/cache/catcache.c */
95
96 /* ----------------
97  *              hardcoded tuple descriptors.  see lib/backend/catalog/pg_attribute.h
98  * ----------------
99  */
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};
106
107 /* ----------------
108  *              global variables
109  *
110  *              Relations are cached two ways, by name and by id,
111  *              thus there are two hash tables for referencing them.
112  * ----------------
113  */
114 HTAB       *RelationNameCache;
115 HTAB       *RelationIdCache;
116
117 /* ----------------
118  *              RelationBuildDescInfo exists so code can be shared
119  *              between RelationIdGetRelation() and RelationNameGetRelation()
120  * ----------------
121  */
122 typedef struct RelationBuildDescInfo
123 {
124         int                     infotype;               /* lookup by id or by name */
125 #define INFO_RELID 1
126 #define INFO_RELNAME 2
127         union
128         {
129                 Oid                     info_id;        /* relation object id */
130                 char       *info_name;  /* relation name */
131         }                       i;
132 } RelationBuildDescInfo;
133
134 typedef struct relidcacheent
135 {
136         Oid                     reloid;
137         Relation        reldesc;
138 } RelIdCacheEnt;
139
140 typedef struct relnamecacheent
141 {
142         NameData        relname;
143         Relation        reldesc;
144 } RelNameCacheEnt;
145
146 /* -----------------
147  *              macros to manipulate name cache and id cache
148  * -----------------
149  */
150 #define RelationCacheInsert(RELATION)   \
151 do { \
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, \
156                                                                                            relname, \
157                                                                                            HASH_ENTER, \
158                                                                                            &found); \
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, \
166                                                                                    (char *)&reloid, \
167                                                                                    HASH_ENTER, \
168                                                                                    &found); \
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; \
174 } while(0)
175
176 #define RelationNameCacheLookup(NAME, RELATION) \
177 do { \
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"); \
183         if (found) \
184                 RELATION = hentry->reldesc; \
185         else \
186                 RELATION = NULL; \
187 } while(0)
188
189 #define RelationIdCacheLookup(ID, RELATION) \
190 do { \
191         RelIdCacheEnt *hentry; \
192         bool found; \
193         hentry = (RelIdCacheEnt*)hash_search(RelationIdCache, \
194                                                                                  (char *)&(ID),HASH_FIND, &found); \
195         if (hentry == NULL) \
196                 elog(FATAL, "error in CACHE"); \
197         if (found) \
198                 RELATION = hentry->reldesc; \
199         else \
200                 RELATION = NULL; \
201 } while(0)
202
203 #define RelationCacheDelete(RELATION) \
204 do { \
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, \
209                                                                                            relname, \
210                                                                                            HASH_REMOVE, \
211                                                                                            &found); \
212         if (namehentry == NULL) \
213                 elog(FATAL, "can't delete from relation descriptor cache"); \
214         if (!found) \
215                 elog(NOTICE, "trying to delete a reldesc that does not exist."); \
216         reloid = RELATION->rd_id; \
217         idhentry = (RelIdCacheEnt*)hash_search(RelationIdCache, \
218                                                                                    (char *)&reloid, \
219                                                                                    HASH_REMOVE, &found); \
220         if (idhentry == NULL) \
221                 elog(FATAL, "can't delete from relation descriptor cache"); \
222         if (!found) \
223                 elog(NOTICE, "trying to delete a reldesc that does not exist."); \
224 } while(0)
225
226 /* non-export function prototypes */
227 static void formrdesc(char *relationName, u_int natts,
228                   FormData_pg_attribute *att);
229
230 #ifdef NOT_USED                                 /* See comments at line 1304 */
231 static void RelationFlushIndexes(Relation *r, Oid accessMethodId);
232
233 #endif
234
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);
249
250 extern void RelationBuildTriggers(Relation relation);
251 extern void FreeTriggerDesc(Relation relation);
252
253 /*
254  * newlyCreatedRelns -
255  *        relations created during this transaction. We need to keep track of
256  *        these.
257  */
258 static List *newlyCreatedRelns = NULL;
259
260 /* ----------------------------------------------------------------
261  *              RelationIdGetRelation() and RelationNameGetRelation()
262  *                                              support functions
263  * ----------------------------------------------------------------
264  */
265
266
267 #if NOT_USED                                    /* XXX This doesn't seem to be used
268                                                                  * anywhere */
269 /* --------------------------------
270  *              BuildDescInfoError returns a string appropriate to
271  *              the buildinfo passed to it
272  * --------------------------------
273  */
274 static char *
275 BuildDescInfoError(RelationBuildDescInfo buildinfo)
276 {
277         static char errBuf[64];
278
279         MemSet(errBuf, 0, (int) sizeof(errBuf));
280         switch (buildinfo.infotype)
281         {
282                 case INFO_RELID:
283                         sprintf(errBuf, "(relation id %d)", buildinfo.i.info_id);
284                         break;
285                 case INFO_RELNAME:
286                         sprintf(errBuf, "(relation name %s)", buildinfo.i.info_name);
287                         break;
288         }
289
290         return errBuf;
291 }
292
293 #endif
294
295 /* --------------------------------
296  *              ScanPgRelation
297  *
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  * --------------------------------
302  */
303 static HeapTuple
304 ScanPgRelation(RelationBuildDescInfo buildinfo)
305 {
306
307         /*
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
310          * can, and do.
311          */
312
313         if (IsBootstrapProcessingMode())
314                 return scan_pg_rel_seq(buildinfo);
315         else
316                 return scan_pg_rel_ind(buildinfo);
317 }
318
319 static HeapTuple
320 scan_pg_rel_seq(RelationBuildDescInfo buildinfo)
321 {
322         HeapTuple       pg_class_tuple;
323         HeapTuple       return_tuple;
324         Relation        pg_class_desc;
325         HeapScanDesc pg_class_scan;
326         ScanKeyData key;
327
328         /* ----------------
329          *      form a scan key
330          * ----------------
331          */
332         switch (buildinfo.infotype)
333         {
334                 case INFO_RELID:
335                         ScanKeyEntryInitialize(&key, 0,
336                                                                    ObjectIdAttributeNumber,
337                                                                    F_OIDEQ,
338                                                                    ObjectIdGetDatum(buildinfo.i.info_id));
339                         break;
340
341                 case INFO_RELNAME:
342                         ScanKeyEntryInitialize(&key, 0,
343                                                                    Anum_pg_class_relname,
344                                                                    F_NAMEEQ,
345                                                                    NameGetDatum(buildinfo.i.info_name));
346                         break;
347
348                 default:
349                         elog(ERROR, "ScanPgRelation: bad buildinfo");
350                         return NULL;
351         }
352
353         /* ----------------
354          *      open pg_class and fetch a tuple
355          * ----------------
356          */
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);
360
361         /* ----------------
362          *      get set to return tuple
363          * ----------------
364          */
365         if (!HeapTupleIsValid(pg_class_tuple))
366                 return_tuple = pg_class_tuple;
367         else
368         {
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                  * -------------------
375                  */
376                 return_tuple = heap_copytuple(pg_class_tuple);
377         }
378
379         /* all done */
380         heap_endscan(pg_class_scan);
381         heap_close(pg_class_desc);
382
383         return return_tuple;
384 }
385
386 static HeapTuple
387 scan_pg_rel_ind(RelationBuildDescInfo buildinfo)
388 {
389         Relation        pg_class_desc;
390         HeapTuple       return_tuple;
391
392         pg_class_desc = heap_openr(RelationRelationName);
393         if (!IsInitProcessingMode())
394                 LockRelation(pg_class_desc, AccessShareLock);
395
396         switch (buildinfo.infotype)
397         {
398                 case INFO_RELID:
399                         return_tuple = ClassOidIndexScan(pg_class_desc,buildinfo.i.info_id);
400                         break;
401
402                 case INFO_RELNAME:
403                         return_tuple = ClassNameIndexScan(pg_class_desc,
404                                                                                           buildinfo.i.info_name);
405                         break;
406
407                 default:
408                         elog(ERROR, "ScanPgRelation: bad buildinfo");
409
410                         /*
411                          * XXX I hope this is right.  It seems better than returning
412                          * an uninitialized value
413                          */
414                         return_tuple = NULL;
415         }
416
417         /* all done */
418         if (!IsInitProcessingMode())
419                 UnlockRelation(pg_class_desc, AccessShareLock);
420         heap_close(pg_class_desc);
421
422         return return_tuple;
423 }
424
425 /* ----------------
426  *              AllocateRelationDesc
427  *
428  *              This is used to allocate memory for a new relation descriptor
429  *              and initialize the rd_rel field.
430  * ----------------
431  */
432 static Relation
433 AllocateRelationDesc(u_int natts, Form_pg_class relp)
434 {
435         Relation        relation;
436         Size            len;
437         Form_pg_class relationForm;
438
439         /* ----------------
440          *      allocate space for the relation tuple form
441          * ----------------
442          */
443         relationForm = (Form_pg_class)
444                 palloc((Size) (sizeof(FormData_pg_class)));
445
446         memmove((char *) relationForm, (char *) relp, CLASS_TUPLE_SIZE);
447
448         /* ----------------
449          *      allocate space for new relation descriptor
450          */
451         len = sizeof(RelationData) + 10;        /* + 10 is voodoo XXX mao */
452
453         relation = (Relation) palloc(len);
454
455         /* ----------------
456          *      clear new reldesc
457          * ----------------
458          */
459         MemSet((char *) relation, 0, len);
460
461         /* initialize attribute tuple form */
462         relation->rd_att = CreateTemplateTupleDesc(natts);
463
464         /* and initialize relation tuple form */
465         relation->rd_rel = relationForm;
466
467         return relation;
468 }
469
470 /* --------------------------------
471  *              RelationBuildTupleDesc
472  *
473  *              Form the relation's tuple descriptor from information in
474  *              the pg_attribute, pg_attrdef & pg_relcheck system cataloges.
475  * --------------------------------
476  */
477 static void
478 RelationBuildTupleDesc(RelationBuildDescInfo buildinfo,
479                                            Relation relation,
480                                            u_int natts)
481 {
482
483         /*
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
486          * can, and do.
487          */
488
489         if (IsBootstrapProcessingMode())
490                 build_tupdesc_seq(buildinfo, relation, natts);
491         else
492                 build_tupdesc_ind(buildinfo, relation, natts);
493 }
494
495 static void
496 build_tupdesc_seq(RelationBuildDescInfo buildinfo,
497                                   Relation relation,
498                                   u_int natts)
499 {
500         HeapTuple       pg_attribute_tuple;
501         Relation        pg_attribute_desc;
502         HeapScanDesc pg_attribute_scan;
503         Form_pg_attribute attp;
504         ScanKeyData key;
505         int                     need;
506
507         /* ----------------
508          *      form a scan key
509          * ----------------
510          */
511         ScanKeyEntryInitialize(&key, 0,
512                                                    Anum_pg_attribute_attrelid,
513                                                    F_OIDEQ,
514                                                    ObjectIdGetDatum(RelationGetRelid(relation)));
515
516         /* ----------------
517          *      open pg_attribute and begin a scan
518          * ----------------
519          */
520         pg_attribute_desc = heap_openr(AttributeRelationName);
521         pg_attribute_scan = heap_beginscan(pg_attribute_desc, 0, SnapshotNow, 1, &key);
522
523         /* ----------------
524          *      add attribute data to relation->rd_att
525          * ----------------
526          */
527         need = natts;
528
529         pg_attribute_tuple = heap_getnext(pg_attribute_scan, 0);
530         while (HeapTupleIsValid(pg_attribute_tuple) && need > 0)
531         {
532                 attp = (Form_pg_attribute) GETSTRUCT(pg_attribute_tuple);
533
534                 if (attp->attnum > 0)
535                 {
536                         relation->rd_att->attrs[attp->attnum - 1] =
537                                 (Form_pg_attribute) palloc(ATTRIBUTE_TUPLE_SIZE);
538
539                         memmove((char *) (relation->rd_att->attrs[attp->attnum - 1]),
540                                         (char *) attp,
541                                         ATTRIBUTE_TUPLE_SIZE);
542                         need--;
543                 }
544                 pg_attribute_tuple = heap_getnext(pg_attribute_scan, 0);
545         }
546
547         if (need > 0)
548                 elog(ERROR, "catalog is missing %d attribute%s for relid %d",
549                          need, (need == 1 ? "" : "s"), RelationGetRelid(relation));
550
551         /* ----------------
552          *      end the scan and close the attribute relation
553          * ----------------
554          */
555         heap_endscan(pg_attribute_scan);
556         heap_close(pg_attribute_desc);
557 }
558
559 static void
560 build_tupdesc_ind(RelationBuildDescInfo buildinfo,
561                                   Relation relation,
562                                   u_int natts)
563 {
564         Relation        attrel;
565         HeapTuple       atttup;
566         Form_pg_attribute attp;
567         TupleConstr *constr = (TupleConstr *) palloc(sizeof(TupleConstr));
568         AttrDefault *attrdef = NULL;
569         int                     ndef = 0;
570         int                     i;
571
572         constr->has_not_null = false;
573
574         attrel = heap_openr(AttributeRelationName);
575
576         for (i = 1; i <= relation->rd_rel->relnatts; i++)
577         {
578                 atttup = (HeapTuple) AttributeNumIndexScan(attrel,
579                                                                                   RelationGetRelid(relation), i);
580
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);
585
586                 relation->rd_att->attrs[i - 1] =
587                         (Form_pg_attribute) palloc(ATTRIBUTE_TUPLE_SIZE);
588
589                 memmove((char *) (relation->rd_att->attrs[i - 1]),
590                                 (char *) attp,
591                                 ATTRIBUTE_TUPLE_SIZE);
592
593                 /* Update if this attribute have a constraint */
594                 if (attp->attnotnull)
595                         constr->has_not_null = true;
596
597                 if (attp->atthasdef)
598                 {
599                         if (attrdef == NULL)
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;
605                         ndef++;
606                 }
607         }
608
609         heap_close(attrel);
610
611         if (constr->has_not_null || ndef > 0 || relation->rd_rel->relchecks)
612         {
613                 relation->rd_att->constr = constr;
614
615                 if (ndef > 0)                   /* DEFAULTs */
616                 {
617                         if (ndef < relation->rd_rel->relnatts)
618                                 constr->defval = (AttrDefault *)
619                                         repalloc(attrdef, ndef * sizeof(AttrDefault));
620                         else
621                                 constr->defval = attrdef;
622                         constr->num_defval = ndef;
623                         AttrDefaultFetch(relation);
624                 }
625                 else
626                         constr->num_defval = 0;
627
628                 if (relation->rd_rel->relchecks > 0)    /* CHECKs */
629                 {
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);
635                 }
636                 else
637                         constr->num_check = 0;
638         }
639         else
640         {
641                 pfree(constr);
642                 relation->rd_att->constr = NULL;
643         }
644
645 }
646
647 /* --------------------------------
648  *              RelationBuildRuleLock
649  *
650  *              Form the relation's rewrite rules from information in
651  *              the pg_rewrite system catalog.
652  * --------------------------------
653  */
654 static void
655 RelationBuildRuleLock(Relation relation)
656 {
657         HeapTuple       pg_rewrite_tuple;
658         Relation        pg_rewrite_desc;
659         TupleDesc       pg_rewrite_tupdesc;
660         HeapScanDesc pg_rewrite_scan;
661         ScanKeyData key;
662         RuleLock   *rulelock;
663         int                     numlocks;
664         RewriteRule **rules;
665         int                     maxlocks;
666
667         /* ----------------
668          *      form an array to hold the rewrite rules (the array is extended if
669          *      necessary)
670          * ----------------
671          */
672         maxlocks = 4;
673         rules = (RewriteRule **) palloc(sizeof(RewriteRule *) * maxlocks);
674         numlocks = 0;
675
676         /* ----------------
677          *      form a scan key
678          * ----------------
679          */
680         ScanKeyEntryInitialize(&key, 0,
681                                                    Anum_pg_rewrite_ev_class,
682                                                    F_OIDEQ,
683                                                    ObjectIdGetDatum(RelationGetRelid(relation)));
684
685         /* ----------------
686          *      open pg_attribute and begin a scan
687          * ----------------
688          */
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);
692
693         /* ----------------
694          *      add attribute data to relation->rd_att
695          * ----------------
696          */
697         while (HeapTupleIsValid(pg_rewrite_tuple = heap_getnext(pg_rewrite_scan, 0)))
698         {
699                 bool            isnull;
700                 Datum           ruleaction;
701                 Datum           rule_evqual_string;
702                 RewriteRule *rule;
703
704                 rule = (RewriteRule *) palloc(sizeof(RewriteRule));
705
706                 rule->ruleId = pg_rewrite_tuple->t_data->t_oid;
707
708                 rule->event = (int) heap_getattr(pg_rewrite_tuple,
709                                                          Anum_pg_rewrite_ev_type, pg_rewrite_tupdesc,
710                                                            &isnull) - 48;
711                 rule->attrno = (int) heap_getattr(pg_rewrite_tuple,
712                                                          Anum_pg_rewrite_ev_attr, pg_rewrite_tupdesc,
713                                                            &isnull);
714                 rule->isInstead = !!heap_getattr(pg_rewrite_tuple,
715                                                    Anum_pg_rewrite_is_instead, pg_rewrite_tupdesc,
716                                                    &isnull);
717
718                 ruleaction = heap_getattr(pg_rewrite_tuple,
719                                                  Anum_pg_rewrite_ev_action, pg_rewrite_tupdesc,
720                                                  &isnull);
721                 rule_evqual_string = heap_getattr(pg_rewrite_tuple,
722                                                  Anum_pg_rewrite_ev_qual, pg_rewrite_tupdesc,
723                                                  &isnull);
724
725                 ruleaction = PointerGetDatum(textout((struct varlena *) DatumGetPointer(ruleaction)));
726                 rule_evqual_string = PointerGetDatum(textout((struct varlena *) DatumGetPointer(rule_evqual_string)));
727
728                 rule->actions = (List *) stringToNode(DatumGetPointer(ruleaction));
729                 rule->qual = (Node *) stringToNode(DatumGetPointer(rule_evqual_string));
730
731                 rules[numlocks++] = rule;
732                 if (numlocks == maxlocks)
733                 {
734                         maxlocks *= 2;
735                         rules = (RewriteRule **) repalloc(rules, sizeof(RewriteRule *) * maxlocks);
736                 }
737         }
738
739         /* ----------------
740          *      end the scan and close the attribute relation
741          * ----------------
742          */
743         heap_endscan(pg_rewrite_scan);
744         heap_close(pg_rewrite_desc);
745
746         /* ----------------
747          *      form a RuleLock and insert into relation
748          * ----------------
749          */
750         rulelock = (RuleLock *) palloc(sizeof(RuleLock));
751         rulelock->numLocks = numlocks;
752         rulelock->rules = rules;
753
754         relation->rd_rules = rulelock;
755         return;
756 }
757
758
759 /* --------------------------------
760  *              RelationBuildDesc
761  *
762  *              To build a relation descriptor, we have to allocate space,
763  *              open the underlying unix file and initialize the following
764  *              fields:
765  *
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
775  *
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
779  *              -cim 2/4/91
780  * --------------------------------
781  */
782 static Relation
783 RelationBuildDesc(RelationBuildDescInfo buildinfo)
784 {
785         File            fd;
786         Relation        relation;
787         u_int           natts;
788         Oid                     relid;
789         Oid                     relam;
790         Form_pg_class relp;
791
792         MemoryContext oldcxt;
793
794         HeapTuple       pg_class_tuple;
795
796         oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
797
798         /* ----------------
799          *      find the tuple in pg_class corresponding to the given relation id
800          * ----------------
801          */
802         pg_class_tuple = ScanPgRelation(buildinfo);
803
804         /* ----------------
805          *      if no such tuple exists, return NULL
806          * ----------------
807          */
808         if (!HeapTupleIsValid(pg_class_tuple))
809         {
810                 MemoryContextSwitchTo(oldcxt);
811
812                 return NULL;
813         }
814
815         /* ----------------
816          *      get information from the pg_class_tuple
817          * ----------------
818          */
819         relid = pg_class_tuple->t_data->t_oid;
820         relp = (Form_pg_class) GETSTRUCT(pg_class_tuple);
821         natts = relp->relnatts;
822
823         /* ----------------
824          *      allocate storage for the relation descriptor,
825          *      initialize relation->rd_rel and get the access method id.
826          * ----------------
827          */
828         relation = AllocateRelationDesc(natts, relp);
829         relam = relation->rd_rel->relam;
830
831         /* ----------------
832          *      initialize the relation's relation id (relation->rd_id)
833          * ----------------
834          */
835         RelationGetRelid(relation) = relid;
836
837         /* ----------------
838          *      initialize relation->rd_refcnt
839          * ----------------
840          */
841         RelationSetReferenceCount(relation, 1);
842
843         /* ----------------
844          *       normal relations are not nailed into the cache
845          * ----------------
846          */
847         relation->rd_isnailed = false;
848
849         /* ----------------
850          *      initialize the access method information (relation->rd_am)
851          * ----------------
852          */
853         if (OidIsValid(relam))
854         {
855                 relation->rd_am = (Form_pg_am) AccessMethodObjectIdGetForm(relam);
856         }
857
858         /* ----------------
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.
863          * ----------------
864          */
865         RelationBuildTupleDesc(buildinfo, relation, natts);
866
867         /* ----------------
868          *      initialize rules that affect this relation
869          * ----------------
870          */
871         if (relp->relhasrules)
872                 RelationBuildRuleLock(relation);
873         else
874                 relation->rd_rules = NULL;
875
876         /* Triggers */
877         if (relp->reltriggers > 0)
878                 RelationBuildTriggers(relation);
879         else
880                 relation->trigdesc = NULL;
881
882         /* ----------------
883          *      initialize index strategy and support information for this relation
884          * ----------------
885          */
886         if (OidIsValid(relam))
887                 IndexedAccessMethodInitialize(relation);
888
889         /* ----------------
890          *      initialize the relation lock manager information
891          * ----------------
892          */
893         RelationInitLockInfo(relation);         /* see lmgr.c */
894
895         /* ----------------
896          *      open the relation and assign the file descriptor returned
897          *      by the storage manager code to rd_fd.
898          * ----------------
899          */
900         fd = smgropen(DEFAULT_SMGR, relation);
901
902         Assert(fd >= -1);
903         if (fd == -1)
904                 elog(NOTICE, "RelationIdBuildRelation: smgropen(%s): %m",
905                          &relp->relname);
906
907         relation->rd_fd = fd;
908
909         /* ----------------
910          *      insert newly created relation into proper relcaches,
911          *      restore memory context and return the new reldesc.
912          * ----------------
913          */
914         RelationCacheInsert(relation);
915
916         /* -------------------
917          *      free the memory allocated for pg_class_tuple
918          *      and for lock data pointed to by pg_class_tuple
919          * -------------------
920          */
921         pfree(pg_class_tuple);
922
923         MemoryContextSwitchTo(oldcxt);
924
925         return relation;
926 }
927
928 static void
929 IndexedAccessMethodInitialize(Relation relation)
930 {
931         IndexStrategy strategy;
932         RegProcedure *support;
933         int                     natts;
934         Size            stratSize;
935         Size            supportSize;
936         uint16          relamstrategies;
937         uint16          relamsupport;
938
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;
944
945         if (relamsupport > 0)
946         {
947                 supportSize = natts * (relamsupport * sizeof(RegProcedure));
948                 support = (RegProcedure *) palloc(supportSize);
949         }
950         else
951                 support = (RegProcedure *) NULL;
952
953         IndexSupportInitialize(strategy, support,
954                                                    relation->rd_att->attrs[0]->attrelid,
955                                                    relation->rd_rel->relam,
956                                                    relamstrategies, relamsupport, natts);
957
958         RelationSetIndexSupport(relation, strategy, support);
959 }
960
961 /* --------------------------------
962  *              formrdesc
963  *
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
968  *              bootstrapping.
969  * --------------------------------
970  */
971 static void
972 formrdesc(char *relationName,
973                   u_int natts,
974                   FormData_pg_attribute *att)
975 {
976         Relation        relation;
977         Size            len;
978         int                     i;
979
980         /* ----------------
981          *      allocate new relation desc
982          * ----------------
983          */
984         len = sizeof(RelationData);
985         relation = (Relation) palloc(len);
986         MemSet((char *) relation, 0, len);
987
988         /* ----------------
989          *      don't open the unix file yet..
990          * ----------------
991          */
992         relation->rd_fd = -1;
993
994         /* ----------------
995          *      initialize reference count
996          * ----------------
997          */
998         RelationSetReferenceCount(relation, 1);
999
1000         /* ----------------
1001          *      initialize relation tuple form
1002          * ----------------
1003          */
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);
1008
1009         /* ----------------
1010            initialize attribute tuple form
1011         */
1012         relation->rd_att = CreateTemplateTupleDesc(natts);
1013
1014         /*
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
1018          * about this.
1019          */
1020
1021         if (IsSystemRelationName(relationName))
1022         {
1023                 relation->rd_rel->relowner = 6; /* XXX use sym const */
1024                 relation->rd_rel->relisshared = IsSharedSystemRelationName(relationName);
1025         }
1026         else
1027         {
1028                 relation->rd_rel->relowner = 0;
1029                 relation->rd_rel->relisshared = false;
1030         }
1031
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;
1037
1038         /* ----------------
1039          *      initialize tuple desc info
1040          * ----------------
1041          */
1042         for (i = 0; i < natts; i++)
1043         {
1044                 relation->rd_att->attrs[i] = (Form_pg_attribute) palloc(ATTRIBUTE_TUPLE_SIZE);
1045
1046                 MemSet((char *) relation->rd_att->attrs[i], 0,
1047                            ATTRIBUTE_TUPLE_SIZE);
1048                 memmove((char *) relation->rd_att->attrs[i],
1049                                 (char *) &att[i],
1050                                 ATTRIBUTE_TUPLE_SIZE);
1051         }
1052
1053         /* ----------------
1054          *      initialize relation id
1055          * ----------------
1056          */
1057         RelationGetRelid(relation) = relation->rd_att->attrs[0]->attrelid;
1058
1059         /* ----------------
1060          *      add new reldesc to relcache
1061          * ----------------
1062          */
1063         RelationCacheInsert(relation);
1064
1065         RelationInitLockInfo(relation);
1066
1067         /*
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.
1071          */
1072         relation->rd_rel->relhasindex =
1073                 CatalogHasIndex(relationName, RelationGetRelid(relation));
1074 }
1075
1076
1077 /* ----------------------------------------------------------------
1078  *                               Relation Descriptor Lookup Interface
1079  * ----------------------------------------------------------------
1080  */
1081
1082 /* --------------------------------
1083  *              RelationIdCacheGetRelation
1084  *
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  * --------------------------------
1089  */
1090 Relation
1091 RelationIdCacheGetRelation(Oid relationId)
1092 {
1093         Relation        rd;
1094
1095         RelationIdCacheLookup(relationId, rd);
1096
1097         if (RelationIsValid(rd))
1098         {
1099                 if (rd->rd_fd == -1)
1100                 {
1101                         rd->rd_fd = smgropen(DEFAULT_SMGR, rd);
1102                         Assert(rd->rd_fd != -1);
1103                 }
1104
1105                 RelationIncrementReferenceCount(rd);
1106
1107         }
1108
1109         return rd;
1110 }
1111
1112 /* --------------------------------
1113  *              RelationNameCacheGetRelation
1114  * --------------------------------
1115  */
1116 static Relation
1117 RelationNameCacheGetRelation(char *relationName)
1118 {
1119         Relation        rd;
1120         NameData        name;
1121
1122         /*
1123          * make sure that the name key used for hash lookup is properly
1124          * null-padded
1125          */
1126         namestrcpy(&name, relationName);
1127         RelationNameCacheLookup(name.data, rd);
1128
1129         if (RelationIsValid(rd))
1130         {
1131                 if (rd->rd_fd == -1)
1132                 {
1133                         rd->rd_fd = smgropen(DEFAULT_SMGR, rd);
1134                         Assert(rd->rd_fd != -1);
1135                 }
1136
1137                 RelationIncrementReferenceCount(rd);
1138
1139         }
1140
1141         return rd;
1142 }
1143
1144 /* --------------------------------
1145  *              RelationIdGetRelation
1146  *
1147  *              return a relation descriptor based on its id.
1148  *              return a cached value if possible
1149  * --------------------------------
1150  */
1151 Relation
1152 RelationIdGetRelation(Oid relationId)
1153 {
1154         Relation        rd;
1155         RelationBuildDescInfo buildinfo;
1156
1157         /* ----------------
1158          *      increment access statistics
1159          * ----------------
1160          */
1161         IncrHeapAccessStat(local_RelationIdGetRelation);
1162         IncrHeapAccessStat(global_RelationIdGetRelation);
1163
1164         /* ----------------
1165          *      first try and get a reldesc from the cache
1166          * ----------------
1167          */
1168         rd = RelationIdCacheGetRelation(relationId);
1169         if (RelationIsValid(rd))
1170                 return rd;
1171
1172         /* ----------------
1173          *      no reldesc in the cache, so have RelationBuildDesc()
1174          *      build one and add it.
1175          * ----------------
1176          */
1177         buildinfo.infotype = INFO_RELID;
1178         buildinfo.i.info_id = relationId;
1179
1180         rd = RelationBuildDesc(buildinfo);
1181         return rd;
1182 }
1183
1184 /* --------------------------------
1185  *              RelationNameGetRelation
1186  *
1187  *              return a relation descriptor based on its name.
1188  *              return a cached value if possible
1189  * --------------------------------
1190  */
1191 Relation
1192 RelationNameGetRelation(char *relationName)
1193 {
1194         Relation        rd;
1195         RelationBuildDescInfo buildinfo;
1196
1197         /* ----------------
1198          *      increment access statistics
1199          * ----------------
1200          */
1201         IncrHeapAccessStat(local_RelationNameGetRelation);
1202         IncrHeapAccessStat(global_RelationNameGetRelation);
1203
1204         /* ----------------
1205          *      first try and get a reldesc from the cache
1206          * ----------------
1207          */
1208         rd = RelationNameCacheGetRelation(relationName);
1209         if (RelationIsValid(rd))
1210                 return rd;
1211
1212         /* ----------------
1213          *      no reldesc in the cache, so have RelationBuildDesc()
1214          *      build one and add it.
1215          * ----------------
1216          */
1217         buildinfo.infotype = INFO_RELNAME;
1218         buildinfo.i.info_name = relationName;
1219
1220         rd = RelationBuildDesc(buildinfo);
1221         return rd;
1222 }
1223
1224 /* ----------------
1225  *              old "getreldesc" interface.
1226  * ----------------
1227  */
1228 #ifdef NOT_USED
1229 Relation
1230 getreldesc(char *relationName)
1231 {
1232         /* ----------------
1233          *      increment access statistics
1234          * ----------------
1235          */
1236         IncrHeapAccessStat(local_getreldesc);
1237         IncrHeapAccessStat(global_getreldesc);
1238
1239         return RelationNameGetRelation(relationName);
1240 }
1241
1242 #endif
1243
1244 /* ----------------------------------------------------------------
1245  *                              cache invalidation support routines
1246  * ----------------------------------------------------------------
1247  */
1248
1249 /* --------------------------------
1250  *              RelationClose - close an open relation
1251  * --------------------------------
1252  */
1253 void
1254 RelationClose(Relation relation)
1255 {
1256         /* Note: no locking manipulations needed */
1257         RelationDecrementReferenceCount(relation);
1258 }
1259
1260 /* --------------------------------
1261  * RelationFlushRelation
1262  *
1263  *       Actually blows away a relation... RelationFree doesn't do
1264  *       anything anymore.
1265  * --------------------------------
1266  */
1267 static void
1268 RelationFlushRelation(Relation *relationPtr,
1269                                           bool onlyFlushReferenceCountZero)
1270 {
1271         MemoryContext oldcxt;
1272         Relation        relation = *relationPtr;
1273
1274         if (relation->rd_isnailed)
1275         {
1276                 /* this is a nailed special relation for bootstraping */
1277                 return;
1278         }
1279
1280         if (!onlyFlushReferenceCountZero ||
1281                 RelationHasReferenceCountZero(relation))
1282         {
1283
1284                 oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
1285
1286                 RelationCacheDelete(relation);
1287
1288                 FreeTupleDesc(relation->rd_att);
1289                 SystemCacheRelationFlushed(RelationGetRelid(relation));
1290
1291                 FreeTriggerDesc(relation);
1292
1293 #ifdef NOT_USED
1294                 if (relation->rd_rules)
1295                 {
1296                         int                     j;
1297
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);
1302                 }
1303 #endif
1304
1305                 pfree(RelationGetLockInfo(relation));
1306                 pfree(RelationGetForm(relation));
1307                 pfree(relation);
1308
1309                 MemoryContextSwitchTo(oldcxt);
1310         }
1311 }
1312
1313 /* --------------------------------
1314  *              RelationForgetRelation -
1315  *                 RelationFlushRelation + if the relation is myxactonly then
1316  *                 get rid of the relation descriptor from the newly created
1317  *                 relation list.
1318  * --------------------------------
1319  */
1320 void
1321 RelationForgetRelation(Oid rid)
1322 {
1323         Relation        relation;
1324
1325         RelationIdCacheLookup(rid, relation);
1326
1327         if (PointerIsValid(relation))
1328         {
1329                 if (relation->rd_myxactonly)
1330                 {
1331                         MemoryContext oldcxt;
1332                         List       *curr;
1333                         List       *prev = NIL;
1334         
1335                         oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
1336         
1337                         foreach(curr, newlyCreatedRelns)
1338                         {
1339                                 Relation        reln = lfirst(curr);
1340         
1341                                 Assert(reln != NULL && reln->rd_myxactonly);
1342                                 if (RelationGetRelid(reln) == rid)
1343                                         break;
1344                                 prev = curr;
1345                         }
1346                         if (curr == NIL)
1347                                 elog(FATAL, "Local relation %s not found in list",
1348                                          (RelationGetRelationName(relation))->data);
1349                         if (prev == NIL)
1350                                 newlyCreatedRelns = lnext(newlyCreatedRelns);
1351                         else
1352                                 lnext(prev) = lnext(curr);
1353                         pfree(curr);
1354                         MemoryContextSwitchTo(oldcxt);
1355                 }
1356         
1357                 RelationFlushRelation(&relation, false);
1358         }
1359 }
1360
1361 /* --------------------------------
1362  *              RelationIdInvalidateRelationCacheByRelationId
1363  * --------------------------------
1364  */
1365 void
1366 RelationIdInvalidateRelationCacheByRelationId(Oid relationId)
1367 {
1368         Relation        relation;
1369
1370         RelationIdCacheLookup(relationId, relation);
1371
1372         /*
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
1378          */
1379         if (PointerIsValid(relation) && !relation->rd_myxactonly)
1380         {
1381                 /*
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.
1386                  */
1387                 RelationFlushRelation(&relation, CurrentXactInProgress());
1388         }
1389 }
1390
1391 #if NOT_USED                                    /* See comments at line 1304 */
1392 /* --------------------------------
1393  *              RelationIdInvalidateRelationCacheByAccessMethodId
1394  *
1395  *              RelationFlushIndexes is needed for use with HashTableWalk..
1396  * --------------------------------
1397  */
1398 static void
1399 RelationFlushIndexes(Relation *r,
1400                                          Oid accessMethodId)
1401 {
1402         Relation        relation = *r;
1403
1404         if (!RelationIsValid(relation))
1405         {
1406                 elog(NOTICE, "inval call to RFI");
1407                 return;
1408         }
1409
1410         if (relation->rd_rel->relkind == RELKIND_INDEX &&       /* XXX style */
1411                 (!OidIsValid(accessMethodId) ||
1412                  relation->rd_rel->relam == accessMethodId))
1413                 RelationFlushRelation(&relation, false);
1414 }
1415
1416 #endif
1417
1418
1419 void
1420 RelationIdInvalidateRelationCacheByAccessMethodId(Oid accessMethodId)
1421 {
1422 #ifdef NOT_USED
1423
1424         /*
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
1430          * this up.
1431          */
1432
1433         HashTableWalk(RelationNameCache, (HashtFunc) RelationFlushIndexes,
1434                                   accessMethodId);
1435 #else
1436         return;
1437 #endif
1438 }
1439
1440 /*
1441  * RelationCacheInvalidate
1442  *
1443  *       Will blow away either all the cached relation descriptors or
1444  *       those that have a zero reference count.
1445  *
1446  */
1447 void
1448 RelationCacheInvalidate(bool onlyFlushReferenceCountZero)
1449 {
1450         HashTableWalk(RelationNameCache, (HashtFunc) RelationFlushRelation,
1451                                   onlyFlushReferenceCountZero);
1452
1453         /*
1454          * nailed-in reldescs will still be in the cache... 7 hardwired heaps
1455          * + 3 hardwired indices == 10 total.
1456          */
1457         if (!onlyFlushReferenceCountZero)
1458         {
1459                 Assert(RelationNameCache->hctl->nkeys == 10);
1460                 Assert(RelationIdCache->hctl->nkeys == 10);
1461         }
1462 }
1463
1464
1465 /* --------------------------------
1466  *              RelationRegisterRelation -
1467  *                 register the Relation descriptor of a newly created relation
1468  *                 with the relation descriptor Cache.
1469  * --------------------------------
1470  */
1471 void
1472 RelationRegisterRelation(Relation relation)
1473 {
1474         MemoryContext oldcxt;
1475
1476         oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
1477
1478         if (oldcxt != (MemoryContext) CacheCxt)
1479                 elog(NOIND, "RelationRegisterRelation: WARNING: Context != CacheCxt");
1480
1481         RelationCacheInsert(relation);
1482
1483         RelationInitLockInfo(relation);
1484
1485         /*
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
1492          */
1493         relation->rd_myxactonly = TRUE;
1494         newlyCreatedRelns = lcons(relation, newlyCreatedRelns);
1495
1496         MemoryContextSwitchTo(oldcxt);
1497 }
1498
1499 /*
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.
1505  */
1506 void
1507 RelationPurgeLocalRelation(bool xactCommitted)
1508 {
1509         MemoryContext oldcxt;
1510
1511         if (newlyCreatedRelns == NULL)
1512                 return;
1513
1514         oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
1515
1516         while (newlyCreatedRelns)
1517         {
1518                 List       *l = newlyCreatedRelns;
1519                 Relation        reln = lfirst(l);
1520
1521                 Assert(reln != NULL && reln->rd_myxactonly);
1522
1523                 if (!xactCommitted)
1524                 {
1525
1526                         /*
1527                          * remove the file if we abort. This is so that files for
1528                          * tables created inside a transaction block get removed.
1529                          */
1530                         if (reln->rd_isnoname)
1531                         {
1532                                 if (!(reln->rd_nonameunlinked))
1533                                 {
1534                                         smgrunlink(DEFAULT_SMGR, reln);
1535                                         reln->rd_nonameunlinked = TRUE;
1536                                 }
1537                         }
1538                         else
1539                                 smgrunlink(DEFAULT_SMGR, reln);
1540                 }
1541                 else if (!IsBootstrapProcessingMode() && !(reln->rd_isnoname))
1542
1543                         /*
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.                  -
1549                          * vadim 05/22/97
1550                          */
1551                         smgrclose(DEFAULT_SMGR, reln);
1552
1553                 reln->rd_myxactonly = FALSE;
1554
1555                 if (!IsBootstrapProcessingMode())
1556                         RelationFlushRelation(&reln, FALSE);
1557
1558                 newlyCreatedRelns = lnext(newlyCreatedRelns);
1559                 pfree(l);
1560         }
1561
1562         MemoryContextSwitchTo(oldcxt);
1563 }
1564
1565 /* --------------------------------
1566  *              RelationInitialize
1567  *
1568  *              This initializes the relation descriptor cache.
1569  * --------------------------------
1570  */
1571
1572 #define INITRELCACHESIZE                400
1573
1574 void
1575 RelationInitialize(void)
1576 {
1577         MemoryContext oldcxt;
1578         HASHCTL         ctl;
1579
1580         /* ----------------
1581          *      switch to cache memory context
1582          * ----------------
1583          */
1584         if (!CacheCxt)
1585                 CacheCxt = CreateGlobalMemory("Cache");
1586
1587         oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
1588
1589         /* ----------------
1590          *      create global caches
1591          * ----------------
1592          */
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);
1597
1598         ctl.keysize = sizeof(Oid);
1599         ctl.hash = tag_hash;
1600         RelationIdCache = hash_create(INITRELCACHESIZE, &ctl,
1601                                                                   HASH_ELEM | HASH_FUNCTION);
1602
1603         /* ----------------
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.
1607          * ----------------
1608          */
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);
1615
1616         /*
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.
1621          */
1622
1623         if (!IsBootstrapProcessingMode())
1624                 init_irels();
1625
1626         MemoryContextSwitchTo(oldcxt);
1627 }
1628
1629 static void
1630 AttrDefaultFetch(Relation relation)
1631 {
1632         AttrDefault *attrdef = relation->rd_att->constr->defval;
1633         int                     ndef = relation->rd_att->constr->num_defval;
1634         Relation        adrel;
1635         Relation        irel;
1636         ScanKeyData skey;
1637         HeapTupleData   tuple;
1638         Form_pg_attrdef adform;
1639         IndexScanDesc sd;
1640         RetrieveIndexResult indexRes;
1641         struct varlena *val;
1642         bool            isnull;
1643         int                     found;
1644         int                     i;
1645
1646         ScanKeyEntryInitialize(&skey,
1647                                                    (bits16) 0x0,
1648                                                    (AttrNumber) 1,
1649                                                    (RegProcedure) F_OIDEQ,
1650                                                    ObjectIdGetDatum(RelationGetRelid(relation)));
1651
1652         adrel = heap_openr(AttrDefaultRelationName);
1653         irel = index_openr(AttrDefaultIndex);
1654         sd = index_beginscan(irel, false, 1, &skey);
1655         tuple.t_data = NULL;
1656
1657         for (found = 0;;)
1658         {
1659                 Buffer          buffer;
1660
1661                 indexRes = index_getnext(sd, ForwardScanDirection);
1662                 if (!indexRes)
1663                         break;
1664
1665                 tuple.t_self = indexRes->heap_iptr;
1666                 heap_fetch(adrel, SnapshotNow, &tuple, &buffer);
1667                 pfree(indexRes);
1668                 if (tuple.t_data == NULL)
1669                         continue;
1670                 found++;
1671                 adform = (Form_pg_attrdef) GETSTRUCT(&tuple);
1672                 for (i = 0; i < ndef; i++)
1673                 {
1674                         if (adform->adnum != attrdef[i].adnum)
1675                                 continue;
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);
1680
1681                         val = (struct varlena *) fastgetattr(&tuple,
1682                                                                                                  Anum_pg_attrdef_adbin,
1683                                                                                                  adrel->rd_att, &isnull);
1684                         if (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);
1692                         if (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);
1697                         break;
1698                 }
1699                 ReleaseBuffer(buffer);
1700
1701                 if (i >= ndef)
1702                         elog(ERROR, "AttrDefaultFetch: unexpected record found for attr %d in rel %s",
1703                                  adform->adnum,
1704                                  relation->rd_rel->relname.data);
1705         }
1706
1707         if (found < ndef)
1708                 elog(ERROR, "AttrDefaultFetch: %d record not found for rel %s",
1709                          ndef - found, relation->rd_rel->relname.data);
1710
1711         index_endscan(sd);
1712         pfree(sd);
1713         index_close(irel);
1714         heap_close(adrel);
1715 }
1716
1717 static void
1718 RelCheckFetch(Relation relation)
1719 {
1720         ConstrCheck *check = relation->rd_att->constr->check;
1721         int                     ncheck = relation->rd_att->constr->num_check;
1722         Relation        rcrel;
1723         Relation        irel;
1724         ScanKeyData skey;
1725         HeapTupleData   tuple;
1726         IndexScanDesc sd;
1727         RetrieveIndexResult indexRes;
1728         Name            rcname;
1729         struct varlena *val;
1730         bool            isnull;
1731         int                     found;
1732
1733         ScanKeyEntryInitialize(&skey,
1734                                                    (bits16) 0x0,
1735                                                    (AttrNumber) 1,
1736                                                    (RegProcedure) F_OIDEQ,
1737                                                    ObjectIdGetDatum(RelationGetRelid(relation)));
1738
1739         rcrel = heap_openr(RelCheckRelationName);
1740         irel = index_openr(RelCheckIndex);
1741         sd = index_beginscan(irel, false, 1, &skey);
1742         tuple.t_data = NULL;
1743
1744         for (found = 0;;)
1745         {
1746                 Buffer          buffer;
1747
1748                 indexRes = index_getnext(sd, ForwardScanDirection);
1749                 if (!indexRes)
1750                         break;
1751
1752                 tuple.t_self = indexRes->heap_iptr;
1753                 heap_fetch(rcrel, SnapshotNow, &tuple, &buffer);
1754                 pfree(indexRes);
1755                 if (tuple.t_data == NULL)
1756                         continue;
1757                 if (found == ncheck)
1758                         elog(ERROR, "RelCheckFetch: unexpected record found for rel %s",
1759                                  relation->rd_rel->relname.data);
1760
1761                 rcname = (Name) fastgetattr(&tuple,
1762                                                                         Anum_pg_relcheck_rcname,
1763                                                                         rcrel->rd_att, &isnull);
1764                 if (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);
1771                 if (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);
1778                 if (isnull)
1779                         elog(ERROR, "RelCheckFetch: rcsrc IS NULL for rel %s",
1780                                  relation->rd_rel->relname.data);
1781                 check[found].ccsrc = textout(val);
1782                 found++;
1783                 ReleaseBuffer(buffer);
1784         }
1785
1786         if (found < ncheck)
1787                 elog(ERROR, "RelCheckFetch: %d record not found for rel %s",
1788                          ncheck - found,
1789                          relation->rd_rel->relname.data);
1790
1791         index_endscan(sd);
1792         pfree(sd);
1793         index_close(irel);
1794         heap_close(rcrel);
1795
1796 }
1797
1798 /*
1799  *      init_irels(), write_irels() -- handle special-case initialization of
1800  *                                                                 index relation descriptors.
1801  *
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.
1805  *
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.
1810  *
1811  *              In order to get around the problem, we do the following:
1812  *
1813  *                 +  When the database system is initialized (at initdb time), we
1814  *                        don't use indices on pg_attribute.  We do sequential scans.
1815  *
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.
1819  *
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.
1823  *
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.
1827  *
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
1834  *              from pg_class.
1835  */
1836
1837 /* pg_attnumind, pg_classnameind, pg_classoidind */
1838 #define Num_indices_bootstrap   3
1839
1840 static void
1841 init_irels(void)
1842 {
1843         Size            len;
1844         int                     nread;
1845         File            fd;
1846         Relation        irel[Num_indices_bootstrap];
1847         Relation        ird;
1848         Form_pg_am      am;
1849         Form_pg_class relform;
1850         IndexStrategy strat;
1851         RegProcedure *support;
1852         int                     i;
1853         int                     relno;
1854
1855 #ifndef __CYGWIN32__
1856         if ((fd = FileNameOpenFile(RELCACHE_INIT_FILENAME, O_RDONLY, 0600)) < 0)
1857 #else
1858         if ((fd = FileNameOpenFile(RELCACHE_INIT_FILENAME, O_RDONLY | O_BINARY, 0600)) < 0)
1859 #endif
1860         {
1861                 write_irels();
1862                 return;
1863         }
1864
1865         FileSeek(fd, 0L, SEEK_SET);
1866
1867         for (relno = 0; relno < Num_indices_bootstrap; relno++)
1868         {
1869                 /* first read the relation descriptor length */
1870                 if ((nread = FileRead(fd, (char *) &len, sizeof(len))) != sizeof(len))
1871                 {
1872                         write_irels();
1873                         return;
1874                 }
1875
1876                 ird = irel[relno] = (Relation) palloc(len);
1877                 MemSet(ird, 0, len);
1878
1879                 /* then, read the Relation structure */
1880                 if ((nread = FileRead(fd, (char *) ird, len)) != len)
1881                 {
1882                         write_irels();
1883                         return;
1884                 }
1885
1886                 /* the file descriptor is not yet opened */
1887                 ird->rd_fd = -1;
1888
1889                 /* lock info is not initialized */
1890                 ird->lockInfo = (char *) NULL;
1891
1892                 /* next, read the access method tuple form */
1893                 if ((nread = FileRead(fd, (char *) &len, sizeof(len))) != sizeof(len))
1894                 {
1895                         write_irels();
1896                         return;
1897                 }
1898
1899                 am = (Form_pg_am) palloc(len);
1900                 if ((nread = FileRead(fd, (char *) am, len)) != len)
1901                 {
1902                         write_irels();
1903                         return;
1904                 }
1905
1906                 ird->rd_am = am;
1907
1908                 /* next read the relation tuple form */
1909                 if ((nread = FileRead(fd, (char *) &len, sizeof(len))) != sizeof(len))
1910                 {
1911                         write_irels();
1912                         return;
1913                 }
1914
1915                 relform = (Form_pg_class) palloc(len);
1916                 if ((nread = FileRead(fd, (char *) relform, len)) != len)
1917                 {
1918                         write_irels();
1919                         return;
1920                 }
1921
1922                 ird->rd_rel = relform;
1923
1924                 /* initialize attribute tuple forms */
1925                 ird->rd_att = CreateTemplateTupleDesc(relform->relnatts);
1926
1927                 /* next read all the attribute tuple form data entries */
1928                 len = ATTRIBUTE_TUPLE_SIZE;
1929                 for (i = 0; i < relform->relnatts; i++)
1930                 {
1931                         if ((nread = FileRead(fd, (char *) &len, sizeof(len))) != sizeof(len))
1932                         {
1933                                 write_irels();
1934                                 return;
1935                         }
1936
1937                         ird->rd_att->attrs[i] = (Form_pg_attribute) palloc(len);
1938
1939                         if ((nread = FileRead(fd, (char *) ird->rd_att->attrs[i], len)) != len)
1940                         {
1941                                 write_irels();
1942                                 return;
1943                         }
1944                 }
1945
1946                 /* next, read the index strategy map */
1947                 if ((nread = FileRead(fd, (char *) &len, sizeof(len))) != sizeof(len))
1948                 {
1949                         write_irels();
1950                         return;
1951                 }
1952
1953                 strat = (IndexStrategy) palloc(len);
1954                 if ((nread = FileRead(fd, (char *) strat, len)) != len)
1955                 {
1956                         write_irels();
1957                         return;
1958                 }
1959
1960                 /* oh, for god's sake... */
1961 #define SMD(i)  strat[0].strategyMapData[i].entry[0]
1962
1963                 /* have to reinit the function pointers in the strategy maps */
1964                 for (i = 0; i < am->amstrategies * relform->relnatts; i++)
1965                 {
1966                         fmgr_info(SMD(i).sk_procedure,
1967                                           &(SMD(i).sk_func));
1968                         SMD(i).sk_nargs = SMD(i).sk_func.fn_nargs;
1969                 }
1970
1971
1972                 /*
1973                  * use a real field called rd_istrat instead of the bogosity of
1974                  * hanging invisible fields off the end of a structure - jolly
1975                  */
1976                 ird->rd_istrat = strat;
1977
1978                 /* finally, read the vector of support procedures */
1979                 if ((nread = FileRead(fd, (char *) &len, sizeof(len))) != sizeof(len))
1980                 {
1981                         write_irels();
1982                         return;
1983                 }
1984
1985                 support = (RegProcedure *) palloc(len);
1986                 if ((nread = FileRead(fd, (char *) support, len)) != len)
1987                 {
1988                         write_irels();
1989                         return;
1990                 }
1991
1992                 /*
1993                  * p += sizeof(IndexStrategy); ((RegProcedure **) p) = support;
1994                  */
1995
1996                 ird->rd_support = support;
1997
1998                 RelationCacheInsert(ird);
1999                 RelationInitLockInfo(ird);
2000         }
2001 }
2002
2003 static void
2004 write_irels(void)
2005 {
2006         Size            len;
2007         int                     nwritten;
2008         File            fd;
2009         Relation        irel[Num_indices_bootstrap];
2010         Relation        ird;
2011         Form_pg_am      am;
2012         Form_pg_class relform;
2013         IndexStrategy strat;
2014         RegProcedure *support;
2015         ProcessingMode oldmode;
2016         int                     i;
2017         int                     relno;
2018         RelationBuildDescInfo bi;
2019
2020 #ifndef __CYGWIN32__
2021         fd = FileNameOpenFile(RELCACHE_INIT_FILENAME, O_WRONLY | O_CREAT | O_TRUNC, 0600);
2022 #else
2023         fd = FileNameOpenFile(RELCACHE_INIT_FILENAME, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0600);
2024 #endif
2025         if (fd < 0)
2026                 elog(FATAL, "cannot create init file %s", RELCACHE_INIT_FILENAME);
2027
2028         FileSeek(fd, 0L, SEEK_SET);
2029
2030         /*
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.
2036          */
2037
2038         oldmode = GetProcessingMode();
2039         SetProcessingMode(BootstrapProcessing);
2040
2041         bi.infotype = INFO_RELNAME;
2042         bi.i.info_name = AttributeNumIndex;
2043         irel[0] = RelationBuildDesc(bi);
2044         irel[0]->rd_isnailed = true;
2045
2046         bi.i.info_name = ClassNameIndex;
2047         irel[1] = RelationBuildDesc(bi);
2048         irel[1]->rd_isnailed = true;
2049
2050         bi.i.info_name = ClassOidIndex;
2051         irel[2] = RelationBuildDesc(bi);
2052         irel[2]->rd_isnailed = true;
2053
2054         SetProcessingMode(oldmode);
2055
2056         /* nail the descriptor in the cache */
2057         for (relno = 0; relno < Num_indices_bootstrap; relno++)
2058         {
2059                 ird = irel[relno];
2060
2061                 /* save the volatile fields in the relation descriptor */
2062                 am = ird->rd_am;
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;
2068
2069                 /*
2070                  * first write the relation descriptor , excluding strategy and
2071                  * support
2072                  */
2073                 len = sizeof(RelationData);
2074
2075                 /* first, write the relation descriptor length */
2076                 if ((nwritten = FileWrite(fd, (char *) &len, sizeof(len)))
2077                         != sizeof(len))
2078                         elog(FATAL, "cannot write init file -- descriptor length");
2079
2080                 /* next, write out the Relation structure */
2081                 if ((nwritten = FileWrite(fd, (char *) ird, len)) != len)
2082                         elog(FATAL, "cannot write init file -- reldesc");
2083
2084                 /* next, write the access method tuple form */
2085                 len = sizeof(FormData_pg_am);
2086                 if ((nwritten = FileWrite(fd, (char *) &len, sizeof(len)))
2087                         != sizeof(len))
2088                         elog(FATAL, "cannot write init file -- am tuple form length");
2089
2090                 if ((nwritten = FileWrite(fd, (char *) am, len)) != len)
2091                         elog(FATAL, "cannot write init file -- am tuple form");
2092
2093                 /* next write the relation tuple form */
2094                 len = sizeof(FormData_pg_class);
2095                 if ((nwritten = FileWrite(fd, (char *) &len, sizeof(len)))
2096                         != sizeof(len))
2097                         elog(FATAL, "cannot write init file -- relation tuple form length");
2098
2099                 if ((nwritten = FileWrite(fd, (char *) relform, len)) != len)
2100                         elog(FATAL, "cannot write init file -- relation tuple form");
2101
2102                 /* next, do all the attribute tuple form data entries */
2103                 len = ATTRIBUTE_TUPLE_SIZE;
2104                 for (i = 0; i < relform->relnatts; i++)
2105                 {
2106                         if ((nwritten = FileWrite(fd, (char *) &len, sizeof(len)))
2107                                 != 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))
2110                                 != len)
2111                                 elog(FATAL, "cannot write init file -- attdesc %d", i);
2112                 }
2113
2114                 /* next, write the index strategy map */
2115                 len = AttributeNumberGetIndexStrategySize(relform->relnatts,
2116                                                                                                   am->amstrategies);
2117                 if ((nwritten = FileWrite(fd, (char *) &len, sizeof(len)))
2118                         != sizeof(len))
2119                         elog(FATAL, "cannot write init file -- strategy map length");
2120
2121                 if ((nwritten = FileWrite(fd, (char *) strat, len)) != len)
2122                         elog(FATAL, "cannot write init file -- strategy map");
2123
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)))
2127                         != sizeof(len))
2128                         elog(FATAL, "cannot write init file -- support vector length");
2129
2130                 if ((nwritten = FileWrite(fd, (char *) support, len)) != len)
2131                         elog(FATAL, "cannot write init file -- support vector");
2132
2133                 /* restore volatile fields */
2134                 ird->rd_am = am;
2135                 ird->rd_rel = relform;
2136         }
2137
2138         FileClose(fd);
2139 }