Commit bbea3643 authored by Tom Lane's avatar Tom Lane

Store current LC_COLLATE and LC_CTYPE settings in pg_control during initdb;

re-adopt these settings at every postmaster or standalone-backend startup.
This should fix problems with indexes becoming corrupt due to failure to
provide consistent locale environment for postmaster at all times.  Also,
refuse to start up a non-locale-enabled compilation in a database originally
initdb'd with a non-C locale.  Suppress LIKE index optimization if locale
is not "C" or "POSIX" (are there any other locales where it's safe?).
Issue NOTICE during initdb if selected locale disables LIKE optimization.
parent 0432ce99
<!-- <!--
$Header: /cvsroot/pgsql/doc/src/sgml/runtime.sgml,v 1.38 2000/11/22 01:41:12 momjian Exp $ $Header: /cvsroot/pgsql/doc/src/sgml/runtime.sgml,v 1.39 2000/11/25 20:33:47 tgl Exp $
--> -->
<Chapter Id="runtime"> <Chapter Id="runtime">
...@@ -79,9 +79,9 @@ $Header: /cvsroot/pgsql/doc/src/sgml/runtime.sgml,v 1.38 2000/11/22 01:41:12 mom ...@@ -79,9 +79,9 @@ $Header: /cvsroot/pgsql/doc/src/sgml/runtime.sgml,v 1.38 2000/11/22 01:41:12 mom
<command>initdb</command> will attempt to create the directory you <command>initdb</command> will attempt to create the directory you
specify if it does not already exist. It is likely that it won't specify if it does not already exist. It is likely that it won't
have the permission to do so (if you followed our advice and have the permission to do so (if you followed our advice and
created an unprivileged account). In that case you can create the created an unprivileged account). In that case you should create the
directory yourself (as root) and transfer ownership of it or grant directory yourself (as root) and transfer ownership of it to the
write access to it. Here is how this might work: Postgres user account. Here is how this might work:
<screen> <screen>
root# <userinput>mkdir /usr/local/pgsql/data</userinput> root# <userinput>mkdir /usr/local/pgsql/data</userinput>
root# <userinput>chown postgres /usr/local/pgsql/data</userinput> root# <userinput>chown postgres /usr/local/pgsql/data</userinput>
...@@ -101,6 +101,28 @@ postgres&gt; <userinput>initdb -D /usr/local/pgsql/data</userinput> ...@@ -101,6 +101,28 @@ postgres&gt; <userinput>initdb -D /usr/local/pgsql/data</userinput>
access. <command>initdb</command> therefore revokes access access. <command>initdb</command> therefore revokes access
permissions from everyone but the Postgres user account. permissions from everyone but the Postgres user account.
</para> </para>
<para>
One surprise you might encounter while running <command>initdb</command> is
a notice similar to this one:
<screen>
NOTICE: Initializing database with en_US collation order.
This locale setting will prevent use of index optimization for
LIKE and regexp searches. If you are concerned about speed of
such queries, you may wish to set LC_COLLATE to "C" and
re-initdb. For more information see the Administrator's Guide.
</screen>
This notice is intended to warn you that the currently selected locale
will cause indexes to be sorted in an order that prevents them from
being used for LIKE and regular-expression searches. If you need
good performance of such searches, you should set your current locale
to "C" and re-run <command>initdb</command>. On most systems, setting the
current locale is done by changing the value of the environment variable
<literal>LC_ALL</literal> or <literal>LANG</literal>. The sort order used
within a particular database cluster is set by <command>initdb</command>
and cannot be changed later, short of dumping all data, re-initdb,
reload data. So it's important to make this choice correctly now.
</para>
</sect1> </sect1>
<sect1 id="postmaster-start"> <sect1 id="postmaster-start">
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Header: /cvsroot/pgsql/src/backend/access/transam/xlog.c,v 1.33 2000/11/21 22:27:26 petere Exp $ * $Header: /cvsroot/pgsql/src/backend/access/transam/xlog.c,v 1.34 2000/11/25 20:33:50 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -20,6 +20,9 @@ ...@@ -20,6 +20,9 @@
#include <sys/time.h> #include <sys/time.h>
#include <sys/types.h> #include <sys/types.h>
#include <dirent.h> #include <dirent.h>
#ifdef USE_LOCALE
#include <locale.h>
#endif
#include "access/transam.h" #include "access/transam.h"
#include "access/xact.h" #include "access/xact.h"
...@@ -30,12 +33,11 @@ ...@@ -30,12 +33,11 @@
#include "storage/s_lock.h" #include "storage/s_lock.h"
#include "access/xlog.h" #include "access/xlog.h"
#include "access/xlogutils.h" #include "access/xlogutils.h"
#include "utils/builtins.h"
#include "utils/relcache.h" #include "utils/relcache.h"
#include "miscadmin.h" #include "miscadmin.h"
char XLogDir[MAXPGPATH];
char ControlFilePath[MAXPGPATH];
int XLOGbuffers = 8; int XLOGbuffers = 8;
XLogRecPtr MyLastRecPtr = {0, 0}; XLogRecPtr MyLastRecPtr = {0, 0};
bool StopIfError = false; bool StopIfError = false;
...@@ -50,6 +52,9 @@ SPINLOCK ControlFileLockId; ...@@ -50,6 +52,9 @@ SPINLOCK ControlFileLockId;
/* To generate new xid */ /* To generate new xid */
SPINLOCK XidGenLockId; SPINLOCK XidGenLockId;
static char XLogDir[MAXPGPATH];
static char ControlFilePath[MAXPGPATH];
#define MinXLOGbuffers 4 #define MinXLOGbuffers 4
typedef struct XLgwrRqst typedef struct XLgwrRqst
...@@ -107,6 +112,10 @@ typedef struct XLogCtlData ...@@ -107,6 +112,10 @@ typedef struct XLogCtlData
static XLogCtlData *XLogCtl = NULL; static XLogCtlData *XLogCtl = NULL;
/*
* Contents of pg_control
*/
typedef enum DBState typedef enum DBState
{ {
DB_STARTUP = 0, DB_STARTUP = 0,
...@@ -116,31 +125,39 @@ typedef enum DBState ...@@ -116,31 +125,39 @@ typedef enum DBState
DB_IN_PRODUCTION DB_IN_PRODUCTION
} DBState; } DBState;
#define LOCALE_NAME_BUFLEN 128
typedef struct ControlFileData typedef struct ControlFileData
{ {
/*
* XLOG state
*/
uint32 logId; /* current log file id */ uint32 logId; /* current log file id */
uint32 logSeg; /* current log file segment (1-based) */ uint32 logSeg; /* current log file segment (1-based) */
XLogRecPtr checkPoint; /* last check point record ptr */ XLogRecPtr checkPoint; /* last check point record ptr */
time_t time; /* time stamp of last modification */ time_t time; /* time stamp of last modification */
DBState state; /* */ DBState state; /* see enum above */
/* /*
* this data is used to make sure that configuration of this DB is * this data is used to make sure that configuration of this DB is
* compatible with the current backend * compatible with the backend executable
*/ */
uint32 blcksz; /* block size for this DB */ uint32 blcksz; /* block size for this DB */
uint32 relseg_size; /* blocks per segment of large relation */ uint32 relseg_size; /* blocks per segment of large relation */
uint32 catalog_version_no; /* internal version number */ uint32 catalog_version_no; /* internal version number */
char archdir[MAXPGPATH]; /* where to move offline log files */ /* active locales --- "C" if compiled without USE_LOCALE: */
char lc_collate[LOCALE_NAME_BUFLEN];
char lc_ctype[LOCALE_NAME_BUFLEN];
/* /*
* MORE DATA FOLLOWS AT THE END OF THIS STRUCTURE - locations of data * important directory locations
* dirs
*/ */
char archdir[MAXPGPATH]; /* where to move offline log files */
} ControlFileData; } ControlFileData;
static ControlFileData *ControlFile = NULL; static ControlFileData *ControlFile = NULL;
typedef struct CheckPoint typedef struct CheckPoint
{ {
XLogRecPtr redo; /* next RecPtr available when we */ XLogRecPtr redo; /* next RecPtr available when we */
...@@ -204,6 +221,8 @@ static void XLogWrite(char *buffer); ...@@ -204,6 +221,8 @@ static void XLogWrite(char *buffer);
static int XLogFileInit(uint32 log, uint32 seg, bool *usexistent); static int XLogFileInit(uint32 log, uint32 seg, bool *usexistent);
static int XLogFileOpen(uint32 log, uint32 seg, bool econt); static int XLogFileOpen(uint32 log, uint32 seg, bool econt);
static XLogRecord *ReadRecord(XLogRecPtr *RecPtr, char *buffer); static XLogRecord *ReadRecord(XLogRecPtr *RecPtr, char *buffer);
static void WriteControlFile(void);
static void ReadControlFile(void);
static char *str_time(time_t tnow); static char *str_time(time_t tnow);
static void xlog_outrec(char *buf, XLogRecord *record); static void xlog_outrec(char *buf, XLogRecord *record);
...@@ -1210,26 +1229,170 @@ next_record_is_invalid:; ...@@ -1210,26 +1229,170 @@ next_record_is_invalid:;
return (record); return (record);
} }
/*
* I/O routines for pg_control
*
* *ControlFile is a buffer in shared memory that holds an image of the
* contents of pg_control. WriteControlFile() initializes pg_control
* given a preloaded buffer, ReadControlFile() loads the buffer from
* the pg_control file (during postmaster or standalone-backend startup),
* and UpdateControlFile() rewrites pg_control after we modify xlog state.
*
* For simplicity, WriteControlFile() initializes the fields of pg_control
* that are related to checking backend/database compatibility, and
* ReadControlFile() verifies they are correct. We could split out the
* I/O and compatibility-check functions, but there seems no need currently.
*/
void
XLOGPathInit(void)
{
/* Init XLOG file paths */
snprintf(XLogDir, MAXPGPATH, "%s/pg_xlog", DataDir);
snprintf(ControlFilePath, MAXPGPATH, "%s/global/pg_control", DataDir);
}
static void
WriteControlFile(void)
{
int fd;
char buffer[BLCKSZ];
#ifdef USE_LOCALE
char *localeptr;
#endif
/*
* Initialize compatibility-check fields
*/
ControlFile->blcksz = BLCKSZ;
ControlFile->relseg_size = RELSEG_SIZE;
ControlFile->catalog_version_no = CATALOG_VERSION_NO;
#ifdef USE_LOCALE
localeptr = setlocale(LC_COLLATE, NULL);
if (!localeptr)
elog(STOP, "Invalid LC_COLLATE setting");
StrNCpy(ControlFile->lc_collate, localeptr, LOCALE_NAME_BUFLEN);
localeptr = setlocale(LC_CTYPE, NULL);
if (!localeptr)
elog(STOP, "Invalid LC_CTYPE setting");
StrNCpy(ControlFile->lc_ctype, localeptr, LOCALE_NAME_BUFLEN);
/*
* Issue warning notice if initdb'ing in a locale that will not permit
* LIKE index optimization. This is not a clean place to do it, but
* I don't see a better place either...
*/
if (!locale_is_like_safe())
elog(NOTICE, "Initializing database with %s collation order."
"\n\tThis locale setting will prevent use of index optimization for"
"\n\tLIKE and regexp searches. If you are concerned about speed of"
"\n\tsuch queries, you may wish to set LC_COLLATE to \"C\" and"
"\n\tre-initdb. For more information see the Administrator's Guide.",
ControlFile->lc_collate);
#else
strcpy(ControlFile->lc_collate, "C");
strcpy(ControlFile->lc_ctype, "C");
#endif
/*
* We write out BLCKSZ bytes into pg_control, zero-padding the
* excess over sizeof(ControlFileData). This reduces the odds
* of premature-EOF errors when reading pg_control. We'll still
* fail when we check the contents of the file, but hopefully with
* a more specific error than "couldn't read pg_control".
*/
if (sizeof(ControlFileData) > BLCKSZ)
elog(STOP, "sizeof(ControlFileData) is too large ... fix xlog.c");
memset(buffer, 0, BLCKSZ);
memcpy(buffer, ControlFile, sizeof(ControlFileData));
fd = BasicOpenFile(ControlFilePath, O_RDWR | O_CREAT | O_EXCL | PG_BINARY, S_IRUSR | S_IWUSR);
if (fd < 0)
elog(STOP, "WriteControlFile failed to create control file (%s): %m",
ControlFilePath);
if (write(fd, buffer, BLCKSZ) != BLCKSZ)
elog(STOP, "WriteControlFile failed to write control file: %m");
if (fsync(fd) != 0)
elog(STOP, "WriteControlFile failed to fsync control file: %m");
close(fd);
}
static void
ReadControlFile(void)
{
int fd;
/*
* Read data...
*/
fd = BasicOpenFile(ControlFilePath, O_RDWR | PG_BINARY, S_IRUSR | S_IWUSR);
if (fd < 0)
elog(STOP, "open(\"%s\") failed: %m", ControlFilePath);
if (read(fd, ControlFile, sizeof(ControlFileData)) != sizeof(ControlFileData))
elog(STOP, "read(\"%s\") failed: %m", ControlFilePath);
close(fd);
/*
* Do compatibility checking immediately. We do this here for 2 reasons:
*
* (1) if the database isn't compatible with the backend executable,
* we want to abort before we can possibly do any damage;
*
* (2) this code is executed in the postmaster, so the setlocale() will
* propagate to forked backends, which aren't going to read this file
* for themselves. (These locale settings are considered critical
* compatibility items because they can affect sort order of indexes.)
*/
if (ControlFile->blcksz != BLCKSZ)
elog(STOP, "database was initialized with BLCKSZ %d,\n\tbut the backend was compiled with BLCKSZ %d.\n\tlooks like you need to initdb.",
ControlFile->blcksz, BLCKSZ);
if (ControlFile->relseg_size != RELSEG_SIZE)
elog(STOP, "database was initialized with RELSEG_SIZE %d,\n\tbut the backend was compiled with RELSEG_SIZE %d.\n\tlooks like you need to initdb.",
ControlFile->relseg_size, RELSEG_SIZE);
if (ControlFile->catalog_version_no != CATALOG_VERSION_NO)
elog(STOP, "database was initialized with CATALOG_VERSION_NO %d,\n\tbut the backend was compiled with CATALOG_VERSION_NO %d.\n\tlooks like you need to initdb.",
ControlFile->catalog_version_no, CATALOG_VERSION_NO);
#ifdef USE_LOCALE
if (setlocale(LC_COLLATE, ControlFile->lc_collate) == NULL)
elog(STOP, "database was initialized with LC_COLLATE '%s',\n\twhich is not recognized by setlocale().\n\tlooks like you need to initdb.",
ControlFile->lc_collate);
if (setlocale(LC_CTYPE, ControlFile->lc_ctype) == NULL)
elog(STOP, "database was initialized with LC_CTYPE '%s',\n\twhich is not recognized by setlocale().\n\tlooks like you need to initdb.",
ControlFile->lc_ctype);
#else
if (strcmp(ControlFile->lc_collate, "C") != 0 ||
strcmp(ControlFile->lc_ctype, "C") != 0)
elog(STOP, "database was initialized with LC_COLLATE '%s' and LC_CTYPE '%s',\n\tbut the backend was compiled without locale support.\n\tlooks like you need to initdb or recompile.",
ControlFile->lc_collate, ControlFile->lc_ctype);
#endif
}
void void
UpdateControlFile() UpdateControlFile(void)
{ {
int fd; int fd;
fd = BasicOpenFile(ControlFilePath, O_RDWR | PG_BINARY, S_IRUSR | S_IWUSR); fd = BasicOpenFile(ControlFilePath, O_RDWR | PG_BINARY, S_IRUSR | S_IWUSR);
if (fd < 0) if (fd < 0)
elog(STOP, "open(cntlfile) failed: %m"); elog(STOP, "open(\"%s\") failed: %m", ControlFilePath);
if (write(fd, ControlFile, BLCKSZ) != BLCKSZ) if (write(fd, ControlFile, sizeof(ControlFileData)) != sizeof(ControlFileData))
elog(STOP, "write(cntlfile) failed: %m"); elog(STOP, "write(cntlfile) failed: %m");
if (fsync(fd) != 0) if (fsync(fd) != 0)
elog(STOP, "fsync(cntlfile) failed: %m"); elog(STOP, "fsync(cntlfile) failed: %m");
close(fd); close(fd);
return;
} }
/*
* Management of shared memory for XLOG
*/
int int
XLOGShmemSize(void) XLOGShmemSize(void)
{ {
...@@ -1237,7 +1400,8 @@ XLOGShmemSize(void) ...@@ -1237,7 +1400,8 @@ XLOGShmemSize(void)
XLOGbuffers = MinXLOGbuffers; XLOGbuffers = MinXLOGbuffers;
return (sizeof(XLogCtlData) + BLCKSZ * XLOGbuffers + return (sizeof(XLogCtlData) + BLCKSZ * XLOGbuffers +
sizeof(XLogRecPtr) * XLOGbuffers + BLCKSZ); sizeof(XLogRecPtr) * XLOGbuffers +
sizeof(ControlFileData));
} }
void void
...@@ -1245,16 +1409,25 @@ XLOGShmemInit(void) ...@@ -1245,16 +1409,25 @@ XLOGShmemInit(void)
{ {
bool found; bool found;
/* this must agree with space requested by XLOGShmemSize() */
if (XLOGbuffers < MinXLOGbuffers) if (XLOGbuffers < MinXLOGbuffers)
XLOGbuffers = MinXLOGbuffers; XLOGbuffers = MinXLOGbuffers;
ControlFile = (ControlFileData *)
ShmemInitStruct("Control File", BLCKSZ, &found);
Assert(!found);
XLogCtl = (XLogCtlData *) XLogCtl = (XLogCtlData *)
ShmemInitStruct("XLOG Ctl", sizeof(XLogCtlData) + BLCKSZ * XLOGbuffers + ShmemInitStruct("XLOG Ctl", sizeof(XLogCtlData) + BLCKSZ * XLOGbuffers +
sizeof(XLogRecPtr) * XLOGbuffers, &found); sizeof(XLogRecPtr) * XLOGbuffers, &found);
Assert(!found); Assert(!found);
ControlFile = (ControlFileData *)
ShmemInitStruct("Control File", sizeof(ControlFileData), &found);
Assert(!found);
/*
* If we are not in bootstrap mode, pg_control should already exist.
* Read and validate it immediately (see comments in ReadControlFile()
* for the reasons why).
*/
if (!IsBootstrapProcessingMode())
ReadControlFile();
} }
/* /*
...@@ -1263,22 +1436,14 @@ XLOGShmemInit(void) ...@@ -1263,22 +1436,14 @@ XLOGShmemInit(void)
void void
BootStrapXLOG() BootStrapXLOG()
{ {
int fd;
char buffer[BLCKSZ];
CheckPoint checkPoint; CheckPoint checkPoint;
#ifdef XLOG #ifdef XLOG
char buffer[BLCKSZ];
bool usexistent = false; bool usexistent = false;
XLogPageHeader page = (XLogPageHeader) buffer; XLogPageHeader page = (XLogPageHeader) buffer;
XLogRecord *record; XLogRecord *record;
#endif #endif
fd = BasicOpenFile(ControlFilePath, O_RDWR | O_CREAT | O_EXCL | PG_BINARY, S_IRUSR | S_IWUSR);
if (fd < 0)
elog(STOP, "BootStrapXLOG failed to create control file (%s): %m",
ControlFilePath);
checkPoint.redo.xlogid = 0; checkPoint.redo.xlogid = 0;
checkPoint.redo.xrecoff = SizeOfXLogPHD; checkPoint.redo.xrecoff = SizeOfXLogPHD;
checkPoint.undo = checkPoint.redo; checkPoint.undo = checkPoint.redo;
...@@ -1319,23 +1484,15 @@ BootStrapXLOG() ...@@ -1319,23 +1484,15 @@ BootStrapXLOG()
#endif #endif
memset(ControlFile, 0, BLCKSZ); memset(ControlFile, 0, sizeof(ControlFileData));
ControlFile->logId = 0; ControlFile->logId = 0;
ControlFile->logSeg = 1; ControlFile->logSeg = 1;
ControlFile->checkPoint = checkPoint.redo; ControlFile->checkPoint = checkPoint.redo;
ControlFile->time = time(NULL); ControlFile->time = time(NULL);
ControlFile->state = DB_SHUTDOWNED; ControlFile->state = DB_SHUTDOWNED;
ControlFile->blcksz = BLCKSZ; /* some additional ControlFile fields are set in WriteControlFile() */
ControlFile->relseg_size = RELSEG_SIZE;
ControlFile->catalog_version_no = CATALOG_VERSION_NO;
if (write(fd, ControlFile, BLCKSZ) != BLCKSZ) WriteControlFile();
elog(STOP, "BootStrapXLOG failed to write control file: %m");
if (fsync(fd) != 0)
elog(STOP, "BootStrapXLOG failed to fsync control file: %m");
close(fd);
} }
static char * static char *
...@@ -1367,7 +1524,6 @@ StartupXLOG() ...@@ -1367,7 +1524,6 @@ StartupXLOG()
bool sie_saved = false; bool sie_saved = false;
#endif #endif
int fd;
elog(LOG, "starting up"); elog(LOG, "starting up");
...@@ -1389,16 +1545,12 @@ StartupXLOG() ...@@ -1389,16 +1545,12 @@ StartupXLOG()
S_INIT_LOCK(&(XLogCtl->chkp_lck)); S_INIT_LOCK(&(XLogCtl->chkp_lck));
/* /*
* Open/read Control file * Read control file and check XLOG status looks valid.
*
* Note: in most control paths, *ControlFile is already valid and we
* need not do ReadControlFile() here, but might as well do it to be sure.
*/ */
fd = BasicOpenFile(ControlFilePath, O_RDWR | PG_BINARY, S_IRUSR | S_IWUSR); ReadControlFile();
if (fd < 0)
elog(STOP, "open(\"%s\") failed: %m", ControlFilePath);
if (read(fd, ControlFile, BLCKSZ) != BLCKSZ)
elog(STOP, "read(\"%s\") failed: %m", ControlFilePath);
close(fd);
if (ControlFile->logSeg == 0 || if (ControlFile->logSeg == 0 ||
ControlFile->time <= 0 || ControlFile->time <= 0 ||
...@@ -1407,17 +1559,6 @@ StartupXLOG() ...@@ -1407,17 +1559,6 @@ StartupXLOG()
!XRecOffIsValid(ControlFile->checkPoint.xrecoff)) !XRecOffIsValid(ControlFile->checkPoint.xrecoff))
elog(STOP, "control file context is broken"); elog(STOP, "control file context is broken");
/* Check for incompatible database */
if (ControlFile->blcksz != BLCKSZ)
elog(STOP, "database was initialized with BLCKSZ %d,\n\tbut the backend was compiled with BLCKSZ %d.\n\tlooks like you need to initdb.",
ControlFile->blcksz, BLCKSZ);
if (ControlFile->relseg_size != RELSEG_SIZE)
elog(STOP, "database was initialized with RELSEG_SIZE %d,\n\tbut the backend was compiled with RELSEG_SIZE %d.\n\tlooks like you need to initdb.",
ControlFile->relseg_size, RELSEG_SIZE);
if (ControlFile->catalog_version_no != CATALOG_VERSION_NO)
elog(STOP, "database was initialized with CATALOG_VERSION_NO %d,\n\tbut the backend was compiled with CATALOG_VERSION_NO %d.\n\tlooks like you need to initdb.",
ControlFile->catalog_version_no, CATALOG_VERSION_NO);
if (ControlFile->state == DB_SHUTDOWNED) if (ControlFile->state == DB_SHUTDOWNED)
elog(LOG, "database system was shut down at %s", elog(LOG, "database system was shut down at %s",
str_time(ControlFile->time)); str_time(ControlFile->time));
...@@ -1425,12 +1566,10 @@ StartupXLOG() ...@@ -1425,12 +1566,10 @@ StartupXLOG()
elog(LOG, "database system shutdown was interrupted at %s", elog(LOG, "database system shutdown was interrupted at %s",
str_time(ControlFile->time)); str_time(ControlFile->time));
else if (ControlFile->state == DB_IN_RECOVERY) else if (ControlFile->state == DB_IN_RECOVERY)
{
elog(LOG, "database system was interrupted being in recovery at %s\n" elog(LOG, "database system was interrupted being in recovery at %s\n"
"\tThis propably means that some data blocks are corrupted\n" "\tThis propably means that some data blocks are corrupted\n"
"\tand you will have to use last backup for recovery.", "\tand you will have to use last backup for recovery.",
str_time(ControlFile->time)); str_time(ControlFile->time));
}
else if (ControlFile->state == DB_IN_PRODUCTION) else if (ControlFile->state == DB_IN_PRODUCTION)
elog(LOG, "database system was interrupted at %s", elog(LOG, "database system was interrupted at %s",
str_time(ControlFile->time)); str_time(ControlFile->time));
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/bootstrap/bootstrap.c,v 1.100 2000/11/21 21:15:59 petere Exp $ * $Header: /cvsroot/pgsql/src/backend/bootstrap/bootstrap.c,v 1.101 2000/11/25 20:33:51 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -321,6 +321,8 @@ BootstrapMain(int argc, char *argv[]) ...@@ -321,6 +321,8 @@ BootstrapMain(int argc, char *argv[])
} }
} }
XLOGPathInit();
BaseInit(); BaseInit();
if (!IsUnderPostmaster) if (!IsUnderPostmaster)
...@@ -333,8 +335,6 @@ BootstrapMain(int argc, char *argv[]) ...@@ -333,8 +335,6 @@ BootstrapMain(int argc, char *argv[])
/* /*
* XLOG operations * XLOG operations
*/ */
snprintf(XLogDir, MAXPGPATH, "%s/pg_xlog", DataDir);
snprintf(ControlFilePath, MAXPGPATH, "%s/global/pg_control", DataDir);
SetProcessingMode(NormalProcessing); SetProcessingMode(NormalProcessing);
if (xlogop == BS_XLOG_NOP) if (xlogop == BS_XLOG_NOP)
StartupXLOG(); StartupXLOG();
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/indxpath.c,v 1.98 2000/11/16 22:30:24 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/optimizer/path/indxpath.c,v 1.99 2000/11/25 20:33:51 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -1746,56 +1746,68 @@ match_special_index_operator(Expr *clause, Oid opclass, Oid relam, ...@@ -1746,56 +1746,68 @@ match_special_index_operator(Expr *clause, Oid opclass, Oid relam,
case OID_BPCHAR_LIKE_OP: case OID_BPCHAR_LIKE_OP:
case OID_VARCHAR_LIKE_OP: case OID_VARCHAR_LIKE_OP:
case OID_NAME_LIKE_OP: case OID_NAME_LIKE_OP:
/* the right-hand const is type text for all of these */ if (locale_is_like_safe())
patt = DatumGetCString(DirectFunctionCall1(textout, {
constvalue)); /* the right-hand const is type text for all of these */
isIndexable = pattern_fixed_prefix(patt, Pattern_Type_Like, patt = DatumGetCString(DirectFunctionCall1(textout,
&prefix, &rest) != Pattern_Prefix_None; constvalue));
if (prefix) isIndexable = pattern_fixed_prefix(patt, Pattern_Type_Like,
pfree(prefix); &prefix, &rest) != Pattern_Prefix_None;
pfree(patt); if (prefix)
pfree(prefix);
pfree(patt);
}
break; break;
case OID_TEXT_ICLIKE_OP: case OID_TEXT_ICLIKE_OP:
case OID_BPCHAR_ICLIKE_OP: case OID_BPCHAR_ICLIKE_OP:
case OID_VARCHAR_ICLIKE_OP: case OID_VARCHAR_ICLIKE_OP:
case OID_NAME_ICLIKE_OP: case OID_NAME_ICLIKE_OP:
/* the right-hand const is type text for all of these */ if (locale_is_like_safe())
patt = DatumGetCString(DirectFunctionCall1(textout, {
constvalue)); /* the right-hand const is type text for all of these */
isIndexable = pattern_fixed_prefix(patt, Pattern_Type_Like_IC, patt = DatumGetCString(DirectFunctionCall1(textout,
&prefix, &rest) != Pattern_Prefix_None; constvalue));
if (prefix) isIndexable = pattern_fixed_prefix(patt, Pattern_Type_Like_IC,
pfree(prefix); &prefix, &rest) != Pattern_Prefix_None;
pfree(patt); if (prefix)
pfree(prefix);
pfree(patt);
}
break; break;
case OID_TEXT_REGEXEQ_OP: case OID_TEXT_REGEXEQ_OP:
case OID_BPCHAR_REGEXEQ_OP: case OID_BPCHAR_REGEXEQ_OP:
case OID_VARCHAR_REGEXEQ_OP: case OID_VARCHAR_REGEXEQ_OP:
case OID_NAME_REGEXEQ_OP: case OID_NAME_REGEXEQ_OP:
/* the right-hand const is type text for all of these */ if (locale_is_like_safe())
patt = DatumGetCString(DirectFunctionCall1(textout, {
constvalue)); /* the right-hand const is type text for all of these */
isIndexable = pattern_fixed_prefix(patt, Pattern_Type_Regex, patt = DatumGetCString(DirectFunctionCall1(textout,
&prefix, &rest) != Pattern_Prefix_None; constvalue));
if (prefix) isIndexable = pattern_fixed_prefix(patt, Pattern_Type_Regex,
pfree(prefix); &prefix, &rest) != Pattern_Prefix_None;
pfree(patt); if (prefix)
pfree(prefix);
pfree(patt);
}
break; break;
case OID_TEXT_ICREGEXEQ_OP: case OID_TEXT_ICREGEXEQ_OP:
case OID_BPCHAR_ICREGEXEQ_OP: case OID_BPCHAR_ICREGEXEQ_OP:
case OID_VARCHAR_ICREGEXEQ_OP: case OID_VARCHAR_ICREGEXEQ_OP:
case OID_NAME_ICREGEXEQ_OP: case OID_NAME_ICREGEXEQ_OP:
/* the right-hand const is type text for all of these */ if (locale_is_like_safe())
patt = DatumGetCString(DirectFunctionCall1(textout, {
constvalue)); /* the right-hand const is type text for all of these */
isIndexable = pattern_fixed_prefix(patt, Pattern_Type_Regex_IC, patt = DatumGetCString(DirectFunctionCall1(textout,
&prefix, &rest) != Pattern_Prefix_None; constvalue));
if (prefix) isIndexable = pattern_fixed_prefix(patt, Pattern_Type_Regex_IC,
pfree(prefix); &prefix, &rest) != Pattern_Prefix_None;
pfree(patt); if (prefix)
pfree(prefix);
pfree(patt);
}
break; break;
} }
...@@ -2053,8 +2065,8 @@ prefix_quals(Var *leftop, Oid expr_op, ...@@ -2053,8 +2065,8 @@ prefix_quals(Var *leftop, Oid expr_op,
result = makeList1(expr); result = makeList1(expr);
/* /*
* If we can create a string larger than the prefix, say "x < * If we can create a string larger than the prefix, we can say
* greaterstr". * "x < greaterstr".
*/ */
greaterstr = make_greater_string(prefix, datatype); greaterstr = make_greater_string(prefix, datatype);
if (greaterstr) if (greaterstr)
......
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/postmaster/postmaster.c,v 1.191 2000/11/25 19:05:42 petere Exp $ * $Header: /cvsroot/pgsql/src/backend/postmaster/postmaster.c,v 1.192 2000/11/25 20:33:52 tgl Exp $
* *
* NOTES * NOTES
* *
...@@ -617,13 +617,11 @@ PostmasterMain(int argc, char *argv[]) ...@@ -617,13 +617,11 @@ PostmasterMain(int argc, char *argv[])
} }
#endif #endif
XLOGPathInit();
/* set up shared memory and semaphores */ /* set up shared memory and semaphores */
reset_shared(PostPortNumber); reset_shared(PostPortNumber);
/* Init XLOG paths */
snprintf(XLogDir, MAXPGPATH, "%s/pg_xlog", DataDir);
snprintf(ControlFilePath, MAXPGPATH, "%s/global/pg_control", DataDir);
/* /*
* Initialize the list of active backends. This list is only used for * Initialize the list of active backends. This list is only used for
* garbage collecting the backend processes. * garbage collecting the backend processes.
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.190 2000/11/25 19:05:42 petere Exp $ * $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.191 2000/11/25 20:33:52 tgl Exp $
* *
* NOTES * NOTES
* this is the "main" module of the postgres backend and * this is the "main" module of the postgres backend and
...@@ -1525,9 +1525,8 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[], const cha ...@@ -1525,9 +1525,8 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[], const cha
*/ */
on_proc_exit(UnlinkPidFile, 0); on_proc_exit(UnlinkPidFile, 0);
XLOGPathInit();
BaseInit(); BaseInit();
snprintf(XLogDir, MAXPGPATH, "%s/pg_xlog", DataDir);
snprintf(ControlFilePath, MAXPGPATH, "%s/global/pg_control", DataDir);
StartupXLOG(); StartupXLOG();
} }
...@@ -1636,7 +1635,7 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[], const cha ...@@ -1636,7 +1635,7 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[], const cha
if (!IsUnderPostmaster) if (!IsUnderPostmaster)
{ {
puts("\nPOSTGRES backend interactive interface "); puts("\nPOSTGRES backend interactive interface ");
puts("$Revision: 1.190 $ $Date: 2000/11/25 19:05:42 $\n"); puts("$Revision: 1.191 $ $Date: 2000/11/25 20:33:52 $\n");
} }
/* /*
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
* workings can be found in the book "Software Solutions in C" by * workings can be found in the book "Software Solutions in C" by
* Dale Schumacher, Academic Press, ISBN: 0-12-632360-7. * Dale Schumacher, Academic Press, ISBN: 0-12-632360-7.
* *
* $Header: /cvsroot/pgsql/src/backend/utils/adt/cash.c,v 1.46 2000/11/18 03:55:51 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/utils/adt/cash.c,v 1.47 2000/11/25 20:33:52 tgl Exp $
*/ */
#include <limits.h> #include <limits.h>
...@@ -84,10 +84,6 @@ cash_in(PG_FUNCTION_ARGS) ...@@ -84,10 +84,6 @@ cash_in(PG_FUNCTION_ARGS)
*nsymbol; *nsymbol;
#ifdef USE_LOCALE #ifdef USE_LOCALE
#ifdef CASHDEBUG
setlocale(LC_ALL, "");
lconvert = localeconv();
#endif
if (lconvert == NULL) if (lconvert == NULL)
lconvert = localeconv(); lconvert = localeconv();
......
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/adt/selfuncs.c,v 1.82 2000/11/16 22:30:31 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/utils/adt/selfuncs.c,v 1.83 2000/11/25 20:33:53 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -24,6 +24,9 @@ ...@@ -24,6 +24,9 @@
#include <ctype.h> #include <ctype.h>
#include <math.h> #include <math.h>
#ifdef USE_LOCALE
#include <locale.h>
#endif
#include "access/heapam.h" #include "access/heapam.h"
#include "catalog/catname.h" #include "catalog/catname.h"
...@@ -1581,6 +1584,11 @@ pattern_fixed_prefix(char *patt, Pattern_Type ptype, ...@@ -1581,6 +1584,11 @@ pattern_fixed_prefix(char *patt, Pattern_Type ptype,
* *
* A fixed prefix "foo" is estimated as the selectivity of the expression * A fixed prefix "foo" is estimated as the selectivity of the expression
* "var >= 'foo' AND var < 'fop'" (see also indxqual.c). * "var >= 'foo' AND var < 'fop'" (see also indxqual.c).
*
* XXX Note: we make use of the upper bound to estimate operator selectivity
* even if the locale is such that we cannot rely on the upper-bound string.
* The selectivity only needs to be approximately right anyway, so it seems
* more useful to use the upper-bound code than not.
*/ */
static Selectivity static Selectivity
prefix_selectivity(char *prefix, prefix_selectivity(char *prefix,
...@@ -1862,6 +1870,44 @@ pattern_selectivity(char *patt, Pattern_Type ptype) ...@@ -1862,6 +1870,44 @@ pattern_selectivity(char *patt, Pattern_Type ptype)
return result; return result;
} }
/*
* Test whether the database's LOCALE setting is safe for LIKE/regexp index
* optimization. The key requirement here is that given a prefix string,
* say "foo", we must be able to generate another string "fop" that is
* greater than all strings "foobar" starting with "foo". Unfortunately,
* many non-C locales have bizarre collation rules in which "fop" > "foo"
* is not sufficient to ensure "fop" > "foobar". Until we can come up
* with a more bulletproof way of generating the upper-bound string,
* disable the optimization in locales where it is not known to be safe.
*/
bool
locale_is_like_safe(void)
{
#ifdef USE_LOCALE
/* Cache result so we only have to compute it once */
static int result = -1;
char *localeptr;
if (result >= 0)
return (bool) result;
localeptr = setlocale(LC_COLLATE, NULL);
if (!localeptr)
elog(STOP, "Invalid LC_COLLATE setting");
/*
* Currently we accept only "C" and "POSIX" (do any systems still
* return "POSIX"?). Which other locales allow safe optimization?
*/
if (strcmp(localeptr, "C") == 0)
result = true;
else if (strcmp(localeptr, "POSIX") == 0)
result = true;
else
result = false;
return (bool) result;
#else /* not USE_LOCALE */
return true; /* We must be in C locale, which is OK */
#endif /* USE_LOCALE */
}
/* /*
* Try to generate a string greater than the given string or any string it is * Try to generate a string greater than the given string or any string it is
...@@ -1878,9 +1924,12 @@ pattern_selectivity(char *patt, Pattern_Type ptype) ...@@ -1878,9 +1924,12 @@ pattern_selectivity(char *patt, Pattern_Type ptype)
* This could be rather slow in the worst case, but in most cases we won't * This could be rather slow in the worst case, but in most cases we won't
* have to try more than one or two strings before succeeding. * have to try more than one or two strings before succeeding.
* *
* XXX in a sufficiently weird locale, this might produce incorrect results? * XXX this is actually not sufficient, since it only copes with the case
* For example, in German I believe "ss" is treated specially --- if we are * where individual characters collate in an order different from their
* given "foos" and return "foot", will this actually be greater than "fooss"? * numeric code assignments. It does not handle cases where there are
* cross-character effects, such as specially sorted digraphs, multiple
* sort passes, etc. For now, we just shut down the whole thing in locales
* that do such things :-(
*/ */
char * char *
make_greater_string(const char *str, Oid datatype) make_greater_string(const char *str, Oid datatype)
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
* *
* PostgreSQL transaction log manager * PostgreSQL transaction log manager
* *
* $Header: /cvsroot/pgsql/src/include/access/xlog.h,v 1.10 2000/11/21 21:16:05 petere Exp $ * $Header: /cvsroot/pgsql/src/include/access/xlog.h,v 1.11 2000/11/25 20:33:53 tgl Exp $
*/ */
#ifndef XLOG_H #ifndef XLOG_H
#define XLOG_H #define XLOG_H
...@@ -107,13 +107,11 @@ extern void xlog_desc(char *buf, uint8 xl_info, char* rec); ...@@ -107,13 +107,11 @@ extern void xlog_desc(char *buf, uint8 xl_info, char* rec);
extern void UpdateControlFile(void); extern void UpdateControlFile(void);
extern int XLOGShmemSize(void); extern int XLOGShmemSize(void);
extern void XLOGShmemInit(void); extern void XLOGShmemInit(void);
extern void XLOGPathInit(void);
extern void BootStrapXLOG(void); extern void BootStrapXLOG(void);
extern void StartupXLOG(void); extern void StartupXLOG(void);
extern void ShutdownXLOG(void); extern void ShutdownXLOG(void);
extern void CreateCheckPoint(bool shutdown); extern void CreateCheckPoint(bool shutdown);
extern void SetThisStartUpID(void); extern void SetThisStartUpID(void);
extern char XLogDir[];
extern char ControlFilePath[];
#endif /* XLOG_H */ #endif /* XLOG_H */
...@@ -37,7 +37,7 @@ ...@@ -37,7 +37,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: catversion.h,v 1.63 2000/11/21 03:23:19 tgl Exp $ * $Id: catversion.h,v 1.64 2000/11/25 20:33:53 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -53,6 +53,6 @@ ...@@ -53,6 +53,6 @@
*/ */
/* yyyymmddN */ /* yyyymmddN */
#define CATALOG_VERSION_NO 200011211 #define CATALOG_VERSION_NO 200011251
#endif #endif
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: builtins.h,v 1.142 2000/11/21 03:23:20 tgl Exp $ * $Id: builtins.h,v 1.143 2000/11/25 20:33:54 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -376,6 +376,7 @@ extern Pattern_Prefix_Status pattern_fixed_prefix(char *patt, ...@@ -376,6 +376,7 @@ extern Pattern_Prefix_Status pattern_fixed_prefix(char *patt,
Pattern_Type ptype, Pattern_Type ptype,
char **prefix, char **prefix,
char **rest); char **rest);
extern bool locale_is_like_safe(void);
extern char *make_greater_string(const char *str, Oid datatype); extern char *make_greater_string(const char *str, Oid datatype);
/* tid.c */ /* tid.c */
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment