|
|
|
@ -7,22 +7,22 @@ |
|
|
|
|
* |
|
|
|
|
* |
|
|
|
|
* IDENTIFICATION |
|
|
|
|
* $Header: /cvsroot/pgsql/src/backend/utils/init/postinit.c,v 1.5 1996/11/08 06:00:33 momjian Exp $ |
|
|
|
|
* $Header: /cvsroot/pgsql/src/backend/utils/init/postinit.c,v 1.6 1996/11/12 06:46:42 bryanh Exp $ |
|
|
|
|
* |
|
|
|
|
* NOTES |
|
|
|
|
* InitPostgres() is the function called from PostgresMain |
|
|
|
|
* which does all non-trival initialization, mainly by calling |
|
|
|
|
* all the other initialization functions. InitPostgres() |
|
|
|
|
* is only used within the "postgres" backend and so that routine |
|
|
|
|
* is in tcop/postgres.c InitPostgres() is needed in cinterface.a |
|
|
|
|
* because things like the bootstrap backend program need it. Hence |
|
|
|
|
* you find that in this file... |
|
|
|
|
* InitPostgres() is the function called from PostgresMain |
|
|
|
|
* which does all non-trival initialization, mainly by calling |
|
|
|
|
* all the other initialization functions. InitPostgres() |
|
|
|
|
* is only used within the "postgres" backend and so that routine |
|
|
|
|
* is in tcop/postgres.c InitPostgres() is needed in cinterface.a |
|
|
|
|
* because things like the bootstrap backend program need it. Hence |
|
|
|
|
* you find that in this file... |
|
|
|
|
* |
|
|
|
|
* If you feel the need to add more initialization code, it should be |
|
|
|
|
* done in InitPostgres() or someplace lower. Do not start |
|
|
|
|
* putting stuff in PostgresMain - if you do then someone |
|
|
|
|
* will have to clean it up later, and it's not going to be me! |
|
|
|
|
* -cim 10/3/90 |
|
|
|
|
* If you feel the need to add more initialization code, it should be |
|
|
|
|
* done in InitPostgres() or someplace lower. Do not start |
|
|
|
|
* putting stuff in PostgresMain - if you do then someone |
|
|
|
|
* will have to clean it up later, and it's not going to be me! |
|
|
|
|
* -cim 10/3/90 |
|
|
|
|
* |
|
|
|
|
*------------------------------------------------------------------------- |
|
|
|
|
*/ |
|
|
|
@ -30,12 +30,14 @@ |
|
|
|
|
#include <stdio.h> |
|
|
|
|
#include <string.h> |
|
|
|
|
#include <sys/file.h> |
|
|
|
|
#include <sys/stat.h> |
|
|
|
|
#include <sys/types.h> |
|
|
|
|
#include <sys/ipc.h> |
|
|
|
|
#include <math.h> |
|
|
|
|
#include <unistd.h> |
|
|
|
|
|
|
|
|
|
#include "postgres.h" |
|
|
|
|
#include "version.h" |
|
|
|
|
|
|
|
|
|
#include <storage/backendid.h> |
|
|
|
|
#include <storage/buf_internals.h> |
|
|
|
@ -46,22 +48,22 @@ |
|
|
|
|
#include "access/heapam.h" |
|
|
|
|
#include "access/xact.h" |
|
|
|
|
#include "storage/bufmgr.h" |
|
|
|
|
#include "access/transam.h" /* XXX dependency problem */ |
|
|
|
|
#include "access/transam.h" /* XXX dependency problem */ |
|
|
|
|
#include "utils/tqual.h" |
|
|
|
|
#include "utils/syscache.h" |
|
|
|
|
#include "storage/bufpage.h" /* for page layout, for InitMyDatabaseId() */ |
|
|
|
|
#include "storage/bufpage.h" /* for page layout, for InitMyDatabaseId() */ |
|
|
|
|
#include "storage/sinval.h" |
|
|
|
|
#include "storage/sinvaladt.h" |
|
|
|
|
#include "storage/lmgr.h" |
|
|
|
|
|
|
|
|
|
#include "miscadmin.h" /* for global decls */ |
|
|
|
|
#include "utils/portal.h" /* for EnablePortalManager, etc. */ |
|
|
|
|
#include "utils/portal.h" /* for EnablePortalManager, etc. */ |
|
|
|
|
|
|
|
|
|
#include "utils/exc.h" /* for EnableExceptionHandling, etc. */ |
|
|
|
|
#include "fmgr.h" /* for EnableDynamicFunctionManager, etc. */ |
|
|
|
|
#include "utils/exc.h" /* for EnableExceptionHandling, etc. */ |
|
|
|
|
#include "fmgr.h" /* for EnableDynamicFunctionManager, etc. */ |
|
|
|
|
#include "utils/elog.h" |
|
|
|
|
#include "utils/palloc.h" |
|
|
|
|
#include "utils/mcxt.h" /* for EnableMemoryContext, etc. */ |
|
|
|
|
#include "utils/mcxt.h" /* for EnableMemoryContext, etc. */ |
|
|
|
|
|
|
|
|
|
#include "catalog/catname.h" |
|
|
|
|
#include "catalog/pg_database.h" |
|
|
|
@ -70,54 +72,54 @@ |
|
|
|
|
#include "libpq/libpq-be.h" |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static IPCKey PostgresIpcKey; |
|
|
|
|
static IPCKey PostgresIpcKey; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#ifndef private |
|
|
|
|
#ifndef EBUG |
|
|
|
|
#define private static |
|
|
|
|
#else /* !defined(EBUG) */ |
|
|
|
|
#ifndef private |
|
|
|
|
#ifndef EBUG |
|
|
|
|
#define private static |
|
|
|
|
#else /* !defined(EBUG) */ |
|
|
|
|
#define private |
|
|
|
|
#endif /* !defined(EBUG) */ |
|
|
|
|
#endif /* !defined(private) */ |
|
|
|
|
#endif /* !defined(EBUG) */ |
|
|
|
|
#endif /* !defined(private) */ |
|
|
|
|
|
|
|
|
|
/* ----------------------------------------------------------------
|
|
|
|
|
* InitPostgres support |
|
|
|
|
* InitPostgres support |
|
|
|
|
* ---------------------------------------------------------------- |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
/* --------------------------------
|
|
|
|
|
* InitMyDatabaseId() -- Find and record the OID of the database we are |
|
|
|
|
* to open. |
|
|
|
|
* to open. |
|
|
|
|
* |
|
|
|
|
* The database's oid forms half of the unique key for the system |
|
|
|
|
* caches and lock tables. We therefore want it initialized before |
|
|
|
|
* we open any relations, since opening relations puts things in the |
|
|
|
|
* cache. To get around this problem, this code opens and scans the |
|
|
|
|
* pg_database relation by hand. |
|
|
|
|
* The database's oid forms half of the unique key for the system |
|
|
|
|
* caches and lock tables. We therefore want it initialized before |
|
|
|
|
* we open any relations, since opening relations puts things in the |
|
|
|
|
* cache. To get around this problem, this code opens and scans the |
|
|
|
|
* pg_database relation by hand. |
|
|
|
|
* |
|
|
|
|
* This algorithm relies on the fact that first attribute in the |
|
|
|
|
* pg_database relation schema is the database name. It also knows |
|
|
|
|
* about the internal format of tuples on disk and the length of |
|
|
|
|
* the datname attribute. It knows the location of the pg_database |
|
|
|
|
* file. |
|
|
|
|
* This algorithm relies on the fact that first attribute in the |
|
|
|
|
* pg_database relation schema is the database name. It also knows |
|
|
|
|
* about the internal format of tuples on disk and the length of |
|
|
|
|
* the datname attribute. It knows the location of the pg_database |
|
|
|
|
* file. |
|
|
|
|
* |
|
|
|
|
* This code is called from InitDatabase(), after we chdir() to the |
|
|
|
|
* database directory but before we open any relations. |
|
|
|
|
* This code is called from InitDatabase(), after we chdir() to the |
|
|
|
|
* database directory but before we open any relations. |
|
|
|
|
* -------------------------------- |
|
|
|
|
*/ |
|
|
|
|
void |
|
|
|
|
InitMyDatabaseId() |
|
|
|
|
{ |
|
|
|
|
int dbfd; |
|
|
|
|
int fileflags; |
|
|
|
|
int nbytes; |
|
|
|
|
int max, i; |
|
|
|
|
HeapTuple tup; |
|
|
|
|
Page pg; |
|
|
|
|
PageHeader ph; |
|
|
|
|
char *dbfname; |
|
|
|
|
Form_pg_database tup_db; |
|
|
|
|
int dbfd; |
|
|
|
|
int fileflags; |
|
|
|
|
int nbytes; |
|
|
|
|
int max, i; |
|
|
|
|
HeapTuple tup; |
|
|
|
|
Page pg; |
|
|
|
|
PageHeader ph; |
|
|
|
|
char *dbfname; |
|
|
|
|
Form_pg_database tup_db; |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* At bootstrap time, we don't need to check the oid of the database |
|
|
|
@ -126,8 +128,8 @@ InitMyDatabaseId() |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
if (IsBootstrapProcessingMode()) { |
|
|
|
|
LockDisable(true); |
|
|
|
|
return; |
|
|
|
|
LockDisable(true); |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
dbfname = (char *) palloc(strlen(DataDir) + strlen("pg_database") + 2); |
|
|
|
@ -138,14 +140,14 @@ InitMyDatabaseId() |
|
|
|
|
#endif /* WIN32 */ |
|
|
|
|
|
|
|
|
|
if ((dbfd = open(dbfname, O_RDONLY, 0666)) < 0) |
|
|
|
|
elog(FATAL, "Cannot open %s", dbfname); |
|
|
|
|
elog(FATAL, "Cannot open %s", dbfname); |
|
|
|
|
|
|
|
|
|
pfree(dbfname); |
|
|
|
|
|
|
|
|
|
/* ----------------
|
|
|
|
|
* read and examine every page in pg_database |
|
|
|
|
* read and examine every page in pg_database |
|
|
|
|
* |
|
|
|
|
* Raw I/O! Read those tuples the hard way! Yow! |
|
|
|
|
* Raw I/O! Read those tuples the hard way! Yow! |
|
|
|
|
* |
|
|
|
|
* Why don't we use the access methods or move this code |
|
|
|
|
* someplace else? This is really pg_database schema dependent |
|
|
|
@ -163,58 +165,58 @@ InitMyDatabaseId() |
|
|
|
|
ph = (PageHeader) pg; |
|
|
|
|
|
|
|
|
|
while ((nbytes = read(dbfd, pg, BLCKSZ)) == BLCKSZ) { |
|
|
|
|
max = PageGetMaxOffsetNumber(pg); |
|
|
|
|
|
|
|
|
|
/* look at each tuple on the page */ |
|
|
|
|
for (i = 0; i <= max; i++) { |
|
|
|
|
int offset; |
|
|
|
|
|
|
|
|
|
/* if it's a freed tuple, ignore it */ |
|
|
|
|
if (!(ph->pd_linp[i].lp_flags & LP_USED)) |
|
|
|
|
continue; |
|
|
|
|
|
|
|
|
|
/* get a pointer to the tuple itself */ |
|
|
|
|
offset = (int) ph->pd_linp[i].lp_off; |
|
|
|
|
tup = (HeapTuple) (((char *) pg) + offset); |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* if the tuple has been deleted (the database was destroyed), |
|
|
|
|
* skip this tuple. XXX warning, will robinson: violation of |
|
|
|
|
* transaction semantics happens right here. we should check |
|
|
|
|
* to be sure that the xact that deleted this tuple actually |
|
|
|
|
* committed. only way to do this at init time is to paw over |
|
|
|
|
* the log relation by hand, too. let's be optimistic. |
|
|
|
|
* |
|
|
|
|
* XXX This is an evil type cast. tup->t_xmax is char[5] while |
|
|
|
|
* TransactionId is struct * { char data[5] }. It works but |
|
|
|
|
* if data is ever moved and no longer the first field this
|
|
|
|
|
* will be broken!! -mer 11 Nov 1991. |
|
|
|
|
*/ |
|
|
|
|
if (TransactionIdIsValid((TransactionId)tup->t_xmax)) |
|
|
|
|
continue; |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Okay, see if this is the one we want. |
|
|
|
|
* XXX 1 july 91: mao and mer discover that tuples now squash |
|
|
|
|
* t_bits. Why is this? |
|
|
|
|
* |
|
|
|
|
* 24 july 92: mer realizes that the t_bits field is only |
|
|
|
|
* used in the event of null values. If no |
|
|
|
|
* fields are null we reduce the header size |
|
|
|
|
* by doing the squash. t_hoff tells you exactly |
|
|
|
|
* how big the header actually is. use the PC |
|
|
|
|
* means of getting at sys cat attrs. |
|
|
|
|
*/ |
|
|
|
|
tup_db = (Form_pg_database)GETSTRUCT(tup); |
|
|
|
|
|
|
|
|
|
if (strncmp(GetDatabaseName(), |
|
|
|
|
&(tup_db->datname.data[0]), |
|
|
|
|
16) == 0) |
|
|
|
|
{ |
|
|
|
|
MyDatabaseId = tup->t_oid; |
|
|
|
|
goto done; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
max = PageGetMaxOffsetNumber(pg); |
|
|
|
|
|
|
|
|
|
/* look at each tuple on the page */ |
|
|
|
|
for (i = 0; i <= max; i++) { |
|
|
|
|
int offset; |
|
|
|
|
|
|
|
|
|
/* if it's a freed tuple, ignore it */ |
|
|
|
|
if (!(ph->pd_linp[i].lp_flags & LP_USED)) |
|
|
|
|
continue; |
|
|
|
|
|
|
|
|
|
/* get a pointer to the tuple itself */ |
|
|
|
|
offset = (int) ph->pd_linp[i].lp_off; |
|
|
|
|
tup = (HeapTuple) (((char *) pg) + offset); |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* if the tuple has been deleted (the database was destroyed), |
|
|
|
|
* skip this tuple. XXX warning, will robinson: violation of |
|
|
|
|
* transaction semantics happens right here. we should check |
|
|
|
|
* to be sure that the xact that deleted this tuple actually |
|
|
|
|
* committed. only way to do this at init time is to paw over |
|
|
|
|
* the log relation by hand, too. let's be optimistic. |
|
|
|
|
* |
|
|
|
|
* XXX This is an evil type cast. tup->t_xmax is char[5] while |
|
|
|
|
* TransactionId is struct * { char data[5] }. It works but |
|
|
|
|
* if data is ever moved and no longer the first field this
|
|
|
|
|
* will be broken!! -mer 11 Nov 1991. |
|
|
|
|
*/ |
|
|
|
|
if (TransactionIdIsValid((TransactionId)tup->t_xmax)) |
|
|
|
|
continue; |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Okay, see if this is the one we want. |
|
|
|
|
* XXX 1 july 91: mao and mer discover that tuples now squash |
|
|
|
|
* t_bits. Why is this? |
|
|
|
|
* |
|
|
|
|
* 24 july 92: mer realizes that the t_bits field is only |
|
|
|
|
* used in the event of null values. If no |
|
|
|
|
* fields are null we reduce the header size |
|
|
|
|
* by doing the squash. t_hoff tells you exactly |
|
|
|
|
* how big the header actually is. use the PC |
|
|
|
|
* means of getting at sys cat attrs. |
|
|
|
|
*/ |
|
|
|
|
tup_db = (Form_pg_database)GETSTRUCT(tup); |
|
|
|
|
|
|
|
|
|
if (strncmp(GetDatabaseName(), |
|
|
|
|
&(tup_db->datname.data[0]), |
|
|
|
|
16) == 0) |
|
|
|
|
{ |
|
|
|
|
MyDatabaseId = tup->t_oid; |
|
|
|
|
goto done; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
done: |
|
|
|
@ -222,84 +224,121 @@ InitMyDatabaseId() |
|
|
|
|
pfree(pg); |
|
|
|
|
|
|
|
|
|
if (!OidIsValid(MyDatabaseId)) |
|
|
|
|
elog(FATAL, |
|
|
|
|
"Database %s does not exist in %s", |
|
|
|
|
GetDatabaseName(), |
|
|
|
|
DatabaseRelationName); |
|
|
|
|
elog(FATAL, |
|
|
|
|
"Database %s does not exist in %s", |
|
|
|
|
GetDatabaseName(), |
|
|
|
|
DatabaseRelationName); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* DoChdirAndInitDatabaseNameAndPath -- |
|
|
|
|
* Sets current directory appropriately for given path and name. |
|
|
|
|
* Set current directory to the database directory for the database |
|
|
|
|
* named <name>. |
|
|
|
|
* Also set global variables DatabasePath and DatabaseName to those |
|
|
|
|
* values. Also check for proper version of database system and |
|
|
|
|
* database. Exit program via elog() if anything doesn't check out. |
|
|
|
|
* |
|
|
|
|
* Arguments: |
|
|
|
|
* Path and name are invalid if it invalid as a string. |
|
|
|
|
* Path is "badly formated" if it is not a string containing a path |
|
|
|
|
* to a writable directory. |
|
|
|
|
* Name is "badly formated" if it contains more than 16 characters or if |
|
|
|
|
* it is a bad file name (e.g., it contains a '/' or an 8-bit character). |
|
|
|
|
* |
|
|
|
|
* Side effects: |
|
|
|
|
* Initially, DatabasePath and DatabaseName are invalid. They are |
|
|
|
|
* set to valid strings before this function returns. |
|
|
|
|
* Path and name are invalid if it invalid as a string. |
|
|
|
|
* Path is "badly formated" if it is not a string containing a path |
|
|
|
|
* to a writable directory. |
|
|
|
|
* Name is "badly formated" if it contains more than 16 characters or if |
|
|
|
|
* it is a bad file name (e.g., it contains a '/' or an 8-bit character). |
|
|
|
|
* |
|
|
|
|
* Exceptions: |
|
|
|
|
* BadState if called more than once. |
|
|
|
|
* BadArg if both path and name are "badly formated" or invalid. |
|
|
|
|
* BadArg if path and name are both "inconsistent" and valid. |
|
|
|
|
*/ |
|
|
|
|
/* ----------------
|
|
|
|
|
* DoChdirAndInitDatabaseNameAndPath |
|
|
|
|
* BadState if called more than once. |
|
|
|
|
* BadArg if both path and name are "badly formated" or invalid. |
|
|
|
|
* BadArg if path and name are both "inconsistent" and valid. |
|
|
|
|
* |
|
|
|
|
* this just chdir's to the proper data/base directory |
|
|
|
|
* XXX clean this up more. |
|
|
|
|
* |
|
|
|
|
* XXX The following code is an incorrect of the semantics |
|
|
|
|
* XXX described in the header file. Handling of defaults |
|
|
|
|
* XXX should happen here, too. |
|
|
|
|
* ---------------- |
|
|
|
|
* This routine is inappropriate in bootstrap mode, since the directories |
|
|
|
|
* and version files need not exist yet if we're in bootstrap mode. |
|
|
|
|
*/ |
|
|
|
|
void |
|
|
|
|
DoChdirAndInitDatabaseNameAndPath(char *name, /* name of database */ |
|
|
|
|
char *path) /* full path to database */ |
|
|
|
|
{ |
|
|
|
|
/* ----------------
|
|
|
|
|
* check the path |
|
|
|
|
* ---------------- |
|
|
|
|
*/ |
|
|
|
|
if (path) |
|
|
|
|
SetDatabasePath(path); |
|
|
|
|
else |
|
|
|
|
elog(FATAL, "DoChdirAndInitDatabaseNameAndPath: path:%s is not valid", |
|
|
|
|
path); |
|
|
|
|
|
|
|
|
|
/* ----------------
|
|
|
|
|
* check the name |
|
|
|
|
* ---------------- |
|
|
|
|
*/ |
|
|
|
|
if (name) |
|
|
|
|
SetDatabaseName(name); |
|
|
|
|
else
|
|
|
|
|
elog(FATAL, "DoChdirAndInitDatabaseNameAndPath: name:%s is not valid", |
|
|
|
|
name); |
|
|
|
|
|
|
|
|
|
/* ----------------
|
|
|
|
|
* change to the directory, or die trying. |
|
|
|
|
* |
|
|
|
|
* XXX unless the path hasn't been set because we're bootstrapping. |
|
|
|
|
* HP-UX doesn't like chdir("") so check for that case before |
|
|
|
|
* doing anything drastic. |
|
|
|
|
* ---------------- |
|
|
|
|
*/ |
|
|
|
|
if (*path && (chdir(path) < 0)) |
|
|
|
|
elog(FATAL, "DoChdirAndInitDatabaseNameAndPath: chdir(\"%s\"): %m", |
|
|
|
|
path); |
|
|
|
|
static void |
|
|
|
|
DoChdirAndInitDatabaseNameAndPath(char *name) { |
|
|
|
|
char *reason;
|
|
|
|
|
/* Failure reason returned by some function. NULL if no failure */ |
|
|
|
|
#ifndef WIN32 |
|
|
|
|
struct stat statbuf; |
|
|
|
|
#else |
|
|
|
|
struct _stat statbuf; |
|
|
|
|
#endif |
|
|
|
|
char errormsg[1000]; |
|
|
|
|
|
|
|
|
|
if (stat(DataDir, &statbuf) < 0)
|
|
|
|
|
sprintf(errormsg, "Database system does not exist. " |
|
|
|
|
"PGDATA directory '%s' not found. Normally, you " |
|
|
|
|
"create a database system by running initdb.", |
|
|
|
|
DataDir); |
|
|
|
|
else { |
|
|
|
|
char myPath[MAXPGPATH]; /* DatabasePath points here! */ |
|
|
|
|
|
|
|
|
|
if (strlen(DataDir) + strlen(name) + 10 > sizeof(myPath)) |
|
|
|
|
sprintf(errormsg, "Internal error in postinit.c: database " |
|
|
|
|
"pathname exceeds maximum allowable length."); |
|
|
|
|
else { |
|
|
|
|
sprintf(myPath, "%s/base/%s", DataDir, name); |
|
|
|
|
|
|
|
|
|
if (stat(myPath, &statbuf) < 0)
|
|
|
|
|
sprintf(errormsg,
|
|
|
|
|
"Database '%s' does not exist. " |
|
|
|
|
"(We know this because the directory '%s' " |
|
|
|
|
"does not exist). You can create a database " |
|
|
|
|
"with the SQL command CREATE DATABASE. To see " |
|
|
|
|
"what databases exist, look at the subdirectories " |
|
|
|
|
"of '%s/base/'.", |
|
|
|
|
name, myPath, DataDir); |
|
|
|
|
else { |
|
|
|
|
ValidatePgVersion(DataDir, &reason); |
|
|
|
|
if (reason != NULL)
|
|
|
|
|
sprintf(errormsg,
|
|
|
|
|
"InitPostgres could not validate that the database " |
|
|
|
|
"system version is compatible with this level of " |
|
|
|
|
"Postgres. You may need to run initdb to create " |
|
|
|
|
"a new database system. %s",
|
|
|
|
|
reason); |
|
|
|
|
else { |
|
|
|
|
ValidatePgVersion(myPath, &reason); |
|
|
|
|
if (reason != NULL) |
|
|
|
|
sprintf(errormsg,
|
|
|
|
|
"InitPostgres could not validate that the " |
|
|
|
|
"database version is compatible with this level " |
|
|
|
|
"of Postgres, even though the database system " |
|
|
|
|
"as a whole appears to be at a compatible level. " |
|
|
|
|
"You may need to recreate the database with SQL " |
|
|
|
|
"commands DROP DATABASE and CREATE DATABASE. " |
|
|
|
|
"%s", |
|
|
|
|
reason); |
|
|
|
|
else { |
|
|
|
|
/* The directories and PG_VERSION files are in order.*/ |
|
|
|
|
int rc; /* return code from some function we call */ |
|
|
|
|
|
|
|
|
|
SetDatabasePath(myPath); |
|
|
|
|
SetDatabaseName(name); |
|
|
|
|
rc = chdir(myPath); |
|
|
|
|
if (rc < 0) |
|
|
|
|
sprintf(errormsg,
|
|
|
|
|
"InitPostgres unable to change " |
|
|
|
|
"current directory to '%s', errno = %s (%d).", |
|
|
|
|
myPath, strerror(errno), errno); |
|
|
|
|
else errormsg[0] = '\0'; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
if (errormsg[0] != '\0') |
|
|
|
|
elog(FATAL, errormsg); |
|
|
|
|
/* Above does not return */ |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* --------------------------------
|
|
|
|
|
* InitUserid |
|
|
|
|
* InitUserid |
|
|
|
|
* |
|
|
|
|
* initializes crap associated with the user id. |
|
|
|
|
* initializes crap associated with the user id. |
|
|
|
|
* -------------------------------- |
|
|
|
|
*/ |
|
|
|
|
void |
|
|
|
@ -310,35 +349,35 @@ InitUserid() |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* --------------------------------
|
|
|
|
|
* InitCommunication |
|
|
|
|
* InitCommunication |
|
|
|
|
* |
|
|
|
|
* This routine initializes stuff needed for ipc, locking, etc. |
|
|
|
|
* it should be called something more informative. |
|
|
|
|
* This routine initializes stuff needed for ipc, locking, etc. |
|
|
|
|
* it should be called something more informative. |
|
|
|
|
* |
|
|
|
|
* Note: |
|
|
|
|
* This does not set MyBackendId. MyBackendTag is set, however. |
|
|
|
|
* This does not set MyBackendId. MyBackendTag is set, however. |
|
|
|
|
* -------------------------------- |
|
|
|
|
*/ |
|
|
|
|
void |
|
|
|
|
InitCommunication() |
|
|
|
|
{ |
|
|
|
|
char *getenv(); /* XXX style */ |
|
|
|
|
char *getenv(); /* XXX style */ |
|
|
|
|
char *postid; |
|
|
|
|
char *postport; |
|
|
|
|
IPCKey key = 0; |
|
|
|
|
IPCKey key = 0; |
|
|
|
|
|
|
|
|
|
/* ----------------
|
|
|
|
|
* try and get the backend tag from POSTID |
|
|
|
|
* try and get the backend tag from POSTID |
|
|
|
|
* ---------------- |
|
|
|
|
*/ |
|
|
|
|
MyBackendId = -1; |
|
|
|
|
|
|
|
|
|
postid = getenv("POSTID"); |
|
|
|
|
if (!PointerIsValid(postid)) { |
|
|
|
|
MyBackendTag = -1; |
|
|
|
|
MyBackendTag = -1; |
|
|
|
|
} else { |
|
|
|
|
MyBackendTag = atoi(postid); |
|
|
|
|
Assert(MyBackendTag >= 0); |
|
|
|
|
MyBackendTag = atoi(postid); |
|
|
|
|
Assert(MyBackendTag >= 0); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* ----------------
|
|
|
|
@ -348,62 +387,62 @@ InitCommunication() |
|
|
|
|
postport = getenv("POSTPORT"); |
|
|
|
|
|
|
|
|
|
if (PointerIsValid(postport)) { |
|
|
|
|
SystemPortAddress address = atoi(postport); |
|
|
|
|
|
|
|
|
|
if (address == 0) |
|
|
|
|
elog(FATAL, "InitCommunication: invalid POSTPORT"); |
|
|
|
|
|
|
|
|
|
if (MyBackendTag == -1) |
|
|
|
|
elog(FATAL, "InitCommunication: missing POSTID"); |
|
|
|
|
|
|
|
|
|
key = SystemPortAddressCreateIPCKey(address); |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Enable this if you are trying to force the backend to run as if it
|
|
|
|
|
* is running under the postmaster. |
|
|
|
|
* |
|
|
|
|
* This goto forces Postgres to attach to shared memory instead of
|
|
|
|
|
* using malloc'ed memory (which is the normal behavior if run |
|
|
|
|
* directly). |
|
|
|
|
* |
|
|
|
|
* To enable emulation, run the following shell commands (in addition |
|
|
|
|
* to enabling this goto) |
|
|
|
|
* |
|
|
|
|
* % setenv POSTID 1 |
|
|
|
|
* % setenv POSTPORT 4321 |
|
|
|
|
* % postmaster & |
|
|
|
|
* % kill -9 %1 |
|
|
|
|
* |
|
|
|
|
* Upon doing this, Postmaster will have allocated the shared memory
|
|
|
|
|
* resources that Postgres will attach to if you enable |
|
|
|
|
* EMULATE_UNDER_POSTMASTER. |
|
|
|
|
* |
|
|
|
|
* This comment may well age with time - it is current as of |
|
|
|
|
* 8 January 1990 |
|
|
|
|
*
|
|
|
|
|
* Greg |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
SystemPortAddress address = atoi(postport); |
|
|
|
|
|
|
|
|
|
if (address == 0) |
|
|
|
|
elog(FATAL, "InitCommunication: invalid POSTPORT"); |
|
|
|
|
|
|
|
|
|
if (MyBackendTag == -1) |
|
|
|
|
elog(FATAL, "InitCommunication: missing POSTID"); |
|
|
|
|
|
|
|
|
|
key = SystemPortAddressCreateIPCKey(address); |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Enable this if you are trying to force the backend to run as if it
|
|
|
|
|
* is running under the postmaster. |
|
|
|
|
* |
|
|
|
|
* This goto forces Postgres to attach to shared memory instead of
|
|
|
|
|
* using malloc'ed memory (which is the normal behavior if run |
|
|
|
|
* directly). |
|
|
|
|
* |
|
|
|
|
* To enable emulation, run the following shell commands (in addition |
|
|
|
|
* to enabling this goto) |
|
|
|
|
* |
|
|
|
|
* % setenv POSTID 1 |
|
|
|
|
* % setenv POSTPORT 4321 |
|
|
|
|
* % postmaster & |
|
|
|
|
* % kill -9 %1 |
|
|
|
|
* |
|
|
|
|
* Upon doing this, Postmaster will have allocated the shared memory
|
|
|
|
|
* resources that Postgres will attach to if you enable |
|
|
|
|
* EMULATE_UNDER_POSTMASTER. |
|
|
|
|
* |
|
|
|
|
* This comment may well age with time - it is current as of |
|
|
|
|
* 8 January 1990 |
|
|
|
|
*
|
|
|
|
|
* Greg |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
#ifdef EMULATE_UNDER_POSTMASTER |
|
|
|
|
|
|
|
|
|
goto forcesharedmemory; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
goto forcesharedmemory; |
|
|
|
|
|
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} else if (IsUnderPostmaster) { |
|
|
|
|
elog(FATAL, |
|
|
|
|
"InitCommunication: under postmaster and POSTPORT not set"); |
|
|
|
|
elog(FATAL, |
|
|
|
|
"InitCommunication: under postmaster and POSTPORT not set"); |
|
|
|
|
} else { |
|
|
|
|
/* ----------------
|
|
|
|
|
* assume we're running a postgres backend by itself with |
|
|
|
|
* no front end or postmaster. |
|
|
|
|
* ---------------- |
|
|
|
|
*/ |
|
|
|
|
if (MyBackendTag == -1) { |
|
|
|
|
MyBackendTag = 1; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
key = PrivateIPCKey; |
|
|
|
|
/* ----------------
|
|
|
|
|
* assume we're running a postgres backend by itself with |
|
|
|
|
* no front end or postmaster. |
|
|
|
|
* ---------------- |
|
|
|
|
*/ |
|
|
|
|
if (MyBackendTag == -1) { |
|
|
|
|
MyBackendTag = 1; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
key = PrivateIPCKey; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* ----------------
|
|
|
|
@ -422,11 +461,11 @@ InitCommunication() |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* --------------------------------
|
|
|
|
|
* InitStdio |
|
|
|
|
* InitStdio |
|
|
|
|
* |
|
|
|
|
* this routine consists of a bunch of code fragments |
|
|
|
|
* that used to be randomly scattered through cinit(). |
|
|
|
|
* they all seem to do stuff associated with io. |
|
|
|
|
* this routine consists of a bunch of code fragments |
|
|
|
|
* that used to be randomly scattered through cinit(). |
|
|
|
|
* they all seem to do stuff associated with io. |
|
|
|
|
* -------------------------------- |
|
|
|
|
*/ |
|
|
|
|
void |
|
|
|
@ -437,10 +476,10 @@ InitStdio() |
|
|
|
|
|
|
|
|
|
/* --------------------------------
|
|
|
|
|
* InitPostgres -- |
|
|
|
|
* Initialize POSTGRES. |
|
|
|
|
* Initialize POSTGRES. |
|
|
|
|
* |
|
|
|
|
* Note: |
|
|
|
|
* Be very careful with the order of calls in the InitPostgres function. |
|
|
|
|
* Be very careful with the order of calls in the InitPostgres function. |
|
|
|
|
* -------------------------------- |
|
|
|
|
*/ |
|
|
|
|
bool PostgresIsInitialized = false; |
|
|
|
@ -452,49 +491,49 @@ extern int NBuffers; |
|
|
|
|
* applications. |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
/*int testFlag = 0;*/ |
|
|
|
|
int lockingOff = 0; |
|
|
|
|
/*int testFlag = 0;*/ |
|
|
|
|
int lockingOff = 0; |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
*/ |
|
|
|
|
void |
|
|
|
|
InitPostgres(char *name) /* database name */ |
|
|
|
|
InitPostgres(char *name) /* database name */ |
|
|
|
|
{ |
|
|
|
|
bool bootstrap; /* true if BootstrapProcessing */ |
|
|
|
|
bool bootstrap; /* true if BootstrapProcessing */ |
|
|
|
|
|
|
|
|
|
/* ----------------
|
|
|
|
|
* see if we're running in BootstrapProcessing mode |
|
|
|
|
* see if we're running in BootstrapProcessing mode |
|
|
|
|
* ---------------- |
|
|
|
|
*/ |
|
|
|
|
bootstrap = IsBootstrapProcessingMode(); |
|
|
|
|
|
|
|
|
|
/* ----------------
|
|
|
|
|
* turn on the exception handler. Note: we cannot use elog, Assert, |
|
|
|
|
* turn on the exception handler. Note: we cannot use elog, Assert, |
|
|
|
|
* AssertState, etc. until after exception handling is on. |
|
|
|
|
* ---------------- |
|
|
|
|
*/ |
|
|
|
|
EnableExceptionHandling(true); |
|
|
|
|
|
|
|
|
|
/* ----------------
|
|
|
|
|
* A stupid check to make sure we don't call this more than once. |
|
|
|
|
* A stupid check to make sure we don't call this more than once. |
|
|
|
|
* But things like ReinitPostgres() get around this by just diddling |
|
|
|
|
* the PostgresIsInitialized flag. |
|
|
|
|
* the PostgresIsInitialized flag. |
|
|
|
|
* ---------------- |
|
|
|
|
*/ |
|
|
|
|
AssertState(!PostgresIsInitialized); |
|
|
|
|
|
|
|
|
|
/* ----------------
|
|
|
|
|
* Memory system initialization. |
|
|
|
|
* Memory system initialization. |
|
|
|
|
* (we may call palloc after EnableMemoryContext()) |
|
|
|
|
* |
|
|
|
|
* Note EnableMemoryContext() must happen before EnablePortalManager(). |
|
|
|
|
* ---------------- |
|
|
|
|
*/ |
|
|
|
|
EnableMemoryContext(true); /* initializes the "top context" */ |
|
|
|
|
EnablePortalManager(true); /* memory for portal/transaction stuff */ |
|
|
|
|
EnableMemoryContext(true); /* initializes the "top context" */ |
|
|
|
|
EnablePortalManager(true); /* memory for portal/transaction stuff */ |
|
|
|
|
|
|
|
|
|
/* ----------------
|
|
|
|
|
* initialize the backend local portal stack used by |
|
|
|
|
* initialize the backend local portal stack used by |
|
|
|
|
* internal PQ function calls. see src/lib/libpq/be-dumpdata.c |
|
|
|
|
* This is different from the "portal manager" so this goes here. |
|
|
|
|
* -cim 2/12/91 |
|
|
|
@ -503,7 +542,7 @@ InitPostgres(char *name) /* database name */ |
|
|
|
|
be_portalinit(); |
|
|
|
|
|
|
|
|
|
/* ----------------
|
|
|
|
|
* attach to shared memory and semaphores, and initialize our |
|
|
|
|
* attach to shared memory and semaphores, and initialize our |
|
|
|
|
* input/output/debugging file descriptors. |
|
|
|
|
* ---------------- |
|
|
|
|
*/ |
|
|
|
@ -518,48 +557,20 @@ InitPostgres(char *name) /* database name */ |
|
|
|
|
if (!TransactionFlushEnabled()) |
|
|
|
|
on_exitpg(FlushBufferPool, (caddr_t) NULL); |
|
|
|
|
|
|
|
|
|
/* ----------------
|
|
|
|
|
* check for valid "meta gunk" (??? -cim 10/5/90) and change to |
|
|
|
|
* database directory. |
|
|
|
|
* |
|
|
|
|
* Note: DatabaseName, MyDatabaseName, and DatabasePath are all |
|
|
|
|
* initialized with DatabaseMetaGunkIsConsistent(), strncpy() and |
|
|
|
|
* DoChdirAndInitDatabase() below! XXX clean this crap up! |
|
|
|
|
* -cim 10/5/90 |
|
|
|
|
* ---------------- |
|
|
|
|
*/ |
|
|
|
|
{ |
|
|
|
|
char myPath[MAXPGPATH] = "."; /* DatabasePath points here! */ |
|
|
|
|
|
|
|
|
|
/* ----------------
|
|
|
|
|
* DatabaseMetaGunkIsConsistent fills in myPath, but what about |
|
|
|
|
* when bootstrap or Noversion is true?? -cim 10/5/90 |
|
|
|
|
* ---------------- |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
if (! bootstrap && |
|
|
|
|
! DatabaseMetaGunkIsConsistent(name, myPath) && |
|
|
|
|
! Noversion) { |
|
|
|
|
elog(NOTICE, "InitPostgres: could not locate valid PG_VERSION\n"); |
|
|
|
|
elog(NOTICE, "files for %s and %s.", DataDir, name); |
|
|
|
|
elog(FATAL, "Have you run initdb/createdb and set PGDATA properly?"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* ----------------
|
|
|
|
|
* ok, we've figured out myName and myPath, now save these |
|
|
|
|
* and chdir to myPath. |
|
|
|
|
* ---------------- |
|
|
|
|
*/ |
|
|
|
|
DoChdirAndInitDatabaseNameAndPath(name, myPath); |
|
|
|
|
if (bootstrap) { |
|
|
|
|
SetDatabasePath("."); |
|
|
|
|
SetDatabaseName(name); |
|
|
|
|
} else { |
|
|
|
|
DoChdirAndInitDatabaseNameAndPath(name); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* ********************************
|
|
|
|
|
* code after this point assumes we are in the proper directory! |
|
|
|
|
* code after this point assumes we are in the proper directory! |
|
|
|
|
* ******************************** |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
/* ----------------
|
|
|
|
|
* initialize the database id used for system caches and lock tables |
|
|
|
|
* initialize the database id used for system caches and lock tables |
|
|
|
|
* ---------------- |
|
|
|
|
*/ |
|
|
|
|
InitMyDatabaseId(); |
|
|
|
@ -567,7 +578,7 @@ InitPostgres(char *name) /* database name */ |
|
|
|
|
smgrinit(); |
|
|
|
|
|
|
|
|
|
/* ----------------
|
|
|
|
|
* initialize the transaction system and the relation descriptor |
|
|
|
|
* initialize the transaction system and the relation descriptor |
|
|
|
|
* cache. Note we have to make certain the lock manager is off while |
|
|
|
|
* we do this. |
|
|
|
|
* ---------------- |
|
|
|
@ -582,13 +593,13 @@ InitPostgres(char *name) /* database name */ |
|
|
|
|
* we only lock it to examine AMI transaction status, and this is |
|
|
|
|
* never written after initdb is done. -mer 15 June 1992 |
|
|
|
|
*/ |
|
|
|
|
RelationInitialize(); /* pre-allocated reldescs created here */ |
|
|
|
|
RelationInitialize(); /* pre-allocated reldescs created here */ |
|
|
|
|
InitializeTransactionSystem(); /* pg_log,etc init/crash recovery here */ |
|
|
|
|
|
|
|
|
|
LockDisable(false); |
|
|
|
|
|
|
|
|
|
/* ----------------
|
|
|
|
|
* anyone knows what this does? something having to do with |
|
|
|
|
* anyone knows what this does? something having to do with |
|
|
|
|
* system catalog cache invalidation in the case of multiple |
|
|
|
|
* backends, I think -cim 10/3/90 |
|
|
|
|
* Sets up MyBackendId a unique backend identifier. |
|
|
|
@ -605,9 +616,9 @@ InitPostgres(char *name) /* database name */ |
|
|
|
|
InitProcess(PostgresIpcKey); |
|
|
|
|
|
|
|
|
|
if (MyBackendId > MaxBackendId || MyBackendId <= 0) { |
|
|
|
|
elog(FATAL, "cinit2: bad backend id %d (%d)", |
|
|
|
|
MyBackendTag, |
|
|
|
|
MyBackendId); |
|
|
|
|
elog(FATAL, "cinit2: bad backend id %d (%d)", |
|
|
|
|
MyBackendTag, |
|
|
|
|
MyBackendId); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* ----------------
|
|
|
|
@ -617,7 +628,7 @@ InitPostgres(char *name) /* database name */ |
|
|
|
|
initam(); |
|
|
|
|
|
|
|
|
|
/* ----------------
|
|
|
|
|
* initialize all the system catalog caches. |
|
|
|
|
* initialize all the system catalog caches. |
|
|
|
|
* ---------------- |
|
|
|
|
*/ |
|
|
|
|
zerocaches(); |
|
|
|
@ -632,7 +643,7 @@ InitPostgres(char *name) /* database name */ |
|
|
|
|
InitUserid(); |
|
|
|
|
|
|
|
|
|
/* ----------------
|
|
|
|
|
* ok, all done, now let's make sure we don't do it again. |
|
|
|
|
* ok, all done, now let's make sure we don't do it again. |
|
|
|
|
* ---------------- |
|
|
|
|
*/ |
|
|
|
|
PostgresIsInitialized = true; |
|
|
|
@ -644,10 +655,10 @@ InitPostgres(char *name) /* database name */ |
|
|
|
|
* ---------------- |
|
|
|
|
*/ |
|
|
|
|
if (!bootstrap) |
|
|
|
|
SetProcessingMode(NormalProcessing); |
|
|
|
|
SetProcessingMode(NormalProcessing); |
|
|
|
|
/* if (testFlag || lockingOff) */ |
|
|
|
|
if (lockingOff) |
|
|
|
|
LockDisable(true); |
|
|
|
|
LockDisable(true); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|