]> granicus.if.org Git - postgresql/blob - src/backend/bootstrap/bootstrap.c
Change Copyright from PostgreSQL, Inc to PostgreSQL Global Development Group.
[postgresql] / src / backend / bootstrap / bootstrap.c
1 /*-------------------------------------------------------------------------
2  *
3  * bootstrap.c
4  *        routines to support running postgres in 'bootstrap' mode
5  *      bootstrap mode is used to create the initial template database
6  *
7  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
8  * Portions Copyright (c) 1994, Regents of the University of California
9  *
10  * IDENTIFICATION
11  *        $Header: /cvsroot/pgsql/src/backend/bootstrap/bootstrap.c,v 1.104 2001/01/24 19:42:51 momjian Exp $
12  *
13  *-------------------------------------------------------------------------
14  */
15 #include "postgres.h"
16
17 #include <unistd.h>
18 #include <time.h>
19 #include <signal.h>
20 #include <setjmp.h>
21
22 #define BOOTSTRAP_INCLUDE               /* mask out stuff in tcop/tcopprot.h */
23
24 #ifdef HAVE_GETOPT_H
25 #include <getopt.h>
26 #endif
27
28 #include "access/genam.h"
29 #include "access/heapam.h"
30 #include "access/xlog.h"
31 #include "bootstrap/bootstrap.h"
32 #include "catalog/catname.h"
33 #include "catalog/index.h"
34 #include "catalog/pg_type.h"
35 #include "libpq/pqsignal.h"
36 #include "miscadmin.h"
37 #include "tcop/tcopprot.h"
38 #include "utils/builtins.h"
39 #include "utils/exc.h"
40 #include "utils/fmgroids.h"
41 #include "utils/guc.h"
42 #include "utils/lsyscache.h"
43 #include "utils/relcache.h"
44
45
46 #define ALLOC(t, c)             ((t *) calloc((unsigned)(c), sizeof(t)))
47
48
49 extern int      Int_yyparse(void);
50 static hashnode *AddStr(char *str, int strlength, int mderef);
51 static Form_pg_attribute AllocateAttribute(void);
52 static bool BootstrapAlreadySeen(Oid id);
53 static int      CompHash(char *str, int len);
54 static hashnode *FindStr(char *str, int length, hashnode *mderef);
55 static Oid      gettype(char *type);
56 static void cleanup(void);
57
58 /* ----------------
59  *              global variables
60  * ----------------
61  */
62 /*
63  * In the lexical analyzer, we need to get the reference number quickly from
64  * the string, and the string from the reference number.  Thus we have
65  * as our data structure a hash table, where the hashing key taken from
66  * the particular string.  The hash table is chained.  One of the fields
67  * of the hash table node is an index into the array of character pointers.
68  * The unique index number that every string is assigned is simply the
69  * position of its string pointer in the array of string pointers.
70  */
71
72 #define STRTABLESIZE    10000
73 #define HASHTABLESIZE   503
74
75 /* Hash function numbers */
76 #define NUM             23
77 #define NUMSQR  529
78 #define NUMCUBE 12167
79
80 char       *strtable[STRTABLESIZE];
81 hashnode   *hashtable[HASHTABLESIZE];
82
83 static int      strtable_end = -1;      /* Tells us last occupied string space */
84
85 /*-
86  * Basic information associated with each type.  This is used before
87  * pg_type is created.
88  *
89  *              XXX several of these input/output functions do catalog scans
90  *                      (e.g., F_REGPROCIN scans pg_proc).      this obviously creates some
91  *                      order dependencies in the catalog creation process.
92  */
93 struct typinfo
94 {
95         char            name[NAMEDATALEN];
96         Oid                     oid;
97         Oid                     elem;
98         int16           len;
99         Oid                     inproc;
100         Oid                     outproc;
101 };
102
103 static struct typinfo Procid[] = {
104         {"bool", BOOLOID, 0, 1, F_BOOLIN, F_BOOLOUT},
105         {"bytea", BYTEAOID, 0, -1, F_BYTEAIN, F_BYTEAOUT},
106         {"char", CHAROID, 0, 1, F_CHARIN, F_CHAROUT},
107         {"name", NAMEOID, 0, NAMEDATALEN, F_NAMEIN, F_NAMEOUT},
108         {"int2", INT2OID, 0, 2, F_INT2IN, F_INT2OUT},
109         {"int2vector", INT2VECTOROID, 0, INDEX_MAX_KEYS * 2, F_INT2VECTORIN, F_INT2VECTOROUT},
110         {"int4", INT4OID, 0, 4, F_INT4IN, F_INT4OUT},
111         {"regproc", REGPROCOID, 0, 4, F_REGPROCIN, F_REGPROCOUT},
112         {"text", TEXTOID, 0, -1, F_TEXTIN, F_TEXTOUT},
113         {"oid", OIDOID, 0, 4, F_OIDIN, F_OIDOUT},
114         {"tid", TIDOID, 0, 6, F_TIDIN, F_TIDOUT},
115         {"xid", XIDOID, 0, 4, F_XIDIN, F_XIDOUT},
116         {"cid", CIDOID, 0, 4, F_CIDIN, F_CIDOUT},
117         {"oidvector", 30, 0, INDEX_MAX_KEYS * 4, F_OIDVECTORIN, F_OIDVECTOROUT},
118         {"smgr", 210, 0, 2, F_SMGRIN, F_SMGROUT},
119         {"_int4", 1007, INT4OID, -1, F_ARRAY_IN, F_ARRAY_OUT},
120         {"_aclitem", 1034, 1033, -1, F_ARRAY_IN, F_ARRAY_OUT}
121 };
122
123 static int      n_types = sizeof(Procid) / sizeof(struct typinfo);
124
125 struct typmap
126 {                                                               /* a hack */
127         Oid                     am_oid;
128         FormData_pg_type am_typ;
129 };
130
131 static struct typmap **Typ = (struct typmap **) NULL;
132 static struct typmap *Ap = (struct typmap *) NULL;
133
134 static int      Warnings = 0;
135 static char Blanks[MAXATTR];
136
137 static char *relname;                   /* current relation name */
138
139 Form_pg_attribute attrtypes[MAXATTR];   /* points to attribute info */
140 static Datum values[MAXATTR];   /* corresponding attribute values */
141 int                     numattr;                        /* number of attributes for cur. rel */
142
143 int                     DebugMode;
144
145 static MemoryContext nogc = NULL; /* special no-gc mem context */
146
147 extern int      optind;
148 extern char *optarg;
149
150 extern void SetRedoRecPtr(void);
151
152 /*
153  *      At bootstrap time, we first declare all the indices to be built, and
154  *      then build them.  The IndexList structure stores enough information
155  *      to allow us to build the indices after they've been declared.
156  */
157
158 typedef struct _IndexList
159 {
160         char       *il_heap;
161         char       *il_ind;
162         IndexInfo  *il_info;
163         struct _IndexList *il_next;
164 } IndexList;
165
166 static IndexList *ILHead = (IndexList *) NULL;
167
168
169 /* ----------------------------------------------------------------
170  *                                              misc functions
171  * ----------------------------------------------------------------
172  */
173
174 /* ----------------
175  *              error handling / abort routines
176  * ----------------
177  */
178 void
179 err_out(void)
180 {
181         Warnings++;
182         cleanup();
183 }
184
185 /* usage:
186    usage help for the bootstrap backen
187 */
188 static void
189 usage(void)
190 {
191         fprintf(stderr, "Usage: postgres -boot [-d] [-C] [-F] [-O] [-Q] ");
192         fprintf(stderr, "[-P portno] [dbName]\n");
193         fprintf(stderr, "     d: debug mode\n");
194         fprintf(stderr, "     C: disable version checking\n");
195         fprintf(stderr, "     F: turn off fsync\n");
196         fprintf(stderr, "     O: set BootstrapProcessing mode\n");
197         fprintf(stderr, "     P portno: specify port number\n");
198
199         proc_exit(1);
200 }
201
202
203
204 int
205 BootstrapMain(int argc, char *argv[])
206 /* ----------------------------------------------------------------
207  *       The main loop for handling the backend in bootstrap mode
208  *       the bootstrap mode is used to initialize the template database
209  *       the bootstrap backend doesn't speak SQL, but instead expects
210  *       commands in a special bootstrap language.
211  *
212  *       The arguments passed in to BootstrapMain are the run-time arguments
213  *       without the argument '-boot', the caller is required to have
214  *       removed -boot from the run-time args
215  * ----------------------------------------------------------------
216  */
217 {
218         int                     i;
219         char       *dbName;
220         int                     flag;
221         int                     xlogop = BS_XLOG_NOP;
222         char       *potential_DataDir = NULL;
223
224         /* --------------------
225          *      initialize globals
226          * -------------------
227          */
228
229         MyProcPid = getpid();
230
231         /*
232          * Fire up essential subsystems: error and memory management
233          *
234          * If we are running under the postmaster, this is done already.
235          */
236         if (!IsUnderPostmaster)
237         {
238                 EnableExceptionHandling(true);
239                 MemoryContextInit();
240         }
241
242         /* ----------------
243          *      process command arguments
244          * ----------------
245          */
246
247         /* Set defaults, to be overriden by explicit options below */
248         Quiet = false;
249         Noversion = false;
250         dbName = NULL;
251         if (!IsUnderPostmaster)
252         {
253                 ResetAllOptions();
254                 potential_DataDir = getenv("PGDATA"); /* Null if no PGDATA variable */
255         }
256
257         while ((flag = getopt(argc, argv, "D:dCQx:pB:F")) != EOF)
258         {
259                 switch (flag)
260                 {
261                         case 'D':
262                                 potential_DataDir = optarg;
263                                 break;
264                         case 'd':
265                                 DebugMode = true;               /* print out debugging info while
266                                                                                  * parsing */
267                                 break;
268                         case 'C':
269                                 Noversion = true;
270                                 break;
271                         case 'F':
272                                 enableFsync = false;
273                                 break;
274                         case 'Q':
275                                 Quiet = true;
276                                 break;
277                         case 'x':
278                                 xlogop = atoi(optarg);
279                                 break;
280                         case 'p':
281                                 /* indicates fork from postmaster */
282                                 break;
283                         case 'B':
284                                 NBuffers = atoi(optarg);
285                                 break;
286                         default:
287                                 usage();
288                                 break;
289                 }
290         }                                                       /* while */
291
292         if (argc - optind > 1)
293                 usage();
294         else if (argc - optind == 1)
295                 dbName = argv[optind];
296
297         SetProcessingMode(BootstrapProcessing);
298         IgnoreSystemIndexes(true);
299
300         if (!IsUnderPostmaster)
301         {
302                 if (!potential_DataDir)
303                 {
304                         fprintf(stderr, "%s does not know where to find the database system "
305                                         "data.  You must specify the directory that contains the "
306                                         "database system either by specifying the -D invocation "
307                                         "option or by setting the PGDATA environment variable.\n\n",
308                                         argv[0]);
309                         proc_exit(1);
310                 }
311                 SetDataDir(potential_DataDir);
312         }
313         Assert(DataDir);
314
315         if (dbName == NULL)
316         {
317                 dbName = getenv("USER");
318                 if (dbName == NULL)
319                 {
320                         fputs("bootstrap backend: failed, no db name specified\n", stderr);
321                         fputs("          and no USER enviroment variable\n", stderr);
322                         proc_exit(1);
323                 }
324         }
325
326         XLOGPathInit();
327
328         BaseInit();
329
330         if (!IsUnderPostmaster)
331         {
332                 pqsignal(SIGHUP, die);
333                 pqsignal(SIGINT, die);
334                 pqsignal(SIGTERM, die);
335                 pqsignal(SIGQUIT, die);
336         }
337
338         /*
339          * XLOG operations
340          */
341         SetProcessingMode(NormalProcessing);
342         if (xlogop == BS_XLOG_NOP)
343                 StartupXLOG();
344         else if (xlogop == BS_XLOG_BOOTSTRAP)
345         {
346                 BootStrapXLOG();
347                 StartupXLOG();
348         }
349         else
350         {
351                 if (xlogop == BS_XLOG_CHECKPOINT)
352                 {
353                         CreateDummyCaches();
354                         CreateCheckPoint(false);
355                         SetRedoRecPtr();
356                 }
357                 else if (xlogop == BS_XLOG_STARTUP)
358                         StartupXLOG();
359                 else if (xlogop == BS_XLOG_SHUTDOWN)
360                         ShutdownXLOG();
361                 else
362                         elog(STOP, "Unsupported XLOG op %d", xlogop);
363                 proc_exit(0);
364         }
365         SetProcessingMode(BootstrapProcessing);
366
367         /*
368          * backend initialization
369          */
370         InitPostgres(dbName, NULL);
371         LockDisable(true);
372
373         for (i = 0; i < MAXATTR; i++)
374         {
375                 attrtypes[i] = (Form_pg_attribute) NULL;
376                 Blanks[i] = ' ';
377         }
378         for (i = 0; i < STRTABLESIZE; ++i)
379                 strtable[i] = NULL;
380         for (i = 0; i < HASHTABLESIZE; ++i)
381                 hashtable[i] = NULL;
382
383         /* ----------------
384          *      abort processing resumes here
385          * ----------------
386          */
387         if (sigsetjmp(Warn_restart, 1) != 0)
388         {
389                 Warnings++;
390                 AbortCurrentTransaction();
391         }
392
393         /* ----------------
394          *      process input.
395          * ----------------
396          */
397
398         /*
399          * the sed script boot.sed renamed yyparse to Int_yyparse for the
400          * bootstrap parser to avoid conflicts with the normal SQL parser
401          */
402         Int_yyparse();
403
404         SetProcessingMode(NormalProcessing);
405         CreateCheckPoint(true);
406         SetProcessingMode(BootstrapProcessing);
407
408         /* clean up processing */
409         StartTransactionCommand();
410         cleanup();
411
412         /* not reached, here to make compiler happy */
413         return 0;
414
415 }
416
417 /* ----------------------------------------------------------------
418  *                              MANUAL BACKEND INTERACTIVE INTERFACE COMMANDS
419  * ----------------------------------------------------------------
420  */
421
422 /* ----------------
423  *              boot_openrel
424  * ----------------
425  */
426 void
427 boot_openrel(char *relname)
428 {
429         int                     i;
430         struct typmap **app;
431         Relation        rel;
432         HeapScanDesc scan;
433         HeapTuple       tup;
434
435         if (strlen(relname) >= NAMEDATALEN - 1)
436                 relname[NAMEDATALEN - 1] = '\0';
437
438         if (Typ == (struct typmap **) NULL)
439         {
440                 rel = heap_openr(TypeRelationName, NoLock);
441                 scan = heap_beginscan(rel, 0, SnapshotNow, 0, (ScanKey) NULL);
442                 i = 0;
443                 while (HeapTupleIsValid(tup = heap_getnext(scan, 0)))
444                         ++i;
445                 heap_endscan(scan);
446                 app = Typ = ALLOC(struct typmap *, i + 1);
447                 while (i-- > 0)
448                         *app++ = ALLOC(struct typmap, 1);
449                 *app = (struct typmap *) NULL;
450                 scan = heap_beginscan(rel, 0, SnapshotNow, 0, (ScanKey) NULL);
451                 app = Typ;
452                 while (HeapTupleIsValid(tup = heap_getnext(scan, 0)))
453                 {
454                         (*app)->am_oid = tup->t_data->t_oid;
455                         memcpy((char *) &(*app)->am_typ,
456                                    (char *) GETSTRUCT(tup),
457                                    sizeof((*app)->am_typ));
458                         app++;
459                 }
460                 heap_endscan(scan);
461                 heap_close(rel, NoLock);
462         }
463
464         if (reldesc != NULL)
465                 closerel(NULL);
466
467         if (!Quiet)
468                 printf("Amopen: relation %s. attrsize %d\n", relname ? relname : "(null)",
469                            (int) ATTRIBUTE_TUPLE_SIZE);
470
471         reldesc = heap_openr(relname, NoLock);
472         numattr = reldesc->rd_rel->relnatts;
473         for (i = 0; i < numattr; i++)
474         {
475                 if (attrtypes[i] == NULL)
476                         attrtypes[i] = AllocateAttribute();
477                 memmove((char *) attrtypes[i],
478                                 (char *) reldesc->rd_att->attrs[i],
479                                 ATTRIBUTE_TUPLE_SIZE);
480
481                 /* Some old pg_attribute tuples might not have attisset. */
482
483                 /*
484                  * If the attname is attisset, don't look for it - it may not be
485                  * defined yet.
486                  */
487                 if (namestrcmp(&attrtypes[i]->attname, "attisset") == 0)
488                         attrtypes[i]->attisset = get_attisset(RelationGetRelid(reldesc),
489                                                                                  NameStr(attrtypes[i]->attname));
490                 else
491                         attrtypes[i]->attisset = false;
492
493                 if (DebugMode)
494                 {
495                         Form_pg_attribute at = attrtypes[i];
496
497                         printf("create attribute %d name %s len %d num %d type %d\n",
498                                    i, NameStr(at->attname), at->attlen, at->attnum,
499                                    at->atttypid
500                                 );
501                         fflush(stdout);
502                 }
503         }
504 }
505
506 /* ----------------
507  *              closerel
508  * ----------------
509  */
510 void
511 closerel(char *name)
512 {
513         if (name)
514         {
515                 if (reldesc)
516                 {
517                         if (strcmp(RelationGetRelationName(reldesc), name) != 0)
518                                 elog(ERROR, "closerel: close of '%s' when '%s' was expected",
519                                          name, relname ? relname : "(null)");
520                 }
521                 else
522                         elog(ERROR, "closerel: close of '%s' before any relation was opened",
523                                  name);
524
525         }
526
527         if (reldesc == NULL)
528                 elog(ERROR, "Warning: no opened relation to close.\n");
529         else
530         {
531                 if (!Quiet)
532                         printf("Amclose: relation %s.\n", relname ? relname : "(null)");
533                 heap_close(reldesc, NoLock);
534                 reldesc = (Relation) NULL;
535         }
536 }
537
538
539
540 /* ----------------
541  * DEFINEATTR()
542  *
543  * define a <field,type> pair
544  * if there are n fields in a relation to be created, this routine
545  * will be called n times
546  * ----------------
547  */
548 void
549 DefineAttr(char *name, char *type, int attnum)
550 {
551         int                     attlen;
552         Oid                     typeoid;
553
554         if (reldesc != NULL)
555         {
556                 fputs("Warning: no open relations allowed with 't' command.\n", stderr);
557                 closerel(relname);
558         }
559
560         typeoid = gettype(type);
561         if (attrtypes[attnum] == (Form_pg_attribute) NULL)
562                 attrtypes[attnum] = AllocateAttribute();
563         if (Typ != (struct typmap **) NULL)
564         {
565                 attrtypes[attnum]->atttypid = Ap->am_oid;
566                 namestrcpy(&attrtypes[attnum]->attname, name);
567                 if (!Quiet)
568                         printf("<%s %s> ", NameStr(attrtypes[attnum]->attname), type);
569                 attrtypes[attnum]->attnum = 1 + attnum; /* fillatt */
570                 attlen = attrtypes[attnum]->attlen = Ap->am_typ.typlen;
571                 attrtypes[attnum]->attbyval = Ap->am_typ.typbyval;
572                 attrtypes[attnum]->attstorage = Ap->am_typ.typstorage;;
573                 attrtypes[attnum]->attalign = Ap->am_typ.typalign;
574         }
575         else
576         {
577                 attrtypes[attnum]->atttypid = Procid[typeoid].oid;
578                 namestrcpy(&attrtypes[attnum]->attname, name);
579                 if (!Quiet)
580                         printf("<%s %s> ", NameStr(attrtypes[attnum]->attname), type);
581                 attrtypes[attnum]->attnum = 1 + attnum; /* fillatt */
582                 attlen = attrtypes[attnum]->attlen = Procid[typeoid].len;
583                 attrtypes[attnum]->attstorage = 'p';
584
585                 /*
586                  * Cheat like mad to fill in these items from the length only.
587                  * This only has to work for types used in the system catalogs...
588                  */
589                 switch (attlen)
590                 {
591                         case 1:
592                                 attrtypes[attnum]->attbyval = true;
593                                 attrtypes[attnum]->attalign = 'c';
594                                 break;
595                         case 2:
596                                 attrtypes[attnum]->attbyval = true;
597                                 attrtypes[attnum]->attalign = 's';
598                                 break;
599                         case 4:
600                                 attrtypes[attnum]->attbyval = true;
601                                 attrtypes[attnum]->attalign = 'i';
602                                 break;
603                         default:
604                                 attrtypes[attnum]->attbyval = false;
605                                 attrtypes[attnum]->attalign = 'i';
606                                 break;
607                 }
608         }
609         attrtypes[attnum]->attcacheoff = -1;
610         attrtypes[attnum]->atttypmod = -1;
611 }
612
613
614 /* ----------------
615  *              InsertOneTuple
616  *              assumes that 'oid' will not be zero.
617  * ----------------
618  */
619 void
620 InsertOneTuple(Oid objectid)
621 {
622         HeapTuple       tuple;
623         TupleDesc       tupDesc;
624
625         int                     i;
626
627         if (DebugMode)
628         {
629                 printf("InsertOneTuple oid %u, %d attrs\n", objectid, numattr);
630                 fflush(stdout);
631         }
632
633         tupDesc = CreateTupleDesc(numattr, attrtypes);
634         tuple = heap_formtuple(tupDesc, values, Blanks);
635         pfree(tupDesc);                         /* just free's tupDesc, not the attrtypes */
636
637         if (objectid != (Oid) 0)
638                 tuple->t_data->t_oid = objectid;
639         heap_insert(reldesc, tuple);
640         heap_freetuple(tuple);
641         if (DebugMode)
642         {
643                 printf("End InsertOneTuple, objectid=%u\n", objectid);
644                 fflush(stdout);
645         }
646
647         /*
648          * Reset blanks for next tuple
649          */
650         for (i = 0; i < numattr; i++)
651                 Blanks[i] = ' ';
652 }
653
654 /* ----------------
655  *              InsertOneValue
656  * ----------------
657  */
658 void
659 InsertOneValue(Oid objectid, char *value, int i)
660 {
661         int                     typeindex;
662         char       *prt;
663         struct typmap **app;
664
665         if (DebugMode)
666                 printf("Inserting value: '%s'\n", value);
667         if (i < 0 || i >= MAXATTR)
668         {
669                 printf("i out of range: %d\n", i);
670                 Assert(0);
671         }
672
673         if (Typ != (struct typmap **) NULL)
674         {
675                 struct typmap *ap;
676
677                 if (DebugMode)
678                         puts("Typ != NULL");
679                 app = Typ;
680                 while (*app && (*app)->am_oid != reldesc->rd_att->attrs[i]->atttypid)
681                         ++app;
682                 ap = *app;
683                 if (ap == NULL)
684                 {
685                         printf("Unable to find atttypid in Typ list! %u\n",
686                                    reldesc->rd_att->attrs[i]->atttypid
687                                 );
688                         Assert(0);
689                 }
690                 values[i] = OidFunctionCall3(ap->am_typ.typinput,
691                                                                          CStringGetDatum(value),
692                                                                          ObjectIdGetDatum(ap->am_typ.typelem),
693                                                                          Int32GetDatum(-1));
694                 prt = DatumGetCString(OidFunctionCall3(ap->am_typ.typoutput,
695                                                           values[i],
696                                                           ObjectIdGetDatum(ap->am_typ.typelem),
697                                                           Int32GetDatum(-1)));
698                 if (!Quiet)
699                         printf("%s ", prt);
700                 pfree(prt);
701         }
702         else
703         {
704                 for (typeindex = 0; typeindex < n_types; typeindex++)
705                 {
706                         if (Procid[typeindex].oid == attrtypes[i]->atttypid)
707                                 break;
708                 }
709                 if (typeindex >= n_types)
710                         elog(ERROR, "can't find type OID %u", attrtypes[i]->atttypid);
711                 if (DebugMode)
712                         printf("Typ == NULL, typeindex = %u idx = %d\n", typeindex, i);
713                 values[i] = OidFunctionCall3(Procid[typeindex].inproc,
714                                                                          CStringGetDatum(value),
715                                                                          ObjectIdGetDatum(Procid[typeindex].elem),
716                                                                          Int32GetDatum(-1));
717                 prt = DatumGetCString(OidFunctionCall3(Procid[typeindex].outproc,
718                                                           values[i],
719                                                           ObjectIdGetDatum(Procid[typeindex].elem),
720                                                           Int32GetDatum(-1)));
721                 if (!Quiet)
722                         printf("%s ", prt);
723                 pfree(prt);
724         }
725         if (DebugMode)
726         {
727                 puts("End InsertValue");
728                 fflush(stdout);
729         }
730 }
731
732 /* ----------------
733  *              InsertOneNull
734  * ----------------
735  */
736 void
737 InsertOneNull(int i)
738 {
739         if (DebugMode)
740                 printf("Inserting null\n");
741         if (i < 0 || i >= MAXATTR)
742                 elog(FATAL, "i out of range (too many attrs): %d\n", i);
743         values[i] = PointerGetDatum(NULL);
744         Blanks[i] = 'n';
745 }
746
747 #define MORE_THAN_THE_NUMBER_OF_CATALOGS 256
748
749 static bool
750 BootstrapAlreadySeen(Oid id)
751 {
752         static Oid      seenArray[MORE_THAN_THE_NUMBER_OF_CATALOGS];
753         static int      nseen = 0;
754         bool            seenthis;
755         int                     i;
756
757         seenthis = false;
758
759         for (i = 0; i < nseen; i++)
760         {
761                 if (seenArray[i] == id)
762                 {
763                         seenthis = true;
764                         break;
765                 }
766         }
767         if (!seenthis)
768         {
769                 seenArray[nseen] = id;
770                 nseen++;
771         }
772         return seenthis;
773 }
774
775 /* ----------------
776  *              cleanup
777  * ----------------
778  */
779 static void
780 cleanup()
781 {
782         static int      beenhere = 0;
783
784         if (!beenhere)
785                 beenhere = 1;
786         else
787         {
788                 elog(FATAL, "Memory manager fault: cleanup called twice.\n");
789                 proc_exit(1);
790         }
791         if (reldesc != (Relation) NULL)
792                 heap_close(reldesc, NoLock);
793         CommitTransactionCommand();
794         proc_exit(Warnings);
795 }
796
797 /* ----------------
798  *              gettype
799  * ----------------
800  */
801 static Oid
802 gettype(char *type)
803 {
804         int                     i;
805         Relation        rel;
806         HeapScanDesc scan;
807         HeapTuple       tup;
808         struct typmap **app;
809
810         if (Typ != (struct typmap **) NULL)
811         {
812                 for (app = Typ; *app != (struct typmap *) NULL; app++)
813                 {
814                         if (strncmp(NameStr((*app)->am_typ.typname), type, NAMEDATALEN) == 0)
815                         {
816                                 Ap = *app;
817                                 return (*app)->am_oid;
818                         }
819                 }
820         }
821         else
822         {
823                 for (i = 0; i <= n_types; i++)
824                 {
825                         if (strncmp(type, Procid[i].name, NAMEDATALEN) == 0)
826                                 return i;
827                 }
828                 if (DebugMode)
829                         printf("bootstrap.c: External Type: %s\n", type);
830                 rel = heap_openr(TypeRelationName, NoLock);
831                 scan = heap_beginscan(rel, 0, SnapshotNow, 0, (ScanKey) NULL);
832                 i = 0;
833                 while (HeapTupleIsValid(tup = heap_getnext(scan, 0)))
834                         ++i;
835                 heap_endscan(scan);
836                 app = Typ = ALLOC(struct typmap *, i + 1);
837                 while (i-- > 0)
838                         *app++ = ALLOC(struct typmap, 1);
839                 *app = (struct typmap *) NULL;
840                 scan = heap_beginscan(rel, 0, SnapshotNow, 0, (ScanKey) NULL);
841                 app = Typ;
842                 while (HeapTupleIsValid(tup = heap_getnext(scan, 0)))
843                 {
844                         (*app)->am_oid = tup->t_data->t_oid;
845                         memmove((char *) &(*app++)->am_typ,
846                                         (char *) GETSTRUCT(tup),
847                                         sizeof((*app)->am_typ));
848                 }
849                 heap_endscan(scan);
850                 heap_close(rel, NoLock);
851                 return gettype(type);
852         }
853         elog(ERROR, "Error: unknown type '%s'.\n", type);
854         err_out();
855         /* not reached, here to make compiler happy */
856         return 0;
857 }
858
859 /* ----------------
860  *              AllocateAttribute
861  * ----------------
862  */
863 static Form_pg_attribute                /* XXX */
864 AllocateAttribute()
865 {
866         Form_pg_attribute attribute = (Form_pg_attribute) malloc(ATTRIBUTE_TUPLE_SIZE);
867
868         if (!PointerIsValid(attribute))
869                 elog(FATAL, "AllocateAttribute: malloc failed");
870         MemSet(attribute, 0, ATTRIBUTE_TUPLE_SIZE);
871
872         return attribute;
873 }
874
875 /* ----------------
876  *              MapArrayTypeName
877  * XXX arrays of "basetype" are always "_basetype".
878  *         this is an evil hack inherited from rel. 3.1.
879  * XXX array dimension is thrown away because we
880  *         don't support fixed-dimension arrays.  again,
881  *         sickness from 3.1.
882  *
883  * the string passed in must have a '[' character in it
884  *
885  * the string returned is a pointer to static storage and should NOT
886  * be freed by the CALLER.
887  * ----------------
888  */
889 char *
890 MapArrayTypeName(char *s)
891 {
892         int                     i,
893                                 j;
894         static char newStr[NAMEDATALEN];        /* array type names < NAMEDATALEN
895                                                                                  * long */
896
897         if (s == NULL || s[0] == '\0')
898                 return s;
899
900         j = 1;
901         newStr[0] = '_';
902         for (i = 0; i < NAMEDATALEN - 1 && s[i] != '['; i++, j++)
903                 newStr[j] = s[i];
904
905         newStr[j] = '\0';
906
907         return newStr;
908 }
909
910 /* ----------------
911  *              EnterString
912  *              returns the string table position of the identifier
913  *              passed to it.  We add it to the table if we can't find it.
914  * ----------------
915  */
916 int
917 EnterString(char *str)
918 {
919         hashnode   *node;
920         int                     len;
921
922         len = strlen(str);
923
924         node = FindStr(str, len, 0);
925         if (node)
926                 return node->strnum;
927         else
928         {
929                 node = AddStr(str, len, 0);
930                 return node->strnum;
931         }
932 }
933
934 /* ----------------
935  *              LexIDStr
936  *              when given an idnum into the 'string-table' return the string
937  *              associated with the idnum
938  * ----------------
939  */
940 char *
941 LexIDStr(int ident_num)
942 {
943         return strtable[ident_num];
944 }
945
946
947 /* ----------------
948  *              CompHash
949  *
950  *              Compute a hash function for a given string.  We look at the first,
951  *              the last, and the middle character of a string to try to get spread
952  *              the strings out.  The function is rather arbitrary, except that we
953  *              are mod'ing by a prime number.
954  * ----------------
955  */
956 static int
957 CompHash(char *str, int len)
958 {
959         int                     result;
960
961         result = (NUM * str[0] + NUMSQR * str[len - 1] + NUMCUBE * str[(len - 1) / 2]);
962
963         return result % HASHTABLESIZE;
964
965 }
966
967 /* ----------------
968  *              FindStr
969  *
970  *              This routine looks for the specified string in the hash
971  *              table.  It returns a pointer to the hash node found,
972  *              or NULL if the string is not in the table.
973  * ----------------
974  */
975 static hashnode *
976 FindStr(char *str, int length, hashnode *mderef)
977 {
978         hashnode   *node;
979
980         node = hashtable[CompHash(str, length)];
981         while (node != NULL)
982         {
983
984                 /*
985                  * We must differentiate between string constants that might have
986                  * the same value as a identifier and the identifier itself.
987                  */
988                 if (!strcmp(str, strtable[node->strnum]))
989                 {
990                         return node;            /* no need to check */
991                 }
992                 else
993                         node = node->next;
994         }
995         /* Couldn't find it in the list */
996         return NULL;
997 }
998
999 /* ----------------
1000  *              AddStr
1001  *
1002  *              This function adds the specified string, along with its associated
1003  *              data, to the hash table and the string table.  We return the node
1004  *              so that the calling routine can find out the unique id that AddStr
1005  *              has assigned to this string.
1006  * ----------------
1007  */
1008 static hashnode *
1009 AddStr(char *str, int strlength, int mderef)
1010 {
1011         hashnode   *temp,
1012                            *trail,
1013                            *newnode;
1014         int                     hashresult;
1015         int                     len;
1016
1017         if (++strtable_end == STRTABLESIZE)
1018         {
1019                 /* Error, string table overflow, so we Punt */
1020                 elog(FATAL,
1021                          "There are too many string constants and identifiers for the compiler to handle.");
1022
1023
1024         }
1025
1026         /*
1027          * Some of the utilites (eg, define type, create relation) assume that
1028          * the string they're passed is a NAMEDATALEN.  We get array bound
1029          * read violations from purify if we don't allocate at least
1030          * NAMEDATALEN bytes for strings of this sort.  Because we're lazy, we
1031          * allocate at least NAMEDATALEN bytes all the time.
1032          */
1033
1034         if ((len = strlength + 1) < NAMEDATALEN)
1035                 len = NAMEDATALEN;
1036
1037         strtable[strtable_end] = malloc((unsigned) len);
1038         strcpy(strtable[strtable_end], str);
1039
1040         /* Now put a node in the hash table */
1041
1042         newnode = (hashnode *) malloc(sizeof(hashnode) * 1);
1043         newnode->strnum = strtable_end;
1044         newnode->next = NULL;
1045
1046         /* Find out where it goes */
1047
1048         hashresult = CompHash(str, strlength);
1049         if (hashtable[hashresult] == NULL)
1050                 hashtable[hashresult] = newnode;
1051         else
1052         {                                                       /* There is something in the list */
1053                 trail = hashtable[hashresult];
1054                 temp = trail->next;
1055                 while (temp != NULL)
1056                 {
1057                         trail = temp;
1058                         temp = temp->next;
1059                 }
1060                 trail->next = newnode;
1061         }
1062         return newnode;
1063 }
1064
1065
1066
1067 /*
1068  *      index_register() -- record an index that has been set up for building
1069  *                                              later.
1070  *
1071  *              At bootstrap time, we define a bunch of indices on system catalogs.
1072  *              We postpone actually building the indices until just before we're
1073  *              finished with initialization, however.  This is because more classes
1074  *              and indices may be defined, and we want to be sure that all of them
1075  *              are present in the index.
1076  */
1077 void
1078 index_register(char *heap,
1079                            char *ind,
1080                            IndexInfo *indexInfo)
1081 {
1082         IndexList  *newind;
1083         MemoryContext oldcxt;
1084
1085         /*
1086          * XXX mao 10/31/92 -- don't gc index reldescs, associated info at
1087          * bootstrap time.      we'll declare the indices now, but want to create
1088          * them later.
1089          */
1090
1091         if (nogc == NULL)
1092                 nogc = AllocSetContextCreate((MemoryContext) NULL,
1093                                                                          "BootstrapNoGC",
1094                                                                          ALLOCSET_DEFAULT_MINSIZE,
1095                                                                          ALLOCSET_DEFAULT_INITSIZE,
1096                                                                          ALLOCSET_DEFAULT_MAXSIZE);
1097
1098         oldcxt = MemoryContextSwitchTo(nogc);
1099
1100         newind = (IndexList *) palloc(sizeof(IndexList));
1101         newind->il_heap = pstrdup(heap);
1102         newind->il_ind = pstrdup(ind);
1103         newind->il_info = (IndexInfo *) palloc(sizeof(IndexInfo));
1104
1105         memcpy(newind->il_info, indexInfo, sizeof(IndexInfo));
1106         /* predicate will likely be null anyway, but may as well copy it */
1107         newind->il_info->ii_Predicate = copyObject(indexInfo->ii_Predicate);
1108
1109         newind->il_next = ILHead;
1110         ILHead = newind;
1111
1112         MemoryContextSwitchTo(oldcxt);
1113 }
1114
1115 void
1116 build_indices()
1117 {
1118         for (; ILHead != (IndexList *) NULL; ILHead = ILHead->il_next)
1119         {
1120                 Relation        heap;
1121                 Relation        ind;
1122
1123                 heap = heap_openr(ILHead->il_heap, NoLock);
1124                 ind = index_openr(ILHead->il_ind);
1125                 index_build(heap, ind, ILHead->il_info, NULL);
1126
1127                 /*
1128                  * In normal processing mode, index_build would close the heap and
1129                  * index, but in bootstrap mode it will not.
1130                  */
1131
1132                 /*
1133                  * All of the rest of this routine is needed only because in
1134                  * bootstrap processing we don't increment xact id's.  The normal
1135                  * DefineIndex code replaces a pg_class tuple with updated info
1136                  * including the relhasindex flag (which we need to have updated).
1137                  * Unfortunately, there are always two indices defined on each
1138                  * catalog causing us to update the same pg_class tuple twice for
1139                  * each catalog getting an index during bootstrap resulting in the
1140                  * ghost tuple problem (see heap_update).       To get around this we
1141                  * change the relhasindex field ourselves in this routine keeping
1142                  * track of what catalogs we already changed so that we don't
1143                  * modify those tuples twice.  The normal mechanism for updating
1144                  * pg_class is disabled during bootstrap.
1145                  *
1146                  * -mer
1147                  */
1148                 if (!BootstrapAlreadySeen(RelationGetRelid(heap)))
1149                         UpdateStats(RelationGetRelid(heap), 0);
1150
1151                 /* XXX Probably we ought to close the heap and index here? */
1152         }
1153 }