~vcs-imports/mammoth-replicator/trunk

« back to all changes in this revision

Viewing changes to src/backend/bootstrap/bootstrap.c

  • Committer: alvherre
  • Date: 2005-12-16 21:24:52 UTC
  • Revision ID: svn-v4:db760fc0-0f08-0410-9d63-cc6633f64896:trunk:1
Initial import of the REL8_0_3 sources from the Pgsql CVS repository.

Show diffs side-by-side

added added

removed removed

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