Finish up the flat-files project: get rid of GetRawDatabaseInfo() hack
in favor of looking at the flat file copy of pg_database during backend startup. This should finally eliminate the various corner cases in which backend startup fails unexpectedly because it isn't able to distinguish live and dead tuples in pg_database. Simplify locking on pg_database to be similar to the rules used with pg_shadow and pg_group, and eliminate FlushRelationBuffers operations that were used only to reduce the odds of failure of GetRawDatabaseInfo. initdb forced due to addition of a trigger to pg_database.
This commit is contained in:
parent
ffef9a9de4
commit
0fc4ecf935
@ -3,13 +3,19 @@
|
||||
* dbcommands.c
|
||||
* Database management commands (create/drop database).
|
||||
*
|
||||
* Note: database creation/destruction commands take ExclusiveLock on
|
||||
* pg_database to ensure that no two proceed in parallel. We must use
|
||||
* at least this level of locking to ensure that no two backends try to
|
||||
* write the flat-file copy of pg_database at once. We avoid using
|
||||
* AccessExclusiveLock since there's no need to lock out ordinary readers
|
||||
* of pg_database.
|
||||
*
|
||||
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/commands/dbcommands.c,v 1.150 2005/02/20 02:21:34 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/commands/dbcommands.c,v 1.151 2005/02/26 18:43:33 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -446,13 +452,13 @@ createdb(const CreatedbStmt *stmt)
|
||||
/*
|
||||
* Now OK to grab exclusive lock on pg_database.
|
||||
*/
|
||||
pg_database_rel = heap_openr(DatabaseRelationName, AccessExclusiveLock);
|
||||
pg_database_rel = heap_openr(DatabaseRelationName, ExclusiveLock);
|
||||
|
||||
/* Check to see if someone else created same DB name meanwhile. */
|
||||
if (get_db_info(dbname, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL))
|
||||
{
|
||||
/* Don't hold lock while doing recursive remove */
|
||||
heap_close(pg_database_rel, AccessExclusiveLock);
|
||||
heap_close(pg_database_rel, ExclusiveLock);
|
||||
remove_dbtablespaces(dboid);
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_DUPLICATE_DATABASE),
|
||||
@ -498,13 +504,6 @@ createdb(const CreatedbStmt *stmt)
|
||||
/* Update indexes */
|
||||
CatalogUpdateIndexes(pg_database_rel, tuple);
|
||||
|
||||
/*
|
||||
* Force dirty buffers out to disk, so that newly-connecting backends
|
||||
* will see the new database in pg_database right away. (They'll see
|
||||
* an uncommitted tuple, but they don't care; see GetRawDatabaseInfo.)
|
||||
*/
|
||||
FlushRelationBuffers(pg_database_rel, MaxBlockNumber);
|
||||
|
||||
/* Close pg_database, but keep exclusive lock till commit */
|
||||
heap_close(pg_database_rel, NoLock);
|
||||
|
||||
@ -542,12 +541,15 @@ dropdb(const char *dbname)
|
||||
* Obtain exclusive lock on pg_database. We need this to ensure that
|
||||
* no new backend starts up in the target database while we are
|
||||
* deleting it. (Actually, a new backend might still manage to start
|
||||
* up, because it will read pg_database without any locking to
|
||||
* discover the database's OID. But it will detect its error in
|
||||
* ReverifyMyDatabase and shut down before any serious damage is done.
|
||||
* See postinit.c.)
|
||||
* up, because it isn't able to lock pg_database while starting. But
|
||||
* it will detect its error in ReverifyMyDatabase and shut down before
|
||||
* any serious damage is done. See postinit.c.)
|
||||
*
|
||||
* An ExclusiveLock, rather than AccessExclusiveLock, is sufficient
|
||||
* since ReverifyMyDatabase takes RowShareLock. This allows ordinary
|
||||
* readers of pg_database to proceed in parallel.
|
||||
*/
|
||||
pgdbrel = heap_openr(DatabaseRelationName, AccessExclusiveLock);
|
||||
pgdbrel = heap_openr(DatabaseRelationName, ExclusiveLock);
|
||||
|
||||
if (!get_db_info(dbname, &db_id, &db_owner, NULL,
|
||||
&db_istemplate, NULL, NULL, NULL, NULL))
|
||||
@ -638,14 +640,6 @@ dropdb(const char *dbname)
|
||||
*/
|
||||
remove_dbtablespaces(db_id);
|
||||
|
||||
/*
|
||||
* Force dirty buffers out to disk, so that newly-connecting backends
|
||||
* will see the database tuple marked dead in pg_database right away.
|
||||
* (They'll see an uncommitted deletion, but they don't care; see
|
||||
* GetRawDatabaseInfo.)
|
||||
*/
|
||||
FlushRelationBuffers(pgdbrel, MaxBlockNumber);
|
||||
|
||||
/* Close pg_database, but keep exclusive lock till commit */
|
||||
heap_close(pgdbrel, NoLock);
|
||||
|
||||
@ -671,10 +665,10 @@ RenameDatabase(const char *oldname, const char *newname)
|
||||
key2;
|
||||
|
||||
/*
|
||||
* Obtain AccessExclusiveLock so that no new session gets started
|
||||
* Obtain ExclusiveLock so that no new session gets started
|
||||
* while the rename is in progress.
|
||||
*/
|
||||
rel = heap_openr(DatabaseRelationName, AccessExclusiveLock);
|
||||
rel = heap_openr(DatabaseRelationName, ExclusiveLock);
|
||||
|
||||
ScanKeyInit(&key,
|
||||
Anum_pg_database_datname,
|
||||
@ -742,14 +736,6 @@ RenameDatabase(const char *oldname, const char *newname)
|
||||
|
||||
systable_endscan(scan);
|
||||
|
||||
/*
|
||||
* Force dirty buffers out to disk, so that newly-connecting backends
|
||||
* will see the renamed database in pg_database right away. (They'll
|
||||
* see an uncommitted tuple, but they don't care; see
|
||||
* GetRawDatabaseInfo.)
|
||||
*/
|
||||
FlushRelationBuffers(rel, MaxBlockNumber);
|
||||
|
||||
/* Close pg_database, but keep exclusive lock till commit */
|
||||
heap_close(rel, NoLock);
|
||||
|
||||
@ -779,9 +765,10 @@ AlterDatabaseSet(AlterDatabaseSetStmt *stmt)
|
||||
valuestr = flatten_set_variable_args(stmt->variable, stmt->value);
|
||||
|
||||
/*
|
||||
* We need AccessExclusiveLock so we can safely do FlushRelationBuffers.
|
||||
* We don't need ExclusiveLock since we aren't updating the
|
||||
* flat file.
|
||||
*/
|
||||
rel = heap_openr(DatabaseRelationName, AccessExclusiveLock);
|
||||
rel = heap_openr(DatabaseRelationName, RowExclusiveLock);
|
||||
ScanKeyInit(&scankey,
|
||||
Anum_pg_database_datname,
|
||||
BTEqualStrategyNumber, F_NAMEEQ,
|
||||
@ -840,15 +827,7 @@ AlterDatabaseSet(AlterDatabaseSetStmt *stmt)
|
||||
|
||||
systable_endscan(scan);
|
||||
|
||||
/*
|
||||
* Force dirty buffers out to disk, so that newly-connecting backends
|
||||
* will see the altered row in pg_database right away. (They'll
|
||||
* see an uncommitted tuple, but they don't care; see
|
||||
* GetRawDatabaseInfo.)
|
||||
*/
|
||||
FlushRelationBuffers(rel, MaxBlockNumber);
|
||||
|
||||
/* Close pg_database, but keep exclusive lock till commit */
|
||||
/* Close pg_database, but keep lock till commit */
|
||||
heap_close(rel, NoLock);
|
||||
|
||||
/*
|
||||
@ -871,9 +850,10 @@ AlterDatabaseOwner(const char *dbname, AclId newOwnerSysId)
|
||||
Form_pg_database datForm;
|
||||
|
||||
/*
|
||||
* We need AccessExclusiveLock so we can safely do FlushRelationBuffers.
|
||||
* We don't need ExclusiveLock since we aren't updating the
|
||||
* flat file.
|
||||
*/
|
||||
rel = heap_openr(DatabaseRelationName, AccessExclusiveLock);
|
||||
rel = heap_openr(DatabaseRelationName, RowExclusiveLock);
|
||||
ScanKeyInit(&scankey,
|
||||
Anum_pg_database_datname,
|
||||
BTEqualStrategyNumber, F_NAMEEQ,
|
||||
@ -937,22 +917,11 @@ AlterDatabaseOwner(const char *dbname, AclId newOwnerSysId)
|
||||
CatalogUpdateIndexes(rel, newtuple);
|
||||
|
||||
heap_freetuple(newtuple);
|
||||
|
||||
/* must release buffer pins before FlushRelationBuffers */
|
||||
systable_endscan(scan);
|
||||
|
||||
/*
|
||||
* Force dirty buffers out to disk, so that newly-connecting backends
|
||||
* will see the altered row in pg_database right away. (They'll
|
||||
* see an uncommitted tuple, but they don't care; see
|
||||
* GetRawDatabaseInfo.)
|
||||
*/
|
||||
FlushRelationBuffers(rel, MaxBlockNumber);
|
||||
}
|
||||
else
|
||||
systable_endscan(scan);
|
||||
|
||||
/* Close pg_database, but keep exclusive lock till commit */
|
||||
systable_endscan(scan);
|
||||
|
||||
/* Close pg_database, but keep lock till commit */
|
||||
heap_close(rel, NoLock);
|
||||
|
||||
/*
|
||||
|
@ -13,7 +13,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/commands/vacuum.c,v 1.301 2005/02/20 02:21:34 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/commands/vacuum.c,v 1.302 2005/02/26 18:43:33 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -704,11 +704,12 @@ vac_update_relstats(Oid relid, BlockNumber num_pages, double num_tuples,
|
||||
* We violate no-overwrite semantics here by storing new values for the
|
||||
* statistics columns directly into the tuple that's already on the page.
|
||||
* As with vac_update_relstats, this avoids leaving dead tuples behind
|
||||
* after a VACUUM; which is good since GetRawDatabaseInfo
|
||||
* can get confused by finding dead tuples in pg_database.
|
||||
* after a VACUUM.
|
||||
*
|
||||
* This routine is shared by full and lazy VACUUM. Note that it is only
|
||||
* applied after a database-wide VACUUM operation.
|
||||
*
|
||||
* Note that we don't bother to update the flat-file copy of pg_database.
|
||||
*/
|
||||
static void
|
||||
vac_update_dbstats(Oid dbid,
|
||||
|
@ -10,12 +10,13 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/libpq/hba.c,v 1.139 2005/02/20 04:45:57 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/libpq/hba.c,v 1.140 2005/02/26 18:43:33 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
#include "postgres.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#include <pwd.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/param.h>
|
||||
@ -37,6 +38,8 @@
|
||||
#include "utils/guc.h"
|
||||
|
||||
|
||||
#define atooid(x) ((Oid) strtoul((x), NULL, 10))
|
||||
|
||||
/* Max size of username ident server can return */
|
||||
#define IDENT_USERNAME_MAX 512
|
||||
|
||||
@ -1059,6 +1062,51 @@ load_hba(void)
|
||||
FreeFile(file);
|
||||
}
|
||||
|
||||
/*
|
||||
* Read and parse one line from the flat pg_database file.
|
||||
*
|
||||
* Returns TRUE on success, FALSE if EOF; bad data causes elog(FATAL).
|
||||
*
|
||||
* Output parameters:
|
||||
* dbname: gets database name (must be of size NAMEDATALEN bytes)
|
||||
* dboid: gets database OID
|
||||
* dbtablespace: gets database's default tablespace's OID
|
||||
*
|
||||
* This is not much related to the other functions in hba.c, but we put it
|
||||
* here because it uses the next_token() infrastructure.
|
||||
*/
|
||||
bool
|
||||
read_pg_database_line(FILE *fp, char *dbname,
|
||||
Oid *dboid, Oid *dbtablespace)
|
||||
{
|
||||
char buf[MAX_TOKEN];
|
||||
|
||||
if (feof(fp))
|
||||
return false;
|
||||
next_token(fp, buf, sizeof(buf));
|
||||
if (!buf[0])
|
||||
return false;
|
||||
if (strlen(buf) >= NAMEDATALEN)
|
||||
elog(FATAL, "bad data in flat pg_database file");
|
||||
strcpy(dbname, buf);
|
||||
next_token(fp, buf, sizeof(buf));
|
||||
if (!isdigit((unsigned char) buf[0]))
|
||||
elog(FATAL, "bad data in flat pg_database file");
|
||||
*dboid = atooid(buf);
|
||||
next_token(fp, buf, sizeof(buf));
|
||||
if (!isdigit((unsigned char) buf[0]))
|
||||
elog(FATAL, "bad data in flat pg_database file");
|
||||
*dbtablespace = atooid(buf);
|
||||
/* discard datfrozenxid */
|
||||
next_token(fp, buf, sizeof(buf));
|
||||
if (!isdigit((unsigned char) buf[0]))
|
||||
elog(FATAL, "bad data in flat pg_database file");
|
||||
/* expect EOL next */
|
||||
next_token(fp, buf, sizeof(buf));
|
||||
if (buf[0])
|
||||
elog(FATAL, "bad data in flat pg_database file");
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Process one line from the ident config file.
|
||||
|
@ -22,7 +22,7 @@
|
||||
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $PostgreSQL: pgsql/src/backend/utils/init/flatfiles.c,v 1.3 2005/02/20 22:02:19 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/utils/init/flatfiles.c,v 1.4 2005/02/26 18:43:33 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -243,10 +243,12 @@ write_database_file(Relation drel)
|
||||
Form_pg_database dbform = (Form_pg_database) GETSTRUCT(tuple);
|
||||
char *datname;
|
||||
Oid datoid;
|
||||
Oid dattablespace;
|
||||
TransactionId datfrozenxid;
|
||||
|
||||
datname = NameStr(dbform->datname);
|
||||
datoid = HeapTupleGetOid(tuple);
|
||||
dattablespace = dbform->dattablespace;
|
||||
datfrozenxid = dbform->datfrozenxid;
|
||||
|
||||
/*
|
||||
@ -276,13 +278,13 @@ write_database_file(Relation drel)
|
||||
}
|
||||
|
||||
/*
|
||||
* The file format is: "dbname" oid frozenxid
|
||||
* The file format is: "dbname" oid tablespace frozenxid
|
||||
*
|
||||
* The xid is not needed for backend startup, but may be of use
|
||||
* for forensic purposes.
|
||||
*/
|
||||
fputs_quote(datname, fp);
|
||||
fprintf(fp, " %u %u\n", datoid, datfrozenxid);
|
||||
fprintf(fp, " %u %u %u\n", datoid, dattablespace, datfrozenxid);
|
||||
}
|
||||
heap_endscan(scan);
|
||||
|
||||
@ -830,15 +832,3 @@ flatfile_update_trigger(PG_FUNCTION_ARGS)
|
||||
|
||||
return PointerGetDatum(NULL);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Old version of trigger --- remove after we can force an initdb
|
||||
*/
|
||||
extern Datum update_pg_pwd_and_pg_group(PG_FUNCTION_ARGS);
|
||||
|
||||
Datum
|
||||
update_pg_pwd_and_pg_group(PG_FUNCTION_ARGS)
|
||||
{
|
||||
return flatfile_update_trigger(fcinfo);
|
||||
}
|
||||
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/utils/init/postinit.c,v 1.140 2005/02/20 21:46:49 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/utils/init/postinit.c,v 1.141 2005/02/26 18:43:33 tgl Exp $
|
||||
*
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
@ -27,14 +27,16 @@
|
||||
#include "catalog/pg_database.h"
|
||||
#include "catalog/pg_shadow.h"
|
||||
#include "catalog/pg_tablespace.h"
|
||||
#include "libpq/hba.h"
|
||||
#include "mb/pg_wchar.h"
|
||||
#include "miscadmin.h"
|
||||
#include "postmaster/postmaster.h"
|
||||
#include "storage/backendid.h"
|
||||
#include "storage/fd.h"
|
||||
#include "storage/ipc.h"
|
||||
#include "storage/proc.h"
|
||||
#include "storage/sinval.h"
|
||||
#include "storage/smgr.h"
|
||||
#include "utils/flatfiles.h"
|
||||
#include "utils/fmgroids.h"
|
||||
#include "utils/guc.h"
|
||||
#include "utils/portal.h"
|
||||
@ -42,6 +44,7 @@
|
||||
#include "utils/syscache.h"
|
||||
|
||||
|
||||
static bool FindMyDatabase(const char *name, Oid *db_id, Oid *db_tablespace);
|
||||
static void ReverifyMyDatabase(const char *name);
|
||||
static void InitCommunication(void);
|
||||
static void ShutdownPostgres(int code, Datum arg);
|
||||
@ -51,18 +54,60 @@ static bool ThereIsAtLeastOneUser(void);
|
||||
/*** InitPostgres support ***/
|
||||
|
||||
|
||||
/* --------------------------------
|
||||
* ReverifyMyDatabase
|
||||
/*
|
||||
* FindMyDatabase -- get the critical info needed to locate my database
|
||||
*
|
||||
* Since we are forced to fetch the database OID out of pg_database without
|
||||
* benefit of locking or transaction ID checking (see utils/misc/database.c),
|
||||
* we might have gotten a wrong answer. Or, we might have attached to a
|
||||
* database that's in process of being destroyed by destroydb(). This
|
||||
* routine is called after we have all the locking and other infrastructure
|
||||
* running --- now we can check that we are really attached to a valid
|
||||
* database.
|
||||
* Find the named database in pg_database, return its database OID and the
|
||||
* OID of its default tablespace. Return TRUE if found, FALSE if not.
|
||||
*
|
||||
* In reality, if destroydb() is running in parallel with our startup,
|
||||
* Since we are not yet up and running as a backend, we cannot look directly
|
||||
* at pg_database (we can't obtain locks nor participate in transactions).
|
||||
* So to get the info we need before starting up, we must look at the "flat
|
||||
* file" copy of pg_database that is helpfully maintained by flatfiles.c.
|
||||
* This is subject to various race conditions, so after we have the
|
||||
* transaction infrastructure started, we have to recheck the information;
|
||||
* see ReverifyMyDatabase.
|
||||
*/
|
||||
static bool
|
||||
FindMyDatabase(const char *name, Oid *db_id, Oid *db_tablespace)
|
||||
{
|
||||
bool result = false;
|
||||
char *filename;
|
||||
FILE *db_file;
|
||||
char thisname[NAMEDATALEN];
|
||||
|
||||
filename = database_getflatfilename();
|
||||
db_file = AllocateFile(filename, "r");
|
||||
if (db_file == NULL)
|
||||
ereport(FATAL,
|
||||
(errcode_for_file_access(),
|
||||
errmsg("could not open file \"%s\": %m", filename)));
|
||||
|
||||
while (read_pg_database_line(db_file, thisname, db_id, db_tablespace))
|
||||
{
|
||||
if (strcmp(thisname, name) == 0)
|
||||
{
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
FreeFile(db_file);
|
||||
pfree(filename);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* ReverifyMyDatabase -- recheck info obtained by FindMyDatabase
|
||||
*
|
||||
* Since FindMyDatabase cannot lock pg_database, the information it read
|
||||
* could be stale; for example we might have attached to a database that's in
|
||||
* process of being destroyed by dropdb(). This routine is called after
|
||||
* we have all the locking and other infrastructure running --- now we can
|
||||
* check that we are really attached to a valid database.
|
||||
*
|
||||
* In reality, if dropdb() is running in parallel with our startup,
|
||||
* it's pretty likely that we will have failed before now, due to being
|
||||
* unable to read some of the system tables within the doomed database.
|
||||
* This routine just exists to make *sure* we have not started up in an
|
||||
@ -75,7 +120,6 @@ static bool ThereIsAtLeastOneUser(void);
|
||||
* To avoid having to read pg_database more times than necessary
|
||||
* during session startup, this place is also fitting to set up any
|
||||
* database-specific configuration variables.
|
||||
* --------------------------------
|
||||
*/
|
||||
static void
|
||||
ReverifyMyDatabase(const char *name)
|
||||
@ -87,10 +131,10 @@ ReverifyMyDatabase(const char *name)
|
||||
Form_pg_database dbform;
|
||||
|
||||
/*
|
||||
* Because we grab AccessShareLock here, we can be sure that destroydb
|
||||
* Because we grab RowShareLock here, we can be sure that dropdb()
|
||||
* is not running in parallel with us (any more).
|
||||
*/
|
||||
pgdbrel = heap_openr(DatabaseRelationName, AccessShareLock);
|
||||
pgdbrel = heap_openr(DatabaseRelationName, RowShareLock);
|
||||
|
||||
ScanKeyInit(&key,
|
||||
Anum_pg_database_datname,
|
||||
@ -104,7 +148,7 @@ ReverifyMyDatabase(const char *name)
|
||||
HeapTupleGetOid(tup) != MyDatabaseId)
|
||||
{
|
||||
/* OOPS */
|
||||
heap_close(pgdbrel, AccessShareLock);
|
||||
heap_close(pgdbrel, RowShareLock);
|
||||
|
||||
/*
|
||||
* The only real problem I could have created is to load dirty
|
||||
@ -131,7 +175,7 @@ ReverifyMyDatabase(const char *name)
|
||||
name)));
|
||||
|
||||
/*
|
||||
* OK, we're golden. Only other to-do item is to save the encoding
|
||||
* OK, we're golden. Next to-do item is to save the encoding
|
||||
* info out of the pg_database tuple.
|
||||
*/
|
||||
SetDatabaseEncoding(dbform->encoding);
|
||||
@ -143,7 +187,7 @@ ReverifyMyDatabase(const char *name)
|
||||
PGC_BACKEND, PGC_S_DEFAULT);
|
||||
|
||||
/*
|
||||
* Set up database-specific configuration variables.
|
||||
* Lastly, set up any database-specific configuration variables.
|
||||
*/
|
||||
if (IsUnderPostmaster)
|
||||
{
|
||||
@ -161,7 +205,7 @@ ReverifyMyDatabase(const char *name)
|
||||
}
|
||||
|
||||
heap_endscan(pgdbscan);
|
||||
heap_close(pgdbrel, AccessShareLock);
|
||||
heap_close(pgdbrel, RowShareLock);
|
||||
}
|
||||
|
||||
|
||||
@ -261,11 +305,9 @@ InitPostgres(const char *dbname, const char *username)
|
||||
/*
|
||||
* Find oid and tablespace of the database we're about to open.
|
||||
* Since we're not yet up and running we have to use the hackish
|
||||
* GetRawDatabaseInfo.
|
||||
* FindMyDatabase.
|
||||
*/
|
||||
GetRawDatabaseInfo(dbname, &MyDatabaseId, &MyDatabaseTableSpace);
|
||||
|
||||
if (!OidIsValid(MyDatabaseId))
|
||||
if (!FindMyDatabase(dbname, &MyDatabaseId, &MyDatabaseTableSpace))
|
||||
ereport(FATAL,
|
||||
(errcode(ERRCODE_UNDEFINED_DATABASE),
|
||||
errmsg("database \"%s\" does not exist",
|
||||
|
@ -1,4 +1,12 @@
|
||||
# $PostgreSQL: pgsql/src/backend/utils/misc/Makefile,v 1.22 2003/11/29 19:52:03 pgsql Exp $
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
# Makefile--
|
||||
# Makefile for utils/misc
|
||||
#
|
||||
# IDENTIFICATION
|
||||
# $PostgreSQL: pgsql/src/backend/utils/misc/Makefile,v 1.23 2005/02/26 18:43:33 tgl Exp $
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
|
||||
subdir = src/backend/utils/misc
|
||||
top_builddir = ../../../..
|
||||
@ -6,10 +14,10 @@ include $(top_builddir)/src/Makefile.global
|
||||
|
||||
override CPPFLAGS := -I$(srcdir) $(CPPFLAGS)
|
||||
|
||||
OBJS = database.o superuser.o guc.o help_config.o ps_status.o
|
||||
OBJS = guc.o help_config.o ps_status.o superuser.o
|
||||
|
||||
# This location might depend on the installation directories. Therefore
|
||||
# we can't subsitute it into config.h.
|
||||
# we can't subsitute it into pg_config.h.
|
||||
ifdef krb_srvtab
|
||||
override CPPFLAGS += -DPG_KRB_SRVTAB='"$(krb_srvtab)"'
|
||||
endif
|
||||
|
@ -1,189 +0,0 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
*
|
||||
* database.c
|
||||
* miscellaneous initialization support stuff
|
||||
*
|
||||
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/utils/misc/database.c,v 1.63 2004/12/31 22:02:45 pgsql Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
#include "postgres.h"
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "access/xact.h"
|
||||
#include "catalog/catname.h"
|
||||
#include "catalog/catalog.h"
|
||||
#include "catalog/pg_database.h"
|
||||
#include "catalog/pg_tablespace.h"
|
||||
#include "miscadmin.h"
|
||||
#include "utils/syscache.h"
|
||||
|
||||
|
||||
static bool PhonyHeapTupleSatisfiesNow(HeapTupleHeader tuple);
|
||||
|
||||
|
||||
/* --------------------------------
|
||||
* GetRawDatabaseInfo() -- Find the OID and tablespace of the database.
|
||||
*
|
||||
* We need both the OID and the default tablespace in order to find
|
||||
* the database's system catalogs. Moreover the database's OID forms
|
||||
* half of the unique key for the system caches and lock tables, so
|
||||
* we must have it before we can use any of the cache mechanisms.
|
||||
* To get around these problems, this code opens and scans the
|
||||
* pg_database relation by hand.
|
||||
*
|
||||
* This code knows way more than it should about the layout of
|
||||
* tuples on disk, but there seems to be no help for that.
|
||||
* We're pulling ourselves up by the bootstraps here...
|
||||
* --------------------------------
|
||||
*/
|
||||
void
|
||||
GetRawDatabaseInfo(const char *name, Oid *db_id, Oid *db_tablespace)
|
||||
{
|
||||
int dbfd;
|
||||
int nbytes;
|
||||
HeapTupleData tup;
|
||||
Form_pg_database tup_db;
|
||||
Page pg;
|
||||
char *dbfname;
|
||||
RelFileNode rnode;
|
||||
|
||||
/* hard-wired path to pg_database */
|
||||
rnode.spcNode = GLOBALTABLESPACE_OID;
|
||||
rnode.dbNode = 0;
|
||||
rnode.relNode = RelOid_pg_database;
|
||||
|
||||
dbfname = relpath(rnode);
|
||||
|
||||
if ((dbfd = open(dbfname, O_RDONLY | PG_BINARY, 0)) < 0)
|
||||
ereport(FATAL,
|
||||
(errcode_for_file_access(),
|
||||
errmsg("could not open file \"%s\": %m", dbfname)));
|
||||
|
||||
pfree(dbfname);
|
||||
|
||||
/*
|
||||
* read and examine every page in pg_database
|
||||
*
|
||||
* 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 code. Perhaps it
|
||||
* should go in lib/catalog/pg_database? -cim 10/3/90
|
||||
*
|
||||
* mao replies 4 apr 91: yeah, maybe this should be moved to
|
||||
* lib/catalog. however, we CANNOT use the access methods since those
|
||||
* use the buffer cache, which uses the relation cache, which requires
|
||||
* that the dbid be set, which is what we're trying to do here.
|
||||
*
|
||||
*/
|
||||
pg = (Page) palloc(BLCKSZ);
|
||||
|
||||
while ((nbytes = read(dbfd, pg, BLCKSZ)) == BLCKSZ)
|
||||
{
|
||||
OffsetNumber max = PageGetMaxOffsetNumber(pg);
|
||||
OffsetNumber lineoff;
|
||||
|
||||
/* look at each tuple on the page */
|
||||
for (lineoff = FirstOffsetNumber; lineoff <= max; lineoff++)
|
||||
{
|
||||
ItemId lpp = PageGetItemId(pg, lineoff);
|
||||
|
||||
/* if it's a freed tuple, ignore it */
|
||||
if (!ItemIdIsUsed(lpp))
|
||||
continue;
|
||||
|
||||
/* get a pointer to the tuple itself */
|
||||
tup.t_datamcxt = NULL;
|
||||
tup.t_data = (HeapTupleHeader) PageGetItem(pg, lpp);
|
||||
|
||||
/*
|
||||
* Check to see if tuple is valid (committed).
|
||||
*
|
||||
* XXX warning, will robinson: violation of transaction semantics
|
||||
* happens right here. We cannot really determine if the
|
||||
* tuple is valid without checking transaction commit status,
|
||||
* and the only way to do that at init time is to paw over
|
||||
* pg_clog by hand, too. Instead of checking, we assume that
|
||||
* the inserting transaction committed, and that any deleting
|
||||
* transaction did also, unless shown otherwise by on-row
|
||||
* commit status bits.
|
||||
*
|
||||
* All in all, this code is pretty shaky. We will cross-check
|
||||
* our result in ReverifyMyDatabase() in postinit.c.
|
||||
*
|
||||
* NOTE: if a bogus tuple in pg_database prevents connection to a
|
||||
* valid database, a fix is to connect to another database and
|
||||
* do "select * from pg_database". That should cause
|
||||
* committed and dead tuples to be marked with correct states.
|
||||
*
|
||||
* XXX wouldn't it be better to let new backends read the
|
||||
* database info from a flat file, handled the same way we
|
||||
* handle the password relation?
|
||||
*/
|
||||
if (!PhonyHeapTupleSatisfiesNow(tup.t_data))
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Okay, see if this is the one we want.
|
||||
*/
|
||||
tup_db = (Form_pg_database) GETSTRUCT(&tup);
|
||||
|
||||
if (strcmp(name, NameStr(tup_db->datname)) == 0)
|
||||
{
|
||||
/* Found it; extract the db's OID and tablespace. */
|
||||
*db_id = HeapTupleGetOid(&tup);
|
||||
*db_tablespace = tup_db->dattablespace;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* failed to find it... */
|
||||
*db_id = InvalidOid;
|
||||
*db_tablespace = InvalidOid;
|
||||
|
||||
done:
|
||||
close(dbfd);
|
||||
pfree(pg);
|
||||
}
|
||||
|
||||
/*
|
||||
* PhonyHeapTupleSatisfiesNow --- cut-down tuple time qual test
|
||||
*
|
||||
* This is a simplified version of HeapTupleSatisfiesNow() that does not
|
||||
* depend on having transaction commit info available. Any transaction
|
||||
* that touched the tuple is assumed committed unless later marked invalid.
|
||||
* (While we could think about more complex rules, this seems appropriate
|
||||
* for examining pg_database, since both CREATE DATABASE and DROP DATABASE
|
||||
* are non-roll-back-able.)
|
||||
*/
|
||||
static bool
|
||||
PhonyHeapTupleSatisfiesNow(HeapTupleHeader tuple)
|
||||
{
|
||||
if (!(tuple->t_infomask & HEAP_XMIN_COMMITTED))
|
||||
{
|
||||
if (tuple->t_infomask & HEAP_XMIN_INVALID)
|
||||
return false;
|
||||
|
||||
if (tuple->t_infomask & HEAP_MOVED_OFF)
|
||||
return false;
|
||||
/* else assume committed */
|
||||
}
|
||||
|
||||
if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid or aborted */
|
||||
return true;
|
||||
|
||||
/* assume xmax transaction committed */
|
||||
if (tuple->t_infomask & HEAP_MARKED_FOR_UPDATE)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
@ -39,7 +39,7 @@
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
* Portions taken from FreeBSD.
|
||||
*
|
||||
* $PostgreSQL: pgsql/src/bin/initdb/initdb.c,v 1.75 2005/02/22 04:38:22 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/bin/initdb/initdb.c,v 1.76 2005/02/26 18:43:34 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -1319,15 +1319,18 @@ setup_shadow(void)
|
||||
char **line;
|
||||
static char *pg_shadow_setup[] = {
|
||||
/*
|
||||
* Create a trigger so that direct updates to pg_shadow will be
|
||||
* written to the flat password/group files pg_pwd and pg_group
|
||||
* Create triggers to ensure manual updates to shared catalogs
|
||||
* will be reflected into their "flat file" copies.
|
||||
*/
|
||||
"CREATE TRIGGER pg_sync_pg_pwd "
|
||||
" AFTER INSERT OR UPDATE OR DELETE ON pg_shadow "
|
||||
" FOR EACH ROW EXECUTE PROCEDURE update_pg_pwd_and_pg_group();\n",
|
||||
"CREATE TRIGGER pg_sync_pg_database "
|
||||
" AFTER INSERT OR UPDATE OR DELETE ON pg_database "
|
||||
" FOR EACH STATEMENT EXECUTE PROCEDURE flatfile_update_trigger();\n",
|
||||
"CREATE TRIGGER pg_sync_pg_group "
|
||||
" AFTER INSERT OR UPDATE OR DELETE ON pg_group "
|
||||
" FOR EACH ROW EXECUTE PROCEDURE update_pg_pwd_and_pg_group();\n",
|
||||
" FOR EACH STATEMENT EXECUTE PROCEDURE flatfile_update_trigger();\n",
|
||||
"CREATE TRIGGER pg_sync_pg_pwd "
|
||||
" AFTER INSERT OR UPDATE OR DELETE ON pg_shadow "
|
||||
" FOR EACH STATEMENT EXECUTE PROCEDURE flatfile_update_trigger();\n",
|
||||
|
||||
/*
|
||||
* needs to be done before alter user, because alter user checks
|
||||
|
@ -37,7 +37,7 @@
|
||||
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.254 2005/02/25 16:13:29 teodor Exp $
|
||||
* $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.255 2005/02/26 18:43:34 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -53,6 +53,6 @@
|
||||
*/
|
||||
|
||||
/* yyyymmddN */
|
||||
#define CATALOG_VERSION_NO 200502251
|
||||
#define CATALOG_VERSION_NO 200502261
|
||||
|
||||
#endif
|
||||
|
@ -7,7 +7,7 @@
|
||||
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.349 2004/12/31 22:03:25 pgsql Exp $
|
||||
* $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.350 2005/02/26 18:43:34 tgl Exp $
|
||||
*
|
||||
* NOTES
|
||||
* The script catalog/genbki.sh reads this file and generates .bki
|
||||
@ -2133,8 +2133,8 @@ DESCR("matches LIKE expression, case-insensitive");
|
||||
DATA(insert OID = 1661 ( bpcharicnlike PGNSP PGUID 12 f f t f i 2 16 "1042 25" _null_ texticnlike - _null_ ));
|
||||
DESCR("does not match LIKE expression, case-insensitive");
|
||||
|
||||
DATA(insert OID = 1689 ( update_pg_pwd_and_pg_group PGNSP PGUID 12 f f t f v 0 2279 "" _null_ update_pg_pwd_and_pg_group - _null_ ));
|
||||
DESCR("update pg_pwd and pg_group files");
|
||||
DATA(insert OID = 1689 ( flatfile_update_trigger PGNSP PGUID 12 f f t f v 0 2279 "" _null_ flatfile_update_trigger - _null_ ));
|
||||
DESCR("update flat-file copy of a shared catalog");
|
||||
|
||||
/* Oracle Compatibility Related Functions - By Edmund Mergl <E.Mergl@bawue.de> */
|
||||
DATA(insert OID = 868 ( strpos PGNSP PGUID 12 f f t f i 2 23 "25 25" _null_ textpos - _null_ ));
|
||||
|
@ -4,19 +4,16 @@
|
||||
* Interface to hba.c
|
||||
*
|
||||
*
|
||||
* $PostgreSQL: pgsql/src/include/libpq/hba.h,v 1.35 2004/02/02 16:58:30 neilc Exp $
|
||||
* $PostgreSQL: pgsql/src/include/libpq/hba.h,v 1.36 2005/02/26 18:43:34 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
#ifndef HBA_H
|
||||
#define HBA_H
|
||||
|
||||
#ifndef WIN32
|
||||
#include <netinet/in.h>
|
||||
#endif
|
||||
|
||||
#include "nodes/pg_list.h"
|
||||
|
||||
|
||||
typedef enum UserAuth
|
||||
{
|
||||
uaReject,
|
||||
@ -41,5 +38,7 @@ extern void load_user(void);
|
||||
extern void load_group(void);
|
||||
extern int hba_getauthmethod(hbaPort *port);
|
||||
extern int authident(hbaPort *port);
|
||||
extern bool read_pg_database_line(FILE *fp, char *dbname,
|
||||
Oid *dboid, Oid *dbtablespace);
|
||||
|
||||
#endif
|
||||
#endif /* HBA_H */
|
||||
|
@ -13,7 +13,7 @@
|
||||
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $PostgreSQL: pgsql/src/include/miscadmin.h,v 1.174 2004/12/31 22:03:19 pgsql Exp $
|
||||
* $PostgreSQL: pgsql/src/include/miscadmin.h,v 1.175 2005/02/26 18:43:34 tgl Exp $
|
||||
*
|
||||
* NOTES
|
||||
* some of the information in this file should be moved to other files.
|
||||
@ -225,9 +225,6 @@ extern void check_stack_depth(void);
|
||||
|
||||
extern char *DatabasePath;
|
||||
|
||||
/* in utils/misc/database.c */
|
||||
extern void GetRawDatabaseInfo(const char *name, Oid *db_id, Oid *db_tablespace);
|
||||
|
||||
/* now in utils/init/miscinit.c */
|
||||
extern void SetDatabasePath(const char *path);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user