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