aboutsummaryrefslogtreecommitdiff
path: root/src/backend/bootstrap
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/bootstrap')
-rw-r--r--src/backend/bootstrap/Makefile.inc63
-rw-r--r--src/backend/bootstrap/boot.sed9
-rw-r--r--src/backend/bootstrap/bootparse.y293
-rw-r--r--src/backend/bootstrap/bootscanner.l108
-rw-r--r--src/backend/bootstrap/bootstrap.c1049
-rw-r--r--src/backend/bootstrap/bootstrap.h78
6 files changed, 1600 insertions, 0 deletions
diff --git a/src/backend/bootstrap/Makefile.inc b/src/backend/bootstrap/Makefile.inc
new file mode 100644
index 00000000000..72871343e83
--- /dev/null
+++ b/src/backend/bootstrap/Makefile.inc
@@ -0,0 +1,63 @@
+#-------------------------------------------------------------------------
+#
+# Makefile.inc--
+# Makefile for the bootstrap module
+#
+# Copyright (c) 1994, Regents of the University of California
+#
+#
+# IDENTIFICATION
+# $Header: /cvsroot/pgsql/src/backend/bootstrap/Attic/Makefile.inc,v 1.1.1.1 1996/07/09 06:21:14 scrappy Exp $
+#
+#
+# Another kinda weird Makefile.inc cause we need two
+# scanner/parsers in the backend and most yaccs and lexs
+# don't have the prefix option.
+#
+# sed files are HACK CITY! - redo...
+#
+#-------------------------------------------------------------------------
+
+bootdir= $(CURDIR)/bootstrap
+VPATH:= $(VPATH):$(bootdir)
+
+#BOOTYACCS= bootstrap_tokens.h bootparse.c
+BOOTYACCS= bootparse.c
+
+SRCS_BOOTSTRAP= bootparse.c bootscanner.c bootstrap.c
+
+$(BOOTYACCS): bootparse.y
+ cd $(objdir); \
+ $(YACC) $(YFLAGS) $<; \
+ sed -f $(bootdir)/boot.sed < y.tab.c > bootparse.c; \
+ mv y.tab.h bootstrap_tokens.h; \
+ rm -f y.tab.c
+
+$(objdir)/bootparse.o: bootparse.c
+ $(cc_inobjdir)
+
+
+bootscanner.c: bootscanner.l
+ cd $(objdir); \
+ $(LEX) $<; \
+ sed -f $(bootdir)/boot.sed < lex.yy.c > bootscanner.c; \
+ rm -f lex.yy.c
+
+$(objdir)/bootscanner.o: bootscanner.c
+ $(cc_inobjdir)
+
+
+
+#
+# The following insures that y.tab.h gets made as bootstrap.c
+# includes it
+#
+bootstrap.o: $(BOOTYACCS)
+
+POSTGRES_DEPEND+= $(BOOTYACCS) bootscanner.c
+
+
+CLEANFILES+= bootscanner.c $(BOOTYACCS) y.tab.h y.output
+
+HEADERS+= bootstrap.h
+
diff --git a/src/backend/bootstrap/boot.sed b/src/backend/bootstrap/boot.sed
new file mode 100644
index 00000000000..8ec71025cea
--- /dev/null
+++ b/src/backend/bootstrap/boot.sed
@@ -0,0 +1,9 @@
+#
+# lex.sed - sed rules to remove conflicts between the
+# bootstrap backend interface LEX scanner and the
+# normal backend SQL LEX scanner
+#
+# $Header: /cvsroot/pgsql/src/backend/bootstrap/Attic/boot.sed,v 1.1.1.1 1996/07/09 06:21:14 scrappy Exp $
+#
+s/^yy/Int_yy/g
+s/\([^a-zA-Z0-9_]\)yy/\1Int_yy/g
diff --git a/src/backend/bootstrap/bootparse.y b/src/backend/bootstrap/bootparse.y
new file mode 100644
index 00000000000..0362b302b16
--- /dev/null
+++ b/src/backend/bootstrap/bootparse.y
@@ -0,0 +1,293 @@
+%{
+/*-------------------------------------------------------------------------
+ *
+ * backendparse.y--
+ * yacc parser grammer for the "backend" initialization program.
+ *
+ * Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ * $Header: /cvsroot/pgsql/src/backend/bootstrap/bootparse.y,v 1.1.1.1 1996/07/09 06:21:14 scrappy Exp $
+ *
+ *-------------------------------------------------------------------------
+ */
+#include "access/heapam.h"
+#include "access/tupdesc.h"
+#include "bootstrap/bootstrap.h"
+#include "utils/portal.h"
+#include "storage/smgr.h"
+#include "nodes/pg_list.h"
+#include "catalog/catalog.h"
+#include "catalog/catname.h"
+#include "catalog/heap.h"
+#include "catalog/index.h"
+#include "commands/rename.h"
+#include "commands/defrem.h"
+#include "access/transam.h"
+#include "access/xact.h"
+
+#define DO_START { StartTransactionCommand();\
+ }
+
+#define DO_END { CommitTransactionCommand();\
+ if (!Quiet) { EMITPROMPT; }\
+ fflush(stdout); \
+ }
+
+int num_tuples_read = 0;
+static Oid objectid;
+
+%}
+
+%union {
+ List *list;
+ IndexElem *ielem;
+ char *str;
+ int ival;
+}
+
+%type <list> arg_list
+%type <ielem> index_params index_on
+%type <ival> const ident
+%type <ival> optbootstrap optoideq tuple tuplelist
+
+%token <ival> CONST ID
+%token OPEN XCLOSE XCREATE INSERT_TUPLE
+%token STRING XDEFINE
+%token XDECLARE INDEX ON USING XBUILD INDICES
+%token COMMA EQUALS LPAREN RPAREN
+%token OBJ_ID XBOOTSTRAP NULLVAL
+%start TopLevel
+
+%nonassoc low
+%nonassoc high
+
+%%
+
+TopLevel:
+ Queries
+ |
+ ;
+
+Queries:
+ Query
+ | Queries Query
+ ;
+
+Query :
+ OpenStmt
+ | CloseStmt
+ | CreateStmt
+ | InsertStmt
+ | DeclareIndexStmt
+ | BuildIndsStmt
+ ;
+
+OpenStmt:
+ OPEN ident
+ {
+ DO_START;
+ boot_openrel(LexIDStr($2));
+ DO_END;
+ }
+ ;
+
+CloseStmt:
+ XCLOSE ident %prec low
+ {
+ DO_START;
+ closerel(LexIDStr($2));
+ DO_END;
+ }
+ | XCLOSE %prec high
+ {
+ DO_START;
+ closerel(NULL);
+ DO_END;
+ }
+ ;
+
+CreateStmt:
+ XCREATE optbootstrap ident LPAREN
+ {
+ DO_START;
+ numattr=(int)0;
+ }
+ typelist
+ {
+ if (!Quiet) putchar('\n');
+ DO_END;
+ }
+ RPAREN
+ {
+ DO_START;
+
+ if ($2) {
+ extern Relation reldesc;
+ TupleDesc tupdesc;
+
+ if (reldesc) {
+ puts("create bootstrap: Warning, open relation");
+ puts("exists, closing first");
+ closerel(NULL);
+ }
+ if (DebugMode)
+ puts("creating bootstrap relation");
+ tupdesc = CreateTupleDesc(numattr,attrtypes);
+ reldesc = heap_creatr(LexIDStr($3),
+ DEFAULT_SMGR,
+ tupdesc);
+ if (DebugMode)
+ puts("bootstrap relation created ok");
+ } else {
+ Oid id;
+ TupleDesc tupdesc;
+ /* extern Oid heap_create();*/
+
+ tupdesc = CreateTupleDesc(numattr,attrtypes);
+ id = heap_create(LexIDStr($3),
+ NULL,
+ 'n',
+ DEFAULT_SMGR,
+ tupdesc);
+ if (!Quiet)
+ printf("CREATED relation %s with OID %d\n",
+ LexIDStr($3), id);
+ }
+ DO_END;
+ if (DebugMode)
+ puts("Commit End");
+ }
+ ;
+
+InsertStmt:
+ INSERT_TUPLE optoideq
+ {
+ DO_START;
+ if (DebugMode)
+ printf("tuple %d<", $2);
+ num_tuples_read = 0;
+ }
+ LPAREN tuplelist RPAREN
+ {
+ if (num_tuples_read != numattr)
+ elog(WARN,"incorrect number of values for tuple");
+ if (reldesc == (Relation)NULL) {
+ elog(WARN,"must OPEN RELATION before INSERT\n");
+ err();
+ }
+ if (DebugMode)
+ puts("Insert Begin");
+ objectid = $2;
+ InsertOneTuple(objectid);
+ if (DebugMode)
+ puts("Insert End");
+ if (!Quiet) { putchar('\n'); }
+ DO_END;
+ if (DebugMode)
+ puts("Transaction End");
+ }
+ ;
+
+DeclareIndexStmt:
+ XDECLARE INDEX ident ON ident USING ident LPAREN index_params RPAREN
+ {
+ List *params;
+
+ DO_START;
+
+ params = lappend(NIL, (List*)$9);
+ DefineIndex(LexIDStr($5),
+ LexIDStr($3),
+ LexIDStr($7),
+ params, NIL, 0, NIL);
+ DO_END;
+ }
+ ;
+
+BuildIndsStmt:
+ XBUILD INDICES { build_indices(); }
+
+index_params:
+ index_on ident
+ {
+ IndexElem *n = (IndexElem*)$1;
+ n->class = LexIDStr($2);
+ $$ = n;
+ }
+
+index_on:
+ ident
+ {
+ IndexElem *n = makeNode(IndexElem);
+ n->name = LexIDStr($1);
+ $$ = n;
+ }
+ | ident LPAREN arg_list RPAREN
+ {
+ IndexElem *n = makeNode(IndexElem);
+ n->name = LexIDStr($1);
+ n->args = (List*)$3;
+ $$ = n;
+ }
+
+arg_list:
+ ident
+ {
+ $$ = lappend(NIL, makeString(LexIDStr($1)));
+ }
+ | arg_list COMMA ident
+ {
+ $$ = lappend((List*)$1, makeString(LexIDStr($3)));
+ }
+
+optbootstrap:
+ XBOOTSTRAP { $$ = 1; }
+ | { $$ = 0; }
+ ;
+
+typelist:
+ typething
+ | typelist COMMA typething
+ ;
+
+typething:
+ ident EQUALS ident
+ {
+ if(++numattr > MAXATTR)
+ elog(FATAL,"Too many attributes\n");
+ DefineAttr(LexIDStr($1),LexIDStr($3),numattr-1);
+ if (DebugMode)
+ printf("\n");
+ }
+ ;
+
+optoideq:
+ OBJ_ID EQUALS ident { $$ = atol(LexIDStr($3)); }
+ | { extern Oid newoid(); $$ = newoid(); }
+ ;
+
+tuplelist:
+ tuple
+ | tuplelist tuple
+ | tuplelist COMMA tuple
+ ;
+
+tuple:
+ ident {InsertOneValue(objectid, LexIDStr($1), num_tuples_read++); }
+ | const {InsertOneValue(objectid, LexIDStr($1), num_tuples_read++); }
+ | NULLVAL
+ { InsertOneNull(num_tuples_read++); }
+ ;
+
+const :
+ CONST { $$=yylval.ival; }
+ ;
+
+ident :
+ ID { $$=yylval.ival; }
+ ;
+%%
+
+
diff --git a/src/backend/bootstrap/bootscanner.l b/src/backend/bootstrap/bootscanner.l
new file mode 100644
index 00000000000..9dbd92cb93a
--- /dev/null
+++ b/src/backend/bootstrap/bootscanner.l
@@ -0,0 +1,108 @@
+%{
+/*-------------------------------------------------------------------------
+ *
+ * bootscanner.lex--
+ * a lexical scanner for the bootstrap parser
+ *
+ * Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ * $Header: /cvsroot/pgsql/src/backend/bootstrap/bootscanner.l,v 1.1.1.1 1996/07/09 06:21:14 scrappy Exp $
+ *
+ *-------------------------------------------------------------------------
+ */
+#include "bootstrap/bootstrap.h"
+#include "utils/portal.h"
+#include "access/xact.h"
+#include "parser/scansup.h"
+
+#include "bootstrap_tokens.h"
+
+/* some versions of lex define this as a macro */
+#if defined(yywrap)
+#undef yywrap
+#endif /* yywrap */
+
+YYSTYPE yylval;
+int yyline; /* keep track of the line number for error reporting */
+
+%}
+
+D [0-9]
+oct \\{D}{D}{D}
+Exp [Ee][-+]?{D}+
+id ([A-Za-z0-9_]|{oct}|\-)+
+sid \"([^\"])*\"
+arrayid [A-Za-z0-9_]+\[{D}*\]
+
+%%
+
+open { return(OPEN); }
+
+close { return(XCLOSE); }
+
+create { return(XCREATE); }
+
+OID { return(OBJ_ID); }
+bootstrap { return(XBOOTSTRAP); }
+_null_ { return(NULLVAL); }
+
+insert { return(INSERT_TUPLE); }
+
+"," { return(COMMA); }
+"=" { return(EQUALS); }
+"(" { return(LPAREN); }
+")" { return(RPAREN); }
+
+[\n] { yyline++; }
+[\t] ;
+" " ;
+
+^\#[^\n]* ; /* drop everything after "#" for comments */
+
+
+"declare" { return(XDECLARE); }
+"build" { return(XBUILD); }
+"indices" { return(INDICES); }
+"index" { return(INDEX); }
+"on" { return(ON); }
+"using" { return(USING); }
+{arrayid} {
+ yylval.ival = EnterString(MapArrayTypeName((char*)yytext));
+ return(ID);
+ }
+{id} {
+ yylval.ival = EnterString(scanstr((char*)yytext));
+ return(ID);
+ }
+{sid} {
+ yylval.ival = EnterString(scanstr((char*)yytext));
+ return(ID);
+ }
+
+(-)?{D}+"."{D}*({Exp})? |
+(-)?{D}*"."{D}+({Exp})? |
+(-)?{D}+{Exp} {
+ yylval.ival = EnterString((char*)yytext);
+ return(CONST);
+ }
+
+. {
+ printf("syntax error %d : -> %s\n", yyline, yytext);
+ }
+
+
+
+%%
+
+yywrap()
+{
+ return 1;
+}
+
+yyerror(str)
+ char *str;
+{
+ fprintf(stderr,"\tsyntax error %d : %s",yyline, str);
+}
diff --git a/src/backend/bootstrap/bootstrap.c b/src/backend/bootstrap/bootstrap.c
new file mode 100644
index 00000000000..e2df755109c
--- /dev/null
+++ b/src/backend/bootstrap/bootstrap.c
@@ -0,0 +1,1049 @@
+/*-------------------------------------------------------------------------
+ *
+ * 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: /cvsroot/pgsql/src/backend/bootstrap/bootstrap.c,v 1.1.1.1 1996/07/09 06:21:14 scrappy Exp $
+ *
+ *-------------------------------------------------------------------------
+ */
+#include <string.h>
+#include <unistd.h>
+#include "libpq/pqsignal.h" /* substitute for <signal.h> */
+#if defined(PORTNAME_linux)
+#ifndef __USE_POSIX
+#define __USE_POSIX
+#endif
+#endif /* defined(PORTNAME_linux) */
+#include <setjmp.h>
+
+#define BOOTSTRAP_INCLUDE /* mask out stuff in tcop/tcopprot.h */
+
+#include "bootstrap/bootstrap.h"
+#include "postgres.h"
+#include "miscadmin.h"
+#include "tcop/tcopprot.h"
+
+#include "access/heapam.h"
+#include "access/genam.h"
+#include "access/tupdesc.h"
+#include "utils/builtins.h"
+#include "utils/rel.h"
+#include "utils/tqual.h"
+#include "utils/lsyscache.h"
+#include "access/xact.h"
+#include "utils/exc.h" /* for ExcAbort and <setjmp.h> */
+#include "fmgr.h"
+#include "utils/palloc.h"
+#include "utils/mcxt.h"
+#include "storage/smgr.h"
+#include "commands/defrem.h"
+
+#include "catalog/pg_type.h"
+#include "catalog/catname.h"
+#include "catalog/indexing.h"
+#include "catalog/index.h"
+
+#define ALLOC(t, c) (t *)calloc((unsigned)(c), sizeof(t))
+#define FIRST_TYPE_OID 16 /* OID of the first type */
+
+/* ----------------
+ * 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 12167
+
+char *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 },
+ { "char16", 20, 0, 16, F_CHAR16IN, F_CHAR16OUT},
+/* { "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;
+ TypeTupleFormData am_typ;
+};
+
+static struct typmap **Typ = (struct typmap **)NULL;
+static struct typmap *Ap = (struct typmap *)NULL;
+
+static int Warnings = 0;
+static char Blanks[MAXATTR];
+
+Relation reldesc; /* current relation descriptor */
+static char *relname; /* current relation name */
+
+AttributeTupleForm attrtypes[MAXATTR]; /* points to attribute info */
+static char *values[MAXATTR]; /* cooresponding attribute values */
+int numattr; /* number of attributes for cur. rel */
+
+#if defined(WIN32) || defined(PORTNAME_next)
+static jmp_buf Warn_restart;
+#define sigsetjmp(x,y) setjmp(x)
+#define siglongjmp longjmp
+#else
+static sigjmp_buf Warn_restart;
+#endif
+
+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
+ * ----------------
+ */
+#if !defined(PORTNAME_bsdi)
+void err()
+{
+ Warnings++;
+ cleanup();
+}
+#endif
+
+/* usage:
+ usage help for the bootstrap backen
+*/
+static void
+usage()
+{
+ fprintf(stderr,"Usage: postgres -boot [-d] [-C] [-O] [-Q] [-P portno] [dbName]\n");
+ fprintf(stderr," d: debug mode\n");
+ fprintf(stderr," C: disable version checking\n");
+ fprintf(stderr," O: set BootstrapProcessing mode\n");
+ fprintf(stderr," P portno: specify port number\n");
+
+ exitpg(1);
+}
+
+/* ----------------------------------------------------------------
+ * BootstrapMain
+ * 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.
+ * they are 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
+BootstrapMain(int argc, char *argv[])
+{
+ 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
+ * ----------------
+ */
+ signal(SIGINT, (sig_func) die);
+#ifndef WIN32
+ signal(SIGHUP, (sig_func) die);
+ signal(SIGTERM, (sig_func) die);
+#endif /* WIN32 */
+
+ /* --------------------
+ * initialize globals
+ * -------------------
+ */
+
+ InitGlobals();
+
+ /* ----------------
+ * process command arguments
+ * ----------------
+ */
+ Quiet = 0;
+ Noversion = 0;
+ dbName = NULL;
+
+ while ((flag = getopt(argc, argv, "dCOQP")) != EOF) {
+ switch (flag) {
+ case 'd':
+ DebugMode = 1; /* print out debuggin info while parsing */
+ break;
+ case 'C':
+ Noversion = 1;
+ break;
+ case 'O':
+ override = true;
+ break;
+ case 'Q':
+ Quiet = 1;
+ 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 (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);
+ exitpg(1);
+ }
+ }
+
+ /* ----------------
+ * initialize input fd
+ * ----------------
+ */
+ if (IsUnderPostmaster == true && portFd < 0) {
+ fputs("backend: failed, no -P option with -postmaster opt.\n", stderr);
+ exitpg(1);
+ }
+
+#ifdef WIN32
+ _nt_init();
+ _nt_attach();
+#endif /* WIN32 */
+
+
+ /* ----------------
+ * backend initialization
+ * ----------------
+ */
+ SetProcessingMode((override) ? BootstrapProcessing : InitProcessing);
+ InitPostgres(dbName);
+ LockDisable(true);
+
+ for (i = 0 ; i < MAXATTR; i++) {
+ attrtypes[i]=(AttributeTupleForm )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 - What to do in WIN32?
+ * ----------------
+ */
+#ifndef WIN32
+ signal(SIGHUP, handle_warn);
+
+ if (sigsetjmp(Warn_restart, 1) != 0) {
+#else
+ if (setjmp(Warn_restart) != 0) {
+#endif /* WIN32 */
+ 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
+ * ----------------
+ */
+void
+boot_openrel(char *relname)
+{
+ int i;
+ struct typmap **app;
+ Relation rdesc;
+ HeapScanDesc sdesc;
+ HeapTuple tup;
+
+ if (strlen(relname) > 15)
+ relname[15] ='\000';
+
+ if (Typ == (struct typmap **)NULL) {
+ StartPortalAllocMode(DefaultAllocMode, 0);
+ rdesc = heap_openr(TypeRelationName);
+ sdesc = heap_beginscan(rdesc, 0, NowTimeQual, 0, (ScanKey)NULL);
+ for (i=0; PointerIsValid(tup=heap_getnext(sdesc,0,(Buffer *)NULL)); ++i);
+ heap_endscan(sdesc);
+ app = Typ = ALLOC(struct typmap *, i + 1);
+ while (i-- > 0)
+ *app++ = ALLOC(struct typmap, 1);
+ *app = (struct typmap *)NULL;
+ sdesc = heap_beginscan(rdesc, 0, NowTimeQual, 0, (ScanKey)NULL);
+ app = Typ;
+ while (PointerIsValid(tup = heap_getnext(sdesc, 0, (Buffer *)NULL))) {
+ (*app)->am_oid = tup->t_oid;
+ memmove((char *)&(*app++)->am_typ,
+ (char *)GETSTRUCT(tup),
+ sizeof ((*app)->am_typ));
+ }
+ heap_endscan(sdesc);
+ heap_close(rdesc);
+ EndPortalAllocMode();
+ }
+
+ if (reldesc != NULL) {
+ closerel(NULL);
+ }
+
+ if (!Quiet)
+ printf("Amopen: relation %s. attrsize %d\n", relname,
+ 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(reldesc->rd_id,
+ attrtypes[i]->attname.data);
+ else
+ attrtypes[i]->attisset = false;
+
+ if (DebugMode) {
+ AttributeTupleForm at = attrtypes[i];
+ printf("create attribute %d name %.*s len %d num %d type %d\n",
+ i, NAMEDATALEN, at->attname.data, at->attlen, at->attnum,
+ at->atttypid
+ );
+ fflush(stdout);
+ }
+ }
+}
+
+/* ----------------
+ * closerel
+ * ----------------
+ */
+void
+closerel(char *name)
+{
+ if (name) {
+ if (reldesc) {
+ if (namestrcmp(RelationGetRelationName(reldesc), name) != 0)
+ elog(WARN,"closerel: close of '%s' when '%s' was expected",
+ name, relname);
+ } else
+ elog(WARN,"closerel: close of '%s' before any relation was opened",
+ name);
+
+ }
+
+ if (reldesc == NULL) {
+ elog(WARN,"Warning: no opened relation to close.\n");
+ } else {
+ if (!Quiet) printf("Amclose: relation %s.\n", relname);
+ 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
+ * ----------------
+ */
+void
+DefineAttr(char *name, char *type, int attnum)
+{
+ int attlen;
+ int t;
+
+ if (reldesc != NULL) {
+ fputs("Warning: no open relations allowed with 't' command.\n",stderr);
+ closerel(relname);
+ }
+
+ t = gettype(type);
+ if (attrtypes[attnum] == (AttributeTupleForm )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> ", NAMEDATALEN,
+ 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;
+ } else {
+ attrtypes[attnum]->atttypid = Procid[t].oid;
+ namestrcpy(&attrtypes[attnum]->attname,name);
+ if (!Quiet) printf("<%.*s %s> ", NAMEDATALEN,
+ attrtypes[attnum]->attname.data, type);
+ attrtypes[attnum]->attnum = 1 + attnum; /* fillatt */
+ attlen = attrtypes[attnum]->attlen = Procid[t].len;
+ attrtypes[attnum]->attbyval = (attlen==1) || (attlen==2)||(attlen==4);
+ }
+}
+
+
+/* ----------------
+ * InsertOneTuple
+ * assumes that 'oid' will not be zero.
+ * ----------------
+ */
+void
+InsertOneTuple(Oid objectid)
+{
+ HeapTuple tuple;
+ TupleDesc tupDesc;
+
+ int i;
+
+ if (DebugMode) {
+ printf("InsertOneTuple oid %d, %d attrs\n", objectid, numattr);
+ fflush(stdout);
+ }
+
+ tupDesc = CreateTupleDesc(numattr,attrtypes);
+ tuple = heap_formtuple(tupDesc,(Datum*)values,Blanks);
+ pfree(tupDesc); /* just free's tupDesc, not the attrtypes */
+
+ if(objectid !=(Oid)0) {
+ tuple->t_oid=objectid;
+ }
+ heap_insert(reldesc, tuple);
+ pfree(tuple);
+ if (DebugMode) {
+ printf("End InsertOneTuple, objectid=%d\n", objectid);
+ fflush(stdout);
+ }
+ /*
+ * Reset blanks for next tuple
+ */
+ for (i = 0; i<numattr; i++)
+ Blanks[i] = ' ';
+}
+
+/* ----------------
+ * InsertOneValue
+ * ----------------
+ */
+void
+InsertOneValue(Oid objectid, char *value, int i)
+{
+ int typeindex;
+ char *prt;
+ struct typmap **app;
+
+ if (DebugMode)
+ printf("Inserting value: '%s'\n", value);
+ if (i < 0 || i >= MAXATTR) {
+ printf("i out of range: %d\n", i);
+ Assert(0);
+ }
+
+ if (Typ != (struct typmap **)NULL) {
+ struct typmap *ap;
+ if (DebugMode)
+ puts("Typ != NULL");
+ app = Typ;
+ while (*app && (*app)->am_oid != reldesc->rd_att->attrs[i]->atttypid)
+ ++app;
+ ap = *app;
+ if (ap == NULL) {
+ printf("Unable to find atttypid in Typ list! %d\n",
+ reldesc->rd_att->attrs[i]->atttypid
+ );
+ Assert(0);
+ }
+ values[i] = fmgr(ap->am_typ.typinput,
+ value,
+ ap->am_typ.typelem,
+ -1); /* shouldn't have char() or varchar() types
+ during boostrapping but just to be safe */
+ prt = fmgr(ap->am_typ.typoutput, values[i],
+ ap->am_typ.typelem);
+ if (!Quiet) printf("%s ", prt);
+ pfree(prt);
+ } else {
+ typeindex = attrtypes[i]->atttypid - FIRST_TYPE_OID;
+ if (DebugMode)
+ printf("Typ == NULL, typeindex = %d idx = %d\n", typeindex, i);
+ values[i] = fmgr(Procid[typeindex].inproc, value,
+ Procid[typeindex].elem, -1);
+ prt = fmgr(Procid[typeindex].outproc, values[i],
+ Procid[typeindex].elem);
+ if (!Quiet) printf("%s ", prt);
+ pfree(prt);
+ }
+ if (DebugMode) {
+ puts("End InsertValue");
+ fflush(stdout);
+ }
+}
+
+/* ----------------
+ * InsertOneNull
+ * ----------------
+ */
+void
+InsertOneNull(int i)
+{
+ if (DebugMode)
+ printf("Inserting null\n");
+ if (i < 0 || i >= MAXATTR) {
+ elog(FATAL, "i out of range (too many attrs): %d\n", i);
+ }
+ values[i] = (char *)NULL;
+ Blanks[i] = 'n';
+}
+
+#define MORE_THAN_THE_NUMBER_OF_CATALOGS 256
+
+bool
+BootstrapAlreadySeen(Oid id)
+{
+ static Oid seenArray[MORE_THAN_THE_NUMBER_OF_CATALOGS];
+ static int nseen = 0;
+ bool seenthis;
+ int i;
+
+ seenthis = false;
+
+ for (i=0; i < nseen; i++) {
+ if (seenArray[i] == id) {
+ seenthis = true;
+ break;
+ }
+ }
+ if (!seenthis) {
+ seenArray[nseen] = id;
+ nseen++;
+ }
+ return (seenthis);
+}
+
+/* ----------------
+ * cleanup
+ * ----------------
+ */
+void
+cleanup()
+{
+ static int beenhere = 0;
+
+ if (!beenhere)
+ beenhere = 1;
+ else {
+ elog(FATAL,"Memory manager fault: cleanup called twice.\n", stderr);
+ exitpg(1);
+ }
+ if (reldesc != (Relation)NULL) {
+ heap_close(reldesc);
+ }
+ CommitTransactionCommand();
+ exitpg(Warnings);
+}
+
+/* ----------------
+ * gettype
+ * ----------------
+ */
+int
+gettype(char *type)
+{
+ int i;
+ Relation rdesc;
+ HeapScanDesc sdesc;
+ HeapTuple tup;
+ struct typmap **app;
+
+ if (Typ != (struct typmap **)NULL) {
+ for (app = Typ; *app != (struct typmap *)NULL; app++) {
+ if (strncmp((*app)->am_typ.typname.data, type, NAMEDATALEN) == 0) {
+ Ap = *app;
+ return((*app)->am_oid);
+ }
+ }
+ } else {
+ for (i = 0; i <= n_types; i++) {
+ if (strncmp(type, Procid[i].name, NAMEDATALEN) == 0) {
+ return(i);
+ }
+ }
+ if (DebugMode)
+ printf("bootstrap.c: External Type: %.*s\n", NAMEDATALEN, type);
+ rdesc = heap_openr(TypeRelationName);
+ sdesc = heap_beginscan(rdesc, 0, NowTimeQual, 0, (ScanKey)NULL);
+ i = 0;
+ while (PointerIsValid(tup = heap_getnext(sdesc, 0, (Buffer *)NULL)))
+ ++i;
+ heap_endscan(sdesc);
+ app = Typ = ALLOC(struct typmap *, i + 1);
+ while (i-- > 0)
+ *app++ = ALLOC(struct typmap, 1);
+ *app = (struct typmap *)NULL;
+ sdesc = heap_beginscan(rdesc, 0, NowTimeQual, 0, (ScanKey)NULL);
+ app = Typ;
+ while (PointerIsValid(tup = heap_getnext(sdesc, 0, (Buffer *)NULL))) {
+ (*app)->am_oid = tup->t_oid;
+ memmove((char *)&(*app++)->am_typ,
+ (char *)GETSTRUCT(tup),
+ sizeof ((*app)->am_typ));
+ }
+ heap_endscan(sdesc);
+ heap_close(rdesc);
+ return(gettype(type));
+ }
+ elog(WARN, "Error: unknown type '%s'.\n", type);
+ err();
+ /* not reached, here to make compiler happy */
+ return 0;
+}
+
+/* ----------------
+ * AllocateAttribute
+ * ----------------
+ */
+AttributeTupleForm /* XXX */
+AllocateAttribute()
+{
+ AttributeTupleForm attribute =
+ (AttributeTupleForm)malloc(ATTRIBUTE_TUPLE_SIZE);
+
+ if (!PointerIsValid(attribute)) {
+ elog(FATAL, "AllocateAttribute: malloc failed");
+ }
+ memset(attribute, 0, ATTRIBUTE_TUPLE_SIZE);
+
+ return (attribute);
+}
+
+/* ----------------
+ * MapArrayTypeName
+ * XXX arrays of "basetype" are always "_basetype".
+ * this is an evil hack inherited from rel. 3.1.
+ * XXX array dimension is thrown away because we
+ * don't support fixed-dimension arrays. again,
+ * sickness from 3.1.
+ *
+ * the string passed in must have a '[' character in it
+ *
+ * the string returned is a pointer to static storage and should NOT
+ * be freed by the CALLER.
+ * ----------------
+ */
+char*
+MapArrayTypeName(char *s)
+{
+ int i, j;
+ static char newStr[NAMEDATALEN]; /* array type names < NAMEDATALEN long */
+
+ if (s == NULL || s[0] == '\0')
+ return s;
+
+ j = 1;
+ newStr[0] = '_';
+ for (i=0; i<NAMEDATALEN-1 && s[i] != '['; i++, j++)
+ newStr[j] = s[i];
+
+ newStr[j] = '\0';
+
+ return newStr;
+}
+
+/* ----------------
+ * EnterString
+ * returns the string table position of the identifier
+ * passed to it. We add it to the table if we can't find it.
+ * ----------------
+ */
+int
+EnterString (char *str)
+{
+ hashnode *node;
+ int len;
+
+ len= strlen(str);
+
+ node = FindStr(str, len, 0);
+ if (node) {
+ return (node->strnum);
+ } else {
+ node = AddStr(str, len, 0);
+ return (node->strnum);
+ }
+}
+
+/* ----------------
+ * LexIDStr
+ * when given an idnum into the 'string-table' return the string
+ * associated with the idnum
+ * ----------------
+ */
+char *
+LexIDStr(int ident_num)
+{
+ return(strtable[ident_num]);
+}
+
+
+/* ----------------
+ * CompHash
+ *
+ * Compute a hash function for a given string. We look at the first,
+ * the last, and the middle character of a string to try to get spread
+ * the strings out. The function is rather arbitrary, except that we
+ * are mod'ing by a prime number.
+ * ----------------
+ */
+int
+CompHash(char *str, int len)
+{
+ register int result;
+
+ result =(NUM * str[0] + NUMSQR * str[len-1] + NUMCUBE * str[(len-1)/2]);
+
+ return (result % HASHTABLESIZE);
+
+}
+
+/* ----------------
+ * FindStr
+ *
+ * This routine looks for the specified string in the hash
+ * table. It returns a pointer to the hash node found,
+ * or NULL if the string is not in the table.
+ * ----------------
+ */
+hashnode *
+FindStr(char *str, int length, hashnode *mderef)
+{
+ hashnode *node;
+ node = hashtable [CompHash (str, length)];
+ while (node != NULL) {
+ /*
+ * We must differentiate between string constants that
+ * might have the same value as a identifier
+ * and the identifier itself.
+ */
+ if (!strcmp(str, strtable[node->strnum])) {
+ return(node); /* no need to check */
+ } else {
+ node = node->next;
+ }
+ }
+ /* Couldn't find it in the list */
+ return (NULL);
+}
+
+/* ----------------
+ * AddStr
+ *
+ * This function adds the specified string, along with its associated
+ * data, to the hash table and the string table. We return the node
+ * so that the calling routine can find out the unique id that AddStr
+ * has assigned to this string.
+ * ----------------
+ */
+hashnode *
+AddStr(char *str, int strlength, int mderef)
+{
+ hashnode *temp, *trail, *newnode;
+ int hashresult;
+ int len;
+
+ if (++strtable_end == STRTABLESIZE) {
+ /* Error, string table overflow, so we Punt */
+ elog(FATAL,
+ "There are too many string constants and identifiers for the compiler to handle.");
+
+
+ }
+
+ /*
+ * Some of the utilites (eg, define type, create relation) assume
+ * that the string they're passed is a NAMEDATALEN. We get array bound
+ * read violations from purify if we don't allocate at least NAMEDATALEN
+ * bytes for strings of this sort. Because we're lazy, we allocate
+ * at least NAMEDATALEN bytes all the time.
+ */
+
+ if ((len = strlength + 1) < NAMEDATALEN)
+ len = NAMEDATALEN;
+
+ strtable [strtable_end] = malloc((unsigned) len);
+ strcpy (strtable[strtable_end], str);
+
+ /* Now put a node in the hash table */
+
+ newnode = (hashnode*)malloc(sizeof(hashnode)*1);
+ newnode->strnum = strtable_end;
+ newnode->next = NULL;
+
+ /* Find out where it goes */
+
+ hashresult = CompHash (str, strlength);
+ if (hashtable [hashresult] == NULL) {
+ hashtable [hashresult] = newnode;
+ } else { /* There is something in the list */
+ trail = hashtable [hashresult];
+ temp = trail->next;
+ while (temp != NULL) {
+ trail = temp;
+ temp = temp->next;
+ }
+ trail->next = newnode;
+ }
+ return (newnode);
+}
+
+
+
+/*
+ * index_register() -- record an index that has been set up for building
+ * later.
+ *
+ * At bootstrap time, we define a bunch of indices on system catalogs.
+ * We postpone actually building the indices until just before we're
+ * finished with initialization, however. This is because more classes
+ * and indices may be defined, and we want to be sure that all of them
+ * are present in the index.
+ */
+void
+index_register(char *heap,
+ char *ind,
+ int natts,
+ AttrNumber *attnos,
+ uint16 nparams,
+ Datum *params,
+ FuncIndexInfo *finfo,
+ PredInfo *predInfo)
+{
+ Datum *v;
+ IndexList *newind;
+ int len;
+ MemoryContext oldcxt;
+
+ /*
+ * XXX mao 10/31/92 -- don't gc index reldescs, associated info
+ * at bootstrap time. we'll declare the indices now, but want to
+ * create them later.
+ */
+
+ if (nogc == (GlobalMemory) NULL)
+ nogc = CreateGlobalMemory("BootstrapNoGC");
+
+ oldcxt = MemoryContextSwitchTo((MemoryContext) nogc);
+
+ newind = (IndexList *) palloc(sizeof(IndexList));
+ newind->il_heap = pstrdup(heap);
+ newind->il_ind = pstrdup(ind);
+ newind->il_natts = natts;
+
+ if (PointerIsValid(finfo))
+ len = FIgetnArgs(finfo) * sizeof(AttrNumber);
+ else
+ len = natts * sizeof(AttrNumber);
+
+ newind->il_attnos = (AttrNumber *) palloc(len);
+ memmove(newind->il_attnos, attnos, len);
+
+ if ((newind->il_nparams = nparams) > 0) {
+ v = newind->il_params = (Datum *) palloc(2 * nparams * sizeof(Datum));
+ nparams *= 2;
+ while (nparams-- > 0) {
+ *v = (Datum) palloc(strlen((char *)(*params)) + 1);
+ strcpy((char *) *v++, (char *) *params++);
+ }
+ } else {
+ newind->il_params = (Datum *) NULL;
+ }
+
+ if (finfo != (FuncIndexInfo *) NULL) {
+ newind->il_finfo = (FuncIndexInfo *) palloc(sizeof(FuncIndexInfo));
+ memmove(newind->il_finfo, finfo, sizeof(FuncIndexInfo));
+ } else {
+ newind->il_finfo = (FuncIndexInfo *) NULL;
+ }
+
+ if (predInfo != NULL) {
+ newind->il_predInfo = (PredInfo*)palloc(sizeof(PredInfo));
+ newind->il_predInfo->pred = predInfo->pred;
+ newind->il_predInfo->oldPred = predInfo->oldPred;
+ } else {
+ newind->il_predInfo = NULL;
+ }
+
+ newind->il_next = ILHead;
+
+ ILHead = newind;
+
+ (void) MemoryContextSwitchTo(oldcxt);
+}
+
+void
+build_indices()
+{
+ Relation heap;
+ Relation ind;
+
+ for ( ; ILHead != (IndexList *) NULL; ILHead = ILHead->il_next) {
+ heap = heap_openr(ILHead->il_heap);
+ ind = index_openr(ILHead->il_ind);
+ index_build(heap, ind, ILHead->il_natts, ILHead->il_attnos,
+ ILHead->il_nparams, ILHead->il_params, ILHead->il_finfo,
+ ILHead->il_predInfo);
+
+ /*
+ * All of the rest of this routine is needed only because in bootstrap
+ * processing we don't increment xact id's. The normal DefineIndex
+ * code replaces a pg_class tuple with updated info including the
+ * relhasindex flag (which we need to have updated). Unfortunately,
+ * there are always two indices defined on each catalog causing us to
+ * update the same pg_class tuple twice for each catalog getting an
+ * index during bootstrap resulting in the ghost tuple problem (see
+ * heap_replace). To get around this we change the relhasindex
+ * field ourselves in this routine keeping track of what catalogs we
+ * already changed so that we don't modify those tuples twice. The
+ * normal mechanism for updating pg_class is disabled during bootstrap.
+ *
+ * -mer
+ */
+ heap = heap_openr(ILHead->il_heap);
+
+ if (!BootstrapAlreadySeen(heap->rd_id))
+ UpdateStats(heap->rd_id, 0, true);
+ }
+}
+
diff --git a/src/backend/bootstrap/bootstrap.h b/src/backend/bootstrap/bootstrap.h
new file mode 100644
index 00000000000..8ade7664f1f
--- /dev/null
+++ b/src/backend/bootstrap/bootstrap.h
@@ -0,0 +1,78 @@
+/*-------------------------------------------------------------------------
+ *
+ * bootstrap.h--
+ * include file for the bootstrapping code
+ *
+ *
+ * Copyright (c) 1994, Regents of the University of California
+ *
+ * $Id: bootstrap.h,v 1.1.1.1 1996/07/09 06:21:14 scrappy Exp $
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef BOOTSTRAP_H
+#define BOOTSTRAP_H
+
+#include <sys/file.h>
+#include <stdio.h>
+#include <string.h>
+#include <signal.h>
+#include <ctype.h>
+
+#include "access/htup.h"
+#include "access/itup.h"
+#include "access/relscan.h"
+#include "access/skey.h"
+#include "utils/tqual.h"
+#include "storage/buf.h"
+#include "storage/bufmgr.h" /* for BufferManagerFlush */
+#include "utils/portal.h"
+#include "utils/elog.h"
+#include "utils/rel.h"
+
+#define MAXATTR 40 /* max. number of attributes in a relation */
+
+typedef struct hashnode {
+ int strnum; /* Index into string table */
+ struct hashnode *next;
+} hashnode;
+
+#define EMITPROMPT printf("> ")
+
+extern Relation reldesc;
+extern AttributeTupleForm attrtypes[MAXATTR];
+extern int numattr;
+extern int DebugMode;
+
+extern int BootstrapMain(int ac, char *av[]);
+extern void index_register(char *heap,
+ char *ind,
+ int natts,
+ AttrNumber *attnos,
+ uint16 nparams,
+ Datum *params,
+ FuncIndexInfo *finfo,
+ PredInfo *predInfo);
+
+extern void err(void);
+extern void InsertOneTuple(Oid objectid);
+extern void closerel(char *name);
+extern void boot_openrel(char *name);
+extern char *LexIDStr(int ident_num);
+
+extern void DefineAttr(char *name, char *type, int attnum);
+extern void InsertOneValue(Oid objectid, char *value, int i);
+extern void InsertOneNull(int i);
+extern bool BootstrapAlreadySeen(Oid id);
+extern void cleanup(void);
+extern int gettype(char *type);
+extern AttributeTupleForm AllocateAttribute(void);
+extern char* MapArrayTypeName(char *s);
+extern char* CleanUpStr(char *s);
+extern int EnterString (char *str);
+extern int CompHash (char *str, int len);
+extern hashnode *FindStr (char *str, int length, hashnode *mderef);
+extern hashnode *AddStr(char *str, int strlength, int mderef);
+extern void build_indices(void);
+
+#endif /* BOOTSTRAP_H */