1 /*-------------------------------------------------------------------------
4 * routines to support running postgres in 'bootstrap' mode
5 * bootstrap mode is used to create the initial template database
7 * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
8 * Portions Copyright (c) 1994, Regents of the University of California
13 *-------------------------------------------------------------------------
24 #include "access/genam.h"
25 #include "access/heapam.h"
26 #include "access/xact.h"
27 #include "bootstrap/bootstrap.h"
28 #include "catalog/index.h"
29 #include "catalog/pg_type.h"
30 #include "libpq/pqsignal.h"
31 #include "miscadmin.h"
32 #include "nodes/makefuncs.h"
33 #include "postmaster/bgwriter.h"
34 #include "postmaster/walwriter.h"
35 #include "storage/bufmgr.h"
36 #include "storage/ipc.h"
37 #include "storage/proc.h"
38 #include "tcop/tcopprot.h"
39 #include "utils/builtins.h"
40 #include "utils/fmgroids.h"
41 #include "utils/memutils.h"
42 #include "utils/ps_status.h"
43 #include "utils/tqual.h"
49 #define ALLOC(t, c) ((t *) calloc((unsigned)(c), sizeof(t)))
51 static void CheckerModeMain(void);
52 static void BootstrapModeMain(void);
53 static void bootstrap_signals(void);
54 static void ShutdownAuxiliaryProcess(int code
, Datum arg
);
55 static hashnode
*AddStr(char *str
, int strlength
, int mderef
);
56 static Form_pg_attribute
AllocateAttribute(void);
57 static int CompHash(char *str
, int len
);
58 static hashnode
*FindStr(char *str
, int length
, hashnode
*mderef
);
59 static Oid
gettype(char *type
);
60 static void cleanup(void);
67 Relation boot_reldesc
; /* current relation descriptor */
70 * In the lexical analyzer, we need to get the reference number quickly from
71 * the string, and the string from the reference number. Thus we have
72 * as our data structure a hash table, where the hashing key taken from
73 * the particular string. The hash table is chained. One of the fields
74 * of the hash table node is an index into the array of character pointers.
75 * The unique index number that every string is assigned is simply the
76 * position of its string pointer in the array of string pointers.
79 #define STRTABLESIZE 10000
80 #define HASHTABLESIZE 503
82 /* Hash function numbers */
87 char *strtable
[STRTABLESIZE
];
88 hashnode
*hashtable
[HASHTABLESIZE
];
90 static int strtable_end
= -1; /* Tells us last occupied string space */
93 * Basic information associated with each type. This is used before
96 * XXX several of these input/output functions do catalog scans
97 * (e.g., F_REGPROCIN scans pg_proc). this obviously creates some
98 * order dependencies in the catalog creation process.
102 char name
[NAMEDATALEN
];
113 static const struct typinfo TypInfo
[] = {
114 {"bool", BOOLOID
, 0, 1, true, 'c', 'p',
115 F_BOOLIN
, F_BOOLOUT
},
116 {"bytea", BYTEAOID
, 0, -1, false, 'i', 'x',
117 F_BYTEAIN
, F_BYTEAOUT
},
118 {"char", CHAROID
, 0, 1, true, 'c', 'p',
119 F_CHARIN
, F_CHAROUT
},
120 {"int2", INT2OID
, 0, 2, true, 's', 'p',
121 F_INT2IN
, F_INT2OUT
},
122 {"int4", INT4OID
, 0, 4, true, 'i', 'p',
123 F_INT4IN
, F_INT4OUT
},
124 {"float4", FLOAT4OID
, 0, 4, FLOAT4PASSBYVAL
, 'i', 'p',
125 F_FLOAT4IN
, F_FLOAT4OUT
},
126 {"name", NAMEOID
, CHAROID
, NAMEDATALEN
, false, 'c', 'p',
127 F_NAMEIN
, F_NAMEOUT
},
128 {"regclass", REGCLASSOID
, 0, 4, true, 'i', 'p',
129 F_REGCLASSIN
, F_REGCLASSOUT
},
130 {"regproc", REGPROCOID
, 0, 4, true, 'i', 'p',
131 F_REGPROCIN
, F_REGPROCOUT
},
132 {"regtype", REGTYPEOID
, 0, 4, true, 'i', 'p',
133 F_REGTYPEIN
, F_REGTYPEOUT
},
134 {"text", TEXTOID
, 0, -1, false, 'i', 'x',
135 F_TEXTIN
, F_TEXTOUT
},
136 {"oid", OIDOID
, 0, 4, true, 'i', 'p',
138 {"tid", TIDOID
, 0, 6, false, 's', 'p',
140 {"xid", XIDOID
, 0, 4, true, 'i', 'p',
142 {"cid", CIDOID
, 0, 4, true, 'i', 'p',
144 {"int2vector", INT2VECTOROID
, INT2OID
, -1, false, 'i', 'p',
145 F_INT2VECTORIN
, F_INT2VECTOROUT
},
146 {"oidvector", OIDVECTOROID
, OIDOID
, -1, false, 'i', 'p',
147 F_OIDVECTORIN
, F_OIDVECTOROUT
},
148 {"_int4", INT4ARRAYOID
, INT4OID
, -1, false, 'i', 'x',
149 F_ARRAY_IN
, F_ARRAY_OUT
},
150 {"_text", 1009, TEXTOID
, -1, false, 'i', 'x',
151 F_ARRAY_IN
, F_ARRAY_OUT
},
152 {"_oid", 1028, OIDOID
, -1, false, 'i', 'x',
153 F_ARRAY_IN
, F_ARRAY_OUT
},
154 {"_char", 1002, CHAROID
, -1, false, 'i', 'x',
155 F_ARRAY_IN
, F_ARRAY_OUT
},
156 {"_aclitem", 1034, ACLITEMOID
, -1, false, 'i', 'x',
157 F_ARRAY_IN
, F_ARRAY_OUT
}
160 static const int n_types
= sizeof(TypInfo
) / sizeof(struct typinfo
);
165 FormData_pg_type am_typ
;
168 static struct typmap
**Typ
= NULL
;
169 static struct typmap
*Ap
= NULL
;
171 static bool Nulls
[MAXATTR
];
173 Form_pg_attribute attrtypes
[MAXATTR
]; /* points to attribute info */
174 static Datum values
[MAXATTR
]; /* corresponding attribute values */
175 int numattr
; /* number of attributes for cur. rel */
177 static MemoryContext nogc
= NULL
; /* special no-gc mem context */
180 * At bootstrap time, we first declare all the indices to be built, and
181 * then build them. The IndexList structure stores enough information
182 * to allow us to build the indices after they've been declared.
185 typedef struct _IndexList
190 struct _IndexList
*il_next
;
193 static IndexList
*ILHead
= NULL
;
197 * AuxiliaryProcessMain
199 * The main entry point for auxiliary processes, such as the bgwriter,
200 * walwriter, bootstrapper and the shared memory checker code.
202 * This code is here just because of historical reasons.
205 AuxiliaryProcessMain(int argc
, char *argv
[])
207 char *progname
= argv
[0];
209 AuxProcType auxType
= CheckerProcess
;
210 char *userDoption
= NULL
;
215 MyProcPid
= getpid();
217 MyStartTime
= time(NULL
);
220 * Fire up essential subsystems: error and memory management
222 * If we are running under the postmaster, this is done already.
224 if (!IsUnderPostmaster
)
227 /* Compute paths, if we didn't inherit them from postmaster */
228 if (my_exec_path
[0] == '\0')
230 if (find_my_exec(progname
, my_exec_path
) < 0)
231 elog(FATAL
, "%s: could not locate my own executable path",
236 * process command arguments
239 /* Set defaults, to be overriden by explicit options below */
240 if (!IsUnderPostmaster
)
241 InitializeGUCOptions();
243 /* Ignore the initial --boot argument, if present */
244 if (argc
> 1 && strcmp(argv
[1], "--boot") == 0)
250 while ((flag
= getopt(argc
, argv
, "B:c:d:D:Fr:x:-:")) != -1)
255 SetConfigOption("shared_buffers", optarg
, PGC_POSTMASTER
, PGC_S_ARGV
);
258 userDoption
= optarg
;
262 /* Turn on debugging for the bootstrap process. */
263 char *debugstr
= palloc(strlen("debug") + strlen(optarg
) + 1);
265 sprintf(debugstr
, "debug%s", optarg
);
266 SetConfigOption("log_min_messages", debugstr
,
267 PGC_POSTMASTER
, PGC_S_ARGV
);
268 SetConfigOption("client_min_messages", debugstr
,
269 PGC_POSTMASTER
, PGC_S_ARGV
);
274 SetConfigOption("fsync", "false", PGC_POSTMASTER
, PGC_S_ARGV
);
277 strlcpy(OutputFileName
, optarg
, MAXPGPATH
);
280 auxType
= atoi(optarg
);
288 ParseLongOption(optarg
, &name
, &value
);
293 (errcode(ERRCODE_SYNTAX_ERROR
),
294 errmsg("--%s requires a value",
298 (errcode(ERRCODE_SYNTAX_ERROR
),
299 errmsg("-c %s requires a value",
303 SetConfigOption(name
, value
, PGC_POSTMASTER
, PGC_S_ARGV
);
310 write_stderr("Try \"%s --help\" for more information.\n",
319 write_stderr("%s: invalid command-line arguments\n", progname
);
324 * Identify myself via ps
326 if (IsUnderPostmaster
)
333 statmsg
= "startup process";
335 case BgWriterProcess
:
336 statmsg
= "writer process";
338 case WalWriterProcess
:
339 statmsg
= "wal writer process";
342 statmsg
= "??? process";
345 init_ps_display(statmsg
, "", "", "");
348 /* Acquire configuration parameters, unless inherited from postmaster */
349 if (!IsUnderPostmaster
)
351 if (!SelectConfigFiles(userDoption
, progname
))
353 /* If timezone is not set, determine what the OS uses */
354 pg_timezone_initialize();
355 /* If timezone_abbreviations is not set, select default */
356 pg_timezone_abbrev_initialize();
359 /* Validate we have been given a reasonable-looking DataDir */
361 ValidatePgVersion(DataDir
);
363 /* Change into DataDir (if under postmaster, should be done already) */
364 if (!IsUnderPostmaster
)
367 /* If standalone, create lockfile for data directory */
368 if (!IsUnderPostmaster
)
369 CreateDataDirLockFile(false);
371 SetProcessingMode(BootstrapProcessing
);
372 IgnoreSystemIndexes
= true;
377 * When we are an auxiliary process, we aren't going to do the full
378 * InitPostgres pushups, but there are a couple of things that need to get
379 * lit up even in an auxiliary process.
381 if (IsUnderPostmaster
)
384 * Create a PGPROC so we can use LWLocks. In the EXEC_BACKEND case,
385 * this was already done by SubPostmasterMain().
388 InitAuxiliaryProcess();
391 /* finish setting up bufmgr.c */
392 InitBufferPoolBackend();
394 /* register a shutdown callback for LWLock cleanup */
395 on_shmem_exit(ShutdownAuxiliaryProcess
, 0);
401 SetProcessingMode(NormalProcessing
);
408 proc_exit(1); /* should never return */
410 case BootstrapProcess
:
415 proc_exit(1); /* should never return */
418 /* don't set signals, startup process has its own agenda */
419 StartupProcessMain();
420 proc_exit(1); /* should never return */
422 case BgWriterProcess
:
423 /* don't set signals, bgwriter has its own agenda */
424 BackgroundWriterMain();
425 proc_exit(1); /* should never return */
427 case WalWriterProcess
:
428 /* don't set signals, walwriter has its own agenda */
431 proc_exit(1); /* should never return */
434 elog(PANIC
, "unrecognized process type: %d", auxType
);
440 * In shared memory checker mode, all we really want to do is create shared
441 * memory and semaphores (just to prove we can do it with the current GUC
445 CheckerModeMain(void)
448 * We must be getting invoked for bootstrap mode
450 Assert(!IsUnderPostmaster
);
452 SetProcessingMode(BootstrapProcessing
);
455 * Do backend-like initialization for bootstrap mode
458 InitPostgres(NULL
, InvalidOid
, NULL
, NULL
);
463 * The main entry point for running the backend in bootstrap mode
465 * The bootstrap mode is used to initialize the template database.
466 * The bootstrap backend doesn't speak SQL, but instead expects
467 * commands in a special bootstrap language.
470 BootstrapModeMain(void)
474 Assert(!IsUnderPostmaster
);
476 SetProcessingMode(BootstrapProcessing
);
479 * Do backend-like initialization for bootstrap mode
482 InitPostgres(NULL
, InvalidOid
, NULL
, NULL
);
484 /* Initialize stuff for bootstrap-file processing */
485 for (i
= 0; i
< MAXATTR
; i
++)
490 for (i
= 0; i
< STRTABLESIZE
; ++i
)
492 for (i
= 0; i
< HASHTABLESIZE
; ++i
)
496 * Process bootstrap input.
500 /* Perform a checkpoint to ensure everything's down to disk */
501 SetProcessingMode(NormalProcessing
);
502 CreateCheckPoint(CHECKPOINT_IS_SHUTDOWN
| CHECKPOINT_IMMEDIATE
);
504 /* Clean up and exit */
510 /* ----------------------------------------------------------------
512 * ----------------------------------------------------------------
516 * Set up signal handling for a bootstrap process
519 bootstrap_signals(void)
521 if (IsUnderPostmaster
)
524 * If possible, make this process a group leader, so that the
525 * postmaster can signal any child processes too.
529 elog(FATAL
, "setsid() failed: %m");
533 * Properly accept or ignore signals the postmaster might send us
535 pqsignal(SIGHUP
, SIG_IGN
);
536 pqsignal(SIGINT
, SIG_IGN
); /* ignore query-cancel */
537 pqsignal(SIGTERM
, die
);
538 pqsignal(SIGQUIT
, quickdie
);
539 pqsignal(SIGALRM
, SIG_IGN
);
540 pqsignal(SIGPIPE
, SIG_IGN
);
541 pqsignal(SIGUSR1
, SIG_IGN
);
542 pqsignal(SIGUSR2
, SIG_IGN
);
545 * Reset some signals that are accepted by postmaster but not here
547 pqsignal(SIGCHLD
, SIG_DFL
);
548 pqsignal(SIGTTIN
, SIG_DFL
);
549 pqsignal(SIGTTOU
, SIG_DFL
);
550 pqsignal(SIGCONT
, SIG_DFL
);
551 pqsignal(SIGWINCH
, SIG_DFL
);
554 * Unblock signals (they were blocked when the postmaster forked us)
556 PG_SETMASK(&UnBlockSig
);
560 /* Set up appropriately for interactive use */
561 pqsignal(SIGHUP
, die
);
562 pqsignal(SIGINT
, die
);
563 pqsignal(SIGTERM
, die
);
564 pqsignal(SIGQUIT
, die
);
569 * Begin shutdown of an auxiliary process. This is approximately the equivalent
570 * of ShutdownPostgres() in postinit.c. We can't run transactions in an
571 * auxiliary process, so most of the work of AbortTransaction() is not needed,
572 * but we do need to make sure we've released any LWLocks we are holding.
573 * (This is only critical during an error exit.)
576 ShutdownAuxiliaryProcess(int code
, Datum arg
)
581 /* ----------------------------------------------------------------
582 * MANUAL BACKEND INTERACTIVE INTERFACE COMMANDS
583 * ----------------------------------------------------------------
591 boot_openrel(char *relname
)
599 if (strlen(relname
) >= NAMEDATALEN
)
600 relname
[NAMEDATALEN
- 1] = '\0';
604 /* We can now load the pg_type data */
605 rel
= heap_open(TypeRelationId
, NoLock
);
606 scan
= heap_beginscan(rel
, SnapshotNow
, 0, NULL
);
608 while ((tup
= heap_getnext(scan
, ForwardScanDirection
)) != NULL
)
611 app
= Typ
= ALLOC(struct typmap
*, i
+ 1);
613 *app
++ = ALLOC(struct typmap
, 1);
615 scan
= heap_beginscan(rel
, SnapshotNow
, 0, NULL
);
617 while ((tup
= heap_getnext(scan
, ForwardScanDirection
)) != NULL
)
619 (*app
)->am_oid
= HeapTupleGetOid(tup
);
620 memcpy((char *) &(*app
)->am_typ
,
621 (char *) GETSTRUCT(tup
),
622 sizeof((*app
)->am_typ
));
626 heap_close(rel
, NoLock
);
629 if (boot_reldesc
!= NULL
)
632 elog(DEBUG4
, "open relation %s, attrsize %d",
633 relname
, (int) ATTRIBUTE_FIXED_PART_SIZE
);
635 boot_reldesc
= heap_openrv(makeRangeVar(NULL
, relname
, -1), NoLock
);
636 numattr
= boot_reldesc
->rd_rel
->relnatts
;
637 for (i
= 0; i
< numattr
; i
++)
639 if (attrtypes
[i
] == NULL
)
640 attrtypes
[i
] = AllocateAttribute();
641 memmove((char *) attrtypes
[i
],
642 (char *) boot_reldesc
->rd_att
->attrs
[i
],
643 ATTRIBUTE_FIXED_PART_SIZE
);
646 Form_pg_attribute at
= attrtypes
[i
];
648 elog(DEBUG4
, "create attribute %d name %s len %d num %d type %u",
649 i
, NameStr(at
->attname
), at
->attlen
, at
->attnum
,
666 if (strcmp(RelationGetRelationName(boot_reldesc
), name
) != 0)
667 elog(ERROR
, "close of %s when %s was expected",
668 name
, RelationGetRelationName(boot_reldesc
));
671 elog(ERROR
, "close of %s before any relation was opened",
675 if (boot_reldesc
== NULL
)
676 elog(ERROR
, "no open relation to close");
679 elog(DEBUG4
, "close relation %s",
680 RelationGetRelationName(boot_reldesc
));
681 heap_close(boot_reldesc
, NoLock
);
691 * define a <field,type> pair
692 * if there are n fields in a relation to be created, this routine
693 * will be called n times
697 DefineAttr(char *name
, char *type
, int attnum
)
701 if (boot_reldesc
!= NULL
)
703 elog(WARNING
, "no open relations allowed with CREATE command");
707 if (attrtypes
[attnum
] == NULL
)
708 attrtypes
[attnum
] = AllocateAttribute();
709 MemSet(attrtypes
[attnum
], 0, ATTRIBUTE_FIXED_PART_SIZE
);
711 namestrcpy(&attrtypes
[attnum
]->attname
, name
);
712 elog(DEBUG4
, "column %s %s", NameStr(attrtypes
[attnum
]->attname
), type
);
713 attrtypes
[attnum
]->attnum
= attnum
+ 1; /* fillatt */
715 typeoid
= gettype(type
);
719 attrtypes
[attnum
]->atttypid
= Ap
->am_oid
;
720 attrtypes
[attnum
]->attlen
= Ap
->am_typ
.typlen
;
721 attrtypes
[attnum
]->attbyval
= Ap
->am_typ
.typbyval
;
722 attrtypes
[attnum
]->attstorage
= Ap
->am_typ
.typstorage
;
723 attrtypes
[attnum
]->attalign
= Ap
->am_typ
.typalign
;
724 /* if an array type, assume 1-dimensional attribute */
725 if (Ap
->am_typ
.typelem
!= InvalidOid
&& Ap
->am_typ
.typlen
< 0)
726 attrtypes
[attnum
]->attndims
= 1;
728 attrtypes
[attnum
]->attndims
= 0;
732 attrtypes
[attnum
]->atttypid
= TypInfo
[typeoid
].oid
;
733 attrtypes
[attnum
]->attlen
= TypInfo
[typeoid
].len
;
734 attrtypes
[attnum
]->attbyval
= TypInfo
[typeoid
].byval
;
735 attrtypes
[attnum
]->attstorage
= TypInfo
[typeoid
].storage
;
736 attrtypes
[attnum
]->attalign
= TypInfo
[typeoid
].align
;
737 /* if an array type, assume 1-dimensional attribute */
738 if (TypInfo
[typeoid
].elem
!= InvalidOid
&&
739 attrtypes
[attnum
]->attlen
< 0)
740 attrtypes
[attnum
]->attndims
= 1;
742 attrtypes
[attnum
]->attndims
= 0;
745 attrtypes
[attnum
]->attstattarget
= -1;
746 attrtypes
[attnum
]->attcacheoff
= -1;
747 attrtypes
[attnum
]->atttypmod
= -1;
748 attrtypes
[attnum
]->attislocal
= true;
751 * Mark as "not null" if type is fixed-width and prior columns are too.
752 * This corresponds to case where column can be accessed directly via C
753 * struct declaration.
755 * oidvector and int2vector are also treated as not-nullable, even though
756 * they are no longer fixed-width.
758 #define MARKNOTNULL(att) \
759 ((att)->attlen > 0 || \
760 (att)->atttypid == OIDVECTOROID || \
761 (att)->atttypid == INT2VECTOROID)
763 if (MARKNOTNULL(attrtypes
[attnum
]))
767 for (i
= 0; i
< attnum
; i
++)
769 if (!MARKNOTNULL(attrtypes
[i
]))
773 attrtypes
[attnum
]->attnotnull
= true;
781 * If objectid is not zero, it is a specific OID to assign to the tuple.
782 * Otherwise, an OID will be assigned (if necessary) by heap_insert.
786 InsertOneTuple(Oid objectid
)
792 elog(DEBUG4
, "inserting row oid %u, %d columns", objectid
, numattr
);
794 tupDesc
= CreateTupleDesc(numattr
,
795 RelationGetForm(boot_reldesc
)->relhasoids
,
797 tuple
= heap_form_tuple(tupDesc
, values
, Nulls
);
798 if (objectid
!= (Oid
) 0)
799 HeapTupleSetOid(tuple
, objectid
);
800 pfree(tupDesc
); /* just free's tupDesc, not the attrtypes */
802 simple_heap_insert(boot_reldesc
, tuple
);
803 heap_freetuple(tuple
);
804 elog(DEBUG4
, "row inserted");
807 * Reset null markers for next tuple
809 for (i
= 0; i
< numattr
; i
++)
818 InsertOneValue(char *value
, int i
)
830 AssertArg(i
>= 0 || i
< MAXATTR
);
832 elog(DEBUG4
, "inserting column %d value \"%s\"", i
, value
);
834 typoid
= boot_reldesc
->rd_att
->attrs
[i
]->atttypid
;
836 boot_get_type_io_data(typoid
,
837 &typlen
, &typbyval
, &typalign
,
838 &typdelim
, &typioparam
,
839 &typinput
, &typoutput
);
841 values
[i
] = OidInputFunctionCall(typinput
, value
, typioparam
, -1);
842 prt
= OidOutputFunctionCall(typoutput
, values
[i
]);
843 elog(DEBUG4
, "inserted -> %s", prt
);
854 elog(DEBUG4
, "inserting column %d NULL", i
);
855 Assert(i
>= 0 || i
< MAXATTR
);
856 values
[i
] = PointerGetDatum(NULL
);
867 if (boot_reldesc
!= NULL
)
874 * NB: this is really ugly; it will return an integer index into TypInfo[],
875 * and not an OID at all, until the first reference to a type not known in
876 * TypInfo[]. At that point it will read and cache pg_type in the Typ array,
877 * and subsequently return a real OID (and set the global pointer Ap to
878 * point at the found row in Typ). So caller must check whether Typ is
879 * still NULL to determine what the return value is!
893 for (app
= Typ
; *app
!= NULL
; app
++)
895 if (strncmp(NameStr((*app
)->am_typ
.typname
), type
, NAMEDATALEN
) == 0)
898 return (*app
)->am_oid
;
904 for (i
= 0; i
< n_types
; i
++)
906 if (strncmp(type
, TypInfo
[i
].name
, NAMEDATALEN
) == 0)
909 elog(DEBUG4
, "external type: %s", type
);
910 rel
= heap_open(TypeRelationId
, NoLock
);
911 scan
= heap_beginscan(rel
, SnapshotNow
, 0, NULL
);
913 while ((tup
= heap_getnext(scan
, ForwardScanDirection
)) != NULL
)
916 app
= Typ
= ALLOC(struct typmap
*, i
+ 1);
918 *app
++ = ALLOC(struct typmap
, 1);
920 scan
= heap_beginscan(rel
, SnapshotNow
, 0, NULL
);
922 while ((tup
= heap_getnext(scan
, ForwardScanDirection
)) != NULL
)
924 (*app
)->am_oid
= HeapTupleGetOid(tup
);
925 memmove((char *) &(*app
++)->am_typ
,
926 (char *) GETSTRUCT(tup
),
927 sizeof((*app
)->am_typ
));
930 heap_close(rel
, NoLock
);
931 return gettype(type
);
933 elog(ERROR
, "unrecognized type \"%s\"", type
);
934 /* not reached, here to make compiler happy */
939 * boot_get_type_io_data
941 * Obtain type I/O information at bootstrap time. This intentionally has
942 * almost the same API as lsyscache.c's get_type_io_data, except that
943 * we only support obtaining the typinput and typoutput routines, not
944 * the binary I/O routines. It is exported so that array_in and array_out
945 * can be made to work during early bootstrap.
949 boot_get_type_io_data(Oid typid
,
960 /* We have the boot-time contents of pg_type, so use it */
965 while (*app
&& (*app
)->am_oid
!= typid
)
969 elog(ERROR
, "type OID %u not found in Typ list", typid
);
971 *typlen
= ap
->am_typ
.typlen
;
972 *typbyval
= ap
->am_typ
.typbyval
;
973 *typalign
= ap
->am_typ
.typalign
;
974 *typdelim
= ap
->am_typ
.typdelim
;
976 /* XXX this logic must match getTypeIOParam() */
977 if (OidIsValid(ap
->am_typ
.typelem
))
978 *typioparam
= ap
->am_typ
.typelem
;
982 *typinput
= ap
->am_typ
.typinput
;
983 *typoutput
= ap
->am_typ
.typoutput
;
987 /* We don't have pg_type yet, so use the hard-wired TypInfo array */
990 for (typeindex
= 0; typeindex
< n_types
; typeindex
++)
992 if (TypInfo
[typeindex
].oid
== typid
)
995 if (typeindex
>= n_types
)
996 elog(ERROR
, "type OID %u not found in TypInfo", typid
);
998 *typlen
= TypInfo
[typeindex
].len
;
999 *typbyval
= TypInfo
[typeindex
].byval
;
1000 *typalign
= TypInfo
[typeindex
].align
;
1001 /* We assume typdelim is ',' for all boot-time types */
1004 /* XXX this logic must match getTypeIOParam() */
1005 if (OidIsValid(TypInfo
[typeindex
].elem
))
1006 *typioparam
= TypInfo
[typeindex
].elem
;
1008 *typioparam
= typid
;
1010 *typinput
= TypInfo
[typeindex
].inproc
;
1011 *typoutput
= TypInfo
[typeindex
].outproc
;
1018 * Note: bootstrap never sets any per-column ACLs, so we only need
1019 * ATTRIBUTE_FIXED_PART_SIZE space per attribute.
1022 static Form_pg_attribute
1023 AllocateAttribute(void)
1025 Form_pg_attribute attribute
= (Form_pg_attribute
) malloc(ATTRIBUTE_FIXED_PART_SIZE
);
1027 if (!PointerIsValid(attribute
))
1028 elog(FATAL
, "out of memory");
1029 MemSet(attribute
, 0, ATTRIBUTE_FIXED_PART_SIZE
);
1036 * XXX arrays of "basetype" are always "_basetype".
1037 * this is an evil hack inherited from rel. 3.1.
1038 * XXX array dimension is thrown away because we
1039 * don't support fixed-dimension arrays. again,
1040 * sickness from 3.1.
1042 * the string passed in must have a '[' character in it
1044 * the string returned is a pointer to static storage and should NOT
1045 * be freed by the CALLER.
1049 MapArrayTypeName(char *s
)
1053 static char newStr
[NAMEDATALEN
]; /* array type names < NAMEDATALEN long */
1055 if (s
== NULL
|| s
[0] == '\0')
1060 for (i
= 0; i
< NAMEDATALEN
- 1 && s
[i
] != '['; i
++, j
++)
1070 * returns the string table position of the identifier
1071 * passed to it. We add it to the table if we can't find it.
1075 EnterString(char *str
)
1082 node
= FindStr(str
, len
, NULL
);
1084 return node
->strnum
;
1087 node
= AddStr(str
, len
, 0);
1088 return node
->strnum
;
1094 * when given an idnum into the 'string-table' return the string
1095 * associated with the idnum
1099 LexIDStr(int ident_num
)
1101 return strtable
[ident_num
];
1108 * Compute a hash function for a given string. We look at the first,
1109 * the last, and the middle character of a string to try to get spread
1110 * the strings out. The function is rather arbitrary, except that we
1111 * are mod'ing by a prime number.
1115 CompHash(char *str
, int len
)
1119 result
= (NUM
* str
[0] + NUMSQR
* str
[len
- 1] + NUMCUBE
* str
[(len
- 1) / 2]);
1121 return result
% HASHTABLESIZE
;
1128 * This routine looks for the specified string in the hash
1129 * table. It returns a pointer to the hash node found,
1130 * or NULL if the string is not in the table.
1134 FindStr(char *str
, int length
, hashnode
*mderef
)
1138 node
= hashtable
[CompHash(str
, length
)];
1139 while (node
!= NULL
)
1142 * We must differentiate between string constants that might have the
1143 * same value as a identifier and the identifier itself.
1145 if (!strcmp(str
, strtable
[node
->strnum
]))
1147 return node
; /* no need to check */
1152 /* Couldn't find it in the list */
1159 * This function adds the specified string, along with its associated
1160 * data, to the hash table and the string table. We return the node
1161 * so that the calling routine can find out the unique id that AddStr
1162 * has assigned to this string.
1166 AddStr(char *str
, int strlength
, int mderef
)
1174 if (++strtable_end
>= STRTABLESIZE
)
1175 elog(FATAL
, "bootstrap string table overflow");
1178 * Some of the utilites (eg, define type, create relation) assume that the
1179 * string they're passed is a NAMEDATALEN. We get array bound read
1180 * violations from purify if we don't allocate at least NAMEDATALEN bytes
1181 * for strings of this sort. Because we're lazy, we allocate at least
1182 * NAMEDATALEN bytes all the time.
1185 if ((len
= strlength
+ 1) < NAMEDATALEN
)
1188 strtable
[strtable_end
] = malloc((unsigned) len
);
1189 strcpy(strtable
[strtable_end
], str
);
1191 /* Now put a node in the hash table */
1193 newnode
= (hashnode
*) malloc(sizeof(hashnode
) * 1);
1194 newnode
->strnum
= strtable_end
;
1195 newnode
->next
= NULL
;
1197 /* Find out where it goes */
1199 hashresult
= CompHash(str
, strlength
);
1200 if (hashtable
[hashresult
] == NULL
)
1201 hashtable
[hashresult
] = newnode
;
1203 { /* There is something in the list */
1204 trail
= hashtable
[hashresult
];
1206 while (temp
!= NULL
)
1211 trail
->next
= newnode
;
1219 * index_register() -- record an index that has been set up for building
1222 * At bootstrap time, we define a bunch of indexes on system catalogs.
1223 * We postpone actually building the indexes until just before we're
1224 * finished with initialization, however. This is because the indexes
1225 * themselves have catalog entries, and those have to be included in the
1226 * indexes on those catalogs. Doing it in two phases is the simplest
1227 * way of making sure the indexes have the right contents at the end.
1230 index_register(Oid heap
,
1232 IndexInfo
*indexInfo
)
1235 MemoryContext oldcxt
;
1238 * XXX mao 10/31/92 -- don't gc index reldescs, associated info at
1239 * bootstrap time. we'll declare the indexes now, but want to create them
1244 nogc
= AllocSetContextCreate(NULL
,
1246 ALLOCSET_DEFAULT_MINSIZE
,
1247 ALLOCSET_DEFAULT_INITSIZE
,
1248 ALLOCSET_DEFAULT_MAXSIZE
);
1250 oldcxt
= MemoryContextSwitchTo(nogc
);
1252 newind
= (IndexList
*) palloc(sizeof(IndexList
));
1253 newind
->il_heap
= heap
;
1254 newind
->il_ind
= ind
;
1255 newind
->il_info
= (IndexInfo
*) palloc(sizeof(IndexInfo
));
1257 memcpy(newind
->il_info
, indexInfo
, sizeof(IndexInfo
));
1258 /* expressions will likely be null, but may as well copy it */
1259 newind
->il_info
->ii_Expressions
= (List
*)
1260 copyObject(indexInfo
->ii_Expressions
);
1261 newind
->il_info
->ii_ExpressionsState
= NIL
;
1262 /* predicate will likely be null, but may as well copy it */
1263 newind
->il_info
->ii_Predicate
= (List
*)
1264 copyObject(indexInfo
->ii_Predicate
);
1265 newind
->il_info
->ii_PredicateState
= NIL
;
1267 newind
->il_next
= ILHead
;
1270 MemoryContextSwitchTo(oldcxt
);
1275 * build_indices -- fill in all the indexes registered earlier
1280 for (; ILHead
!= NULL
; ILHead
= ILHead
->il_next
)
1285 /* need not bother with locks during bootstrap */
1286 heap
= heap_open(ILHead
->il_heap
, NoLock
);
1287 ind
= index_open(ILHead
->il_ind
, NoLock
);
1289 index_build(heap
, ind
, ILHead
->il_info
, false);
1291 index_close(ind
, NoLock
);
1292 heap_close(heap
, NoLock
);