]> granicus.if.org Git - postgresql/blob - src/backend/bootstrap/bootstrap.c
Invent ResourceOwner mechanism as per my recent proposal, and use it to
[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-2003, PostgreSQL Global Development Group
8  * Portions Copyright (c) 1994, Regents of the University of California
9  *
10  * IDENTIFICATION
11  *        $PostgreSQL: pgsql/src/backend/bootstrap/bootstrap.c,v 1.187 2004/07/17 03:28:37 tgl Exp $
12  *
13  *-------------------------------------------------------------------------
14  */
15 #include "postgres.h"
16
17 #include <unistd.h>
18 #include <signal.h>
19 #include <setjmp.h>
20 #ifdef HAVE_GETOPT_H
21 #include <getopt.h>
22 #endif
23
24 #define BOOTSTRAP_INCLUDE               /* mask out stuff in tcop/tcopprot.h */
25
26 #include "access/genam.h"
27 #include "access/heapam.h"
28 #include "access/xlog.h"
29 #include "bootstrap/bootstrap.h"
30 #include "catalog/catname.h"
31 #include "catalog/index.h"
32 #include "catalog/pg_type.h"
33 #include "executor/executor.h"
34 #include "libpq/pqsignal.h"
35 #include "miscadmin.h"
36 #include "postmaster/bgwriter.h"
37 #include "storage/freespace.h"
38 #include "storage/ipc.h"
39 #include "storage/pg_shmem.h"
40 #include "storage/proc.h"
41 #include "tcop/tcopprot.h"
42 #include "utils/builtins.h"
43 #include "utils/fmgroids.h"
44 #include "utils/guc.h"
45 #include "utils/lsyscache.h"
46 #include "utils/ps_status.h"
47 #include "utils/relcache.h"
48
49
50 #define ALLOC(t, c)             ((t *) calloc((unsigned)(c), sizeof(t)))
51
52 extern int      Int_yyparse(void);
53 static void usage(void);
54 static void bootstrap_signals(void);
55 static hashnode *AddStr(char *str, int strlength, int mderef);
56 static Form_pg_attribute AllocateAttribute(void);
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 Relation        boot_reldesc;           /* current relation descriptor */
68
69 /*
70  * In the lexical analyzer, we need to get the reference number quickly from
71  * the string, and the string from the reference number.  Thus we have
72  * as our data structure a hash table, where the hashing key taken from
73  * the particular string.  The hash table is chained.  One of the fields
74  * of the hash table node is an index into the array of character pointers.
75  * The unique index number that every string is assigned is simply the
76  * position of its string pointer in the array of string pointers.
77  */
78
79 #define STRTABLESIZE    10000
80 #define HASHTABLESIZE   503
81
82 /* Hash function numbers */
83 #define NUM             23
84 #define NUMSQR  529
85 #define NUMCUBE 12167
86
87 char       *strtable[STRTABLESIZE];
88 hashnode   *hashtable[HASHTABLESIZE];
89
90 static int      strtable_end = -1;      /* Tells us last occupied string space */
91
92 /*-
93  * Basic information associated with each type.  This is used before
94  * pg_type is created.
95  *
96  *              XXX several of these input/output functions do catalog scans
97  *                      (e.g., F_REGPROCIN scans pg_proc).      this obviously creates some
98  *                      order dependencies in the catalog creation process.
99  */
100 struct typinfo
101 {
102         char            name[NAMEDATALEN];
103         Oid                     oid;
104         Oid                     elem;
105         int16           len;
106         bool            byval;
107         char            align;
108         char            storage;
109         Oid                     inproc;
110         Oid                     outproc;
111 };
112
113 static const struct typinfo TypInfo[] = {
114         {"bool", BOOLOID, 0, 1, true, 'c', 'p',
115          F_BOOLIN, F_BOOLOUT},
116         {"bytea", BYTEAOID, 0, -1, false, 'i', 'x',
117          F_BYTEAIN, F_BYTEAOUT},
118         {"char", CHAROID, 0, 1, true, 'c', 'p',
119          F_CHARIN, F_CHAROUT},
120         {"name", NAMEOID, CHAROID, NAMEDATALEN, false, 'i', 'p',
121          F_NAMEIN, F_NAMEOUT},
122         {"int2", INT2OID, 0, 2, true, 's', 'p',
123          F_INT2IN, F_INT2OUT},
124         {"int4", INT4OID, 0, 4, true, 'i', 'p',
125          F_INT4IN, F_INT4OUT},
126         {"regproc", REGPROCOID, 0, 4, true, 'i', 'p',
127          F_REGPROCIN, F_REGPROCOUT},
128         {"regclass", REGCLASSOID, 0, 4, true, 'i', 'p',
129          F_REGCLASSIN, F_REGCLASSOUT},
130         {"regtype", REGTYPEOID, 0, 4, true, 'i', 'p',
131          F_REGTYPEIN, F_REGTYPEOUT},
132         {"text", TEXTOID, 0, -1, false, 'i', 'x',
133          F_TEXTIN, F_TEXTOUT},
134         {"oid", OIDOID, 0, 4, true, 'i', 'p',
135          F_OIDIN, F_OIDOUT},
136         {"tid", TIDOID, 0, 6, false, 's', 'p',
137          F_TIDIN, F_TIDOUT},
138         {"xid", XIDOID, 0, 4, true, 'i', 'p',
139          F_XIDIN, F_XIDOUT},
140         {"cid", CIDOID, 0, 4, true, 'i', 'p',
141          F_CIDIN, F_CIDOUT},
142         {"int2vector", INT2VECTOROID, INT2OID, INDEX_MAX_KEYS * 2, false, 's', 'p',
143          F_INT2VECTORIN, F_INT2VECTOROUT},
144         {"oidvector", OIDVECTOROID, OIDOID, INDEX_MAX_KEYS * 4, false, 'i', 'p',
145          F_OIDVECTORIN, F_OIDVECTOROUT},
146         {"_int4", INT4ARRAYOID, INT4OID, -1, false, 'i', 'x',
147          F_ARRAY_IN, F_ARRAY_OUT},
148         {"_text", 1009, TEXTOID, -1, false, 'i', 'x',
149          F_ARRAY_IN, F_ARRAY_OUT},
150         {"_aclitem", 1034, ACLITEMOID, -1, false, 'i', 'x',
151          F_ARRAY_IN, F_ARRAY_OUT}
152 };
153
154 static const int        n_types = sizeof(TypInfo) / sizeof(struct typinfo);
155
156 struct typmap
157 {                                                               /* a hack */
158         Oid                     am_oid;
159         FormData_pg_type am_typ;
160 };
161
162 static struct typmap **Typ = NULL;
163 static struct typmap *Ap = NULL;
164
165 static int      Warnings = 0;
166 static char Blanks[MAXATTR];
167
168 static char *relname;                   /* current relation name */
169
170 Form_pg_attribute attrtypes[MAXATTR];   /* points to attribute info */
171 static Datum values[MAXATTR];   /* corresponding attribute values */
172 int                     numattr;                        /* number of attributes for cur. rel */
173
174 static MemoryContext nogc = NULL;               /* special no-gc mem context */
175
176 extern int      optind;
177 extern char *optarg;
178
179 /*
180  *      At bootstrap time, we first declare all the indices to be built, and
181  *      then build them.  The IndexList structure stores enough information
182  *      to allow us to build the indices after they've been declared.
183  */
184
185 typedef struct _IndexList
186 {
187         Oid                     il_heap;
188         Oid                     il_ind;
189         IndexInfo  *il_info;
190         struct _IndexList *il_next;
191 } IndexList;
192
193 static IndexList *ILHead = NULL;
194
195
196 /*
197  *       The main entry point for running the backend in bootstrap mode
198  *
199  *       The bootstrap mode is used to initialize the template database.
200  *       The bootstrap backend doesn't speak SQL, but instead expects
201  *       commands in a special bootstrap language.
202  *
203  *       For historical reasons, BootstrapMain is also used as the control
204  *       routine for non-backend subprocesses launched by the postmaster,
205  *       such as startup and shutdown.
206  */
207 int
208 BootstrapMain(int argc, char *argv[])
209 {
210         int                     i;
211         char       *dbname;
212         int                     flag;
213         int                     xlogop = BS_XLOG_NOP;
214         char       *userPGDATA = NULL;
215
216         /*
217          * initialize globals
218          */
219         MyProcPid = getpid();
220
221         /*
222          * Fire up essential subsystems: error and memory management
223          *
224          * If we are running under the postmaster, this is done already.
225          */
226         if (!IsUnderPostmaster)
227                 MemoryContextInit();
228
229         /*
230          * process command arguments
231          */
232
233         /* Set defaults, to be overriden by explicit options below */
234         dbname = NULL;
235         if (!IsUnderPostmaster)
236         {
237                 InitializeGUCOptions();
238                 userPGDATA = getenv("PGDATA");  /* Null if no PGDATA variable */
239         }
240
241         /* Ignore the initial -boot argument, if present */
242         if (argc > 1 && strcmp(argv[1], "-boot") == 0)
243         {
244                 argv++;
245                 argc--;
246         }
247
248         while ((flag = getopt(argc, argv, "B:c:d:D:Fo:p:x:-:")) != -1)
249         {
250                 switch (flag)
251                 {
252                         case 'D':
253                                 userPGDATA = optarg;
254                                 break;
255                         case 'd':
256                                 {
257                                         /* Turn on debugging for the bootstrap process. */
258                                         char       *debugstr = palloc(strlen("debug") + strlen(optarg) + 1);
259
260                                         sprintf(debugstr, "debug%s", optarg);
261                                         SetConfigOption("log_min_messages", debugstr,
262                                                                         PGC_POSTMASTER, PGC_S_ARGV);
263                                         SetConfigOption("client_min_messages", debugstr,
264                                                                         PGC_POSTMASTER, PGC_S_ARGV);
265                                         pfree(debugstr);
266                                         break;
267                                 }
268                                 break;
269                         case 'F':
270                                 SetConfigOption("fsync", "false", PGC_POSTMASTER, PGC_S_ARGV);
271                                 break;
272                         case 'o':
273                                 StrNCpy(OutputFileName, optarg, MAXPGPATH);
274                                 break;
275                         case 'x':
276                                 xlogop = atoi(optarg);
277                                 break;
278                         case 'p':
279                                 dbname = strdup(optarg);
280                                 break;
281                         case 'B':
282                                 SetConfigOption("shared_buffers", optarg, PGC_POSTMASTER, PGC_S_ARGV);
283                                 break;
284                         case 'c':
285                         case '-':
286                                 {
287                                         char       *name,
288                                                            *value;
289
290                                         ParseLongOption(optarg, &name, &value);
291                                         if (!value)
292                                         {
293                                                 if (flag == '-')
294                                                         ereport(ERROR,
295                                                                         (errcode(ERRCODE_SYNTAX_ERROR),
296                                                                          errmsg("--%s requires a value",
297                                                                                         optarg)));
298                                                 else
299                                                         ereport(ERROR,
300                                                                         (errcode(ERRCODE_SYNTAX_ERROR),
301                                                                          errmsg("-c %s requires a value",
302                                                                                         optarg)));
303                                         }
304
305                                         SetConfigOption(name, value, PGC_POSTMASTER, PGC_S_ARGV);
306                                         free(name);
307                                         if (value)
308                                                 free(value);
309                                         break;
310                                 }
311                         default:
312                                 usage();
313                                 break;
314                 }
315         }
316
317         if (!dbname && argc - optind == 1)
318         {
319                 dbname = argv[optind];
320                 optind++;
321         }
322         if (!dbname || argc != optind)
323                 usage();
324
325         if (!IsUnderPostmaster)
326         {
327                 if (!userPGDATA)
328                 {
329                         write_stderr("%s does not know where to find the database system data.\n"
330                                                  "You must specify the directory that contains the database system\n"
331                                                  "either by specifying the -D invocation option or by setting the\n"
332                                                  "PGDATA environment variable.\n",
333                                                  argv[0]);
334                         proc_exit(1);
335                 }
336                 SetDataDir(userPGDATA);
337         }
338
339         /* Validate we have been given a reasonable-looking DataDir */
340         Assert(DataDir);
341         ValidatePgVersion(DataDir);
342
343         /*
344          * Identify myself via ps
345          */
346         if (IsUnderPostmaster)
347         {
348                 const char *statmsg;
349
350                 switch (xlogop)
351                 {
352                         case BS_XLOG_STARTUP:
353                                 statmsg = "startup process";
354                                 break;
355                         case BS_XLOG_BGWRITER:
356                                 statmsg = "writer process";
357                                 break;
358                         default:
359                                 statmsg = "??? process";
360                                 break;
361                 }
362                 init_ps_display(statmsg, "", "");
363                 set_ps_display("");
364         }
365
366         /* Acquire configuration parameters, unless inherited from postmaster */
367         if (!IsUnderPostmaster)
368         {
369                 ProcessConfigFile(PGC_POSTMASTER);
370
371                 /* If timezone is not set, determine what the OS uses */
372                 pg_timezone_initialize();
373         }
374
375         /* If standalone, create lockfile for data directory */
376         if (!IsUnderPostmaster)
377                 CreateDataDirLockFile(DataDir, false);
378
379         SetProcessingMode(BootstrapProcessing);
380         IgnoreSystemIndexes(true);
381
382         XLOGPathInit();
383
384         BaseInit();
385
386         /* needed to get LWLocks */
387         if (IsUnderPostmaster)
388         {
389                 switch (xlogop)
390                 {
391                         case BS_XLOG_BGWRITER:
392                                 InitDummyProcess(DUMMY_PROC_BGWRITER);
393                                 break;
394
395                         default:
396                                 InitDummyProcess(DUMMY_PROC_DEFAULT);
397                                 break;
398                 }
399         }
400
401         /*
402          * XLOG operations
403          */
404         SetProcessingMode(NormalProcessing);
405
406         switch (xlogop)
407         {
408                 case BS_XLOG_NOP:
409                         bootstrap_signals();
410                         break;
411
412                 case BS_XLOG_BOOTSTRAP:
413                         bootstrap_signals();
414                         BootStrapXLOG();
415                         StartupXLOG();
416                         break;
417
418                 case BS_XLOG_STARTUP:
419                         bootstrap_signals();
420                         StartupXLOG();
421                         LoadFreeSpaceMap();
422                         proc_exit(0);           /* startup done */
423
424                 case BS_XLOG_BGWRITER:
425                         /* don't set signals, bgwriter has its own agenda */
426                         InitXLOGAccess();
427                         BackgroundWriterMain();
428                         proc_exit(1);           /* should never return */
429
430                 default:
431                         elog(PANIC, "unrecognized XLOG op: %d", xlogop);
432                         proc_exit(1);
433         }
434
435         SetProcessingMode(BootstrapProcessing);
436
437         /*
438          * backend initialization
439          */
440         InitPostgres(dbname, NULL);
441
442         /*
443          * In NOP mode, all we really want to do is create shared memory and
444          * semaphores (just to prove we can do it with the current GUC
445          * settings). So, quit now.
446          */
447         if (xlogop == BS_XLOG_NOP)
448                 proc_exit(0);
449
450         /* Initialize stuff for bootstrap-file processing */
451         for (i = 0; i < MAXATTR; i++)
452         {
453                 attrtypes[i] = NULL;
454                 Blanks[i] = ' ';
455         }
456         for (i = 0; i < STRTABLESIZE; ++i)
457                 strtable[i] = NULL;
458         for (i = 0; i < HASHTABLESIZE; ++i)
459                 hashtable[i] = NULL;
460
461         /*
462          * abort processing resumes here (this is probably dead code?)
463          */
464         if (sigsetjmp(Warn_restart, 1) != 0)
465         {
466                 Warnings++;
467                 AbortCurrentTransaction();
468         }
469
470         /*
471          * Process bootstrap input.
472          *
473          * the sed script boot.sed renamed yyparse to Int_yyparse for the
474          * bootstrap parser to avoid conflicts with the normal SQL parser
475          */
476         Int_yyparse();
477
478         /* Perform a checkpoint to ensure everything's down to disk */
479         SetProcessingMode(NormalProcessing);
480         CreateCheckPoint(true, true);
481         SetProcessingMode(BootstrapProcessing);
482
483         /* Clean up and exit */
484         StartTransactionCommand();
485         cleanup();
486
487         /* not reached, here to make compiler happy */
488         return 0;
489 }
490
491
492 /* ----------------------------------------------------------------
493  *                                              misc functions
494  * ----------------------------------------------------------------
495  */
496
497 /* usage:
498  *              usage help for the bootstrap backend
499  */
500 static void
501 usage(void)
502 {
503         write_stderr("Usage:\n"
504                                         "  postgres -boot [OPTION]... DBNAME\n"
505                                         "  -c NAME=VALUE    set run-time parameter\n"
506                                         "  -d 1-5           debug level\n"
507                                         "  -D datadir       data directory\n"
508                                         "  -F               turn off fsync\n"
509                                         "  -o file          send debug output to file\n"
510                                         "  -x num           internal use\n");
511
512         proc_exit(1);
513 }
514
515 /*
516  * Set up signal handling for a bootstrap process
517  */
518 static void
519 bootstrap_signals(void)
520 {
521         if (IsUnderPostmaster)
522         {
523                 /*
524                  * Properly accept or ignore signals the postmaster might send us
525                  */
526                 pqsignal(SIGHUP, SIG_IGN);
527                 pqsignal(SIGINT, SIG_IGN);              /* ignore query-cancel */
528                 pqsignal(SIGTERM, die);
529                 pqsignal(SIGQUIT, quickdie);
530                 pqsignal(SIGALRM, SIG_IGN);
531                 pqsignal(SIGPIPE, SIG_IGN);
532                 pqsignal(SIGUSR1, SIG_IGN);
533                 pqsignal(SIGUSR2, SIG_IGN);
534
535                 /*
536                  * Reset some signals that are accepted by postmaster but not here
537                  */
538                 pqsignal(SIGCHLD, SIG_DFL);
539                 pqsignal(SIGTTIN, SIG_DFL);
540                 pqsignal(SIGTTOU, SIG_DFL);
541                 pqsignal(SIGCONT, SIG_DFL);
542                 pqsignal(SIGWINCH, SIG_DFL);
543
544                 /*
545                  * Unblock signals (they were blocked when the postmaster forked
546                  * us)
547                  */
548                 PG_SETMASK(&UnBlockSig);
549         }
550         else
551         {
552                 /* Set up appropriately for interactive use */
553                 pqsignal(SIGHUP, die);
554                 pqsignal(SIGINT, die);
555                 pqsignal(SIGTERM, die);
556                 pqsignal(SIGQUIT, die);
557         }
558 }
559
560 /* ----------------
561  *              error handling / abort routines
562  * ----------------
563  */
564 void
565 err_out(void)
566 {
567         Warnings++;
568         cleanup();
569 }
570
571
572 /* ----------------------------------------------------------------
573  *                              MANUAL BACKEND INTERACTIVE INTERFACE COMMANDS
574  * ----------------------------------------------------------------
575  */
576
577 /* ----------------
578  *              boot_openrel
579  * ----------------
580  */
581 void
582 boot_openrel(char *relname)
583 {
584         int                     i;
585         struct typmap **app;
586         Relation        rel;
587         HeapScanDesc scan;
588         HeapTuple       tup;
589
590         if (strlen(relname) >= NAMEDATALEN - 1)
591                 relname[NAMEDATALEN - 1] = '\0';
592
593         if (Typ == NULL)
594         {
595                 rel = heap_openr(TypeRelationName, NoLock);
596                 scan = heap_beginscan(rel, SnapshotNow, 0, NULL);
597                 i = 0;
598                 while ((tup = heap_getnext(scan, ForwardScanDirection)) != NULL)
599                         ++i;
600                 heap_endscan(scan);
601                 app = Typ = ALLOC(struct typmap *, i + 1);
602                 while (i-- > 0)
603                         *app++ = ALLOC(struct typmap, 1);
604                 *app = NULL;
605                 scan = heap_beginscan(rel, SnapshotNow, 0, NULL);
606                 app = Typ;
607                 while ((tup = heap_getnext(scan, ForwardScanDirection)) != NULL)
608                 {
609                         (*app)->am_oid = HeapTupleGetOid(tup);
610                         memcpy((char *) &(*app)->am_typ,
611                                    (char *) GETSTRUCT(tup),
612                                    sizeof((*app)->am_typ));
613                         app++;
614                 }
615                 heap_endscan(scan);
616                 heap_close(rel, NoLock);
617         }
618
619         if (boot_reldesc != NULL)
620                 closerel(NULL);
621
622         elog(DEBUG4, "open relation %s, attrsize %d",
623                  relname ? relname : "(null)",
624                  (int) ATTRIBUTE_TUPLE_SIZE);
625
626         boot_reldesc = heap_openr(relname, NoLock);
627         numattr = boot_reldesc->rd_rel->relnatts;
628         for (i = 0; i < numattr; i++)
629         {
630                 if (attrtypes[i] == NULL)
631                         attrtypes[i] = AllocateAttribute();
632                 memmove((char *) attrtypes[i],
633                                 (char *) boot_reldesc->rd_att->attrs[i],
634                                 ATTRIBUTE_TUPLE_SIZE);
635
636                 {
637                         Form_pg_attribute at = attrtypes[i];
638
639                         elog(DEBUG4, "create attribute %d name %s len %d num %d type %u",
640                                  i, NameStr(at->attname), at->attlen, at->attnum,
641                                  at->atttypid);
642                 }
643         }
644 }
645
646 /* ----------------
647  *              closerel
648  * ----------------
649  */
650 void
651 closerel(char *name)
652 {
653         if (name)
654         {
655                 if (boot_reldesc)
656                 {
657                         if (strcmp(RelationGetRelationName(boot_reldesc), name) != 0)
658                                 elog(ERROR, "close of %s when %s was expected",
659                                          name, relname ? relname : "(null)");
660                 }
661                 else
662                         elog(ERROR, "close of %s before any relation was opened",
663                                  name);
664         }
665
666         if (boot_reldesc == NULL)
667                 elog(ERROR, "no open relation to close");
668         else
669         {
670                 elog(DEBUG4, "close relation %s", relname ? relname : "(null)");
671                 heap_close(boot_reldesc, NoLock);
672                 boot_reldesc = NULL;
673         }
674 }
675
676
677
678 /* ----------------
679  * DEFINEATTR()
680  *
681  * define a <field,type> pair
682  * if there are n fields in a relation to be created, this routine
683  * will be called n times
684  * ----------------
685  */
686 void
687 DefineAttr(char *name, char *type, int attnum)
688 {
689         int                     attlen;
690         Oid                     typeoid;
691
692         if (boot_reldesc != NULL)
693         {
694                 elog(WARNING, "no open relations allowed with CREATE command");
695                 closerel(relname);
696         }
697
698         if (attrtypes[attnum] == NULL)
699                 attrtypes[attnum] = AllocateAttribute();
700         MemSet(attrtypes[attnum], 0, ATTRIBUTE_TUPLE_SIZE);
701
702         namestrcpy(&attrtypes[attnum]->attname, name);
703         elog(DEBUG4, "column %s %s", NameStr(attrtypes[attnum]->attname), type);
704         attrtypes[attnum]->attnum = attnum + 1;         /* fillatt */
705
706         typeoid = gettype(type);
707
708         if (Typ != NULL)
709         {
710                 attrtypes[attnum]->atttypid = Ap->am_oid;
711                 attlen = attrtypes[attnum]->attlen = Ap->am_typ.typlen;
712                 attrtypes[attnum]->attbyval = Ap->am_typ.typbyval;
713                 attrtypes[attnum]->attstorage = Ap->am_typ.typstorage;
714                 attrtypes[attnum]->attalign = Ap->am_typ.typalign;
715                 /* if an array type, assume 1-dimensional attribute */
716                 if (Ap->am_typ.typelem != InvalidOid && Ap->am_typ.typlen < 0)
717                         attrtypes[attnum]->attndims = 1;
718                 else
719                         attrtypes[attnum]->attndims = 0;
720         }
721         else
722         {
723                 attrtypes[attnum]->atttypid = TypInfo[typeoid].oid;
724                 attlen = attrtypes[attnum]->attlen = TypInfo[typeoid].len;
725                 attrtypes[attnum]->attbyval = TypInfo[typeoid].byval;
726                 attrtypes[attnum]->attstorage = TypInfo[typeoid].storage;
727                 attrtypes[attnum]->attalign = TypInfo[typeoid].align;
728                 /* if an array type, assume 1-dimensional attribute */
729                 if (TypInfo[typeoid].elem != InvalidOid && attlen < 0)
730                         attrtypes[attnum]->attndims = 1;
731                 else
732                         attrtypes[attnum]->attndims = 0;
733         }
734
735         attrtypes[attnum]->attstattarget = -1;
736         attrtypes[attnum]->attcacheoff = -1;
737         attrtypes[attnum]->atttypmod = -1;
738         attrtypes[attnum]->attislocal = true;
739
740         /*
741          * Mark as "not null" if type is fixed-width and prior columns are
742          * too. This corresponds to case where column can be accessed directly
743          * via C struct declaration.
744          */
745         if (attlen > 0)
746         {
747                 int                     i;
748
749                 for (i = 0; i < attnum; i++)
750                 {
751                         if (attrtypes[i]->attlen <= 0)
752                                 break;
753                 }
754                 if (i == attnum)
755                         attrtypes[attnum]->attnotnull = true;
756         }
757 }
758
759
760 /* ----------------
761  *              InsertOneTuple
762  *
763  * If objectid is not zero, it is a specific OID to assign to the tuple.
764  * Otherwise, an OID will be assigned (if necessary) by heap_insert.
765  * ----------------
766  */
767 void
768 InsertOneTuple(Oid objectid)
769 {
770         HeapTuple       tuple;
771         TupleDesc       tupDesc;
772         int                     i;
773
774         elog(DEBUG4, "inserting row oid %u, %d columns", objectid, numattr);
775
776         tupDesc = CreateTupleDesc(numattr,
777                                                           RelationGetForm(boot_reldesc)->relhasoids,
778                                                           attrtypes);
779         tuple = heap_formtuple(tupDesc, values, Blanks);
780         if (objectid != (Oid) 0)
781                 HeapTupleSetOid(tuple, objectid);
782         pfree(tupDesc);                         /* just free's tupDesc, not the attrtypes */
783
784         simple_heap_insert(boot_reldesc, tuple);
785         heap_freetuple(tuple);
786         elog(DEBUG4, "row inserted");
787
788         /*
789          * Reset blanks for next tuple
790          */
791         for (i = 0; i < numattr; i++)
792                 Blanks[i] = ' ';
793 }
794
795 /* ----------------
796  *              InsertOneValue
797  * ----------------
798  */
799 void
800 InsertOneValue(char *value, int i)
801 {
802         Oid                     typoid;
803         Oid                     typioparam;
804         Oid                     typinput;
805         Oid                     typoutput;
806         char       *prt;
807
808         AssertArg(i >= 0 || i < MAXATTR);
809
810         elog(DEBUG4, "inserting column %d value \"%s\"", i, value);
811
812         if (Typ != NULL)
813         {
814                 struct typmap **app;
815                 struct typmap *ap;
816
817                 elog(DEBUG5, "Typ != NULL");
818                 typoid = boot_reldesc->rd_att->attrs[i]->atttypid;
819                 app = Typ;
820                 while (*app && (*app)->am_oid != typoid)
821                         ++app;
822                 ap = *app;
823                 if (ap == NULL)
824                         elog(ERROR, "could not find atttypid %u in Typ list", typoid);
825
826                 /* XXX this should match getTypeIOParam() */
827                 if (ap->am_typ.typtype == 'c')
828                         typioparam = typoid;
829                 else
830                         typioparam = ap->am_typ.typelem;
831
832                 typinput = ap->am_typ.typinput;
833                 typoutput = ap->am_typ.typoutput;
834         }
835         else
836         {
837                 int                     typeindex;
838
839                 /* XXX why is typoid determined differently in this path? */
840                 typoid = attrtypes[i]->atttypid;
841                 for (typeindex = 0; typeindex < n_types; typeindex++)
842                 {
843                         if (TypInfo[typeindex].oid == typoid)
844                                 break;
845                 }
846                 if (typeindex >= n_types)
847                         elog(ERROR, "type oid %u not found", typoid);
848                 elog(DEBUG5, "Typ == NULL, typeindex = %u", typeindex);
849
850                 /* XXX there are no composite types in TypInfo */
851                 typioparam = TypInfo[typeindex].elem;
852
853                 typinput = TypInfo[typeindex].inproc;
854                 typoutput = TypInfo[typeindex].outproc;
855         }
856
857         values[i] = OidFunctionCall3(typinput,
858                                                                  CStringGetDatum(value),
859                                                                  ObjectIdGetDatum(typioparam),
860                                                                  Int32GetDatum(-1));
861         prt = DatumGetCString(OidFunctionCall3(typoutput,
862                                                                                    values[i],
863                                                                                    ObjectIdGetDatum(typioparam),
864                                                                                    Int32GetDatum(-1)));
865         elog(DEBUG4, "inserted -> %s", prt);
866         pfree(prt);
867 }
868
869 /* ----------------
870  *              InsertOneNull
871  * ----------------
872  */
873 void
874 InsertOneNull(int i)
875 {
876         elog(DEBUG4, "inserting column %d NULL", i);
877         Assert(i >= 0 || i < MAXATTR);
878         values[i] = PointerGetDatum(NULL);
879         Blanks[i] = 'n';
880 }
881
882 /* ----------------
883  *              cleanup
884  * ----------------
885  */
886 static void
887 cleanup(void)
888 {
889         static int      beenhere = 0;
890
891         if (!beenhere)
892                 beenhere = 1;
893         else
894         {
895                 elog(FATAL, "cleanup called twice");
896                 proc_exit(1);
897         }
898         if (boot_reldesc != NULL)
899                 closerel(NULL);
900         CommitTransactionCommand();
901         proc_exit(Warnings ? 1 : 0);
902 }
903
904 /* ----------------
905  *              gettype
906  *
907  * NB: this is really ugly; it will return an integer index into TypInfo[],
908  * and not an OID at all, until the first reference to a type not known in
909  * TypInfo[].  At that point it will read and cache pg_type in the Typ array,
910  * and subsequently return a real OID (and set the global pointer Ap to
911  * point at the found row in Typ).      So caller must check whether Typ is
912  * still NULL to determine what the return value is!
913  * ----------------
914  */
915 static Oid
916 gettype(char *type)
917 {
918         int                     i;
919         Relation        rel;
920         HeapScanDesc scan;
921         HeapTuple       tup;
922         struct typmap **app;
923
924         if (Typ != NULL)
925         {
926                 for (app = Typ; *app != NULL; app++)
927                 {
928                         if (strncmp(NameStr((*app)->am_typ.typname), type, NAMEDATALEN) == 0)
929                         {
930                                 Ap = *app;
931                                 return (*app)->am_oid;
932                         }
933                 }
934         }
935         else
936         {
937                 for (i = 0; i < n_types; i++)
938                 {
939                         if (strncmp(type, TypInfo[i].name, NAMEDATALEN) == 0)
940                                 return i;
941                 }
942                 elog(DEBUG4, "external type: %s", type);
943                 rel = heap_openr(TypeRelationName, NoLock);
944                 scan = heap_beginscan(rel, SnapshotNow, 0, NULL);
945                 i = 0;
946                 while ((tup = heap_getnext(scan, ForwardScanDirection)) != NULL)
947                         ++i;
948                 heap_endscan(scan);
949                 app = Typ = ALLOC(struct typmap *, i + 1);
950                 while (i-- > 0)
951                         *app++ = ALLOC(struct typmap, 1);
952                 *app = NULL;
953                 scan = heap_beginscan(rel, SnapshotNow, 0, NULL);
954                 app = Typ;
955                 while ((tup = heap_getnext(scan, ForwardScanDirection)) != NULL)
956                 {
957                         (*app)->am_oid = HeapTupleGetOid(tup);
958                         memmove((char *) &(*app++)->am_typ,
959                                         (char *) GETSTRUCT(tup),
960                                         sizeof((*app)->am_typ));
961                 }
962                 heap_endscan(scan);
963                 heap_close(rel, NoLock);
964                 return gettype(type);
965         }
966         elog(ERROR, "unrecognized type \"%s\"", type);
967         err_out();
968         /* not reached, here to make compiler happy */
969         return 0;
970 }
971
972 /* ----------------
973  *              AllocateAttribute
974  * ----------------
975  */
976 static Form_pg_attribute
977 AllocateAttribute(void)
978 {
979         Form_pg_attribute attribute = (Form_pg_attribute) malloc(ATTRIBUTE_TUPLE_SIZE);
980
981         if (!PointerIsValid(attribute))
982                 elog(FATAL, "out of memory");
983         MemSet(attribute, 0, ATTRIBUTE_TUPLE_SIZE);
984
985         return attribute;
986 }
987
988 /* ----------------
989  *              MapArrayTypeName
990  * XXX arrays of "basetype" are always "_basetype".
991  *         this is an evil hack inherited from rel. 3.1.
992  * XXX array dimension is thrown away because we
993  *         don't support fixed-dimension arrays.  again,
994  *         sickness from 3.1.
995  *
996  * the string passed in must have a '[' character in it
997  *
998  * the string returned is a pointer to static storage and should NOT
999  * be freed by the CALLER.
1000  * ----------------
1001  */
1002 char *
1003 MapArrayTypeName(char *s)
1004 {
1005         int                     i,
1006                                 j;
1007         static char newStr[NAMEDATALEN];        /* array type names < NAMEDATALEN
1008                                                                                  * long */
1009
1010         if (s == NULL || s[0] == '\0')
1011                 return s;
1012
1013         j = 1;
1014         newStr[0] = '_';
1015         for (i = 0; i < NAMEDATALEN - 1 && s[i] != '['; i++, j++)
1016                 newStr[j] = s[i];
1017
1018         newStr[j] = '\0';
1019
1020         return newStr;
1021 }
1022
1023 /* ----------------
1024  *              EnterString
1025  *              returns the string table position of the identifier
1026  *              passed to it.  We add it to the table if we can't find it.
1027  * ----------------
1028  */
1029 int
1030 EnterString(char *str)
1031 {
1032         hashnode   *node;
1033         int                     len;
1034
1035         len = strlen(str);
1036
1037         node = FindStr(str, len, 0);
1038         if (node)
1039                 return node->strnum;
1040         else
1041         {
1042                 node = AddStr(str, len, 0);
1043                 return node->strnum;
1044         }
1045 }
1046
1047 /* ----------------
1048  *              LexIDStr
1049  *              when given an idnum into the 'string-table' return the string
1050  *              associated with the idnum
1051  * ----------------
1052  */
1053 char *
1054 LexIDStr(int ident_num)
1055 {
1056         return strtable[ident_num];
1057 }
1058
1059
1060 /* ----------------
1061  *              CompHash
1062  *
1063  *              Compute a hash function for a given string.  We look at the first,
1064  *              the last, and the middle character of a string to try to get spread
1065  *              the strings out.  The function is rather arbitrary, except that we
1066  *              are mod'ing by a prime number.
1067  * ----------------
1068  */
1069 static int
1070 CompHash(char *str, int len)
1071 {
1072         int                     result;
1073
1074         result = (NUM * str[0] + NUMSQR * str[len - 1] + NUMCUBE * str[(len - 1) / 2]);
1075
1076         return result % HASHTABLESIZE;
1077
1078 }
1079
1080 /* ----------------
1081  *              FindStr
1082  *
1083  *              This routine looks for the specified string in the hash
1084  *              table.  It returns a pointer to the hash node found,
1085  *              or NULL if the string is not in the table.
1086  * ----------------
1087  */
1088 static hashnode *
1089 FindStr(char *str, int length, hashnode *mderef)
1090 {
1091         hashnode   *node;
1092
1093         node = hashtable[CompHash(str, length)];
1094         while (node != NULL)
1095         {
1096                 /*
1097                  * We must differentiate between string constants that might have
1098                  * the same value as a identifier and the identifier itself.
1099                  */
1100                 if (!strcmp(str, strtable[node->strnum]))
1101                 {
1102                         return node;            /* no need to check */
1103                 }
1104                 else
1105                         node = node->next;
1106         }
1107         /* Couldn't find it in the list */
1108         return NULL;
1109 }
1110
1111 /* ----------------
1112  *              AddStr
1113  *
1114  *              This function adds the specified string, along with its associated
1115  *              data, to the hash table and the string table.  We return the node
1116  *              so that the calling routine can find out the unique id that AddStr
1117  *              has assigned to this string.
1118  * ----------------
1119  */
1120 static hashnode *
1121 AddStr(char *str, int strlength, int mderef)
1122 {
1123         hashnode   *temp,
1124                            *trail,
1125                            *newnode;
1126         int                     hashresult;
1127         int                     len;
1128
1129         if (++strtable_end >= STRTABLESIZE)
1130                 elog(FATAL, "bootstrap string table overflow");
1131
1132         /*
1133          * Some of the utilites (eg, define type, create relation) assume that
1134          * the string they're passed is a NAMEDATALEN.  We get array bound
1135          * read violations from purify if we don't allocate at least
1136          * NAMEDATALEN bytes for strings of this sort.  Because we're lazy, we
1137          * allocate at least NAMEDATALEN bytes all the time.
1138          */
1139
1140         if ((len = strlength + 1) < NAMEDATALEN)
1141                 len = NAMEDATALEN;
1142
1143         strtable[strtable_end] = malloc((unsigned) len);
1144         strcpy(strtable[strtable_end], str);
1145
1146         /* Now put a node in the hash table */
1147
1148         newnode = (hashnode *) malloc(sizeof(hashnode) * 1);
1149         newnode->strnum = strtable_end;
1150         newnode->next = NULL;
1151
1152         /* Find out where it goes */
1153
1154         hashresult = CompHash(str, strlength);
1155         if (hashtable[hashresult] == NULL)
1156                 hashtable[hashresult] = newnode;
1157         else
1158         {                                                       /* There is something in the list */
1159                 trail = hashtable[hashresult];
1160                 temp = trail->next;
1161                 while (temp != NULL)
1162                 {
1163                         trail = temp;
1164                         temp = temp->next;
1165                 }
1166                 trail->next = newnode;
1167         }
1168         return newnode;
1169 }
1170
1171
1172
1173 /*
1174  *      index_register() -- record an index that has been set up for building
1175  *                                              later.
1176  *
1177  *              At bootstrap time, we define a bunch of indices on system catalogs.
1178  *              We postpone actually building the indices until just before we're
1179  *              finished with initialization, however.  This is because more classes
1180  *              and indices may be defined, and we want to be sure that all of them
1181  *              are present in the index.
1182  */
1183 void
1184 index_register(Oid heap,
1185                            Oid ind,
1186                            IndexInfo *indexInfo)
1187 {
1188         IndexList  *newind;
1189         MemoryContext oldcxt;
1190
1191         /*
1192          * XXX mao 10/31/92 -- don't gc index reldescs, associated info at
1193          * bootstrap time.      we'll declare the indices now, but want to create
1194          * them later.
1195          */
1196
1197         if (nogc == NULL)
1198                 nogc = AllocSetContextCreate(NULL,
1199                                                                          "BootstrapNoGC",
1200                                                                          ALLOCSET_DEFAULT_MINSIZE,
1201                                                                          ALLOCSET_DEFAULT_INITSIZE,
1202                                                                          ALLOCSET_DEFAULT_MAXSIZE);
1203
1204         oldcxt = MemoryContextSwitchTo(nogc);
1205
1206         newind = (IndexList *) palloc(sizeof(IndexList));
1207         newind->il_heap = heap;
1208         newind->il_ind = ind;
1209         newind->il_info = (IndexInfo *) palloc(sizeof(IndexInfo));
1210
1211         memcpy(newind->il_info, indexInfo, sizeof(IndexInfo));
1212         /* expressions will likely be null, but may as well copy it */
1213         newind->il_info->ii_Expressions = (List *)
1214                 copyObject(indexInfo->ii_Expressions);
1215         newind->il_info->ii_ExpressionsState = NIL;
1216         /* predicate will likely be null, but may as well copy it */
1217         newind->il_info->ii_Predicate = (List *)
1218                 copyObject(indexInfo->ii_Predicate);
1219         newind->il_info->ii_PredicateState = NIL;
1220
1221         newind->il_next = ILHead;
1222         ILHead = newind;
1223
1224         MemoryContextSwitchTo(oldcxt);
1225 }
1226
1227 void
1228 build_indices(void)
1229 {
1230         for (; ILHead != NULL; ILHead = ILHead->il_next)
1231         {
1232                 Relation        heap;
1233                 Relation        ind;
1234
1235                 heap = heap_open(ILHead->il_heap, NoLock);
1236                 ind = index_open(ILHead->il_ind);
1237                 index_build(heap, ind, ILHead->il_info);
1238
1239                 /*
1240                  * In normal processing mode, index_build would close the heap and
1241                  * index, but in bootstrap mode it will not.
1242                  */
1243
1244                 /* XXX Probably we ought to close the heap and index here? */
1245         }
1246 }