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