aboutsummaryrefslogtreecommitdiff
path: root/src/backend/bootstrap/bootstrap.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/bootstrap/bootstrap.c')
-rw-r--r--src/backend/bootstrap/bootstrap.c1049
1 files changed, 1049 insertions, 0 deletions
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);
+ }
+}
+