]> granicus.if.org Git - postgresql/blob - src/backend/bootstrap/bootstrap.c
New WAL version - CRC and data blocks backup.
[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-2000, PostgreSQL, Inc
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.102 2000/12/28 13:00:12 vadim 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(SIGINT, (pqsigfunc) die);
333                 pqsignal(SIGHUP, (pqsigfunc) die);
334                 pqsignal(SIGTERM, (pqsigfunc) die);
335         }
336
337         /*
338          * XLOG operations
339          */
340         SetProcessingMode(NormalProcessing);
341         if (xlogop == BS_XLOG_NOP)
342                 StartupXLOG();
343         else if (xlogop == BS_XLOG_BOOTSTRAP)
344         {
345                 BootStrapXLOG();
346                 StartupXLOG();
347         }
348         else
349         {
350                 if (xlogop == BS_XLOG_CHECKPOINT)
351                 {
352                         CreateDummyCaches();
353                         CreateCheckPoint(false);
354                         SetRedoRecPtr();
355                 }
356                 else if (xlogop == BS_XLOG_STARTUP)
357                         StartupXLOG();
358                 else if (xlogop == BS_XLOG_SHUTDOWN)
359                         ShutdownXLOG();
360                 else
361                         elog(STOP, "Unsupported XLOG op %d", xlogop);
362                 proc_exit(0);
363         }
364         SetProcessingMode(BootstrapProcessing);
365
366         /*
367          * backend initialization
368          */
369         InitPostgres(dbName, NULL);
370         LockDisable(true);
371
372         for (i = 0; i < MAXATTR; i++)
373         {
374                 attrtypes[i] = (Form_pg_attribute) NULL;
375                 Blanks[i] = ' ';
376         }
377         for (i = 0; i < STRTABLESIZE; ++i)
378                 strtable[i] = NULL;
379         for (i = 0; i < HASHTABLESIZE; ++i)
380                 hashtable[i] = NULL;
381
382         /* ----------------
383          *      abort processing resumes here
384          * ----------------
385          */
386         pqsignal(SIGHUP, handle_warn);
387
388         if (sigsetjmp(Warn_restart, 1) != 0)
389         {
390                 Warnings++;
391                 AbortCurrentTransaction();
392         }
393
394         /* ----------------
395          *      process input.
396          * ----------------
397          */
398
399         /*
400          * the sed script boot.sed renamed yyparse to Int_yyparse for the
401          * bootstrap parser to avoid conflicts with the normal SQL parser
402          */
403         Int_yyparse();
404
405         SetProcessingMode(NormalProcessing);
406         CreateCheckPoint(true);
407         SetProcessingMode(BootstrapProcessing);
408
409         /* clean up processing */
410         StartTransactionCommand();
411         cleanup();
412
413         /* not reached, here to make compiler happy */
414         return 0;
415
416 }
417
418 /* ----------------------------------------------------------------
419  *                              MANUAL BACKEND INTERACTIVE INTERFACE COMMANDS
420  * ----------------------------------------------------------------
421  */
422
423 /* ----------------
424  *              boot_openrel
425  * ----------------
426  */
427 void
428 boot_openrel(char *relname)
429 {
430         int                     i;
431         struct typmap **app;
432         Relation        rel;
433         HeapScanDesc scan;
434         HeapTuple       tup;
435
436         if (strlen(relname) >= NAMEDATALEN - 1)
437                 relname[NAMEDATALEN - 1] = '\0';
438
439         if (Typ == (struct typmap **) NULL)
440         {
441                 rel = heap_openr(TypeRelationName, NoLock);
442                 scan = heap_beginscan(rel, 0, SnapshotNow, 0, (ScanKey) NULL);
443                 i = 0;
444                 while (HeapTupleIsValid(tup = heap_getnext(scan, 0)))
445                         ++i;
446                 heap_endscan(scan);
447                 app = Typ = ALLOC(struct typmap *, i + 1);
448                 while (i-- > 0)
449                         *app++ = ALLOC(struct typmap, 1);
450                 *app = (struct typmap *) NULL;
451                 scan = heap_beginscan(rel, 0, SnapshotNow, 0, (ScanKey) NULL);
452                 app = Typ;
453                 while (HeapTupleIsValid(tup = heap_getnext(scan, 0)))
454                 {
455                         (*app)->am_oid = tup->t_data->t_oid;
456                         memcpy((char *) &(*app)->am_typ,
457                                    (char *) GETSTRUCT(tup),
458                                    sizeof((*app)->am_typ));
459                         app++;
460                 }
461                 heap_endscan(scan);
462                 heap_close(rel, NoLock);
463         }
464
465         if (reldesc != NULL)
466                 closerel(NULL);
467
468         if (!Quiet)
469                 printf("Amopen: relation %s. attrsize %d\n", relname ? relname : "(null)",
470                            (int) ATTRIBUTE_TUPLE_SIZE);
471
472         reldesc = heap_openr(relname, NoLock);
473         numattr = reldesc->rd_rel->relnatts;
474         for (i = 0; i < numattr; i++)
475         {
476                 if (attrtypes[i] == NULL)
477                         attrtypes[i] = AllocateAttribute();
478                 memmove((char *) attrtypes[i],
479                                 (char *) reldesc->rd_att->attrs[i],
480                                 ATTRIBUTE_TUPLE_SIZE);
481
482                 /* Some old pg_attribute tuples might not have attisset. */
483
484                 /*
485                  * If the attname is attisset, don't look for it - it may not be
486                  * defined yet.
487                  */
488                 if (namestrcmp(&attrtypes[i]->attname, "attisset") == 0)
489                         attrtypes[i]->attisset = get_attisset(RelationGetRelid(reldesc),
490                                                                                  NameStr(attrtypes[i]->attname));
491                 else
492                         attrtypes[i]->attisset = false;
493
494                 if (DebugMode)
495                 {
496                         Form_pg_attribute at = attrtypes[i];
497
498                         printf("create attribute %d name %s len %d num %d type %d\n",
499                                    i, NameStr(at->attname), at->attlen, at->attnum,
500                                    at->atttypid
501                                 );
502                         fflush(stdout);
503                 }
504         }
505 }
506
507 /* ----------------
508  *              closerel
509  * ----------------
510  */
511 void
512 closerel(char *name)
513 {
514         if (name)
515         {
516                 if (reldesc)
517                 {
518                         if (strcmp(RelationGetRelationName(reldesc), name) != 0)
519                                 elog(ERROR, "closerel: close of '%s' when '%s' was expected",
520                                          name, relname ? relname : "(null)");
521                 }
522                 else
523                         elog(ERROR, "closerel: close of '%s' before any relation was opened",
524                                  name);
525
526         }
527
528         if (reldesc == NULL)
529                 elog(ERROR, "Warning: no opened relation to close.\n");
530         else
531         {
532                 if (!Quiet)
533                         printf("Amclose: relation %s.\n", relname ? relname : "(null)");
534                 heap_close(reldesc, NoLock);
535                 reldesc = (Relation) NULL;
536         }
537 }
538
539
540
541 /* ----------------
542  * DEFINEATTR()
543  *
544  * define a <field,type> pair
545  * if there are n fields in a relation to be created, this routine
546  * will be called n times
547  * ----------------
548  */
549 void
550 DefineAttr(char *name, char *type, int attnum)
551 {
552         int                     attlen;
553         Oid                     typeoid;
554
555         if (reldesc != NULL)
556         {
557                 fputs("Warning: no open relations allowed with 't' command.\n", stderr);
558                 closerel(relname);
559         }
560
561         typeoid = gettype(type);
562         if (attrtypes[attnum] == (Form_pg_attribute) NULL)
563                 attrtypes[attnum] = AllocateAttribute();
564         if (Typ != (struct typmap **) NULL)
565         {
566                 attrtypes[attnum]->atttypid = Ap->am_oid;
567                 namestrcpy(&attrtypes[attnum]->attname, name);
568                 if (!Quiet)
569                         printf("<%s %s> ", NameStr(attrtypes[attnum]->attname), type);
570                 attrtypes[attnum]->attnum = 1 + attnum; /* fillatt */
571                 attlen = attrtypes[attnum]->attlen = Ap->am_typ.typlen;
572                 attrtypes[attnum]->attbyval = Ap->am_typ.typbyval;
573                 attrtypes[attnum]->attstorage = Ap->am_typ.typstorage;;
574                 attrtypes[attnum]->attalign = Ap->am_typ.typalign;
575         }
576         else
577         {
578                 attrtypes[attnum]->atttypid = Procid[typeoid].oid;
579                 namestrcpy(&attrtypes[attnum]->attname, name);
580                 if (!Quiet)
581                         printf("<%s %s> ", NameStr(attrtypes[attnum]->attname), type);
582                 attrtypes[attnum]->attnum = 1 + attnum; /* fillatt */
583                 attlen = attrtypes[attnum]->attlen = Procid[typeoid].len;
584                 attrtypes[attnum]->attstorage = 'p';
585
586                 /*
587                  * Cheat like mad to fill in these items from the length only.
588                  * This only has to work for types used in the system catalogs...
589                  */
590                 switch (attlen)
591                 {
592                         case 1:
593                                 attrtypes[attnum]->attbyval = true;
594                                 attrtypes[attnum]->attalign = 'c';
595                                 break;
596                         case 2:
597                                 attrtypes[attnum]->attbyval = true;
598                                 attrtypes[attnum]->attalign = 's';
599                                 break;
600                         case 4:
601                                 attrtypes[attnum]->attbyval = true;
602                                 attrtypes[attnum]->attalign = 'i';
603                                 break;
604                         default:
605                                 attrtypes[attnum]->attbyval = false;
606                                 attrtypes[attnum]->attalign = 'i';
607                                 break;
608                 }
609         }
610         attrtypes[attnum]->attcacheoff = -1;
611         attrtypes[attnum]->atttypmod = -1;
612 }
613
614
615 /* ----------------
616  *              InsertOneTuple
617  *              assumes that 'oid' will not be zero.
618  * ----------------
619  */
620 void
621 InsertOneTuple(Oid objectid)
622 {
623         HeapTuple       tuple;
624         TupleDesc       tupDesc;
625
626         int                     i;
627
628         if (DebugMode)
629         {
630                 printf("InsertOneTuple oid %u, %d attrs\n", objectid, numattr);
631                 fflush(stdout);
632         }
633
634         tupDesc = CreateTupleDesc(numattr, attrtypes);
635         tuple = heap_formtuple(tupDesc, values, Blanks);
636         pfree(tupDesc);                         /* just free's tupDesc, not the attrtypes */
637
638         if (objectid != (Oid) 0)
639                 tuple->t_data->t_oid = objectid;
640         heap_insert(reldesc, tuple);
641         heap_freetuple(tuple);
642         if (DebugMode)
643         {
644                 printf("End InsertOneTuple, objectid=%u\n", objectid);
645                 fflush(stdout);
646         }
647
648         /*
649          * Reset blanks for next tuple
650          */
651         for (i = 0; i < numattr; i++)
652                 Blanks[i] = ' ';
653 }
654
655 /* ----------------
656  *              InsertOneValue
657  * ----------------
658  */
659 void
660 InsertOneValue(Oid objectid, char *value, int i)
661 {
662         int                     typeindex;
663         char       *prt;
664         struct typmap **app;
665
666         if (DebugMode)
667                 printf("Inserting value: '%s'\n", value);
668         if (i < 0 || i >= MAXATTR)
669         {
670                 printf("i out of range: %d\n", i);
671                 Assert(0);
672         }
673
674         if (Typ != (struct typmap **) NULL)
675         {
676                 struct typmap *ap;
677
678                 if (DebugMode)
679                         puts("Typ != NULL");
680                 app = Typ;
681                 while (*app && (*app)->am_oid != reldesc->rd_att->attrs[i]->atttypid)
682                         ++app;
683                 ap = *app;
684                 if (ap == NULL)
685                 {
686                         printf("Unable to find atttypid in Typ list! %u\n",
687                                    reldesc->rd_att->attrs[i]->atttypid
688                                 );
689                         Assert(0);
690                 }
691                 values[i] = OidFunctionCall3(ap->am_typ.typinput,
692                                                                          CStringGetDatum(value),
693                                                                          ObjectIdGetDatum(ap->am_typ.typelem),
694                                                                          Int32GetDatum(-1));
695                 prt = DatumGetCString(OidFunctionCall3(ap->am_typ.typoutput,
696                                                           values[i],
697                                                           ObjectIdGetDatum(ap->am_typ.typelem),
698                                                           Int32GetDatum(-1)));
699                 if (!Quiet)
700                         printf("%s ", prt);
701                 pfree(prt);
702         }
703         else
704         {
705                 for (typeindex = 0; typeindex < n_types; typeindex++)
706                 {
707                         if (Procid[typeindex].oid == attrtypes[i]->atttypid)
708                                 break;
709                 }
710                 if (typeindex >= n_types)
711                         elog(ERROR, "can't find type OID %u", attrtypes[i]->atttypid);
712                 if (DebugMode)
713                         printf("Typ == NULL, typeindex = %u idx = %d\n", typeindex, i);
714                 values[i] = OidFunctionCall3(Procid[typeindex].inproc,
715                                                                          CStringGetDatum(value),
716                                                                          ObjectIdGetDatum(Procid[typeindex].elem),
717                                                                          Int32GetDatum(-1));
718                 prt = DatumGetCString(OidFunctionCall3(Procid[typeindex].outproc,
719                                                           values[i],
720                                                           ObjectIdGetDatum(Procid[typeindex].elem),
721                                                           Int32GetDatum(-1)));
722                 if (!Quiet)
723                         printf("%s ", prt);
724                 pfree(prt);
725         }
726         if (DebugMode)
727         {
728                 puts("End InsertValue");
729                 fflush(stdout);
730         }
731 }
732
733 /* ----------------
734  *              InsertOneNull
735  * ----------------
736  */
737 void
738 InsertOneNull(int i)
739 {
740         if (DebugMode)
741                 printf("Inserting null\n");
742         if (i < 0 || i >= MAXATTR)
743                 elog(FATAL, "i out of range (too many attrs): %d\n", i);
744         values[i] = PointerGetDatum(NULL);
745         Blanks[i] = 'n';
746 }
747
748 #define MORE_THAN_THE_NUMBER_OF_CATALOGS 256
749
750 static bool
751 BootstrapAlreadySeen(Oid id)
752 {
753         static Oid      seenArray[MORE_THAN_THE_NUMBER_OF_CATALOGS];
754         static int      nseen = 0;
755         bool            seenthis;
756         int                     i;
757
758         seenthis = false;
759
760         for (i = 0; i < nseen; i++)
761         {
762                 if (seenArray[i] == id)
763                 {
764                         seenthis = true;
765                         break;
766                 }
767         }
768         if (!seenthis)
769         {
770                 seenArray[nseen] = id;
771                 nseen++;
772         }
773         return seenthis;
774 }
775
776 /* ----------------
777  *              cleanup
778  * ----------------
779  */
780 static void
781 cleanup()
782 {
783         static int      beenhere = 0;
784
785         if (!beenhere)
786                 beenhere = 1;
787         else
788         {
789                 elog(FATAL, "Memory manager fault: cleanup called twice.\n");
790                 proc_exit(1);
791         }
792         if (reldesc != (Relation) NULL)
793                 heap_close(reldesc, NoLock);
794         CommitTransactionCommand();
795         proc_exit(Warnings);
796 }
797
798 /* ----------------
799  *              gettype
800  * ----------------
801  */
802 static Oid
803 gettype(char *type)
804 {
805         int                     i;
806         Relation        rel;
807         HeapScanDesc scan;
808         HeapTuple       tup;
809         struct typmap **app;
810
811         if (Typ != (struct typmap **) NULL)
812         {
813                 for (app = Typ; *app != (struct typmap *) NULL; app++)
814                 {
815                         if (strncmp(NameStr((*app)->am_typ.typname), type, NAMEDATALEN) == 0)
816                         {
817                                 Ap = *app;
818                                 return (*app)->am_oid;
819                         }
820                 }
821         }
822         else
823         {
824                 for (i = 0; i <= n_types; i++)
825                 {
826                         if (strncmp(type, Procid[i].name, NAMEDATALEN) == 0)
827                                 return i;
828                 }
829                 if (DebugMode)
830                         printf("bootstrap.c: External Type: %s\n", type);
831                 rel = heap_openr(TypeRelationName, NoLock);
832                 scan = heap_beginscan(rel, 0, SnapshotNow, 0, (ScanKey) NULL);
833                 i = 0;
834                 while (HeapTupleIsValid(tup = heap_getnext(scan, 0)))
835                         ++i;
836                 heap_endscan(scan);
837                 app = Typ = ALLOC(struct typmap *, i + 1);
838                 while (i-- > 0)
839                         *app++ = ALLOC(struct typmap, 1);
840                 *app = (struct typmap *) NULL;
841                 scan = heap_beginscan(rel, 0, SnapshotNow, 0, (ScanKey) NULL);
842                 app = Typ;
843                 while (HeapTupleIsValid(tup = heap_getnext(scan, 0)))
844                 {
845                         (*app)->am_oid = tup->t_data->t_oid;
846                         memmove((char *) &(*app++)->am_typ,
847                                         (char *) GETSTRUCT(tup),
848                                         sizeof((*app)->am_typ));
849                 }
850                 heap_endscan(scan);
851                 heap_close(rel, NoLock);
852                 return gettype(type);
853         }
854         elog(ERROR, "Error: unknown type '%s'.\n", type);
855         err_out();
856         /* not reached, here to make compiler happy */
857         return 0;
858 }
859
860 /* ----------------
861  *              AllocateAttribute
862  * ----------------
863  */
864 static Form_pg_attribute                /* XXX */
865 AllocateAttribute()
866 {
867         Form_pg_attribute attribute = (Form_pg_attribute) malloc(ATTRIBUTE_TUPLE_SIZE);
868
869         if (!PointerIsValid(attribute))
870                 elog(FATAL, "AllocateAttribute: malloc failed");
871         MemSet(attribute, 0, ATTRIBUTE_TUPLE_SIZE);
872
873         return attribute;
874 }
875
876 /* ----------------
877  *              MapArrayTypeName
878  * XXX arrays of "basetype" are always "_basetype".
879  *         this is an evil hack inherited from rel. 3.1.
880  * XXX array dimension is thrown away because we
881  *         don't support fixed-dimension arrays.  again,
882  *         sickness from 3.1.
883  *
884  * the string passed in must have a '[' character in it
885  *
886  * the string returned is a pointer to static storage and should NOT
887  * be freed by the CALLER.
888  * ----------------
889  */
890 char *
891 MapArrayTypeName(char *s)
892 {
893         int                     i,
894                                 j;
895         static char newStr[NAMEDATALEN];        /* array type names < NAMEDATALEN
896                                                                                  * long */
897
898         if (s == NULL || s[0] == '\0')
899                 return s;
900
901         j = 1;
902         newStr[0] = '_';
903         for (i = 0; i < NAMEDATALEN - 1 && s[i] != '['; i++, j++)
904                 newStr[j] = s[i];
905
906         newStr[j] = '\0';
907
908         return newStr;
909 }
910
911 /* ----------------
912  *              EnterString
913  *              returns the string table position of the identifier
914  *              passed to it.  We add it to the table if we can't find it.
915  * ----------------
916  */
917 int
918 EnterString(char *str)
919 {
920         hashnode   *node;
921         int                     len;
922
923         len = strlen(str);
924
925         node = FindStr(str, len, 0);
926         if (node)
927                 return node->strnum;
928         else
929         {
930                 node = AddStr(str, len, 0);
931                 return node->strnum;
932         }
933 }
934
935 /* ----------------
936  *              LexIDStr
937  *              when given an idnum into the 'string-table' return the string
938  *              associated with the idnum
939  * ----------------
940  */
941 char *
942 LexIDStr(int ident_num)
943 {
944         return strtable[ident_num];
945 }
946
947
948 /* ----------------
949  *              CompHash
950  *
951  *              Compute a hash function for a given string.  We look at the first,
952  *              the last, and the middle character of a string to try to get spread
953  *              the strings out.  The function is rather arbitrary, except that we
954  *              are mod'ing by a prime number.
955  * ----------------
956  */
957 static int
958 CompHash(char *str, int len)
959 {
960         int                     result;
961
962         result = (NUM * str[0] + NUMSQR * str[len - 1] + NUMCUBE * str[(len - 1) / 2]);
963
964         return result % HASHTABLESIZE;
965
966 }
967
968 /* ----------------
969  *              FindStr
970  *
971  *              This routine looks for the specified string in the hash
972  *              table.  It returns a pointer to the hash node found,
973  *              or NULL if the string is not in the table.
974  * ----------------
975  */
976 static hashnode *
977 FindStr(char *str, int length, hashnode *mderef)
978 {
979         hashnode   *node;
980
981         node = hashtable[CompHash(str, length)];
982         while (node != NULL)
983         {
984
985                 /*
986                  * We must differentiate between string constants that might have
987                  * the same value as a identifier and the identifier itself.
988                  */
989                 if (!strcmp(str, strtable[node->strnum]))
990                 {
991                         return node;            /* no need to check */
992                 }
993                 else
994                         node = node->next;
995         }
996         /* Couldn't find it in the list */
997         return NULL;
998 }
999
1000 /* ----------------
1001  *              AddStr
1002  *
1003  *              This function adds the specified string, along with its associated
1004  *              data, to the hash table and the string table.  We return the node
1005  *              so that the calling routine can find out the unique id that AddStr
1006  *              has assigned to this string.
1007  * ----------------
1008  */
1009 static hashnode *
1010 AddStr(char *str, int strlength, int mderef)
1011 {
1012         hashnode   *temp,
1013                            *trail,
1014                            *newnode;
1015         int                     hashresult;
1016         int                     len;
1017
1018         if (++strtable_end == STRTABLESIZE)
1019         {
1020                 /* Error, string table overflow, so we Punt */
1021                 elog(FATAL,
1022                          "There are too many string constants and identifiers for the compiler to handle.");
1023
1024
1025         }
1026
1027         /*
1028          * Some of the utilites (eg, define type, create relation) assume that
1029          * the string they're passed is a NAMEDATALEN.  We get array bound
1030          * read violations from purify if we don't allocate at least
1031          * NAMEDATALEN bytes for strings of this sort.  Because we're lazy, we
1032          * allocate at least NAMEDATALEN bytes all the time.
1033          */
1034
1035         if ((len = strlength + 1) < NAMEDATALEN)
1036                 len = NAMEDATALEN;
1037
1038         strtable[strtable_end] = malloc((unsigned) len);
1039         strcpy(strtable[strtable_end], str);
1040
1041         /* Now put a node in the hash table */
1042
1043         newnode = (hashnode *) malloc(sizeof(hashnode) * 1);
1044         newnode->strnum = strtable_end;
1045         newnode->next = NULL;
1046
1047         /* Find out where it goes */
1048
1049         hashresult = CompHash(str, strlength);
1050         if (hashtable[hashresult] == NULL)
1051                 hashtable[hashresult] = newnode;
1052         else
1053         {                                                       /* There is something in the list */
1054                 trail = hashtable[hashresult];
1055                 temp = trail->next;
1056                 while (temp != NULL)
1057                 {
1058                         trail = temp;
1059                         temp = temp->next;
1060                 }
1061                 trail->next = newnode;
1062         }
1063         return newnode;
1064 }
1065
1066
1067
1068 /*
1069  *      index_register() -- record an index that has been set up for building
1070  *                                              later.
1071  *
1072  *              At bootstrap time, we define a bunch of indices on system catalogs.
1073  *              We postpone actually building the indices until just before we're
1074  *              finished with initialization, however.  This is because more classes
1075  *              and indices may be defined, and we want to be sure that all of them
1076  *              are present in the index.
1077  */
1078 void
1079 index_register(char *heap,
1080                            char *ind,
1081                            IndexInfo *indexInfo)
1082 {
1083         IndexList  *newind;
1084         MemoryContext oldcxt;
1085
1086         /*
1087          * XXX mao 10/31/92 -- don't gc index reldescs, associated info at
1088          * bootstrap time.      we'll declare the indices now, but want to create
1089          * them later.
1090          */
1091
1092         if (nogc == NULL)
1093                 nogc = AllocSetContextCreate((MemoryContext) NULL,
1094                                                                          "BootstrapNoGC",
1095                                                                          ALLOCSET_DEFAULT_MINSIZE,
1096                                                                          ALLOCSET_DEFAULT_INITSIZE,
1097                                                                          ALLOCSET_DEFAULT_MAXSIZE);
1098
1099         oldcxt = MemoryContextSwitchTo(nogc);
1100
1101         newind = (IndexList *) palloc(sizeof(IndexList));
1102         newind->il_heap = pstrdup(heap);
1103         newind->il_ind = pstrdup(ind);
1104         newind->il_info = (IndexInfo *) palloc(sizeof(IndexInfo));
1105
1106         memcpy(newind->il_info, indexInfo, sizeof(IndexInfo));
1107         /* predicate will likely be null anyway, but may as well copy it */
1108         newind->il_info->ii_Predicate = copyObject(indexInfo->ii_Predicate);
1109
1110         newind->il_next = ILHead;
1111         ILHead = newind;
1112
1113         MemoryContextSwitchTo(oldcxt);
1114 }
1115
1116 void
1117 build_indices()
1118 {
1119         for (; ILHead != (IndexList *) NULL; ILHead = ILHead->il_next)
1120         {
1121                 Relation        heap;
1122                 Relation        ind;
1123
1124                 heap = heap_openr(ILHead->il_heap, NoLock);
1125                 ind = index_openr(ILHead->il_ind);
1126                 index_build(heap, ind, ILHead->il_info, NULL);
1127
1128                 /*
1129                  * In normal processing mode, index_build would close the heap and
1130                  * index, but in bootstrap mode it will not.
1131                  */
1132
1133                 /*
1134                  * All of the rest of this routine is needed only because in
1135                  * bootstrap processing we don't increment xact id's.  The normal
1136                  * DefineIndex code replaces a pg_class tuple with updated info
1137                  * including the relhasindex flag (which we need to have updated).
1138                  * Unfortunately, there are always two indices defined on each
1139                  * catalog causing us to update the same pg_class tuple twice for
1140                  * each catalog getting an index during bootstrap resulting in the
1141                  * ghost tuple problem (see heap_update).       To get around this we
1142                  * change the relhasindex field ourselves in this routine keeping
1143                  * track of what catalogs we already changed so that we don't
1144                  * modify those tuples twice.  The normal mechanism for updating
1145                  * pg_class is disabled during bootstrap.
1146                  *
1147                  * -mer
1148                  */
1149                 if (!BootstrapAlreadySeen(RelationGetRelid(heap)))
1150                         UpdateStats(RelationGetRelid(heap), 0);
1151
1152                 /* XXX Probably we ought to close the heap and index here? */
1153         }
1154 }