1996-07-09 08:22:35 +02:00
|
|
|
/*-------------------------------------------------------------------------
|
|
|
|
*
|
1999-02-14 00:22:53 +01:00
|
|
|
* bootstrap.c
|
1997-09-07 07:04:48 +02:00
|
|
|
* routines to support running postgres in 'bootstrap' mode
|
|
|
|
* bootstrap mode is used to create the initial template database
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
2011-01-01 19:18:15 +01:00
|
|
|
* Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group
|
2000-01-26 06:58:53 +01:00
|
|
|
* Portions Copyright (c) 1994, Regents of the University of California
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
|
|
|
* IDENTIFICATION
|
2010-09-20 22:08:53 +02:00
|
|
|
* src/backend/bootstrap/bootstrap.c
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
*/
|
2000-11-04 13:43:24 +01:00
|
|
|
#include "postgres.h"
|
|
|
|
|
2008-02-17 05:21:05 +01:00
|
|
|
#include <time.h>
|
1999-07-16 05:14:30 +02:00
|
|
|
#include <unistd.h>
|
1996-10-23 09:42:13 +02:00
|
|
|
#include <signal.h>
|
1999-07-19 04:27:16 +02:00
|
|
|
#ifdef HAVE_GETOPT_H
|
|
|
|
#include <getopt.h>
|
|
|
|
#endif
|
1998-04-26 06:12:15 +02:00
|
|
|
|
|
|
|
#include "access/genam.h"
|
|
|
|
#include "access/heapam.h"
|
2006-07-13 18:49:20 +02:00
|
|
|
#include "access/xact.h"
|
1998-04-26 06:12:15 +02:00
|
|
|
#include "bootstrap/bootstrap.h"
|
|
|
|
#include "catalog/index.h"
|
|
|
|
#include "catalog/pg_type.h"
|
|
|
|
#include "libpq/pqsignal.h"
|
1999-07-16 07:00:38 +02:00
|
|
|
#include "miscadmin.h"
|
2005-04-14 22:03:27 +02:00
|
|
|
#include "nodes/makefuncs.h"
|
2004-05-30 00:48:23 +02:00
|
|
|
#include "postmaster/bgwriter.h"
|
2007-07-24 06:54:09 +02:00
|
|
|
#include "postmaster/walwriter.h"
|
2010-01-15 10:19:10 +01:00
|
|
|
#include "replication/walreceiver.h"
|
2008-05-12 02:00:54 +02:00
|
|
|
#include "storage/bufmgr.h"
|
2002-05-05 02:03:29 +02:00
|
|
|
#include "storage/ipc.h"
|
2001-09-29 06:02:27 +02:00
|
|
|
#include "storage/proc.h"
|
2009-07-31 22:26:23 +02:00
|
|
|
#include "storage/procsignal.h"
|
1998-04-26 06:12:15 +02:00
|
|
|
#include "tcop/tcopprot.h"
|
|
|
|
#include "utils/builtins.h"
|
2000-05-28 19:56:29 +02:00
|
|
|
#include "utils/fmgroids.h"
|
2005-05-06 19:24:55 +02:00
|
|
|
#include "utils/memutils.h"
|
2004-05-28 07:13:32 +02:00
|
|
|
#include "utils/ps_status.h"
|
2010-02-07 21:48:13 +01:00
|
|
|
#include "utils/relmapper.h"
|
2008-03-26 22:10:39 +01:00
|
|
|
#include "utils/tqual.h"
|
2000-06-28 05:33:33 +02:00
|
|
|
|
2005-04-14 22:03:27 +02:00
|
|
|
extern int optind;
|
|
|
|
extern char *optarg;
|
|
|
|
|
1996-10-21 10:31:23 +02:00
|
|
|
|
2000-06-05 09:29:25 +02:00
|
|
|
#define ALLOC(t, c) ((t *) calloc((unsigned)(c), sizeof(t)))
|
1996-07-09 08:22:35 +02:00
|
|
|
|
2007-03-07 14:35:03 +01:00
|
|
|
static void CheckerModeMain(void);
|
|
|
|
static void BootstrapModeMain(void);
|
2004-05-30 00:48:23 +02:00
|
|
|
static void bootstrap_signals(void);
|
2007-03-07 14:35:03 +01:00
|
|
|
static void ShutdownAuxiliaryProcess(int code, Datum arg);
|
1998-09-01 05:29:17 +02:00
|
|
|
static Form_pg_attribute AllocateAttribute(void);
|
1998-08-24 21:04:04 +02:00
|
|
|
static Oid gettype(char *type);
|
1997-09-08 04:41:22 +02:00
|
|
|
static void cleanup(void);
|
1996-10-23 09:42:13 +02:00
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
/* ----------------
|
1997-09-07 07:04:48 +02:00
|
|
|
* global variables
|
1996-07-09 08:22:35 +02:00
|
|
|
* ----------------
|
|
|
|
*/
|
2002-04-27 23:24:34 +02:00
|
|
|
|
|
|
|
Relation boot_reldesc; /* current relation descriptor */
|
|
|
|
|
2009-09-27 03:32:11 +02:00
|
|
|
Form_pg_attribute attrtypes[MAXATTR]; /* points to attribute info */
|
|
|
|
int numattr; /* number of attributes for cur. rel */
|
1996-07-09 08:22:35 +02:00
|
|
|
|
|
|
|
|
2009-09-27 03:32:11 +02:00
|
|
|
/*
|
1996-07-09 08:22:35 +02:00
|
|
|
* Basic information associated with each type. This is used before
|
2010-09-03 03:34:55 +02:00
|
|
|
* pg_type is filled, so it has to cover the datatypes used as column types
|
|
|
|
* in the core "bootstrapped" catalogs.
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
1997-09-07 07:04:48 +02:00
|
|
|
* 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.
|
1996-07-09 08:22:35 +02:00
|
|
|
*/
|
1997-09-07 07:04:48 +02:00
|
|
|
struct typinfo
|
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
char name[NAMEDATALEN];
|
|
|
|
Oid oid;
|
|
|
|
Oid elem;
|
|
|
|
int16 len;
|
2004-04-01 23:28:47 +02:00
|
|
|
bool byval;
|
|
|
|
char align;
|
|
|
|
char storage;
|
1997-09-08 04:41:22 +02:00
|
|
|
Oid inproc;
|
|
|
|
Oid outproc;
|
1996-07-09 08:22:35 +02:00
|
|
|
};
|
|
|
|
|
2004-04-01 23:28:47 +02:00
|
|
|
static const struct typinfo TypInfo[] = {
|
|
|
|
{"bool", BOOLOID, 0, 1, true, 'c', 'p',
|
2004-08-29 07:07:03 +02:00
|
|
|
F_BOOLIN, F_BOOLOUT},
|
2004-04-01 23:28:47 +02:00
|
|
|
{"bytea", BYTEAOID, 0, -1, false, 'i', 'x',
|
2004-08-29 07:07:03 +02:00
|
|
|
F_BYTEAIN, F_BYTEAOUT},
|
2004-04-01 23:28:47 +02:00
|
|
|
{"char", CHAROID, 0, 1, true, 'c', 'p',
|
2004-08-29 07:07:03 +02:00
|
|
|
F_CHARIN, F_CHAROUT},
|
2004-04-01 23:28:47 +02:00
|
|
|
{"int2", INT2OID, 0, 2, true, 's', 'p',
|
2004-08-29 07:07:03 +02:00
|
|
|
F_INT2IN, F_INT2OUT},
|
2004-04-01 23:28:47 +02:00
|
|
|
{"int4", INT4OID, 0, 4, true, 'i', 'p',
|
2004-08-29 07:07:03 +02:00
|
|
|
F_INT4IN, F_INT4OUT},
|
2008-04-21 02:26:47 +02:00
|
|
|
{"float4", FLOAT4OID, 0, 4, FLOAT4PASSBYVAL, 'i', 'p',
|
2007-01-22 02:35:23 +01:00
|
|
|
F_FLOAT4IN, F_FLOAT4OUT},
|
Reduce the alignment requirement of type "name" from int to char, and arrange
to suppress zero-padding of "name" entries in indexes.
The alignment change is unlikely to save any space, but it is really needed
anyway to make the world safe for our widespread practice of passing plain
old C strings to functions that are declared as taking Name. In the previous
coding, the C compiler was entitled to assume that a Name pointer was
word-aligned; but we were failing to guarantee that. I think the reason
we'd not seen failures is that usually the only thing that gets done with
such a pointer is strcmp(), which is hard to optimize in a way that exploits
word-alignment. Still, some enterprising compiler guy will probably think
of a way eventually, or we might change our code in a way that exposes
more-obvious optimization opportunities.
The padding change is accomplished in one-liner fashion by declaring the
"name" index opclasses to use storage type "cstring" in pg_opclass.h.
Normally btree and hash don't allow a nondefault storage type, because they
don't have any provisions for converting the input datum to another type.
However, because name and cstring are effectively the same thing except for
padding, no conversion is needed --- we only need index_form_tuple() to treat
the datum as being cstring not name, and this is sufficient. This seems to
make for about a one-third reduction in the typical sizes of system catalog
indexes that involve "name" columns, of which we have many.
These two changes are only weakly related, but the alignment change makes
me feel safer that the padding change won't introduce problems, so I'm
committing them together.
2008-06-24 19:58:27 +02:00
|
|
|
{"name", NAMEOID, CHAROID, NAMEDATALEN, false, 'c', 'p',
|
2007-01-22 02:35:23 +01:00
|
|
|
F_NAMEIN, F_NAMEOUT},
|
2004-04-01 23:28:47 +02:00
|
|
|
{"regclass", REGCLASSOID, 0, 4, true, 'i', 'p',
|
2004-08-29 07:07:03 +02:00
|
|
|
F_REGCLASSIN, F_REGCLASSOUT},
|
2007-01-22 02:35:23 +01:00
|
|
|
{"regproc", REGPROCOID, 0, 4, true, 'i', 'p',
|
|
|
|
F_REGPROCIN, F_REGPROCOUT},
|
2004-04-01 23:28:47 +02:00
|
|
|
{"regtype", REGTYPEOID, 0, 4, true, 'i', 'p',
|
2004-08-29 07:07:03 +02:00
|
|
|
F_REGTYPEIN, F_REGTYPEOUT},
|
2004-04-01 23:28:47 +02:00
|
|
|
{"text", TEXTOID, 0, -1, false, 'i', 'x',
|
2004-08-29 07:07:03 +02:00
|
|
|
F_TEXTIN, F_TEXTOUT},
|
2004-04-01 23:28:47 +02:00
|
|
|
{"oid", OIDOID, 0, 4, true, 'i', 'p',
|
2004-08-29 07:07:03 +02:00
|
|
|
F_OIDIN, F_OIDOUT},
|
2004-04-01 23:28:47 +02:00
|
|
|
{"tid", TIDOID, 0, 6, false, 's', 'p',
|
2004-08-29 07:07:03 +02:00
|
|
|
F_TIDIN, F_TIDOUT},
|
2004-04-01 23:28:47 +02:00
|
|
|
{"xid", XIDOID, 0, 4, true, 'i', 'p',
|
2004-08-29 07:07:03 +02:00
|
|
|
F_XIDIN, F_XIDOUT},
|
2004-04-01 23:28:47 +02:00
|
|
|
{"cid", CIDOID, 0, 4, true, 'i', 'p',
|
2004-08-29 07:07:03 +02:00
|
|
|
F_CIDIN, F_CIDOUT},
|
2010-09-03 03:34:55 +02:00
|
|
|
{"pg_node_tree", PGNODETREEOID, 0, -1, false, 'i', 'x',
|
|
|
|
F_PG_NODE_TREE_IN, F_PG_NODE_TREE_OUT},
|
2005-03-29 02:17:27 +02:00
|
|
|
{"int2vector", INT2VECTOROID, INT2OID, -1, false, 'i', 'p',
|
2004-08-29 07:07:03 +02:00
|
|
|
F_INT2VECTORIN, F_INT2VECTOROUT},
|
2005-03-29 02:17:27 +02:00
|
|
|
{"oidvector", OIDVECTOROID, OIDOID, -1, false, 'i', 'p',
|
2004-08-29 07:07:03 +02:00
|
|
|
F_OIDVECTORIN, F_OIDVECTOROUT},
|
2004-04-01 23:28:47 +02:00
|
|
|
{"_int4", INT4ARRAYOID, INT4OID, -1, false, 'i', 'x',
|
2004-08-29 07:07:03 +02:00
|
|
|
F_ARRAY_IN, F_ARRAY_OUT},
|
2004-04-01 23:28:47 +02:00
|
|
|
{"_text", 1009, TEXTOID, -1, false, 'i', 'x',
|
2004-08-29 07:07:03 +02:00
|
|
|
F_ARRAY_IN, F_ARRAY_OUT},
|
2005-03-29 21:44:23 +02:00
|
|
|
{"_oid", 1028, OIDOID, -1, false, 'i', 'x',
|
|
|
|
F_ARRAY_IN, F_ARRAY_OUT},
|
|
|
|
{"_char", 1002, CHAROID, -1, false, 'i', 'x',
|
|
|
|
F_ARRAY_IN, F_ARRAY_OUT},
|
2004-04-01 23:28:47 +02:00
|
|
|
{"_aclitem", 1034, ACLITEMOID, -1, false, 'i', 'x',
|
2004-08-29 07:07:03 +02:00
|
|
|
F_ARRAY_IN, F_ARRAY_OUT}
|
1996-07-09 08:22:35 +02:00
|
|
|
};
|
|
|
|
|
2004-08-29 07:07:03 +02:00
|
|
|
static const int n_types = sizeof(TypInfo) / sizeof(struct typinfo);
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
struct typmap
|
|
|
|
{ /* a hack */
|
1997-09-08 04:41:22 +02:00
|
|
|
Oid am_oid;
|
1998-09-01 05:29:17 +02:00
|
|
|
FormData_pg_type am_typ;
|
1996-07-09 08:22:35 +02:00
|
|
|
};
|
|
|
|
|
2004-01-07 19:56:30 +01:00
|
|
|
static struct typmap **Typ = NULL;
|
|
|
|
static struct typmap *Ap = NULL;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2009-09-27 03:32:11 +02:00
|
|
|
static Datum values[MAXATTR]; /* current row's attribute values */
|
2008-11-02 02:45:28 +01:00
|
|
|
static bool Nulls[MAXATTR];
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
static MemoryContext nogc = NULL; /* special no-gc mem context */
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
/*
|
1997-09-07 07:04:48 +02:00
|
|
|
* 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.
|
1996-07-09 08:22:35 +02:00
|
|
|
*/
|
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
typedef struct _IndexList
|
|
|
|
{
|
2002-03-26 20:17:02 +01:00
|
|
|
Oid il_heap;
|
|
|
|
Oid il_ind;
|
2000-07-15 00:18:02 +02:00
|
|
|
IndexInfo *il_info;
|
1997-09-07 07:04:48 +02:00
|
|
|
struct _IndexList *il_next;
|
1997-09-08 23:56:23 +02:00
|
|
|
} IndexList;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
2004-01-07 19:56:30 +01:00
|
|
|
static IndexList *ILHead = NULL;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
|
2004-05-28 07:13:32 +02:00
|
|
|
/*
|
2007-03-07 14:35:03 +01:00
|
|
|
* AuxiliaryProcessMain
|
2004-05-28 07:13:32 +02:00
|
|
|
*
|
2007-03-07 14:35:03 +01:00
|
|
|
* The main entry point for auxiliary processes, such as the bgwriter,
|
2010-01-15 10:19:10 +01:00
|
|
|
* walwriter, walreceiver, bootstrapper and the shared memory checker code.
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
2007-03-07 14:35:03 +01:00
|
|
|
* This code is here just because of historical reasons.
|
1996-07-09 08:22:35 +02:00
|
|
|
*/
|
2007-03-07 14:35:03 +01:00
|
|
|
void
|
|
|
|
AuxiliaryProcessMain(int argc, char *argv[])
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
2005-01-14 22:08:44 +01:00
|
|
|
char *progname = argv[0];
|
1997-09-08 04:41:22 +02:00
|
|
|
int flag;
|
2007-11-15 22:14:46 +01:00
|
|
|
AuxProcType auxType = CheckerProcess;
|
2004-10-08 03:36:36 +02:00
|
|
|
char *userDoption = NULL;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
|
|
|
* initialize globals
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
1998-01-25 06:15:15 +01:00
|
|
|
MyProcPid = getpid();
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2007-08-03 01:39:45 +02:00
|
|
|
MyStartTime = time(NULL);
|
|
|
|
|
2000-06-28 05:33:33 +02:00
|
|
|
/*
|
|
|
|
* Fire up essential subsystems: error and memory management
|
|
|
|
*
|
|
|
|
* If we are running under the postmaster, this is done already.
|
|
|
|
*/
|
2004-05-28 07:13:32 +02:00
|
|
|
if (!IsUnderPostmaster)
|
2000-06-28 05:33:33 +02:00
|
|
|
MemoryContextInit();
|
|
|
|
|
2004-07-31 19:57:11 +02:00
|
|
|
/* Compute paths, if we didn't inherit them from postmaster */
|
|
|
|
if (my_exec_path[0] == '\0')
|
|
|
|
{
|
2005-01-14 22:08:44 +01:00
|
|
|
if (find_my_exec(progname, my_exec_path) < 0)
|
2004-07-31 19:57:11 +02:00
|
|
|
elog(FATAL, "%s: could not locate my own executable path",
|
2005-01-14 22:08:44 +01:00
|
|
|
progname);
|
2004-07-31 19:57:11 +02:00
|
|
|
}
|
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
|
|
|
* process command arguments
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
|
|
|
|
|
|
|
/* Set defaults, to be overriden by explicit options below */
|
2003-12-25 04:52:51 +01:00
|
|
|
if (!IsUnderPostmaster)
|
2002-05-17 03:19:19 +02:00
|
|
|
InitializeGUCOptions();
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2006-06-18 17:38:37 +02:00
|
|
|
/* Ignore the initial --boot argument, if present */
|
|
|
|
if (argc > 1 && strcmp(argv[1], "--boot") == 0)
|
2004-05-28 07:13:32 +02:00
|
|
|
{
|
|
|
|
argv++;
|
|
|
|
argc--;
|
|
|
|
}
|
|
|
|
|
2007-02-16 03:10:07 +01:00
|
|
|
while ((flag = getopt(argc, argv, "B:c:d:D:Fr:x:-:")) != -1)
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
|
|
|
switch (flag)
|
|
|
|
{
|
2006-01-05 11:07:46 +01:00
|
|
|
case 'B':
|
|
|
|
SetConfigOption("shared_buffers", optarg, PGC_POSTMASTER, PGC_S_ARGV);
|
|
|
|
break;
|
1997-09-08 04:41:22 +02:00
|
|
|
case 'D':
|
2004-10-08 03:36:36 +02:00
|
|
|
userDoption = optarg;
|
1997-09-08 04:41:22 +02:00
|
|
|
break;
|
|
|
|
case 'd':
|
2002-09-04 22:31:48 +02:00
|
|
|
{
|
|
|
|
/* Turn on debugging for the bootstrap process. */
|
|
|
|
char *debugstr = palloc(strlen("debug") + strlen(optarg) + 1);
|
|
|
|
|
|
|
|
sprintf(debugstr, "debug%s", optarg);
|
2002-11-15 00:53:27 +01:00
|
|
|
SetConfigOption("log_min_messages", debugstr,
|
2002-09-04 22:31:48 +02:00
|
|
|
PGC_POSTMASTER, PGC_S_ARGV);
|
|
|
|
SetConfigOption("client_min_messages", debugstr,
|
|
|
|
PGC_POSTMASTER, PGC_S_ARGV);
|
|
|
|
pfree(debugstr);
|
|
|
|
}
|
1997-09-08 04:41:22 +02:00
|
|
|
break;
|
|
|
|
case 'F':
|
2002-02-23 02:31:37 +01:00
|
|
|
SetConfigOption("fsync", "false", PGC_POSTMASTER, PGC_S_ARGV);
|
1997-09-08 04:41:22 +02:00
|
|
|
break;
|
2006-01-05 11:07:46 +01:00
|
|
|
case 'r':
|
2007-02-10 15:58:55 +01:00
|
|
|
strlcpy(OutputFileName, optarg, MAXPGPATH);
|
2001-08-25 02:31:17 +02:00
|
|
|
break;
|
1999-10-06 23:58:18 +02:00
|
|
|
case 'x':
|
2007-03-07 14:35:03 +01:00
|
|
|
auxType = atoi(optarg);
|
1999-10-06 23:58:18 +02:00
|
|
|
break;
|
2003-07-15 02:11:14 +02:00
|
|
|
case 'c':
|
|
|
|
case '-':
|
|
|
|
{
|
|
|
|
char *name,
|
|
|
|
*value;
|
|
|
|
|
|
|
|
ParseLongOption(optarg, &name, &value);
|
|
|
|
if (!value)
|
|
|
|
{
|
|
|
|
if (flag == '-')
|
2003-07-23 01:30:39 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_SYNTAX_ERROR),
|
|
|
|
errmsg("--%s requires a value",
|
|
|
|
optarg)));
|
2003-07-15 02:11:14 +02:00
|
|
|
else
|
2003-07-23 01:30:39 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_SYNTAX_ERROR),
|
|
|
|
errmsg("-c %s requires a value",
|
|
|
|
optarg)));
|
2003-07-15 02:11:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
SetConfigOption(name, value, PGC_POSTMASTER, PGC_S_ARGV);
|
|
|
|
free(name);
|
|
|
|
if (value)
|
|
|
|
free(value);
|
|
|
|
break;
|
|
|
|
}
|
1997-09-08 04:41:22 +02:00
|
|
|
default:
|
2006-06-18 17:38:37 +02:00
|
|
|
write_stderr("Try \"%s --help\" for more information.\n",
|
|
|
|
progname);
|
|
|
|
proc_exit(1);
|
1997-09-08 04:41:22 +02:00
|
|
|
break;
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
2003-05-07 01:34:56 +02:00
|
|
|
}
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2007-02-16 03:10:07 +01:00
|
|
|
if (argc != optind)
|
2006-06-18 17:38:37 +02:00
|
|
|
{
|
|
|
|
write_stderr("%s: invalid command-line arguments\n", progname);
|
|
|
|
proc_exit(1);
|
|
|
|
}
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2004-05-28 07:13:32 +02:00
|
|
|
/*
|
|
|
|
* Identify myself via ps
|
|
|
|
*/
|
2003-09-02 21:04:12 +02:00
|
|
|
if (IsUnderPostmaster)
|
|
|
|
{
|
2004-05-28 07:13:32 +02:00
|
|
|
const char *statmsg;
|
2003-12-25 04:52:51 +01:00
|
|
|
|
2007-03-07 14:35:03 +01:00
|
|
|
switch (auxType)
|
2004-05-28 07:13:32 +02:00
|
|
|
{
|
2007-03-07 14:35:03 +01:00
|
|
|
case StartupProcess:
|
2004-05-30 00:48:23 +02:00
|
|
|
statmsg = "startup process";
|
2004-05-28 07:13:32 +02:00
|
|
|
break;
|
2007-03-07 14:35:03 +01:00
|
|
|
case BgWriterProcess:
|
2004-05-30 00:48:23 +02:00
|
|
|
statmsg = "writer process";
|
2004-05-28 07:13:32 +02:00
|
|
|
break;
|
2007-07-24 06:54:09 +02:00
|
|
|
case WalWriterProcess:
|
|
|
|
statmsg = "wal writer process";
|
|
|
|
break;
|
2010-01-15 10:19:10 +01:00
|
|
|
case WalReceiverProcess:
|
|
|
|
statmsg = "wal receiver process";
|
|
|
|
break;
|
2004-05-28 07:13:32 +02:00
|
|
|
default:
|
2004-05-30 00:48:23 +02:00
|
|
|
statmsg = "??? process";
|
2004-05-28 07:13:32 +02:00
|
|
|
break;
|
|
|
|
}
|
2006-06-28 00:16:44 +02:00
|
|
|
init_ps_display(statmsg, "", "", "");
|
2003-09-02 21:04:12 +02:00
|
|
|
}
|
2004-05-28 07:13:32 +02:00
|
|
|
|
|
|
|
/* Acquire configuration parameters, unless inherited from postmaster */
|
|
|
|
if (!IsUnderPostmaster)
|
|
|
|
{
|
2005-01-14 22:08:44 +01:00
|
|
|
if (!SelectConfigFiles(userDoption, progname))
|
2004-10-08 03:36:36 +02:00
|
|
|
proc_exit(1);
|
2005-10-20 22:05:45 +02:00
|
|
|
/* If timezone is not set, determine what the OS uses */
|
|
|
|
pg_timezone_initialize();
|
2006-07-29 05:02:56 +02:00
|
|
|
/* If timezone_abbreviations is not set, select default */
|
|
|
|
pg_timezone_abbrev_initialize();
|
2004-05-28 07:13:32 +02:00
|
|
|
}
|
2004-05-21 07:08:06 +02:00
|
|
|
|
2004-10-08 03:36:36 +02:00
|
|
|
/* Validate we have been given a reasonable-looking DataDir */
|
|
|
|
Assert(DataDir);
|
|
|
|
ValidatePgVersion(DataDir);
|
|
|
|
|
2005-07-04 06:51:52 +02:00
|
|
|
/* Change into DataDir (if under postmaster, should be done already) */
|
|
|
|
if (!IsUnderPostmaster)
|
|
|
|
ChangeToDataDir();
|
|
|
|
|
2004-05-30 00:48:23 +02:00
|
|
|
/* If standalone, create lockfile for data directory */
|
|
|
|
if (!IsUnderPostmaster)
|
2005-07-04 06:51:52 +02:00
|
|
|
CreateDataDirLockFile(false);
|
1999-10-06 23:58:18 +02:00
|
|
|
|
XLOG (and related) changes:
* Store two past checkpoint locations, not just one, in pg_control.
On startup, we fall back to the older checkpoint if the newer one
is unreadable. Also, a physical copy of the newest checkpoint record
is kept in pg_control for possible use in disaster recovery (ie,
complete loss of pg_xlog). Also add a version number for pg_control
itself. Remove archdir from pg_control; it ought to be a GUC
parameter, not a special case (not that it's implemented yet anyway).
* Suppress successive checkpoint records when nothing has been entered
in the WAL log since the last one. This is not so much to avoid I/O
as to make it actually useful to keep track of the last two
checkpoints. If the things are right next to each other then there's
not a lot of redundancy gained...
* Change CRC scheme to a true 64-bit CRC, not a pair of 32-bit CRCs
on alternate bytes. Polynomial borrowed from ECMA DLT1 standard.
* Fix XLOG record length handling so that it will work at BLCKSZ = 32k.
* Change XID allocation to work more like OID allocation. (This is of
dubious necessity, but I think it's a good idea anyway.)
* Fix a number of minor bugs, such as off-by-one logic for XLOG file
wraparound at the 4 gig mark.
* Add documentation and clean up some coding infelicities; move file
format declarations out to include files where planned contrib
utilities can get at them.
* Checkpoint will now occur every CHECKPOINT_SEGMENTS log segments or
every CHECKPOINT_TIMEOUT seconds, whichever comes first. It is also
possible to force a checkpoint by sending SIGUSR1 to the postmaster
(undocumented feature...)
* Defend against kill -9 postmaster by storing shmem block's key and ID
in postmaster.pid lockfile, and checking at startup to ensure that no
processes are still connected to old shmem block (if it still exists).
* Switch backends to accept SIGQUIT rather than SIGUSR1 for emergency
stop, for symmetry with postmaster and xlog utilities. Clean up signal
handling in bootstrap.c so that xlog utilities launched by postmaster
will react to signals better.
* Standalone bootstrap now grabs lockfile in target directory, as added
insurance against running it in parallel with live postmaster.
2001-03-13 02:17:06 +01:00
|
|
|
SetProcessingMode(BootstrapProcessing);
|
2006-01-05 11:07:46 +01:00
|
|
|
IgnoreSystemIndexes = true;
|
XLOG (and related) changes:
* Store two past checkpoint locations, not just one, in pg_control.
On startup, we fall back to the older checkpoint if the newer one
is unreadable. Also, a physical copy of the newest checkpoint record
is kept in pg_control for possible use in disaster recovery (ie,
complete loss of pg_xlog). Also add a version number for pg_control
itself. Remove archdir from pg_control; it ought to be a GUC
parameter, not a special case (not that it's implemented yet anyway).
* Suppress successive checkpoint records when nothing has been entered
in the WAL log since the last one. This is not so much to avoid I/O
as to make it actually useful to keep track of the last two
checkpoints. If the things are right next to each other then there's
not a lot of redundancy gained...
* Change CRC scheme to a true 64-bit CRC, not a pair of 32-bit CRCs
on alternate bytes. Polynomial borrowed from ECMA DLT1 standard.
* Fix XLOG record length handling so that it will work at BLCKSZ = 32k.
* Change XID allocation to work more like OID allocation. (This is of
dubious necessity, but I think it's a good idea anyway.)
* Fix a number of minor bugs, such as off-by-one logic for XLOG file
wraparound at the 4 gig mark.
* Add documentation and clean up some coding infelicities; move file
format declarations out to include files where planned contrib
utilities can get at them.
* Checkpoint will now occur every CHECKPOINT_SEGMENTS log segments or
every CHECKPOINT_TIMEOUT seconds, whichever comes first. It is also
possible to force a checkpoint by sending SIGUSR1 to the postmaster
(undocumented feature...)
* Defend against kill -9 postmaster by storing shmem block's key and ID
in postmaster.pid lockfile, and checking at startup to ensure that no
processes are still connected to old shmem block (if it still exists).
* Switch backends to accept SIGQUIT rather than SIGUSR1 for emergency
stop, for symmetry with postmaster and xlog utilities. Clean up signal
handling in bootstrap.c so that xlog utilities launched by postmaster
will react to signals better.
* Standalone bootstrap now grabs lockfile in target directory, as added
insurance against running it in parallel with live postmaster.
2001-03-13 02:17:06 +01:00
|
|
|
|
|
|
|
BaseInit();
|
|
|
|
|
2005-08-08 05:12:16 +02:00
|
|
|
/*
|
2007-03-07 14:35:03 +01:00
|
|
|
* When we are an auxiliary process, we aren't going to do the full
|
2006-10-04 02:30:14 +02:00
|
|
|
* InitPostgres pushups, but there are a couple of things that need to get
|
2007-03-07 14:35:03 +01:00
|
|
|
* lit up even in an auxiliary process.
|
2005-08-08 05:12:16 +02:00
|
|
|
*/
|
2002-09-25 22:31:40 +02:00
|
|
|
if (IsUnderPostmaster)
|
2003-11-19 16:55:08 +01:00
|
|
|
{
|
2006-01-04 22:06:32 +01:00
|
|
|
/*
|
|
|
|
* Create a PGPROC so we can use LWLocks. In the EXEC_BACKEND case,
|
|
|
|
* this was already done by SubPostmasterMain().
|
|
|
|
*/
|
|
|
|
#ifndef EXEC_BACKEND
|
2007-03-07 14:35:03 +01:00
|
|
|
InitAuxiliaryProcess();
|
2006-01-04 22:06:32 +01:00
|
|
|
#endif
|
2005-08-08 05:12:16 +02:00
|
|
|
|
2009-07-31 22:26:23 +02:00
|
|
|
/*
|
2010-02-26 03:01:40 +01:00
|
|
|
* Assign the ProcSignalSlot for an auxiliary process. Since it
|
2009-07-31 22:26:23 +02:00
|
|
|
* doesn't have a BackendId, the slot is statically allocated based on
|
|
|
|
* the auxiliary process type (auxType). Backends use slots indexed
|
|
|
|
* in the range from 1 to MaxBackends (inclusive), so we use
|
|
|
|
* MaxBackends + AuxProcType + 1 as the index of the slot for an
|
|
|
|
* auxiliary process.
|
|
|
|
*
|
|
|
|
* This will need rethinking if we ever want more than one of a
|
|
|
|
* particular auxiliary process type.
|
|
|
|
*/
|
|
|
|
ProcSignalInit(MaxBackends + auxType + 1);
|
|
|
|
|
2005-08-08 05:12:16 +02:00
|
|
|
/* finish setting up bufmgr.c */
|
|
|
|
InitBufferPoolBackend();
|
2006-06-09 01:55:48 +02:00
|
|
|
|
|
|
|
/* register a shutdown callback for LWLock cleanup */
|
2007-03-07 14:35:03 +01:00
|
|
|
on_shmem_exit(ShutdownAuxiliaryProcess, 0);
|
2003-11-19 16:55:08 +01:00
|
|
|
}
|
2002-09-25 22:31:40 +02:00
|
|
|
|
1999-10-06 23:58:18 +02:00
|
|
|
/*
|
2000-11-09 12:26:00 +01:00
|
|
|
* XLOG operations
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
2000-11-21 10:39:57 +01:00
|
|
|
SetProcessingMode(NormalProcessing);
|
2001-09-29 06:02:27 +02:00
|
|
|
|
2007-03-07 14:35:03 +01:00
|
|
|
switch (auxType)
|
2000-11-21 10:39:57 +01:00
|
|
|
{
|
2007-03-07 14:35:03 +01:00
|
|
|
case CheckerProcess:
|
2010-04-20 03:38:52 +02:00
|
|
|
/* don't set signals, they're useless here */
|
2007-03-07 14:35:03 +01:00
|
|
|
CheckerModeMain();
|
|
|
|
proc_exit(1); /* should never return */
|
2001-09-29 06:02:27 +02:00
|
|
|
|
2007-03-07 14:35:03 +01:00
|
|
|
case BootstrapProcess:
|
2004-05-30 00:48:23 +02:00
|
|
|
bootstrap_signals();
|
2001-09-29 06:02:27 +02:00
|
|
|
BootStrapXLOG();
|
2007-03-07 14:35:03 +01:00
|
|
|
BootstrapModeMain();
|
|
|
|
proc_exit(1); /* should never return */
|
2001-09-29 06:02:27 +02:00
|
|
|
|
2007-03-07 14:35:03 +01:00
|
|
|
case StartupProcess:
|
Start background writer during archive recovery. Background writer now performs
its usual buffer cleaning duties during archive recovery, and it's responsible
for performing restartpoints.
This requires some changes in postmaster. When the startup process has done
all the initialization and is ready to start WAL redo, it signals the
postmaster to launch the background writer. The postmaster is signaled again
when the point in recovery is reached where we know that the database is in
consistent state. Postmaster isn't interested in that at the moment, but
that's the point where we could let other backends in to perform read-only
queries. The postmaster is signaled third time when the recovery has ended,
so that postmaster knows that it's safe to start accepting connections.
The startup process now traps SIGTERM, and performs a "clean" shutdown. If
you do a fast shutdown during recovery, a shutdown restartpoint is performed,
like a shutdown checkpoint, and postmaster kills the processes cleanly. You
still have to continue the recovery at next startup, though.
Currently, the background writer is only launched during archive recovery.
We could launch it during crash recovery as well, but it seems better to keep
that codepath as simple as possible, for the sake of robustness. And it
couldn't do any restartpoints during crash recovery anyway, so it wouldn't be
that useful.
log_restartpoints is gone. Use log_checkpoints instead. This is yet to be
documented.
This whole operation is a pre-requisite for Hot Standby, but has some value of
its own whether the hot standby patch makes 8.4 or not.
Simon Riggs, with lots of modifications by me.
2009-02-18 16:58:41 +01:00
|
|
|
/* don't set signals, startup process has its own agenda */
|
|
|
|
StartupProcessMain();
|
|
|
|
proc_exit(1); /* should never return */
|
2001-09-29 06:02:27 +02:00
|
|
|
|
2007-03-07 14:35:03 +01:00
|
|
|
case BgWriterProcess:
|
2004-05-30 00:48:23 +02:00
|
|
|
/* don't set signals, bgwriter has its own agenda */
|
|
|
|
BackgroundWriterMain();
|
|
|
|
proc_exit(1); /* should never return */
|
2007-07-24 06:54:09 +02:00
|
|
|
|
|
|
|
case WalWriterProcess:
|
|
|
|
/* don't set signals, walwriter has its own agenda */
|
|
|
|
InitXLOGAccess();
|
|
|
|
WalWriterMain();
|
|
|
|
proc_exit(1); /* should never return */
|
2007-11-15 22:14:46 +01:00
|
|
|
|
2010-01-15 10:19:10 +01:00
|
|
|
case WalReceiverProcess:
|
|
|
|
/* don't set signals, walreceiver has its own agenda */
|
2010-01-20 10:16:24 +01:00
|
|
|
WalReceiverMain();
|
2010-01-15 10:19:10 +01:00
|
|
|
proc_exit(1); /* should never return */
|
|
|
|
|
2001-09-29 06:02:27 +02:00
|
|
|
default:
|
2007-03-07 14:35:03 +01:00
|
|
|
elog(PANIC, "unrecognized process type: %d", auxType);
|
2004-05-30 00:48:23 +02:00
|
|
|
proc_exit(1);
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
2007-03-07 14:35:03 +01:00
|
|
|
}
|
2001-09-29 06:02:27 +02:00
|
|
|
|
2007-03-07 14:35:03 +01:00
|
|
|
/*
|
|
|
|
* In shared memory checker mode, all we really want to do is create shared
|
|
|
|
* memory and semaphores (just to prove we can do it with the current GUC
|
2010-04-20 03:38:52 +02:00
|
|
|
* settings). Since, in fact, that was already done by BaseInit(),
|
|
|
|
* we have nothing more to do here.
|
2007-03-07 14:35:03 +01:00
|
|
|
*/
|
|
|
|
static void
|
|
|
|
CheckerModeMain(void)
|
|
|
|
{
|
|
|
|
proc_exit(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The main entry point for running 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.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
BootstrapModeMain(void)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
Assert(!IsUnderPostmaster);
|
|
|
|
|
|
|
|
SetProcessingMode(BootstrapProcessing);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2003-07-15 02:11:14 +02:00
|
|
|
/*
|
2007-03-07 14:35:03 +01:00
|
|
|
* Do backend-like initialization for bootstrap mode
|
2003-07-15 02:11:14 +02:00
|
|
|
*/
|
2007-03-07 14:35:03 +01:00
|
|
|
InitProcess();
|
2010-04-20 03:38:52 +02:00
|
|
|
|
2007-03-07 14:35:03 +01:00
|
|
|
InitPostgres(NULL, InvalidOid, NULL, NULL);
|
2003-07-15 02:11:14 +02:00
|
|
|
|
|
|
|
/* Initialize stuff for bootstrap-file processing */
|
1997-09-07 07:04:48 +02:00
|
|
|
for (i = 0; i < MAXATTR; i++)
|
|
|
|
{
|
2004-01-07 19:56:30 +01:00
|
|
|
attrtypes[i] = NULL;
|
2008-11-02 02:45:28 +01:00
|
|
|
Nulls[i] = false;
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
2003-07-15 02:11:14 +02:00
|
|
|
* Process bootstrap input.
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
2006-03-07 02:03:12 +01:00
|
|
|
boot_yyparse();
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2010-02-07 21:48:13 +01:00
|
|
|
/*
|
2010-02-26 03:01:40 +01:00
|
|
|
* We should now know about all mapped relations, so it's okay to write
|
|
|
|
* out the initial relation mapping files.
|
2010-02-07 21:48:13 +01:00
|
|
|
*/
|
|
|
|
RelationMapFinishBootstrap();
|
|
|
|
|
2003-07-15 02:11:14 +02:00
|
|
|
/* Clean up and exit */
|
1997-09-07 07:04:48 +02:00
|
|
|
cleanup();
|
2007-03-07 14:35:03 +01:00
|
|
|
proc_exit(0);
|
2004-05-30 00:48:23 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* ----------------------------------------------------------------
|
|
|
|
* misc functions
|
|
|
|
* ----------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Set up signal handling for a bootstrap process
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
bootstrap_signals(void)
|
|
|
|
{
|
|
|
|
if (IsUnderPostmaster)
|
|
|
|
{
|
2006-11-21 21:59:53 +01:00
|
|
|
/*
|
|
|
|
* If possible, make this process a group leader, so that the
|
|
|
|
* postmaster can signal any child processes too.
|
|
|
|
*/
|
|
|
|
#ifdef HAVE_SETSID
|
|
|
|
if (setsid() < 0)
|
|
|
|
elog(FATAL, "setsid() failed: %m");
|
|
|
|
#endif
|
|
|
|
|
2004-05-30 00:48:23 +02:00
|
|
|
/*
|
|
|
|
* Properly accept or ignore signals the postmaster might send us
|
|
|
|
*/
|
|
|
|
pqsignal(SIGHUP, SIG_IGN);
|
|
|
|
pqsignal(SIGINT, SIG_IGN); /* ignore query-cancel */
|
|
|
|
pqsignal(SIGTERM, die);
|
|
|
|
pqsignal(SIGQUIT, quickdie);
|
|
|
|
pqsignal(SIGALRM, SIG_IGN);
|
|
|
|
pqsignal(SIGPIPE, SIG_IGN);
|
|
|
|
pqsignal(SIGUSR1, SIG_IGN);
|
|
|
|
pqsignal(SIGUSR2, SIG_IGN);
|
1996-07-09 08:22:35 +02:00
|
|
|
|
2004-05-30 00:48:23 +02:00
|
|
|
/*
|
|
|
|
* Reset some signals that are accepted by postmaster but not here
|
|
|
|
*/
|
|
|
|
pqsignal(SIGCHLD, SIG_DFL);
|
|
|
|
pqsignal(SIGTTIN, SIG_DFL);
|
|
|
|
pqsignal(SIGTTOU, SIG_DFL);
|
|
|
|
pqsignal(SIGCONT, SIG_DFL);
|
|
|
|
pqsignal(SIGWINCH, SIG_DFL);
|
|
|
|
|
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
* Unblock signals (they were blocked when the postmaster forked us)
|
2004-05-30 00:48:23 +02:00
|
|
|
*/
|
|
|
|
PG_SETMASK(&UnBlockSig);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Set up appropriately for interactive use */
|
|
|
|
pqsignal(SIGHUP, die);
|
|
|
|
pqsignal(SIGINT, die);
|
|
|
|
pqsignal(SIGTERM, die);
|
|
|
|
pqsignal(SIGQUIT, die);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-06-09 01:55:48 +02:00
|
|
|
/*
|
2007-11-15 22:14:46 +01:00
|
|
|
* Begin shutdown of an auxiliary process. This is approximately the equivalent
|
2007-03-07 14:35:03 +01:00
|
|
|
* of ShutdownPostgres() in postinit.c. We can't run transactions in an
|
|
|
|
* auxiliary process, so most of the work of AbortTransaction() is not needed,
|
2006-06-09 01:55:48 +02:00
|
|
|
* but we do need to make sure we've released any LWLocks we are holding.
|
|
|
|
* (This is only critical during an error exit.)
|
|
|
|
*/
|
|
|
|
static void
|
2007-03-07 14:35:03 +01:00
|
|
|
ShutdownAuxiliaryProcess(int code, Datum arg)
|
2006-06-09 01:55:48 +02:00
|
|
|
{
|
|
|
|
LWLockReleaseAll();
|
|
|
|
}
|
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
/* ----------------------------------------------------------------
|
1997-09-07 07:04:48 +02:00
|
|
|
* MANUAL BACKEND INTERACTIVE INTERFACE COMMANDS
|
1996-07-09 08:22:35 +02:00
|
|
|
* ----------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* ----------------
|
1997-09-07 07:04:48 +02:00
|
|
|
* boot_openrel
|
1996-07-09 08:22:35 +02:00
|
|
|
* ----------------
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
boot_openrel(char *relname)
|
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
int i;
|
1997-09-07 07:04:48 +02:00
|
|
|
struct typmap **app;
|
1998-08-19 04:04:17 +02:00
|
|
|
Relation rel;
|
|
|
|
HeapScanDesc scan;
|
1997-09-08 04:41:22 +02:00
|
|
|
HeapTuple tup;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2005-04-14 22:03:27 +02:00
|
|
|
if (strlen(relname) >= NAMEDATALEN)
|
1998-02-26 05:46:47 +01:00
|
|
|
relname[NAMEDATALEN - 1] = '\0';
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2004-01-07 19:56:30 +01:00
|
|
|
if (Typ == NULL)
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
2006-08-16 00:36:17 +02:00
|
|
|
/* We can now load the pg_type data */
|
2005-04-14 22:03:27 +02:00
|
|
|
rel = heap_open(TypeRelationId, NoLock);
|
2004-01-07 19:56:30 +01:00
|
|
|
scan = heap_beginscan(rel, SnapshotNow, 0, NULL);
|
1998-08-19 04:04:17 +02:00
|
|
|
i = 0;
|
2002-05-21 01:51:44 +02:00
|
|
|
while ((tup = heap_getnext(scan, ForwardScanDirection)) != NULL)
|
1998-08-19 04:04:17 +02:00
|
|
|
++i;
|
|
|
|
heap_endscan(scan);
|
1997-09-07 07:04:48 +02:00
|
|
|
app = Typ = ALLOC(struct typmap *, i + 1);
|
|
|
|
while (i-- > 0)
|
|
|
|
*app++ = ALLOC(struct typmap, 1);
|
2004-01-07 19:56:30 +01:00
|
|
|
*app = NULL;
|
|
|
|
scan = heap_beginscan(rel, SnapshotNow, 0, NULL);
|
1997-09-07 07:04:48 +02:00
|
|
|
app = Typ;
|
2002-05-21 01:51:44 +02:00
|
|
|
while ((tup = heap_getnext(scan, ForwardScanDirection)) != NULL)
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
2002-07-20 07:16:59 +02:00
|
|
|
(*app)->am_oid = HeapTupleGetOid(tup);
|
2000-06-28 05:33:33 +02:00
|
|
|
memcpy((char *) &(*app)->am_typ,
|
|
|
|
(char *) GETSTRUCT(tup),
|
|
|
|
sizeof((*app)->am_typ));
|
|
|
|
app++;
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
1998-08-19 04:04:17 +02:00
|
|
|
heap_endscan(scan);
|
1999-09-18 21:08:25 +02:00
|
|
|
heap_close(rel, NoLock);
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
|
|
|
|
2002-04-27 23:24:34 +02:00
|
|
|
if (boot_reldesc != NULL)
|
1997-09-07 07:04:48 +02:00
|
|
|
closerel(NULL);
|
|
|
|
|
2003-07-23 01:30:39 +02:00
|
|
|
elog(DEBUG4, "open relation %s, attrsize %d",
|
2009-01-22 21:16:10 +01:00
|
|
|
relname, (int) ATTRIBUTE_FIXED_PART_SIZE);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2008-09-01 22:42:46 +02:00
|
|
|
boot_reldesc = heap_openrv(makeRangeVar(NULL, relname, -1), NoLock);
|
2002-04-27 23:24:34 +02:00
|
|
|
numattr = boot_reldesc->rd_rel->relnatts;
|
1997-09-07 07:04:48 +02:00
|
|
|
for (i = 0; i < numattr; i++)
|
|
|
|
{
|
|
|
|
if (attrtypes[i] == NULL)
|
|
|
|
attrtypes[i] = AllocateAttribute();
|
|
|
|
memmove((char *) attrtypes[i],
|
2002-04-27 23:24:34 +02:00
|
|
|
(char *) boot_reldesc->rd_att->attrs[i],
|
2009-01-22 21:16:10 +01:00
|
|
|
ATTRIBUTE_FIXED_PART_SIZE);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
{
|
1998-09-01 05:29:17 +02:00
|
|
|
Form_pg_attribute at = attrtypes[i];
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2003-05-27 19:49:47 +02:00
|
|
|
elog(DEBUG4, "create attribute %d name %s len %d num %d type %u",
|
2001-05-12 03:48:49 +02:00
|
|
|
i, NameStr(at->attname), at->attlen, at->attnum,
|
Commit to match discussed elog() changes. Only update is that LOG is
now just below FATAL in server_min_messages. Added more text to
highlight ordering difference between it and client_min_messages.
---------------------------------------------------------------------------
REALLYFATAL => PANIC
STOP => PANIC
New INFO level the prints to client by default
New LOG level the prints to server log by default
Cause VACUUM information to print only to the client
NOTICE => INFO where purely information messages are sent
DEBUG => LOG for purely server status messages
DEBUG removed, kept as backward compatible
DEBUG5, DEBUG4, DEBUG3, DEBUG2, DEBUG1 added
DebugLvl removed in favor of new DEBUG[1-5] symbols
New server_min_messages GUC parameter with values:
DEBUG[5-1], INFO, NOTICE, ERROR, LOG, FATAL, PANIC
New client_min_messages GUC parameter with values:
DEBUG[5-1], LOG, INFO, NOTICE, ERROR, FATAL, PANIC
Server startup now logged with LOG instead of DEBUG
Remove debug_level GUC parameter
elog() numbers now start at 10
Add test to print error message if older elog() values are passed to elog()
Bootstrap mode now has a -d that requires an argument, like postmaster
2002-03-02 22:39:36 +01:00
|
|
|
at->atttypid);
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
|
|
|
}
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* ----------------
|
1997-09-07 07:04:48 +02:00
|
|
|
* closerel
|
1996-07-09 08:22:35 +02:00
|
|
|
* ----------------
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
closerel(char *name)
|
|
|
|
{
|
1997-09-07 07:04:48 +02:00
|
|
|
if (name)
|
|
|
|
{
|
2002-04-27 23:24:34 +02:00
|
|
|
if (boot_reldesc)
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
2002-04-27 23:24:34 +02:00
|
|
|
if (strcmp(RelationGetRelationName(boot_reldesc), name) != 0)
|
2003-07-23 01:30:39 +02:00
|
|
|
elog(ERROR, "close of %s when %s was expected",
|
2005-04-14 22:03:27 +02:00
|
|
|
name, RelationGetRelationName(boot_reldesc));
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
|
|
|
else
|
2003-07-23 01:30:39 +02:00
|
|
|
elog(ERROR, "close of %s before any relation was opened",
|
1997-09-07 07:04:48 +02:00
|
|
|
name);
|
|
|
|
}
|
|
|
|
|
2002-04-27 23:24:34 +02:00
|
|
|
if (boot_reldesc == NULL)
|
2001-05-12 03:48:49 +02:00
|
|
|
elog(ERROR, "no open relation to close");
|
1997-09-07 07:04:48 +02:00
|
|
|
else
|
|
|
|
{
|
2005-04-14 22:03:27 +02:00
|
|
|
elog(DEBUG4, "close relation %s",
|
|
|
|
RelationGetRelationName(boot_reldesc));
|
2002-04-27 23:24:34 +02:00
|
|
|
heap_close(boot_reldesc, NoLock);
|
2004-01-07 19:56:30 +01:00
|
|
|
boot_reldesc = NULL;
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
/* ----------------
|
|
|
|
* 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)
|
|
|
|
{
|
1998-08-24 21:04:04 +02:00
|
|
|
Oid typeoid;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2002-04-27 23:24:34 +02:00
|
|
|
if (boot_reldesc != NULL)
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
2003-07-23 01:30:39 +02:00
|
|
|
elog(WARNING, "no open relations allowed with CREATE command");
|
2005-04-14 22:03:27 +02:00
|
|
|
closerel(NULL);
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
|
|
|
|
2004-01-07 19:56:30 +01:00
|
|
|
if (attrtypes[attnum] == NULL)
|
1997-09-07 07:04:48 +02:00
|
|
|
attrtypes[attnum] = AllocateAttribute();
|
2009-01-22 21:16:10 +01:00
|
|
|
MemSet(attrtypes[attnum], 0, ATTRIBUTE_FIXED_PART_SIZE);
|
2002-08-02 20:15:10 +02:00
|
|
|
|
|
|
|
namestrcpy(&attrtypes[attnum]->attname, name);
|
2003-05-27 19:49:47 +02:00
|
|
|
elog(DEBUG4, "column %s %s", NameStr(attrtypes[attnum]->attname), type);
|
2002-09-22 21:42:52 +02:00
|
|
|
attrtypes[attnum]->attnum = attnum + 1; /* fillatt */
|
2002-08-02 20:15:10 +02:00
|
|
|
|
|
|
|
typeoid = gettype(type);
|
|
|
|
|
2004-01-07 19:56:30 +01:00
|
|
|
if (Typ != NULL)
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
|
|
|
attrtypes[attnum]->atttypid = Ap->am_oid;
|
2005-03-29 02:17:27 +02:00
|
|
|
attrtypes[attnum]->attlen = Ap->am_typ.typlen;
|
1997-09-07 07:04:48 +02:00
|
|
|
attrtypes[attnum]->attbyval = Ap->am_typ.typbyval;
|
2002-04-25 04:56:56 +02:00
|
|
|
attrtypes[attnum]->attstorage = Ap->am_typ.typstorage;
|
1998-08-24 21:04:04 +02:00
|
|
|
attrtypes[attnum]->attalign = Ap->am_typ.typalign;
|
2004-01-07 00:55:19 +01:00
|
|
|
/* if an array type, assume 1-dimensional attribute */
|
|
|
|
if (Ap->am_typ.typelem != InvalidOid && Ap->am_typ.typlen < 0)
|
|
|
|
attrtypes[attnum]->attndims = 1;
|
|
|
|
else
|
|
|
|
attrtypes[attnum]->attndims = 0;
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2004-04-01 23:28:47 +02:00
|
|
|
attrtypes[attnum]->atttypid = TypInfo[typeoid].oid;
|
2005-03-29 02:17:27 +02:00
|
|
|
attrtypes[attnum]->attlen = TypInfo[typeoid].len;
|
2004-04-01 23:28:47 +02:00
|
|
|
attrtypes[attnum]->attbyval = TypInfo[typeoid].byval;
|
|
|
|
attrtypes[attnum]->attstorage = TypInfo[typeoid].storage;
|
|
|
|
attrtypes[attnum]->attalign = TypInfo[typeoid].align;
|
2004-01-07 00:55:19 +01:00
|
|
|
/* if an array type, assume 1-dimensional attribute */
|
2005-03-29 02:17:27 +02:00
|
|
|
if (TypInfo[typeoid].elem != InvalidOid &&
|
|
|
|
attrtypes[attnum]->attlen < 0)
|
2004-01-07 00:55:19 +01:00
|
|
|
attrtypes[attnum]->attndims = 1;
|
|
|
|
else
|
|
|
|
attrtypes[attnum]->attndims = 0;
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
2004-01-07 00:55:19 +01:00
|
|
|
|
|
|
|
attrtypes[attnum]->attstattarget = -1;
|
1998-02-06 20:18:06 +01:00
|
|
|
attrtypes[attnum]->attcacheoff = -1;
|
1998-02-07 07:11:56 +01:00
|
|
|
attrtypes[attnum]->atttypmod = -1;
|
2002-09-22 21:42:52 +02:00
|
|
|
attrtypes[attnum]->attislocal = true;
|
2002-09-04 22:31:48 +02:00
|
|
|
|
2002-08-02 20:15:10 +02:00
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
* Mark as "not null" if type is fixed-width and prior columns are too.
|
|
|
|
* This corresponds to case where column can be accessed directly via C
|
|
|
|
* struct declaration.
|
2005-03-29 02:17:27 +02:00
|
|
|
*
|
2005-10-15 04:49:52 +02:00
|
|
|
* oidvector and int2vector are also treated as not-nullable, even though
|
|
|
|
* they are no longer fixed-width.
|
2002-08-02 20:15:10 +02:00
|
|
|
*/
|
2005-03-29 02:17:27 +02:00
|
|
|
#define MARKNOTNULL(att) \
|
|
|
|
((att)->attlen > 0 || \
|
|
|
|
(att)->atttypid == OIDVECTOROID || \
|
|
|
|
(att)->atttypid == INT2VECTOROID)
|
|
|
|
|
|
|
|
if (MARKNOTNULL(attrtypes[attnum]))
|
2002-08-02 20:15:10 +02:00
|
|
|
{
|
2002-09-04 22:31:48 +02:00
|
|
|
int i;
|
2002-08-02 20:15:10 +02:00
|
|
|
|
|
|
|
for (i = 0; i < attnum; i++)
|
|
|
|
{
|
2005-03-29 02:17:27 +02:00
|
|
|
if (!MARKNOTNULL(attrtypes[i]))
|
2002-08-02 20:15:10 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (i == attnum)
|
|
|
|
attrtypes[attnum]->attnotnull = true;
|
|
|
|
}
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* ----------------
|
1997-09-07 07:04:48 +02:00
|
|
|
* InsertOneTuple
|
2001-08-10 20:57:42 +02:00
|
|
|
*
|
|
|
|
* If objectid is not zero, it is a specific OID to assign to the tuple.
|
|
|
|
* Otherwise, an OID will be assigned (if necessary) by heap_insert.
|
1996-07-09 08:22:35 +02:00
|
|
|
* ----------------
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
InsertOneTuple(Oid objectid)
|
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
HeapTuple tuple;
|
|
|
|
TupleDesc tupDesc;
|
|
|
|
int i;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2003-05-27 19:49:47 +02:00
|
|
|
elog(DEBUG4, "inserting row oid %u, %d columns", objectid, numattr);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2002-09-02 03:05:06 +02:00
|
|
|
tupDesc = CreateTupleDesc(numattr,
|
|
|
|
RelationGetForm(boot_reldesc)->relhasoids,
|
|
|
|
attrtypes);
|
2008-11-02 02:45:28 +01:00
|
|
|
tuple = heap_form_tuple(tupDesc, values, Nulls);
|
1997-09-07 07:04:48 +02:00
|
|
|
if (objectid != (Oid) 0)
|
2002-07-20 07:16:59 +02:00
|
|
|
HeapTupleSetOid(tuple, objectid);
|
|
|
|
pfree(tupDesc); /* just free's tupDesc, not the attrtypes */
|
2002-09-02 03:05:06 +02:00
|
|
|
|
2002-05-22 00:05:55 +02:00
|
|
|
simple_heap_insert(boot_reldesc, tuple);
|
1999-12-16 23:20:03 +01:00
|
|
|
heap_freetuple(tuple);
|
2003-05-27 19:49:47 +02:00
|
|
|
elog(DEBUG4, "row inserted");
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
/*
|
2008-11-02 02:45:28 +01:00
|
|
|
* Reset null markers for next tuple
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
|
|
|
for (i = 0; i < numattr; i++)
|
2008-11-02 02:45:28 +01:00
|
|
|
Nulls[i] = false;
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* ----------------
|
1997-09-07 07:04:48 +02:00
|
|
|
* InsertOneValue
|
1996-07-09 08:22:35 +02:00
|
|
|
* ----------------
|
|
|
|
*/
|
|
|
|
void
|
2001-08-10 20:57:42 +02:00
|
|
|
InsertOneValue(char *value, int i)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
2004-06-06 02:41:28 +02:00
|
|
|
Oid typoid;
|
2006-08-16 00:36:17 +02:00
|
|
|
int16 typlen;
|
|
|
|
bool typbyval;
|
|
|
|
char typalign;
|
|
|
|
char typdelim;
|
2004-06-06 02:41:28 +02:00
|
|
|
Oid typioparam;
|
|
|
|
Oid typinput;
|
|
|
|
Oid typoutput;
|
1997-09-08 04:41:22 +02:00
|
|
|
char *prt;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2001-05-12 03:48:49 +02:00
|
|
|
AssertArg(i >= 0 || i < MAXATTR);
|
|
|
|
|
2003-07-23 01:30:39 +02:00
|
|
|
elog(DEBUG4, "inserting column %d value \"%s\"", i, value);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2007-03-07 14:35:03 +01:00
|
|
|
typoid = boot_reldesc->rd_att->attrs[i]->atttypid;
|
2004-06-06 02:41:28 +02:00
|
|
|
|
2006-08-16 00:36:17 +02:00
|
|
|
boot_get_type_io_data(typoid,
|
|
|
|
&typlen, &typbyval, &typalign,
|
|
|
|
&typdelim, &typioparam,
|
|
|
|
&typinput, &typoutput);
|
|
|
|
|
2006-04-04 21:35:37 +02:00
|
|
|
values[i] = OidInputFunctionCall(typinput, value, typioparam, -1);
|
|
|
|
prt = OidOutputFunctionCall(typoutput, values[i]);
|
2004-06-06 02:41:28 +02:00
|
|
|
elog(DEBUG4, "inserted -> %s", prt);
|
|
|
|
pfree(prt);
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* ----------------
|
1997-09-07 07:04:48 +02:00
|
|
|
* InsertOneNull
|
1996-07-09 08:22:35 +02:00
|
|
|
* ----------------
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
InsertOneNull(int i)
|
|
|
|
{
|
2003-05-27 19:49:47 +02:00
|
|
|
elog(DEBUG4, "inserting column %d NULL", i);
|
2001-05-12 03:48:49 +02:00
|
|
|
Assert(i >= 0 || i < MAXATTR);
|
2000-05-30 06:25:00 +02:00
|
|
|
values[i] = PointerGetDatum(NULL);
|
2008-11-02 02:45:28 +01:00
|
|
|
Nulls[i] = true;
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* ----------------
|
1997-09-07 07:04:48 +02:00
|
|
|
* cleanup
|
1996-07-09 08:22:35 +02:00
|
|
|
* ----------------
|
|
|
|
*/
|
1997-08-19 23:40:56 +02:00
|
|
|
static void
|
2003-05-28 20:19:09 +02:00
|
|
|
cleanup(void)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
2002-08-03 00:36:05 +02:00
|
|
|
if (boot_reldesc != NULL)
|
|
|
|
closerel(NULL);
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* ----------------
|
1997-09-07 07:04:48 +02:00
|
|
|
* gettype
|
2002-04-25 04:56:56 +02:00
|
|
|
*
|
2004-04-01 23:28:47 +02:00
|
|
|
* NB: this is really ugly; it will return an integer index into TypInfo[],
|
2002-04-25 04:56:56 +02:00
|
|
|
* and not an OID at all, until the first reference to a type not known in
|
2004-04-01 23:28:47 +02:00
|
|
|
* TypInfo[]. At that point it will read and cache pg_type in the Typ array,
|
2002-04-25 04:56:56 +02:00
|
|
|
* and subsequently return a real OID (and set the global pointer Ap to
|
2002-09-04 22:31:48 +02:00
|
|
|
* point at the found row in Typ). So caller must check whether Typ is
|
2002-04-25 04:56:56 +02:00
|
|
|
* still NULL to determine what the return value is!
|
1996-07-09 08:22:35 +02:00
|
|
|
* ----------------
|
|
|
|
*/
|
1998-08-24 21:04:04 +02:00
|
|
|
static Oid
|
1996-07-09 08:22:35 +02:00
|
|
|
gettype(char *type)
|
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
int i;
|
1998-08-19 04:04:17 +02:00
|
|
|
Relation rel;
|
|
|
|
HeapScanDesc scan;
|
1997-09-08 04:41:22 +02:00
|
|
|
HeapTuple tup;
|
1997-09-07 07:04:48 +02:00
|
|
|
struct typmap **app;
|
|
|
|
|
2004-01-07 19:56:30 +01:00
|
|
|
if (Typ != NULL)
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
2004-01-07 19:56:30 +01:00
|
|
|
for (app = Typ; *app != NULL; app++)
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
1999-11-08 00:08:36 +01:00
|
|
|
if (strncmp(NameStr((*app)->am_typ.typname), type, NAMEDATALEN) == 0)
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
|
|
|
Ap = *app;
|
1998-09-01 05:29:17 +02:00
|
|
|
return (*app)->am_oid;
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2002-04-25 04:56:56 +02:00
|
|
|
for (i = 0; i < n_types; i++)
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
2004-04-01 23:28:47 +02:00
|
|
|
if (strncmp(type, TypInfo[i].name, NAMEDATALEN) == 0)
|
1998-09-01 05:29:17 +02:00
|
|
|
return i;
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
2003-05-27 19:49:47 +02:00
|
|
|
elog(DEBUG4, "external type: %s", type);
|
2005-04-14 22:03:27 +02:00
|
|
|
rel = heap_open(TypeRelationId, NoLock);
|
2004-01-07 19:56:30 +01:00
|
|
|
scan = heap_beginscan(rel, SnapshotNow, 0, NULL);
|
1997-09-07 07:04:48 +02:00
|
|
|
i = 0;
|
2002-05-21 01:51:44 +02:00
|
|
|
while ((tup = heap_getnext(scan, ForwardScanDirection)) != NULL)
|
1997-09-07 07:04:48 +02:00
|
|
|
++i;
|
1998-08-19 04:04:17 +02:00
|
|
|
heap_endscan(scan);
|
1997-09-07 07:04:48 +02:00
|
|
|
app = Typ = ALLOC(struct typmap *, i + 1);
|
|
|
|
while (i-- > 0)
|
|
|
|
*app++ = ALLOC(struct typmap, 1);
|
2004-01-07 19:56:30 +01:00
|
|
|
*app = NULL;
|
|
|
|
scan = heap_beginscan(rel, SnapshotNow, 0, NULL);
|
1997-09-07 07:04:48 +02:00
|
|
|
app = Typ;
|
2002-05-21 01:51:44 +02:00
|
|
|
while ((tup = heap_getnext(scan, ForwardScanDirection)) != NULL)
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
2002-07-20 07:16:59 +02:00
|
|
|
(*app)->am_oid = HeapTupleGetOid(tup);
|
1997-09-07 07:04:48 +02:00
|
|
|
memmove((char *) &(*app++)->am_typ,
|
|
|
|
(char *) GETSTRUCT(tup),
|
|
|
|
sizeof((*app)->am_typ));
|
|
|
|
}
|
1998-08-19 04:04:17 +02:00
|
|
|
heap_endscan(scan);
|
1999-09-18 21:08:25 +02:00
|
|
|
heap_close(rel, NoLock);
|
1998-09-01 05:29:17 +02:00
|
|
|
return gettype(type);
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
2003-07-23 01:30:39 +02:00
|
|
|
elog(ERROR, "unrecognized type \"%s\"", type);
|
1997-09-07 07:04:48 +02:00
|
|
|
/* not reached, here to make compiler happy */
|
|
|
|
return 0;
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
2006-08-16 00:36:17 +02:00
|
|
|
/* ----------------
|
|
|
|
* boot_get_type_io_data
|
|
|
|
*
|
|
|
|
* Obtain type I/O information at bootstrap time. This intentionally has
|
|
|
|
* almost the same API as lsyscache.c's get_type_io_data, except that
|
|
|
|
* we only support obtaining the typinput and typoutput routines, not
|
|
|
|
* the binary I/O routines. It is exported so that array_in and array_out
|
|
|
|
* can be made to work during early bootstrap.
|
|
|
|
* ----------------
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
boot_get_type_io_data(Oid typid,
|
|
|
|
int16 *typlen,
|
|
|
|
bool *typbyval,
|
|
|
|
char *typalign,
|
|
|
|
char *typdelim,
|
|
|
|
Oid *typioparam,
|
|
|
|
Oid *typinput,
|
|
|
|
Oid *typoutput)
|
|
|
|
{
|
|
|
|
if (Typ != NULL)
|
|
|
|
{
|
|
|
|
/* We have the boot-time contents of pg_type, so use it */
|
|
|
|
struct typmap **app;
|
|
|
|
struct typmap *ap;
|
|
|
|
|
|
|
|
app = Typ;
|
|
|
|
while (*app && (*app)->am_oid != typid)
|
|
|
|
++app;
|
|
|
|
ap = *app;
|
|
|
|
if (ap == NULL)
|
|
|
|
elog(ERROR, "type OID %u not found in Typ list", typid);
|
|
|
|
|
|
|
|
*typlen = ap->am_typ.typlen;
|
|
|
|
*typbyval = ap->am_typ.typbyval;
|
|
|
|
*typalign = ap->am_typ.typalign;
|
|
|
|
*typdelim = ap->am_typ.typdelim;
|
|
|
|
|
|
|
|
/* XXX this logic must match getTypeIOParam() */
|
|
|
|
if (OidIsValid(ap->am_typ.typelem))
|
|
|
|
*typioparam = ap->am_typ.typelem;
|
|
|
|
else
|
|
|
|
*typioparam = typid;
|
|
|
|
|
|
|
|
*typinput = ap->am_typ.typinput;
|
|
|
|
*typoutput = ap->am_typ.typoutput;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* We don't have pg_type yet, so use the hard-wired TypInfo array */
|
|
|
|
int typeindex;
|
|
|
|
|
|
|
|
for (typeindex = 0; typeindex < n_types; typeindex++)
|
|
|
|
{
|
|
|
|
if (TypInfo[typeindex].oid == typid)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (typeindex >= n_types)
|
|
|
|
elog(ERROR, "type OID %u not found in TypInfo", typid);
|
|
|
|
|
|
|
|
*typlen = TypInfo[typeindex].len;
|
|
|
|
*typbyval = TypInfo[typeindex].byval;
|
|
|
|
*typalign = TypInfo[typeindex].align;
|
|
|
|
/* We assume typdelim is ',' for all boot-time types */
|
|
|
|
*typdelim = ',';
|
|
|
|
|
|
|
|
/* XXX this logic must match getTypeIOParam() */
|
|
|
|
if (OidIsValid(TypInfo[typeindex].elem))
|
|
|
|
*typioparam = TypInfo[typeindex].elem;
|
|
|
|
else
|
|
|
|
*typioparam = typid;
|
|
|
|
|
|
|
|
*typinput = TypInfo[typeindex].inproc;
|
|
|
|
*typoutput = TypInfo[typeindex].outproc;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
/* ----------------
|
1997-09-07 07:04:48 +02:00
|
|
|
* AllocateAttribute
|
2009-01-22 21:16:10 +01:00
|
|
|
*
|
|
|
|
* Note: bootstrap never sets any per-column ACLs, so we only need
|
|
|
|
* ATTRIBUTE_FIXED_PART_SIZE space per attribute.
|
1996-07-09 08:22:35 +02:00
|
|
|
* ----------------
|
|
|
|
*/
|
2002-08-02 20:15:10 +02:00
|
|
|
static Form_pg_attribute
|
|
|
|
AllocateAttribute(void)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
2009-01-22 21:16:10 +01:00
|
|
|
Form_pg_attribute attribute = (Form_pg_attribute) malloc(ATTRIBUTE_FIXED_PART_SIZE);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
if (!PointerIsValid(attribute))
|
2003-07-23 01:30:39 +02:00
|
|
|
elog(FATAL, "out of memory");
|
2009-01-22 21:16:10 +01:00
|
|
|
MemSet(attribute, 0, ATTRIBUTE_FIXED_PART_SIZE);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1998-09-01 05:29:17 +02:00
|
|
|
return attribute;
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* ----------------
|
1997-09-07 07:04:48 +02:00
|
|
|
* MapArrayTypeName
|
1996-07-09 08:22:35 +02:00
|
|
|
* XXX arrays of "basetype" are always "_basetype".
|
1997-09-07 07:04:48 +02:00
|
|
|
* this is an evil hack inherited from rel. 3.1.
|
1996-07-09 08:22:35 +02:00
|
|
|
* XXX array dimension is thrown away because we
|
1997-09-07 07:04:48 +02:00
|
|
|
* don't support fixed-dimension arrays. again,
|
|
|
|
* sickness from 3.1.
|
|
|
|
*
|
|
|
|
* the string passed in must have a '[' character in it
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
|
|
|
* the string returned is a pointer to static storage and should NOT
|
|
|
|
* be freed by the CALLER.
|
|
|
|
* ----------------
|
|
|
|
*/
|
1998-02-26 05:46:47 +01:00
|
|
|
char *
|
1996-07-09 08:22:35 +02:00
|
|
|
MapArrayTypeName(char *s)
|
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
int i,
|
|
|
|
j;
|
2005-10-15 04:49:52 +02:00
|
|
|
static char newStr[NAMEDATALEN]; /* array type names < NAMEDATALEN long */
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
if (s == NULL || s[0] == '\0')
|
|
|
|
return s;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
j = 1;
|
|
|
|
newStr[0] = '_';
|
|
|
|
for (i = 0; i < NAMEDATALEN - 1 && s[i] != '['; i++, j++)
|
|
|
|
newStr[j] = s[i];
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
newStr[j] = '\0';
|
|
|
|
|
|
|
|
return newStr;
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
1997-09-07 07:04:48 +02:00
|
|
|
* index_register() -- record an index that has been set up for building
|
|
|
|
* later.
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
2006-05-11 01:18:39 +02:00
|
|
|
* At bootstrap time, we define a bunch of indexes on system catalogs.
|
|
|
|
* We postpone actually building the indexes until just before we're
|
|
|
|
* finished with initialization, however. This is because the indexes
|
|
|
|
* themselves have catalog entries, and those have to be included in the
|
2006-10-04 02:30:14 +02:00
|
|
|
* indexes on those catalogs. Doing it in two phases is the simplest
|
2006-05-11 01:18:39 +02:00
|
|
|
* way of making sure the indexes have the right contents at the end.
|
1996-07-09 08:22:35 +02:00
|
|
|
*/
|
|
|
|
void
|
2002-03-26 20:17:02 +01:00
|
|
|
index_register(Oid heap,
|
|
|
|
Oid ind,
|
2000-07-15 00:18:02 +02:00
|
|
|
IndexInfo *indexInfo)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
IndexList *newind;
|
|
|
|
MemoryContext oldcxt;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* XXX mao 10/31/92 -- don't gc index reldescs, associated info at
|
2006-05-11 01:18:39 +02:00
|
|
|
* bootstrap time. we'll declare the indexes now, but want to create them
|
2005-10-15 04:49:52 +02:00
|
|
|
* later.
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
|
|
|
|
2000-06-28 05:33:33 +02:00
|
|
|
if (nogc == NULL)
|
2004-01-07 19:56:30 +01:00
|
|
|
nogc = AllocSetContextCreate(NULL,
|
2000-06-28 05:33:33 +02:00
|
|
|
"BootstrapNoGC",
|
|
|
|
ALLOCSET_DEFAULT_MINSIZE,
|
|
|
|
ALLOCSET_DEFAULT_INITSIZE,
|
|
|
|
ALLOCSET_DEFAULT_MAXSIZE);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2000-06-28 05:33:33 +02:00
|
|
|
oldcxt = MemoryContextSwitchTo(nogc);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
newind = (IndexList *) palloc(sizeof(IndexList));
|
2002-03-26 20:17:02 +01:00
|
|
|
newind->il_heap = heap;
|
|
|
|
newind->il_ind = ind;
|
2000-07-15 00:18:02 +02:00
|
|
|
newind->il_info = (IndexInfo *) palloc(sizeof(IndexInfo));
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2000-07-15 00:18:02 +02:00
|
|
|
memcpy(newind->il_info, indexInfo, sizeof(IndexInfo));
|
2003-05-28 18:04:02 +02:00
|
|
|
/* expressions will likely be null, but may as well copy it */
|
|
|
|
newind->il_info->ii_Expressions = (List *)
|
|
|
|
copyObject(indexInfo->ii_Expressions);
|
|
|
|
newind->il_info->ii_ExpressionsState = NIL;
|
2001-07-16 07:07:00 +02:00
|
|
|
/* predicate will likely be null, but may as well copy it */
|
|
|
|
newind->il_info->ii_Predicate = (List *)
|
|
|
|
copyObject(indexInfo->ii_Predicate);
|
2002-12-15 17:17:59 +01:00
|
|
|
newind->il_info->ii_PredicateState = NIL;
|
2009-12-07 06:22:23 +01:00
|
|
|
/* no exclusion constraints at bootstrap time, so no need to copy */
|
|
|
|
Assert(indexInfo->ii_ExclusionOps == NULL);
|
|
|
|
Assert(indexInfo->ii_ExclusionProcs == NULL);
|
|
|
|
Assert(indexInfo->ii_ExclusionStrats == NULL);
|
2000-06-18 01:41:51 +02:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
newind->il_next = ILHead;
|
|
|
|
ILHead = newind;
|
|
|
|
|
|
|
|
MemoryContextSwitchTo(oldcxt);
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
2006-05-11 01:18:39 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* build_indices -- fill in all the indexes registered earlier
|
|
|
|
*/
|
1996-07-09 08:22:35 +02:00
|
|
|
void
|
2004-01-07 19:56:30 +01:00
|
|
|
build_indices(void)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
2004-01-07 19:56:30 +01:00
|
|
|
for (; ILHead != NULL; ILHead = ILHead->il_next)
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
2000-07-15 00:18:02 +02:00
|
|
|
Relation heap;
|
|
|
|
Relation ind;
|
|
|
|
|
2006-07-31 22:09:10 +02:00
|
|
|
/* need not bother with locks during bootstrap */
|
2002-03-26 20:17:02 +01:00
|
|
|
heap = heap_open(ILHead->il_heap, NoLock);
|
2006-07-31 22:09:10 +02:00
|
|
|
ind = index_open(ILHead->il_ind, NoLock);
|
2000-04-12 19:17:23 +02:00
|
|
|
|
2006-07-31 03:16:38 +02:00
|
|
|
index_build(heap, ind, ILHead->il_info, false);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2006-07-31 22:09:10 +02:00
|
|
|
index_close(ind, NoLock);
|
2006-05-11 01:18:39 +02:00
|
|
|
heap_close(heap, NoLock);
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|