Header And Logo

PostgreSQL
| The world's most advanced open source database.

bootstrap.c

Go to the documentation of this file.
00001 /*-------------------------------------------------------------------------
00002  *
00003  * bootstrap.c
00004  *    routines to support running postgres in 'bootstrap' mode
00005  *  bootstrap mode is used to create the initial template database
00006  *
00007  * Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group
00008  * Portions Copyright (c) 1994, Regents of the University of California
00009  *
00010  * IDENTIFICATION
00011  *    src/backend/bootstrap/bootstrap.c
00012  *
00013  *-------------------------------------------------------------------------
00014  */
00015 #include "postgres.h"
00016 
00017 #include <time.h>
00018 #include <unistd.h>
00019 #include <signal.h>
00020 #ifdef HAVE_GETOPT_H
00021 #include <getopt.h>
00022 #endif
00023 
00024 #include "access/htup_details.h"
00025 #include "bootstrap/bootstrap.h"
00026 #include "catalog/index.h"
00027 #include "catalog/pg_collation.h"
00028 #include "catalog/pg_type.h"
00029 #include "libpq/pqsignal.h"
00030 #include "miscadmin.h"
00031 #include "nodes/makefuncs.h"
00032 #include "postmaster/bgwriter.h"
00033 #include "postmaster/startup.h"
00034 #include "postmaster/walwriter.h"
00035 #include "replication/walreceiver.h"
00036 #include "storage/bufmgr.h"
00037 #include "storage/bufpage.h"
00038 #include "storage/ipc.h"
00039 #include "storage/proc.h"
00040 #include "tcop/tcopprot.h"
00041 #include "utils/builtins.h"
00042 #include "utils/fmgroids.h"
00043 #include "utils/memutils.h"
00044 #include "utils/ps_status.h"
00045 #include "utils/rel.h"
00046 #include "utils/relmapper.h"
00047 #include "utils/tqual.h"
00048 
00049 extern int  optind;
00050 extern char *optarg;
00051 
00052 uint32 bootstrap_data_checksum_version = 0;  /* No checksum */
00053 
00054 
00055 #define ALLOC(t, c)     ((t *) calloc((unsigned)(c), sizeof(t)))
00056 
00057 static void CheckerModeMain(void);
00058 static void BootstrapModeMain(void);
00059 static void bootstrap_signals(void);
00060 static void ShutdownAuxiliaryProcess(int code, Datum arg);
00061 static Form_pg_attribute AllocateAttribute(void);
00062 static Oid  gettype(char *type);
00063 static void cleanup(void);
00064 
00065 /* ----------------
00066  *      global variables
00067  * ----------------
00068  */
00069 
00070 AuxProcType MyAuxProcType = NotAnAuxProcess;    /* declared in miscadmin.h */
00071 
00072 Relation    boot_reldesc;       /* current relation descriptor */
00073 
00074 Form_pg_attribute attrtypes[MAXATTR];   /* points to attribute info */
00075 int         numattr;            /* number of attributes for cur. rel */
00076 
00077 
00078 /*
00079  * Basic information associated with each type.  This is used before
00080  * pg_type is filled, so it has to cover the datatypes used as column types
00081  * in the core "bootstrapped" catalogs.
00082  *
00083  *      XXX several of these input/output functions do catalog scans
00084  *          (e.g., F_REGPROCIN scans pg_proc).  this obviously creates some
00085  *          order dependencies in the catalog creation process.
00086  */
00087 struct typinfo
00088 {
00089     char        name[NAMEDATALEN];
00090     Oid         oid;
00091     Oid         elem;
00092     int16       len;
00093     bool        byval;
00094     char        align;
00095     char        storage;
00096     Oid         collation;
00097     Oid         inproc;
00098     Oid         outproc;
00099 };
00100 
00101 static const struct typinfo TypInfo[] = {
00102     {"bool", BOOLOID, 0, 1, true, 'c', 'p', InvalidOid,
00103     F_BOOLIN, F_BOOLOUT},
00104     {"bytea", BYTEAOID, 0, -1, false, 'i', 'x', InvalidOid,
00105     F_BYTEAIN, F_BYTEAOUT},
00106     {"char", CHAROID, 0, 1, true, 'c', 'p', InvalidOid,
00107     F_CHARIN, F_CHAROUT},
00108     {"int2", INT2OID, 0, 2, true, 's', 'p', InvalidOid,
00109     F_INT2IN, F_INT2OUT},
00110     {"int4", INT4OID, 0, 4, true, 'i', 'p', InvalidOid,
00111     F_INT4IN, F_INT4OUT},
00112     {"float4", FLOAT4OID, 0, 4, FLOAT4PASSBYVAL, 'i', 'p', InvalidOid,
00113     F_FLOAT4IN, F_FLOAT4OUT},
00114     {"name", NAMEOID, CHAROID, NAMEDATALEN, false, 'c', 'p', InvalidOid,
00115     F_NAMEIN, F_NAMEOUT},
00116     {"regclass", REGCLASSOID, 0, 4, true, 'i', 'p', InvalidOid,
00117     F_REGCLASSIN, F_REGCLASSOUT},
00118     {"regproc", REGPROCOID, 0, 4, true, 'i', 'p', InvalidOid,
00119     F_REGPROCIN, F_REGPROCOUT},
00120     {"regtype", REGTYPEOID, 0, 4, true, 'i', 'p', InvalidOid,
00121     F_REGTYPEIN, F_REGTYPEOUT},
00122     {"text", TEXTOID, 0, -1, false, 'i', 'x', DEFAULT_COLLATION_OID,
00123     F_TEXTIN, F_TEXTOUT},
00124     {"oid", OIDOID, 0, 4, true, 'i', 'p', InvalidOid,
00125     F_OIDIN, F_OIDOUT},
00126     {"tid", TIDOID, 0, 6, false, 's', 'p', InvalidOid,
00127     F_TIDIN, F_TIDOUT},
00128     {"xid", XIDOID, 0, 4, true, 'i', 'p', InvalidOid,
00129     F_XIDIN, F_XIDOUT},
00130     {"cid", CIDOID, 0, 4, true, 'i', 'p', InvalidOid,
00131     F_CIDIN, F_CIDOUT},
00132     {"pg_node_tree", PGNODETREEOID, 0, -1, false, 'i', 'x', DEFAULT_COLLATION_OID,
00133     F_PG_NODE_TREE_IN, F_PG_NODE_TREE_OUT},
00134     {"int2vector", INT2VECTOROID, INT2OID, -1, false, 'i', 'p', InvalidOid,
00135     F_INT2VECTORIN, F_INT2VECTOROUT},
00136     {"oidvector", OIDVECTOROID, OIDOID, -1, false, 'i', 'p', InvalidOid,
00137     F_OIDVECTORIN, F_OIDVECTOROUT},
00138     {"_int4", INT4ARRAYOID, INT4OID, -1, false, 'i', 'x', InvalidOid,
00139     F_ARRAY_IN, F_ARRAY_OUT},
00140     {"_text", 1009, TEXTOID, -1, false, 'i', 'x', DEFAULT_COLLATION_OID,
00141     F_ARRAY_IN, F_ARRAY_OUT},
00142     {"_oid", 1028, OIDOID, -1, false, 'i', 'x', InvalidOid,
00143     F_ARRAY_IN, F_ARRAY_OUT},
00144     {"_char", 1002, CHAROID, -1, false, 'i', 'x', InvalidOid,
00145     F_ARRAY_IN, F_ARRAY_OUT},
00146     {"_aclitem", 1034, ACLITEMOID, -1, false, 'i', 'x', InvalidOid,
00147     F_ARRAY_IN, F_ARRAY_OUT}
00148 };
00149 
00150 static const int n_types = sizeof(TypInfo) / sizeof(struct typinfo);
00151 
00152 struct typmap
00153 {                               /* a hack */
00154     Oid         am_oid;
00155     FormData_pg_type am_typ;
00156 };
00157 
00158 static struct typmap **Typ = NULL;
00159 static struct typmap *Ap = NULL;
00160 
00161 static Datum values[MAXATTR];   /* current row's attribute values */
00162 static bool Nulls[MAXATTR];
00163 
00164 static MemoryContext nogc = NULL;       /* special no-gc mem context */
00165 
00166 /*
00167  *  At bootstrap time, we first declare all the indices to be built, and
00168  *  then build them.  The IndexList structure stores enough information
00169  *  to allow us to build the indices after they've been declared.
00170  */
00171 
00172 typedef struct _IndexList
00173 {
00174     Oid         il_heap;
00175     Oid         il_ind;
00176     IndexInfo  *il_info;
00177     struct _IndexList *il_next;
00178 } IndexList;
00179 
00180 static IndexList *ILHead = NULL;
00181 
00182 
00183 /*
00184  *   AuxiliaryProcessMain
00185  *
00186  *   The main entry point for auxiliary processes, such as the bgwriter,
00187  *   walwriter, walreceiver, bootstrapper and the shared memory checker code.
00188  *
00189  *   This code is here just because of historical reasons.
00190  */
00191 void
00192 AuxiliaryProcessMain(int argc, char *argv[])
00193 {
00194     char       *progname = argv[0];
00195     int         flag;
00196     char       *userDoption = NULL;
00197 
00198     /*
00199      * initialize globals
00200      */
00201     MyProcPid = getpid();
00202 
00203     MyStartTime = time(NULL);
00204 
00205     /*
00206      * Fire up essential subsystems: error and memory management
00207      *
00208      * If we are running under the postmaster, this is done already.
00209      */
00210     if (!IsUnderPostmaster)
00211         MemoryContextInit();
00212 
00213     /* Compute paths, if we didn't inherit them from postmaster */
00214     if (my_exec_path[0] == '\0')
00215     {
00216         if (find_my_exec(progname, my_exec_path) < 0)
00217             elog(FATAL, "%s: could not locate my own executable path",
00218                  progname);
00219     }
00220 
00221     /*
00222      * process command arguments
00223      */
00224 
00225     /* Set defaults, to be overriden by explicit options below */
00226     if (!IsUnderPostmaster)
00227         InitializeGUCOptions();
00228 
00229     /* Ignore the initial --boot argument, if present */
00230     if (argc > 1 && strcmp(argv[1], "--boot") == 0)
00231     {
00232         argv++;
00233         argc--;
00234     }
00235 
00236     /* If no -x argument, we are a CheckerProcess */
00237     MyAuxProcType = CheckerProcess;
00238 
00239     while ((flag = getopt(argc, argv, "B:c:d:D:Fkr:x:-:")) != -1)
00240     {
00241         switch (flag)
00242         {
00243             case 'B':
00244                 SetConfigOption("shared_buffers", optarg, PGC_POSTMASTER, PGC_S_ARGV);
00245                 break;
00246             case 'D':
00247                 userDoption = strdup(optarg);
00248                 break;
00249             case 'd':
00250                 {
00251                     /* Turn on debugging for the bootstrap process. */
00252                     char       *debugstr = palloc(strlen("debug") + strlen(optarg) + 1);
00253 
00254                     sprintf(debugstr, "debug%s", optarg);
00255                     SetConfigOption("log_min_messages", debugstr,
00256                                     PGC_POSTMASTER, PGC_S_ARGV);
00257                     SetConfigOption("client_min_messages", debugstr,
00258                                     PGC_POSTMASTER, PGC_S_ARGV);
00259                     pfree(debugstr);
00260                 }
00261                 break;
00262             case 'F':
00263                 SetConfigOption("fsync", "false", PGC_POSTMASTER, PGC_S_ARGV);
00264                 break;
00265             case 'k':
00266                 bootstrap_data_checksum_version = PG_DATA_CHECKSUM_VERSION;
00267                 break;
00268             case 'r':
00269                 strlcpy(OutputFileName, optarg, MAXPGPATH);
00270                 break;
00271             case 'x':
00272                 MyAuxProcType = atoi(optarg);
00273                 break;
00274             case 'c':
00275             case '-':
00276                 {
00277                     char       *name,
00278                                *value;
00279 
00280                     ParseLongOption(optarg, &name, &value);
00281                     if (!value)
00282                     {
00283                         if (flag == '-')
00284                             ereport(ERROR,
00285                                     (errcode(ERRCODE_SYNTAX_ERROR),
00286                                      errmsg("--%s requires a value",
00287                                             optarg)));
00288                         else
00289                             ereport(ERROR,
00290                                     (errcode(ERRCODE_SYNTAX_ERROR),
00291                                      errmsg("-c %s requires a value",
00292                                             optarg)));
00293                     }
00294 
00295                     SetConfigOption(name, value, PGC_POSTMASTER, PGC_S_ARGV);
00296                     free(name);
00297                     if (value)
00298                         free(value);
00299                     break;
00300                 }
00301             default:
00302                 write_stderr("Try \"%s --help\" for more information.\n",
00303                              progname);
00304                 proc_exit(1);
00305                 break;
00306         }
00307     }
00308 
00309     if (argc != optind)
00310     {
00311         write_stderr("%s: invalid command-line arguments\n", progname);
00312         proc_exit(1);
00313     }
00314 
00315     /*
00316      * Identify myself via ps
00317      */
00318     if (IsUnderPostmaster)
00319     {
00320         const char *statmsg;
00321 
00322         switch (MyAuxProcType)
00323         {
00324             case StartupProcess:
00325                 statmsg = "startup process";
00326                 break;
00327             case BgWriterProcess:
00328                 statmsg = "writer process";
00329                 break;
00330             case CheckpointerProcess:
00331                 statmsg = "checkpointer process";
00332                 break;
00333             case WalWriterProcess:
00334                 statmsg = "wal writer process";
00335                 break;
00336             case WalReceiverProcess:
00337                 statmsg = "wal receiver process";
00338                 break;
00339             default:
00340                 statmsg = "??? process";
00341                 break;
00342         }
00343         init_ps_display(statmsg, "", "", "");
00344     }
00345 
00346     /* Acquire configuration parameters, unless inherited from postmaster */
00347     if (!IsUnderPostmaster)
00348     {
00349         if (!SelectConfigFiles(userDoption, progname))
00350             proc_exit(1);
00351     }
00352 
00353     /* Validate we have been given a reasonable-looking DataDir */
00354     Assert(DataDir);
00355     ValidatePgVersion(DataDir);
00356 
00357     /* Change into DataDir (if under postmaster, should be done already) */
00358     if (!IsUnderPostmaster)
00359         ChangeToDataDir();
00360 
00361     /* If standalone, create lockfile for data directory */
00362     if (!IsUnderPostmaster)
00363         CreateDataDirLockFile(false);
00364 
00365     SetProcessingMode(BootstrapProcessing);
00366     IgnoreSystemIndexes = true;
00367 
00368     /* Initialize MaxBackends (if under postmaster, was done already) */
00369     if (!IsUnderPostmaster)
00370         InitializeMaxBackends();
00371 
00372     BaseInit();
00373 
00374     /*
00375      * When we are an auxiliary process, we aren't going to do the full
00376      * InitPostgres pushups, but there are a couple of things that need to get
00377      * lit up even in an auxiliary process.
00378      */
00379     if (IsUnderPostmaster)
00380     {
00381         /*
00382          * Create a PGPROC so we can use LWLocks.  In the EXEC_BACKEND case,
00383          * this was already done by SubPostmasterMain().
00384          */
00385 #ifndef EXEC_BACKEND
00386         InitAuxiliaryProcess();
00387 #endif
00388 
00389         /*
00390          * Assign the ProcSignalSlot for an auxiliary process.  Since it
00391          * doesn't have a BackendId, the slot is statically allocated based on
00392          * the auxiliary process type (MyAuxProcType).  Backends use slots
00393          * indexed in the range from 1 to MaxBackends (inclusive), so we use
00394          * MaxBackends + AuxProcType + 1 as the index of the slot for an
00395          * auxiliary process.
00396          *
00397          * This will need rethinking if we ever want more than one of a
00398          * particular auxiliary process type.
00399          */
00400         ProcSignalInit(MaxBackends + MyAuxProcType + 1);
00401 
00402         /* finish setting up bufmgr.c */
00403         InitBufferPoolBackend();
00404 
00405         /* register a shutdown callback for LWLock cleanup */
00406         on_shmem_exit(ShutdownAuxiliaryProcess, 0);
00407     }
00408 
00409     /*
00410      * XLOG operations
00411      */
00412     SetProcessingMode(NormalProcessing);
00413 
00414     switch (MyAuxProcType)
00415     {
00416         case CheckerProcess:
00417             /* don't set signals, they're useless here */
00418             CheckerModeMain();
00419             proc_exit(1);       /* should never return */
00420 
00421         case BootstrapProcess:
00422             bootstrap_signals();
00423             BootStrapXLOG();
00424             BootstrapModeMain();
00425             proc_exit(1);       /* should never return */
00426 
00427         case StartupProcess:
00428             /* don't set signals, startup process has its own agenda */
00429             StartupProcessMain();
00430             proc_exit(1);       /* should never return */
00431 
00432         case BgWriterProcess:
00433             /* don't set signals, bgwriter has its own agenda */
00434             BackgroundWriterMain();
00435             proc_exit(1);       /* should never return */
00436 
00437         case CheckpointerProcess:
00438             /* don't set signals, checkpointer has its own agenda */
00439             CheckpointerMain();
00440             proc_exit(1);       /* should never return */
00441 
00442         case WalWriterProcess:
00443             /* don't set signals, walwriter has its own agenda */
00444             InitXLOGAccess();
00445             WalWriterMain();
00446             proc_exit(1);       /* should never return */
00447 
00448         case WalReceiverProcess:
00449             /* don't set signals, walreceiver has its own agenda */
00450             WalReceiverMain();
00451             proc_exit(1);       /* should never return */
00452 
00453         default:
00454             elog(PANIC, "unrecognized process type: %d", (int) MyAuxProcType);
00455             proc_exit(1);
00456     }
00457 }
00458 
00459 /*
00460  * In shared memory checker mode, all we really want to do is create shared
00461  * memory and semaphores (just to prove we can do it with the current GUC
00462  * settings).  Since, in fact, that was already done by BaseInit(),
00463  * we have nothing more to do here.
00464  */
00465 static void
00466 CheckerModeMain(void)
00467 {
00468     proc_exit(0);
00469 }
00470 
00471 /*
00472  *   The main entry point for running the backend in bootstrap mode
00473  *
00474  *   The bootstrap mode is used to initialize the template database.
00475  *   The bootstrap backend doesn't speak SQL, but instead expects
00476  *   commands in a special bootstrap language.
00477  */
00478 static void
00479 BootstrapModeMain(void)
00480 {
00481     int         i;
00482 
00483     Assert(!IsUnderPostmaster);
00484 
00485     SetProcessingMode(BootstrapProcessing);
00486 
00487     /*
00488      * Do backend-like initialization for bootstrap mode
00489      */
00490     InitProcess();
00491 
00492     InitPostgres(NULL, InvalidOid, NULL, NULL);
00493 
00494     /* Initialize stuff for bootstrap-file processing */
00495     for (i = 0; i < MAXATTR; i++)
00496     {
00497         attrtypes[i] = NULL;
00498         Nulls[i] = false;
00499     }
00500 
00501     /*
00502      * Process bootstrap input.
00503      */
00504     boot_yyparse();
00505 
00506     /*
00507      * We should now know about all mapped relations, so it's okay to write
00508      * out the initial relation mapping files.
00509      */
00510     RelationMapFinishBootstrap();
00511 
00512     /* Clean up and exit */
00513     cleanup();
00514     proc_exit(0);
00515 }
00516 
00517 
00518 /* ----------------------------------------------------------------
00519  *                      misc functions
00520  * ----------------------------------------------------------------
00521  */
00522 
00523 /*
00524  * Set up signal handling for a bootstrap process
00525  */
00526 static void
00527 bootstrap_signals(void)
00528 {
00529     if (IsUnderPostmaster)
00530     {
00531         /*
00532          * If possible, make this process a group leader, so that the
00533          * postmaster can signal any child processes too.
00534          */
00535 #ifdef HAVE_SETSID
00536         if (setsid() < 0)
00537             elog(FATAL, "setsid() failed: %m");
00538 #endif
00539 
00540         /*
00541          * Properly accept or ignore signals the postmaster might send us
00542          */
00543         pqsignal(SIGHUP, SIG_IGN);
00544         pqsignal(SIGINT, SIG_IGN);      /* ignore query-cancel */
00545         pqsignal(SIGTERM, die);
00546         pqsignal(SIGQUIT, quickdie);
00547         pqsignal(SIGALRM, SIG_IGN);
00548         pqsignal(SIGPIPE, SIG_IGN);
00549         pqsignal(SIGUSR1, SIG_IGN);
00550         pqsignal(SIGUSR2, SIG_IGN);
00551 
00552         /*
00553          * Reset some signals that are accepted by postmaster but not here
00554          */
00555         pqsignal(SIGCHLD, SIG_DFL);
00556         pqsignal(SIGTTIN, SIG_DFL);
00557         pqsignal(SIGTTOU, SIG_DFL);
00558         pqsignal(SIGCONT, SIG_DFL);
00559         pqsignal(SIGWINCH, SIG_DFL);
00560 
00561         /*
00562          * Unblock signals (they were blocked when the postmaster forked us)
00563          */
00564         PG_SETMASK(&UnBlockSig);
00565     }
00566     else
00567     {
00568         /* Set up appropriately for interactive use */
00569         pqsignal(SIGHUP, die);
00570         pqsignal(SIGINT, die);
00571         pqsignal(SIGTERM, die);
00572         pqsignal(SIGQUIT, die);
00573     }
00574 }
00575 
00576 /*
00577  * Begin shutdown of an auxiliary process.  This is approximately the equivalent
00578  * of ShutdownPostgres() in postinit.c.  We can't run transactions in an
00579  * auxiliary process, so most of the work of AbortTransaction() is not needed,
00580  * but we do need to make sure we've released any LWLocks we are holding.
00581  * (This is only critical during an error exit.)
00582  */
00583 static void
00584 ShutdownAuxiliaryProcess(int code, Datum arg)
00585 {
00586     LWLockReleaseAll();
00587 }
00588 
00589 /* ----------------------------------------------------------------
00590  *              MANUAL BACKEND INTERACTIVE INTERFACE COMMANDS
00591  * ----------------------------------------------------------------
00592  */
00593 
00594 /* ----------------
00595  *      boot_openrel
00596  * ----------------
00597  */
00598 void
00599 boot_openrel(char *relname)
00600 {
00601     int         i;
00602     struct typmap **app;
00603     Relation    rel;
00604     HeapScanDesc scan;
00605     HeapTuple   tup;
00606 
00607     if (strlen(relname) >= NAMEDATALEN)
00608         relname[NAMEDATALEN - 1] = '\0';
00609 
00610     if (Typ == NULL)
00611     {
00612         /* We can now load the pg_type data */
00613         rel = heap_open(TypeRelationId, NoLock);
00614         scan = heap_beginscan(rel, SnapshotNow, 0, NULL);
00615         i = 0;
00616         while ((tup = heap_getnext(scan, ForwardScanDirection)) != NULL)
00617             ++i;
00618         heap_endscan(scan);
00619         app = Typ = ALLOC(struct typmap *, i + 1);
00620         while (i-- > 0)
00621             *app++ = ALLOC(struct typmap, 1);
00622         *app = NULL;
00623         scan = heap_beginscan(rel, SnapshotNow, 0, NULL);
00624         app = Typ;
00625         while ((tup = heap_getnext(scan, ForwardScanDirection)) != NULL)
00626         {
00627             (*app)->am_oid = HeapTupleGetOid(tup);
00628             memcpy((char *) &(*app)->am_typ,
00629                    (char *) GETSTRUCT(tup),
00630                    sizeof((*app)->am_typ));
00631             app++;
00632         }
00633         heap_endscan(scan);
00634         heap_close(rel, NoLock);
00635     }
00636 
00637     if (boot_reldesc != NULL)
00638         closerel(NULL);
00639 
00640     elog(DEBUG4, "open relation %s, attrsize %d",
00641          relname, (int) ATTRIBUTE_FIXED_PART_SIZE);
00642 
00643     boot_reldesc = heap_openrv(makeRangeVar(NULL, relname, -1), NoLock);
00644     numattr = boot_reldesc->rd_rel->relnatts;
00645     for (i = 0; i < numattr; i++)
00646     {
00647         if (attrtypes[i] == NULL)
00648             attrtypes[i] = AllocateAttribute();
00649         memmove((char *) attrtypes[i],
00650                 (char *) boot_reldesc->rd_att->attrs[i],
00651                 ATTRIBUTE_FIXED_PART_SIZE);
00652 
00653         {
00654             Form_pg_attribute at = attrtypes[i];
00655 
00656             elog(DEBUG4, "create attribute %d name %s len %d num %d type %u",
00657                  i, NameStr(at->attname), at->attlen, at->attnum,
00658                  at->atttypid);
00659         }
00660     }
00661 }
00662 
00663 /* ----------------
00664  *      closerel
00665  * ----------------
00666  */
00667 void
00668 closerel(char *name)
00669 {
00670     if (name)
00671     {
00672         if (boot_reldesc)
00673         {
00674             if (strcmp(RelationGetRelationName(boot_reldesc), name) != 0)
00675                 elog(ERROR, "close of %s when %s was expected",
00676                      name, RelationGetRelationName(boot_reldesc));
00677         }
00678         else
00679             elog(ERROR, "close of %s before any relation was opened",
00680                  name);
00681     }
00682 
00683     if (boot_reldesc == NULL)
00684         elog(ERROR, "no open relation to close");
00685     else
00686     {
00687         elog(DEBUG4, "close relation %s",
00688              RelationGetRelationName(boot_reldesc));
00689         heap_close(boot_reldesc, NoLock);
00690         boot_reldesc = NULL;
00691     }
00692 }
00693 
00694 
00695 
00696 /* ----------------
00697  * DEFINEATTR()
00698  *
00699  * define a <field,type> pair
00700  * if there are n fields in a relation to be created, this routine
00701  * will be called n times
00702  * ----------------
00703  */
00704 void
00705 DefineAttr(char *name, char *type, int attnum)
00706 {
00707     Oid         typeoid;
00708 
00709     if (boot_reldesc != NULL)
00710     {
00711         elog(WARNING, "no open relations allowed with CREATE command");
00712         closerel(NULL);
00713     }
00714 
00715     if (attrtypes[attnum] == NULL)
00716         attrtypes[attnum] = AllocateAttribute();
00717     MemSet(attrtypes[attnum], 0, ATTRIBUTE_FIXED_PART_SIZE);
00718 
00719     namestrcpy(&attrtypes[attnum]->attname, name);
00720     elog(DEBUG4, "column %s %s", NameStr(attrtypes[attnum]->attname), type);
00721     attrtypes[attnum]->attnum = attnum + 1;     /* fillatt */
00722 
00723     typeoid = gettype(type);
00724 
00725     if (Typ != NULL)
00726     {
00727         attrtypes[attnum]->atttypid = Ap->am_oid;
00728         attrtypes[attnum]->attlen = Ap->am_typ.typlen;
00729         attrtypes[attnum]->attbyval = Ap->am_typ.typbyval;
00730         attrtypes[attnum]->attstorage = Ap->am_typ.typstorage;
00731         attrtypes[attnum]->attalign = Ap->am_typ.typalign;
00732         attrtypes[attnum]->attcollation = Ap->am_typ.typcollation;
00733         /* if an array type, assume 1-dimensional attribute */
00734         if (Ap->am_typ.typelem != InvalidOid && Ap->am_typ.typlen < 0)
00735             attrtypes[attnum]->attndims = 1;
00736         else
00737             attrtypes[attnum]->attndims = 0;
00738     }
00739     else
00740     {
00741         attrtypes[attnum]->atttypid = TypInfo[typeoid].oid;
00742         attrtypes[attnum]->attlen = TypInfo[typeoid].len;
00743         attrtypes[attnum]->attbyval = TypInfo[typeoid].byval;
00744         attrtypes[attnum]->attstorage = TypInfo[typeoid].storage;
00745         attrtypes[attnum]->attalign = TypInfo[typeoid].align;
00746         attrtypes[attnum]->attcollation = TypInfo[typeoid].collation;
00747         /* if an array type, assume 1-dimensional attribute */
00748         if (TypInfo[typeoid].elem != InvalidOid &&
00749             attrtypes[attnum]->attlen < 0)
00750             attrtypes[attnum]->attndims = 1;
00751         else
00752             attrtypes[attnum]->attndims = 0;
00753     }
00754 
00755     attrtypes[attnum]->attstattarget = -1;
00756     attrtypes[attnum]->attcacheoff = -1;
00757     attrtypes[attnum]->atttypmod = -1;
00758     attrtypes[attnum]->attislocal = true;
00759 
00760     /*
00761      * Mark as "not null" if type is fixed-width and prior columns are too.
00762      * This corresponds to case where column can be accessed directly via C
00763      * struct declaration.
00764      *
00765      * oidvector and int2vector are also treated as not-nullable, even though
00766      * they are no longer fixed-width.
00767      */
00768 #define MARKNOTNULL(att) \
00769     ((att)->attlen > 0 || \
00770      (att)->atttypid == OIDVECTOROID || \
00771      (att)->atttypid == INT2VECTOROID)
00772 
00773     if (MARKNOTNULL(attrtypes[attnum]))
00774     {
00775         int         i;
00776 
00777         for (i = 0; i < attnum; i++)
00778         {
00779             if (!MARKNOTNULL(attrtypes[i]))
00780                 break;
00781         }
00782         if (i == attnum)
00783             attrtypes[attnum]->attnotnull = true;
00784     }
00785 }
00786 
00787 
00788 /* ----------------
00789  *      InsertOneTuple
00790  *
00791  * If objectid is not zero, it is a specific OID to assign to the tuple.
00792  * Otherwise, an OID will be assigned (if necessary) by heap_insert.
00793  * ----------------
00794  */
00795 void
00796 InsertOneTuple(Oid objectid)
00797 {
00798     HeapTuple   tuple;
00799     TupleDesc   tupDesc;
00800     int         i;
00801 
00802     elog(DEBUG4, "inserting row oid %u, %d columns", objectid, numattr);
00803 
00804     tupDesc = CreateTupleDesc(numattr,
00805                               RelationGetForm(boot_reldesc)->relhasoids,
00806                               attrtypes);
00807     tuple = heap_form_tuple(tupDesc, values, Nulls);
00808     if (objectid != (Oid) 0)
00809         HeapTupleSetOid(tuple, objectid);
00810     pfree(tupDesc);             /* just free's tupDesc, not the attrtypes */
00811 
00812     simple_heap_insert(boot_reldesc, tuple);
00813     heap_freetuple(tuple);
00814     elog(DEBUG4, "row inserted");
00815 
00816     /*
00817      * Reset null markers for next tuple
00818      */
00819     for (i = 0; i < numattr; i++)
00820         Nulls[i] = false;
00821 }
00822 
00823 /* ----------------
00824  *      InsertOneValue
00825  * ----------------
00826  */
00827 void
00828 InsertOneValue(char *value, int i)
00829 {
00830     Oid         typoid;
00831     int16       typlen;
00832     bool        typbyval;
00833     char        typalign;
00834     char        typdelim;
00835     Oid         typioparam;
00836     Oid         typinput;
00837     Oid         typoutput;
00838     char       *prt;
00839 
00840     AssertArg(i >= 0 && i < MAXATTR);
00841 
00842     elog(DEBUG4, "inserting column %d value \"%s\"", i, value);
00843 
00844     typoid = boot_reldesc->rd_att->attrs[i]->atttypid;
00845 
00846     boot_get_type_io_data(typoid,
00847                           &typlen, &typbyval, &typalign,
00848                           &typdelim, &typioparam,
00849                           &typinput, &typoutput);
00850 
00851     values[i] = OidInputFunctionCall(typinput, value, typioparam, -1);
00852     prt = OidOutputFunctionCall(typoutput, values[i]);
00853     elog(DEBUG4, "inserted -> %s", prt);
00854     pfree(prt);
00855 }
00856 
00857 /* ----------------
00858  *      InsertOneNull
00859  * ----------------
00860  */
00861 void
00862 InsertOneNull(int i)
00863 {
00864     elog(DEBUG4, "inserting column %d NULL", i);
00865     Assert(i >= 0 && i < MAXATTR);
00866     values[i] = PointerGetDatum(NULL);
00867     Nulls[i] = true;
00868 }
00869 
00870 /* ----------------
00871  *      cleanup
00872  * ----------------
00873  */
00874 static void
00875 cleanup(void)
00876 {
00877     if (boot_reldesc != NULL)
00878         closerel(NULL);
00879 }
00880 
00881 /* ----------------
00882  *      gettype
00883  *
00884  * NB: this is really ugly; it will return an integer index into TypInfo[],
00885  * and not an OID at all, until the first reference to a type not known in
00886  * TypInfo[].  At that point it will read and cache pg_type in the Typ array,
00887  * and subsequently return a real OID (and set the global pointer Ap to
00888  * point at the found row in Typ).  So caller must check whether Typ is
00889  * still NULL to determine what the return value is!
00890  * ----------------
00891  */
00892 static Oid
00893 gettype(char *type)
00894 {
00895     int         i;
00896     Relation    rel;
00897     HeapScanDesc scan;
00898     HeapTuple   tup;
00899     struct typmap **app;
00900 
00901     if (Typ != NULL)
00902     {
00903         for (app = Typ; *app != NULL; app++)
00904         {
00905             if (strncmp(NameStr((*app)->am_typ.typname), type, NAMEDATALEN) == 0)
00906             {
00907                 Ap = *app;
00908                 return (*app)->am_oid;
00909             }
00910         }
00911     }
00912     else
00913     {
00914         for (i = 0; i < n_types; i++)
00915         {
00916             if (strncmp(type, TypInfo[i].name, NAMEDATALEN) == 0)
00917                 return i;
00918         }
00919         elog(DEBUG4, "external type: %s", type);
00920         rel = heap_open(TypeRelationId, NoLock);
00921         scan = heap_beginscan(rel, SnapshotNow, 0, NULL);
00922         i = 0;
00923         while ((tup = heap_getnext(scan, ForwardScanDirection)) != NULL)
00924             ++i;
00925         heap_endscan(scan);
00926         app = Typ = ALLOC(struct typmap *, i + 1);
00927         while (i-- > 0)
00928             *app++ = ALLOC(struct typmap, 1);
00929         *app = NULL;
00930         scan = heap_beginscan(rel, SnapshotNow, 0, NULL);
00931         app = Typ;
00932         while ((tup = heap_getnext(scan, ForwardScanDirection)) != NULL)
00933         {
00934             (*app)->am_oid = HeapTupleGetOid(tup);
00935             memmove((char *) &(*app++)->am_typ,
00936                     (char *) GETSTRUCT(tup),
00937                     sizeof((*app)->am_typ));
00938         }
00939         heap_endscan(scan);
00940         heap_close(rel, NoLock);
00941         return gettype(type);
00942     }
00943     elog(ERROR, "unrecognized type \"%s\"", type);
00944     /* not reached, here to make compiler happy */
00945     return 0;
00946 }
00947 
00948 /* ----------------
00949  *      boot_get_type_io_data
00950  *
00951  * Obtain type I/O information at bootstrap time.  This intentionally has
00952  * almost the same API as lsyscache.c's get_type_io_data, except that
00953  * we only support obtaining the typinput and typoutput routines, not
00954  * the binary I/O routines.  It is exported so that array_in and array_out
00955  * can be made to work during early bootstrap.
00956  * ----------------
00957  */
00958 void
00959 boot_get_type_io_data(Oid typid,
00960                       int16 *typlen,
00961                       bool *typbyval,
00962                       char *typalign,
00963                       char *typdelim,
00964                       Oid *typioparam,
00965                       Oid *typinput,
00966                       Oid *typoutput)
00967 {
00968     if (Typ != NULL)
00969     {
00970         /* We have the boot-time contents of pg_type, so use it */
00971         struct typmap **app;
00972         struct typmap *ap;
00973 
00974         app = Typ;
00975         while (*app && (*app)->am_oid != typid)
00976             ++app;
00977         ap = *app;
00978         if (ap == NULL)
00979             elog(ERROR, "type OID %u not found in Typ list", typid);
00980 
00981         *typlen = ap->am_typ.typlen;
00982         *typbyval = ap->am_typ.typbyval;
00983         *typalign = ap->am_typ.typalign;
00984         *typdelim = ap->am_typ.typdelim;
00985 
00986         /* XXX this logic must match getTypeIOParam() */
00987         if (OidIsValid(ap->am_typ.typelem))
00988             *typioparam = ap->am_typ.typelem;
00989         else
00990             *typioparam = typid;
00991 
00992         *typinput = ap->am_typ.typinput;
00993         *typoutput = ap->am_typ.typoutput;
00994     }
00995     else
00996     {
00997         /* We don't have pg_type yet, so use the hard-wired TypInfo array */
00998         int         typeindex;
00999 
01000         for (typeindex = 0; typeindex < n_types; typeindex++)
01001         {
01002             if (TypInfo[typeindex].oid == typid)
01003                 break;
01004         }
01005         if (typeindex >= n_types)
01006             elog(ERROR, "type OID %u not found in TypInfo", typid);
01007 
01008         *typlen = TypInfo[typeindex].len;
01009         *typbyval = TypInfo[typeindex].byval;
01010         *typalign = TypInfo[typeindex].align;
01011         /* We assume typdelim is ',' for all boot-time types */
01012         *typdelim = ',';
01013 
01014         /* XXX this logic must match getTypeIOParam() */
01015         if (OidIsValid(TypInfo[typeindex].elem))
01016             *typioparam = TypInfo[typeindex].elem;
01017         else
01018             *typioparam = typid;
01019 
01020         *typinput = TypInfo[typeindex].inproc;
01021         *typoutput = TypInfo[typeindex].outproc;
01022     }
01023 }
01024 
01025 /* ----------------
01026  *      AllocateAttribute
01027  *
01028  * Note: bootstrap never sets any per-column ACLs, so we only need
01029  * ATTRIBUTE_FIXED_PART_SIZE space per attribute.
01030  * ----------------
01031  */
01032 static Form_pg_attribute
01033 AllocateAttribute(void)
01034 {
01035     Form_pg_attribute attribute = (Form_pg_attribute) malloc(ATTRIBUTE_FIXED_PART_SIZE);
01036 
01037     if (!PointerIsValid(attribute))
01038         elog(FATAL, "out of memory");
01039     MemSet(attribute, 0, ATTRIBUTE_FIXED_PART_SIZE);
01040 
01041     return attribute;
01042 }
01043 
01044 /* ----------------
01045  *      MapArrayTypeName
01046  * XXX arrays of "basetype" are always "_basetype".
01047  *     this is an evil hack inherited from rel. 3.1.
01048  * XXX array dimension is thrown away because we
01049  *     don't support fixed-dimension arrays.  again,
01050  *     sickness from 3.1.
01051  *
01052  * the string passed in must have a '[' character in it
01053  *
01054  * the string returned is a pointer to static storage and should NOT
01055  * be freed by the CALLER.
01056  * ----------------
01057  */
01058 char *
01059 MapArrayTypeName(char *s)
01060 {
01061     int         i,
01062                 j;
01063     static char newStr[NAMEDATALEN];    /* array type names < NAMEDATALEN long */
01064 
01065     if (s == NULL || s[0] == '\0')
01066         return s;
01067 
01068     j = 1;
01069     newStr[0] = '_';
01070     for (i = 0; i < NAMEDATALEN - 1 && s[i] != '['; i++, j++)
01071         newStr[j] = s[i];
01072 
01073     newStr[j] = '\0';
01074 
01075     return newStr;
01076 }
01077 
01078 
01079 /*
01080  *  index_register() -- record an index that has been set up for building
01081  *                      later.
01082  *
01083  *      At bootstrap time, we define a bunch of indexes on system catalogs.
01084  *      We postpone actually building the indexes until just before we're
01085  *      finished with initialization, however.  This is because the indexes
01086  *      themselves have catalog entries, and those have to be included in the
01087  *      indexes on those catalogs.  Doing it in two phases is the simplest
01088  *      way of making sure the indexes have the right contents at the end.
01089  */
01090 void
01091 index_register(Oid heap,
01092                Oid ind,
01093                IndexInfo *indexInfo)
01094 {
01095     IndexList  *newind;
01096     MemoryContext oldcxt;
01097 
01098     /*
01099      * XXX mao 10/31/92 -- don't gc index reldescs, associated info at
01100      * bootstrap time.  we'll declare the indexes now, but want to create them
01101      * later.
01102      */
01103 
01104     if (nogc == NULL)
01105         nogc = AllocSetContextCreate(NULL,
01106                                      "BootstrapNoGC",
01107                                      ALLOCSET_DEFAULT_MINSIZE,
01108                                      ALLOCSET_DEFAULT_INITSIZE,
01109                                      ALLOCSET_DEFAULT_MAXSIZE);
01110 
01111     oldcxt = MemoryContextSwitchTo(nogc);
01112 
01113     newind = (IndexList *) palloc(sizeof(IndexList));
01114     newind->il_heap = heap;
01115     newind->il_ind = ind;
01116     newind->il_info = (IndexInfo *) palloc(sizeof(IndexInfo));
01117 
01118     memcpy(newind->il_info, indexInfo, sizeof(IndexInfo));
01119     /* expressions will likely be null, but may as well copy it */
01120     newind->il_info->ii_Expressions = (List *)
01121         copyObject(indexInfo->ii_Expressions);
01122     newind->il_info->ii_ExpressionsState = NIL;
01123     /* predicate will likely be null, but may as well copy it */
01124     newind->il_info->ii_Predicate = (List *)
01125         copyObject(indexInfo->ii_Predicate);
01126     newind->il_info->ii_PredicateState = NIL;
01127     /* no exclusion constraints at bootstrap time, so no need to copy */
01128     Assert(indexInfo->ii_ExclusionOps == NULL);
01129     Assert(indexInfo->ii_ExclusionProcs == NULL);
01130     Assert(indexInfo->ii_ExclusionStrats == NULL);
01131 
01132     newind->il_next = ILHead;
01133     ILHead = newind;
01134 
01135     MemoryContextSwitchTo(oldcxt);
01136 }
01137 
01138 
01139 /*
01140  * build_indices -- fill in all the indexes registered earlier
01141  */
01142 void
01143 build_indices(void)
01144 {
01145     for (; ILHead != NULL; ILHead = ILHead->il_next)
01146     {
01147         Relation    heap;
01148         Relation    ind;
01149 
01150         /* need not bother with locks during bootstrap */
01151         heap = heap_open(ILHead->il_heap, NoLock);
01152         ind = index_open(ILHead->il_ind, NoLock);
01153 
01154         index_build(heap, ind, ILHead->il_info, false, false);
01155 
01156         index_close(ind, NoLock);
01157         heap_close(heap, NoLock);
01158     }
01159 }