📄 bootstrap.c
字号:
/*------------------------------------------------------------------------- * * bootstrap.c * routines to support running postgres in 'bootstrap' mode * bootstrap mode is used to create the initial template database * * Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION * $Header: /usr/local/cvsroot/pgsql/src/backend/bootstrap/bootstrap.c,v 1.60.2.1 1999/08/02 05:56:52 scrappy Exp $ * *------------------------------------------------------------------------- */#include <unistd.h>#include <time.h>#include <signal.h>#include <setjmp.h>#define BOOTSTRAP_INCLUDE /* mask out stuff in tcop/tcopprot.h */#include "postgres.h"#ifdef HAVE_GETOPT_H#include <getopt.h>#endif#include "access/genam.h"#include "access/heapam.h"#include "bootstrap/bootstrap.h"#include "catalog/catname.h"#include "catalog/index.h"#include "catalog/pg_type.h"#include "libpq/pqsignal.h"#include "miscadmin.h"#include "tcop/tcopprot.h"#include "utils/builtins.h"#include "utils/lsyscache.h"#include "utils/portal.h"#define ALLOC(t, c) (t *)calloc((unsigned)(c), sizeof(t))#define FIRST_TYPE_OID 16 /* OID of the first type */extern int Int_yyparse(void);static hashnode *AddStr(char *str, int strlength, int mderef);static Form_pg_attribute AllocateAttribute(void);static bool BootstrapAlreadySeen(Oid id);static int CompHash(char *str, int len);static hashnode *FindStr(char *str, int length, hashnode *mderef);static Oid gettype(char *type);static void cleanup(void);/* ---------------- * global variables * ---------------- *//* * In the lexical analyzer, we need to get the reference number quickly from * the string, and the string from the reference number. Thus we have * as our data structure a hash table, where the hashing key taken from * the particular string. The hash table is chained. One of the fields * of the hash table node is an index into the array of character pointers. * The unique index number that every string is assigned is simply the * position of its string pointer in the array of string pointers. */#define STRTABLESIZE 10000#define HASHTABLESIZE 503/* Hash function numbers */#define NUM 23#define NUMSQR 529#define NUMCUBE 12167char *strtable[STRTABLESIZE];hashnode *hashtable[HASHTABLESIZE];static int strtable_end = -1; /* Tells us last occupied string space *//*- * Basic information associated with each type. This is used before * pg_type is created. * * XXX several of these input/output functions do catalog scans * (e.g., F_REGPROCIN scans pg_proc). this obviously creates some * order dependencies in the catalog creation process. */struct typinfo{ char name[NAMEDATALEN]; Oid oid; Oid elem; int16 len; Oid inproc; Oid outproc;};static struct typinfo Procid[] = { {"bool", 16, 0, 1, F_BOOLIN, F_BOOLOUT}, {"bytea", 17, 0, -1, F_BYTEAIN, F_BYTEAOUT}, {"char", 18, 0, 1, F_CHARIN, F_CHAROUT}, {"name", 19, 0, NAMEDATALEN, F_NAMEIN, F_NAMEOUT}, {"dummy", 20, 0, 16, 0, 0},/* { "dt", 20, 0, 4, F_DTIN, F_DTOUT}, */ {"int2", 21, 0, 2, F_INT2IN, F_INT2OUT}, {"int28", 22, 0, 16, F_INT28IN, F_INT28OUT}, {"int4", 23, 0, 4, F_INT4IN, F_INT4OUT}, {"regproc", 24, 0, 4, F_REGPROCIN, F_REGPROCOUT}, {"text", 25, 0, -1, F_TEXTIN, F_TEXTOUT}, {"oid", 26, 0, 4, F_INT4IN, F_INT4OUT}, {"tid", 27, 0, 6, F_TIDIN, F_TIDOUT}, {"xid", 28, 0, 5, F_XIDIN, F_XIDOUT}, {"iid", 29, 0, 1, F_CIDIN, F_CIDOUT}, {"oid8", 30, 0, 32, F_OID8IN, F_OID8OUT}, {"smgr", 210, 0, 2, F_SMGRIN, F_SMGROUT}, {"_int4", 1007, 23, -1, F_ARRAY_IN, F_ARRAY_OUT}, {"_aclitem", 1034, 1033, -1, F_ARRAY_IN, F_ARRAY_OUT}};static int n_types = sizeof(Procid) / sizeof(struct typinfo);struct typmap{ /* a hack */ Oid am_oid; FormData_pg_type am_typ;};static struct typmap **Typ = (struct typmap **) NULL;static struct typmap *Ap = (struct typmap *) NULL;static int Warnings = 0;static char Blanks[MAXATTR];static char *relname; /* current relation name */Form_pg_attribute attrtypes[MAXATTR]; /* points to attribute info */static char *values[MAXATTR]; /* cooresponding attribute values */int numattr; /* number of attributes for cur. rel */extern bool disableFsync; /* do not fsync the database */int DebugMode;static GlobalMemory nogc = (GlobalMemory) NULL; /* special no-gc mem * context */extern int optind;extern char *optarg;/* * At bootstrap time, we first declare all the indices to be built, and * then build them. The IndexList structure stores enough information * to allow us to build the indices after they've been declared. */typedef struct _IndexList{ char *il_heap; char *il_ind; int il_natts; AttrNumber *il_attnos; uint16 il_nparams; Datum *il_params; FuncIndexInfo *il_finfo; PredInfo *il_predInfo; struct _IndexList *il_next;} IndexList;static IndexList *ILHead = (IndexList *) NULL;typedef void (*sig_func) ();/* ---------------------------------------------------------------- * misc functions * ---------------------------------------------------------------- *//* ---------------- * error handling / abort routines * ---------------- */voiderr_out(void){ Warnings++; cleanup();}/* usage: usage help for the bootstrap backen*/static voidusage(void){ fprintf(stderr, "Usage: postgres -boot [-d] [-C] [-F] [-O] [-Q] "); fprintf(stderr, "[-P portno] [dbName]\n"); fprintf(stderr, " d: debug mode\n"); fprintf(stderr, " C: disable version checking\n"); fprintf(stderr, " F: turn off fsync\n"); fprintf(stderr, " O: set BootstrapProcessing mode\n"); fprintf(stderr, " P portno: specify port number\n"); proc_exit(1);}intBootstrapMain(int argc, char *argv[])/* ---------------------------------------------------------------- * The main loop for handling the backend in bootstrap mode * the bootstrap mode is used to initialize the template database * the bootstrap backend doesn't speak SQL, but instead expects * commands in a special bootstrap language. * * The arguments passed in to BootstrapMain are the run-time arguments * without the argument '-boot', the caller is required to have * removed -boot from the run-time args * ---------------------------------------------------------------- */{ int i; int portFd = -1; char *dbName; int flag; int override = 1; /* use BootstrapProcessing or * InitProcessing mode */ extern int optind; extern char *optarg; /* ---------------- * initialize signal handlers * ---------------- */ pqsignal(SIGINT, (sig_func) die); pqsignal(SIGHUP, (sig_func) die); pqsignal(SIGTERM, (sig_func) die); /* -------------------- * initialize globals * ------------------- */ MyProcPid = getpid(); /* ---------------- * process command arguments * ---------------- */ /* Set defaults, to be overriden by explicit options below */ Quiet = false; Noversion = false; dbName = NULL; DataDir = getenv("PGDATA"); /* Null if no PGDATA variable */ while ((flag = getopt(argc, argv, "D:dCOQP:F")) != EOF) { switch (flag) { case 'D': DataDir = optarg; break; case 'd': DebugMode = true; /* print out debugging info while * parsing */ break; case 'C': Noversion = true; break; case 'F': disableFsync = true; break; case 'O': override = true; break; case 'Q': Quiet = true; break; case 'P': /* specify port */ portFd = atoi(optarg); break; default: usage(); break; } } /* while */ if (argc - optind > 1) usage(); else if (argc - optind == 1) dbName = argv[optind]; if (!DataDir) { fprintf(stderr, "%s does not know where to find the database system " "data. You must specify the directory that contains the " "database system either by specifying the -D invocation " "option or by setting the PGDATA environment variable.\n\n", argv[0]); proc_exit(1); } if (dbName == NULL) { dbName = getenv("USER"); if (dbName == NULL) { fputs("bootstrap backend: failed, no db name specified\n", stderr); fputs(" and no USER enviroment variable\n", stderr); proc_exit(1); } } /* ---------------- * initialize input fd * ---------------- */ if (IsUnderPostmaster && portFd < 0) { fputs("backend: failed, no -P option with -postmaster opt.\n", stderr); proc_exit(1); } /* ---------------- * backend initialization * ---------------- */ SetProcessingMode((override) ? BootstrapProcessing : InitProcessing); InitPostgres(dbName); LockDisable(true); for (i = 0; i < MAXATTR; i++) { attrtypes[i] = (Form_pg_attribute) NULL; Blanks[i] = ' '; } for (i = 0; i < STRTABLESIZE; ++i) strtable[i] = NULL; for (i = 0; i < HASHTABLESIZE; ++i) hashtable[i] = NULL; /* ---------------- * abort processing resumes here * ---------------- */ pqsignal(SIGHUP, handle_warn); if (sigsetjmp(Warn_restart, 1) != 0) { Warnings++; AbortCurrentTransaction(); } /* ---------------- * process input. * ---------------- */ /* * the sed script boot.sed renamed yyparse to Int_yyparse for the * bootstrap parser to avoid conflicts with the normal SQL parser */ Int_yyparse(); /* clean up processing */ StartTransactionCommand(); cleanup(); /* not reached, here to make compiler happy */ return 0;}/* ---------------------------------------------------------------- * MANUAL BACKEND INTERACTIVE INTERFACE COMMANDS * ---------------------------------------------------------------- *//* ---------------- * boot_openrel * ---------------- */voidboot_openrel(char *relname){ int i; struct typmap **app; Relation rel; HeapScanDesc scan; HeapTuple tup; if (strlen(relname) >= NAMEDATALEN - 1) relname[NAMEDATALEN - 1] = '\0'; if (Typ == (struct typmap **) NULL) { StartPortalAllocMode(DefaultAllocMode, 0); rel = heap_openr(TypeRelationName); scan = heap_beginscan(rel, 0, SnapshotNow, 0, (ScanKey) NULL); i = 0; while (HeapTupleIsValid(tup = heap_getnext(scan, 0))) ++i; heap_endscan(scan); app = Typ = ALLOC(struct typmap *, i + 1); while (i-- > 0) *app++ = ALLOC(struct typmap, 1); *app = (struct typmap *) NULL; scan = heap_beginscan(rel, 0, SnapshotNow, 0, (ScanKey) NULL); app = Typ; while (HeapTupleIsValid(tup = heap_getnext(scan, 0))) { (*app)->am_oid = tup->t_data->t_oid; memmove((char *) &(*app++)->am_typ, (char *) GETSTRUCT(tup), sizeof((*app)->am_typ)); } heap_endscan(scan); heap_close(rel); EndPortalAllocMode(); } if (reldesc != NULL) closerel(NULL); if (!Quiet) printf("Amopen: relation %s. attrsize %d\n", relname ? relname : "(null)", (int) ATTRIBUTE_TUPLE_SIZE); reldesc = heap_openr(relname); Assert(reldesc); numattr = reldesc->rd_rel->relnatts; for (i = 0; i < numattr; i++) { if (attrtypes[i] == NULL) attrtypes[i] = AllocateAttribute(); memmove((char *) attrtypes[i], (char *) reldesc->rd_att->attrs[i], ATTRIBUTE_TUPLE_SIZE); /* Some old pg_attribute tuples might not have attisset. */ /* * If the attname is attisset, don't look for it - it may not be * defined yet. */ if (namestrcmp(&attrtypes[i]->attname, "attisset") == 0) attrtypes[i]->attisset = get_attisset(RelationGetRelid(reldesc), attrtypes[i]->attname.data); else attrtypes[i]->attisset = false; if (DebugMode) { Form_pg_attribute at = attrtypes[i]; printf("create attribute %d name %s len %d num %d type %d\n", i, at->attname.data, at->attlen, at->attnum, at->atttypid ); fflush(stdout); } }}/* ---------------- * closerel * ---------------- */voidcloserel(char *name){ if (name) { if (reldesc) { if (namestrcmp(RelationGetRelationName(reldesc), name) != 0) elog(ERROR, "closerel: close of '%s' when '%s' was expected", name, relname ? relname : "(null)"); } else elog(ERROR, "closerel: close of '%s' before any relation was opened", name); } if (reldesc == NULL) elog(ERROR, "Warning: no opened relation to close.\n"); else { if (!Quiet) printf("Amclose: relation %s.\n", relname ? relname : "(null)"); heap_close(reldesc); reldesc = (Relation) NULL; }}/* ---------------- * DEFINEATTR() * * define a <field,type> pair * if there are n fields in a relation to be created, this routine * will be called n times * ---------------- */voidDefineAttr(char *name, char *type, int attnum){ int attlen; Oid typeoid; if (reldesc != NULL) { fputs("Warning: no open relations allowed with 't' command.\n", stderr); closerel(relname); } typeoid = gettype(type); if (attrtypes[attnum] == (Form_pg_attribute) NULL) attrtypes[attnum] = AllocateAttribute(); if (Typ != (struct typmap **) NULL) { attrtypes[attnum]->atttypid = Ap->am_oid; namestrcpy(&attrtypes[attnum]->attname, name); if (!Quiet) printf("<%s %s> ", attrtypes[attnum]->attname.data, type); attrtypes[attnum]->attnum = 1 + attnum; /* fillatt */ attlen = attrtypes[attnum]->attlen = Ap->am_typ.typlen; attrtypes[attnum]->attbyval = Ap->am_typ.typbyval; attrtypes[attnum]->attalign = Ap->am_typ.typalign; } else { attrtypes[attnum]->atttypid = Procid[typeoid].oid; namestrcpy(&attrtypes[attnum]->attname, name); if (!Quiet) printf("<%s %s> ", attrtypes[attnum]->attname.data, type); attrtypes[attnum]->attnum = 1 + attnum; /* fillatt */ attlen = attrtypes[attnum]->attlen = Procid[typeoid].len; /* * Cheat like mad to fill in these items from the length only. * This only has to work for types used in the system catalogs... */ switch (attlen) { case 1: attrtypes[attnum]->attbyval = true; attrtypes[attnum]->attalign = 'c'; break; case 2: attrtypes[attnum]->attbyval = true; attrtypes[attnum]->attalign = 's'; break; case 4: attrtypes[attnum]->attbyval = true; attrtypes[attnum]->attalign = 'i'; break; default: attrtypes[attnum]->attbyval = false; attrtypes[attnum]->attalign = 'i'; break; } } attrtypes[attnum]->attcacheoff = -1; attrtypes[attnum]->atttypmod = -1;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -