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