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