diff options
author | Marc G. Fournier <scrappy@hub.org> | 1996-07-09 06:22:35 +0000 |
---|---|---|
committer | Marc G. Fournier <scrappy@hub.org> | 1996-07-09 06:22:35 +0000 |
commit | d31084e9d1118b25fd16580d9d8c2924b5740dff (patch) | |
tree | 3179e66307d54df9c7b966543550e601eb55e668 /src/backend/bootstrap | |
download | postgresql-PG95-1_01.tar.gz postgresql-PG95-1_01.zip |
Postgres95 1.01 Distribution - Virgin SourcesPG95-1_01
Diffstat (limited to 'src/backend/bootstrap')
-rw-r--r-- | src/backend/bootstrap/Makefile.inc | 63 | ||||
-rw-r--r-- | src/backend/bootstrap/boot.sed | 9 | ||||
-rw-r--r-- | src/backend/bootstrap/bootparse.y | 293 | ||||
-rw-r--r-- | src/backend/bootstrap/bootscanner.l | 108 | ||||
-rw-r--r-- | src/backend/bootstrap/bootstrap.c | 1049 | ||||
-rw-r--r-- | src/backend/bootstrap/bootstrap.h | 78 |
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 */ |