2000-02-15 21:49:31 +01:00
|
|
|
/*-------------------------------------------------------------------------
|
|
|
|
*
|
|
|
|
* variable.c
|
2002-05-17 03:19:19 +02:00
|
|
|
* Routines for handling specialized SET variables.
|
|
|
|
*
|
2000-02-15 21:49:31 +01:00
|
|
|
*
|
2002-06-20 22:29:54 +02:00
|
|
|
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
2000-02-15 21:49:31 +01:00
|
|
|
* Portions Copyright (c) 1994, Regents of the University of California
|
|
|
|
*
|
1997-04-17 15:50:57 +02:00
|
|
|
*
|
2000-02-15 21:49:31 +01:00
|
|
|
* IDENTIFICATION
|
I have committed many support files for CREATE CONVERSION. Default
conversion procs and conversions are added in initdb. Currently
supported conversions are:
UTF-8(UNICODE) <--> SQL_ASCII, ISO-8859-1 to 16, EUC_JP, EUC_KR,
EUC_CN, EUC_TW, SJIS, BIG5, GBK, GB18030, UHC,
JOHAB, TCVN
EUC_JP <--> SJIS
EUC_TW <--> BIG5
MULE_INTERNAL <--> EUC_JP, SJIS, EUC_TW, BIG5
Note that initial contents of pg_conversion system catalog are created
in the initdb process. So doing initdb required is ideal, it's
possible to add them to your databases by hand, however. To accomplish
this:
psql -f your_postgresql_install_path/share/conversion_create.sql your_database
So I did not bump up the version in cataversion.h.
TODO:
Add more conversion procs
Add [CASCADE|RESTRICT] to DROP CONVERSION
Add tuples to pg_depend
Add regression tests
Write docs
Add SQL99 CONVERT command?
--
Tatsuo Ishii
2002-07-18 04:02:30 +02:00
|
|
|
* $Header: /cvsroot/pgsql/src/backend/commands/variable.c,v 1.70 2002/07/18 02:02:29 ishii Exp $
|
1997-04-17 15:50:57 +02:00
|
|
|
*
|
2000-02-15 21:49:31 +01:00
|
|
|
*-------------------------------------------------------------------------
|
1997-04-17 15:50:57 +02:00
|
|
|
*/
|
|
|
|
|
2000-10-25 21:44:44 +02:00
|
|
|
#include "postgres.h"
|
|
|
|
|
1997-06-20 19:17:03 +02:00
|
|
|
#include <ctype.h>
|
1997-11-21 19:12:58 +01:00
|
|
|
#include <time.h>
|
1999-07-16 07:00:38 +02:00
|
|
|
|
|
|
|
#include "access/xact.h"
|
1999-09-27 22:27:32 +02:00
|
|
|
#include "catalog/pg_shadow.h"
|
1998-01-05 19:43:18 +01:00
|
|
|
#include "commands/variable.h"
|
1999-07-16 07:00:38 +02:00
|
|
|
#include "miscadmin.h"
|
|
|
|
#include "utils/builtins.h"
|
2000-05-31 02:28:42 +02:00
|
|
|
#include "utils/guc.h"
|
2002-05-17 03:19:19 +02:00
|
|
|
#include "utils/syscache.h"
|
1999-06-17 17:16:09 +02:00
|
|
|
#include "utils/tqual.h"
|
1998-07-26 06:31:41 +02:00
|
|
|
#include "mb/pg_wchar.h"
|
2000-02-15 21:49:31 +01:00
|
|
|
|
1998-10-14 07:10:12 +02:00
|
|
|
/*
|
2002-05-17 03:19:19 +02:00
|
|
|
* DATESTYLE
|
1998-10-14 07:10:12 +02:00
|
|
|
*/
|
1997-04-24 17:41:37 +02:00
|
|
|
|
1998-10-14 07:10:12 +02:00
|
|
|
/*
|
2002-05-17 03:19:19 +02:00
|
|
|
* assign_datestyle: GUC assign_hook for datestyle
|
1998-10-14 07:10:12 +02:00
|
|
|
*/
|
2002-05-17 03:19:19 +02:00
|
|
|
const char *
|
|
|
|
assign_datestyle(const char *value, bool doit, bool interactive)
|
1997-06-02 13:00:57 +02:00
|
|
|
{
|
2002-05-17 03:19:19 +02:00
|
|
|
int newDateStyle = DateStyle;
|
|
|
|
bool newEuroDates = EuroDates;
|
|
|
|
bool ok = true;
|
1997-09-08 04:41:22 +02:00
|
|
|
int dcnt = 0,
|
|
|
|
ecnt = 0;
|
2002-05-17 03:19:19 +02:00
|
|
|
char *rawstring;
|
|
|
|
char *result;
|
|
|
|
List *elemlist;
|
|
|
|
List *l;
|
1997-06-20 19:17:03 +02:00
|
|
|
|
2002-05-17 03:19:19 +02:00
|
|
|
/* Need a modifiable copy of string */
|
|
|
|
rawstring = pstrdup(value);
|
1997-11-07 07:43:16 +01:00
|
|
|
|
2002-05-17 03:19:19 +02:00
|
|
|
/* Parse string into list of identifiers */
|
|
|
|
if (!SplitIdentifierString(rawstring, ',', &elemlist))
|
1997-06-02 13:00:57 +02:00
|
|
|
{
|
2002-05-17 03:19:19 +02:00
|
|
|
/* syntax error in list */
|
|
|
|
pfree(rawstring);
|
|
|
|
freeList(elemlist);
|
|
|
|
if (interactive)
|
|
|
|
elog(ERROR, "SET DATESTYLE: invalid list syntax");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
foreach(l, elemlist)
|
|
|
|
{
|
|
|
|
char *tok = (char *) lfirst(l);
|
|
|
|
|
1997-04-17 15:50:57 +02:00
|
|
|
/* Ugh. Somebody ought to write a table driven version -- mjl */
|
1997-06-20 19:17:03 +02:00
|
|
|
|
2002-05-17 03:19:19 +02:00
|
|
|
if (strcasecmp(tok, "ISO") == 0)
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
2002-05-17 03:19:19 +02:00
|
|
|
newDateStyle = USE_ISO_DATES;
|
1997-04-17 15:50:57 +02:00
|
|
|
dcnt++;
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
2002-05-17 03:19:19 +02:00
|
|
|
else if (strcasecmp(tok, "SQL") == 0)
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
2002-05-17 03:19:19 +02:00
|
|
|
newDateStyle = USE_SQL_DATES;
|
1997-04-17 15:50:57 +02:00
|
|
|
dcnt++;
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
2002-05-17 03:19:19 +02:00
|
|
|
else if (strncasecmp(tok, "POSTGRESQL", 8) == 0)
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
2002-05-17 03:19:19 +02:00
|
|
|
newDateStyle = USE_POSTGRES_DATES;
|
1997-04-17 15:50:57 +02:00
|
|
|
dcnt++;
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
2002-05-17 03:19:19 +02:00
|
|
|
else if (strcasecmp(tok, "GERMAN") == 0)
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
2002-05-17 03:19:19 +02:00
|
|
|
newDateStyle = USE_GERMAN_DATES;
|
1997-12-05 00:17:13 +01:00
|
|
|
dcnt++;
|
2002-05-17 03:19:19 +02:00
|
|
|
if ((ecnt > 0) && (!newEuroDates))
|
|
|
|
ok = false;
|
|
|
|
newEuroDates = TRUE;
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
2002-05-17 03:19:19 +02:00
|
|
|
else if (strncasecmp(tok, "EURO", 4) == 0)
|
1997-12-05 00:17:13 +01:00
|
|
|
{
|
2002-05-17 03:19:19 +02:00
|
|
|
newEuroDates = TRUE;
|
|
|
|
ecnt++;
|
1997-12-05 00:17:13 +01:00
|
|
|
}
|
2002-05-17 03:19:19 +02:00
|
|
|
else if (strcasecmp(tok, "US") == 0
|
|
|
|
|| strncasecmp(tok, "NONEURO", 7) == 0)
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
2002-05-17 03:19:19 +02:00
|
|
|
newEuroDates = FALSE;
|
|
|
|
ecnt++;
|
|
|
|
if ((dcnt > 0) && (newDateStyle == USE_GERMAN_DATES))
|
|
|
|
ok = false;
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
2002-05-17 03:19:19 +02:00
|
|
|
else if (strcasecmp(tok, "DEFAULT") == 0)
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
2002-05-17 03:19:19 +02:00
|
|
|
/*
|
|
|
|
* Easiest way to get the current DEFAULT state is to fetch
|
|
|
|
* the DEFAULT string from guc.c and recursively parse it.
|
|
|
|
*
|
|
|
|
* We can't simply "return assign_datestyle(...)" because we
|
|
|
|
* need to handle constructs like "DEFAULT, ISO".
|
|
|
|
*/
|
|
|
|
int saveDateStyle = DateStyle;
|
|
|
|
bool saveEuroDates = EuroDates;
|
|
|
|
const char *subval;
|
|
|
|
|
|
|
|
subval = assign_datestyle(GetConfigOptionResetString("datestyle"),
|
|
|
|
true, interactive);
|
|
|
|
newDateStyle = DateStyle;
|
|
|
|
newEuroDates = EuroDates;
|
|
|
|
DateStyle = saveDateStyle;
|
|
|
|
EuroDates = saveEuroDates;
|
|
|
|
if (!subval)
|
|
|
|
{
|
|
|
|
ok = false;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
/* Here we know that our own return value is always malloc'd */
|
|
|
|
/* when doit is true */
|
|
|
|
free((char *) subval);
|
|
|
|
dcnt++;
|
1997-04-17 15:50:57 +02:00
|
|
|
ecnt++;
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
1997-04-17 15:50:57 +02:00
|
|
|
else
|
2002-05-17 03:19:19 +02:00
|
|
|
{
|
|
|
|
if (interactive)
|
|
|
|
elog(ERROR, "SET DATESTYLE: unrecognized keyword %s", tok);
|
|
|
|
ok = false;
|
|
|
|
break;
|
|
|
|
}
|
1997-06-02 13:00:57 +02:00
|
|
|
}
|
1997-06-20 19:17:03 +02:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
if (dcnt > 1 || ecnt > 1)
|
2002-05-17 03:19:19 +02:00
|
|
|
ok = false;
|
2001-10-18 19:30:21 +02:00
|
|
|
|
2002-05-17 03:19:19 +02:00
|
|
|
pfree(rawstring);
|
|
|
|
freeList(elemlist);
|
2001-10-18 19:30:21 +02:00
|
|
|
|
2002-05-17 03:19:19 +02:00
|
|
|
if (!ok)
|
2002-04-21 21:12:46 +02:00
|
|
|
{
|
2002-05-17 03:19:19 +02:00
|
|
|
if (interactive)
|
|
|
|
elog(ERROR, "SET DATESTYLE: conflicting specifications");
|
|
|
|
return NULL;
|
|
|
|
}
|
2002-04-21 21:12:46 +02:00
|
|
|
|
2002-05-17 03:19:19 +02:00
|
|
|
/*
|
|
|
|
* If we aren't going to do the assignment, just return OK indicator.
|
|
|
|
*/
|
|
|
|
if (!doit)
|
|
|
|
return value;
|
2002-04-21 21:12:46 +02:00
|
|
|
|
2002-05-17 03:19:19 +02:00
|
|
|
/*
|
|
|
|
* Prepare the canonical string to return. GUC wants it malloc'd.
|
|
|
|
*/
|
|
|
|
result = (char *) malloc(32);
|
|
|
|
if (!result)
|
|
|
|
return NULL;
|
2002-04-21 21:12:46 +02:00
|
|
|
|
2002-05-17 03:19:19 +02:00
|
|
|
switch (newDateStyle)
|
|
|
|
{
|
|
|
|
case USE_ISO_DATES:
|
|
|
|
strcpy(result, "ISO");
|
|
|
|
break;
|
|
|
|
case USE_SQL_DATES:
|
|
|
|
strcpy(result, "SQL");
|
|
|
|
break;
|
|
|
|
case USE_GERMAN_DATES:
|
|
|
|
strcpy(result, "GERMAN");
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
strcpy(result, "POSTGRESQL");
|
|
|
|
break;
|
2002-04-21 21:12:46 +02:00
|
|
|
}
|
2002-05-17 03:19:19 +02:00
|
|
|
strcat(result, newEuroDates ? ", EURO" : ", US");
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Finally, it's safe to assign to the global variables;
|
|
|
|
* the assignment cannot fail now.
|
|
|
|
*/
|
|
|
|
DateStyle = newDateStyle;
|
|
|
|
EuroDates = newEuroDates;
|
2001-10-18 19:30:21 +02:00
|
|
|
|
2002-05-17 03:19:19 +02:00
|
|
|
return result;
|
2001-10-18 19:30:21 +02:00
|
|
|
}
|
|
|
|
|
2002-05-17 03:19:19 +02:00
|
|
|
/*
|
|
|
|
* show_datestyle: GUC show_hook for datestyle
|
|
|
|
*/
|
|
|
|
const char *
|
2001-06-07 06:50:57 +02:00
|
|
|
show_datestyle(void)
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
2002-05-17 03:19:19 +02:00
|
|
|
static char buf[64];
|
To: Thomas Lockhart <Thomas.G.Lockhart@jpl.nasa.gov>
Subject: Re: [PATCHES] SET DateStyle patches
On Tue, 22 Apr 1997, Thomas Lockhart wrote:
> Some more patches! These (try to) finish implementing SET variable TO value
> for "DateStyle" (changed the name from simply "date" to be more descriptive).
> This is based on code from Martin and Bruce (?), which was easy to modify.
> The syntax is
>
> SET DateStyle TO 'iso'
> SET DateStyle TO 'postgres'
> SET DateStyle TO 'sql'
> SET DateStyle TO 'european'
> SET DateStyle TO 'noneuropean'
> SET DateStyle TO 'us' (same as "noneuropean")
> SET DateStyle TO 'default' (current same as "postgres,us")
>
> ("european" is just compared for the first 4 characters, and "noneuropean"
> is compared for the first 7 to allow less typing).
>
> Multiple arguments are allowed, so SET datestyle TO 'sql,euro' is valid.
>
> My mods also try to implement "SHOW variable" and "RESET variable", but
> that part just core dumps at the moment. I would guess that my errors
> are obvious to someone who knows what they are doing with the parser stuff,
> so if someone (Bruce and/or Martin??) could have it do the right thing
> we will have a more complete set of what we need.
>
> Also, I would like to have a floating point precision global variable to
> implement "SET precision TO 10" and perhaps "SET precision TO 10,2" for
> float8 and float4, but I don't know how to do that for integer types rather
> than strings. If someone is fixing the SHOW and RESET code, perhaps they can
> add some hooks for me to do the floats while they are at it.
>
> I've left some remnants of variable structures in the source code which
> I did not use in the interests of getting something working for v6.1.
> We'll have time to clean things up for the next release...
1997-04-23 05:18:27 +02:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
switch (DateStyle)
|
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
case USE_ISO_DATES:
|
2002-05-17 03:19:19 +02:00
|
|
|
strcpy(buf, "ISO");
|
1997-09-08 04:41:22 +02:00
|
|
|
break;
|
|
|
|
case USE_SQL_DATES:
|
2002-05-17 03:19:19 +02:00
|
|
|
strcpy(buf, "SQL");
|
1997-09-08 04:41:22 +02:00
|
|
|
break;
|
1997-12-05 00:17:13 +01:00
|
|
|
case USE_GERMAN_DATES:
|
2002-05-17 03:19:19 +02:00
|
|
|
strcpy(buf, "German");
|
1997-12-05 00:17:13 +01:00
|
|
|
break;
|
1997-09-08 04:41:22 +02:00
|
|
|
default:
|
2002-05-17 03:19:19 +02:00
|
|
|
strcpy(buf, "Postgres");
|
1997-09-08 04:41:22 +02:00
|
|
|
break;
|
1997-05-16 09:24:13 +02:00
|
|
|
};
|
1997-09-07 07:04:48 +02:00
|
|
|
strcat(buf, " with ");
|
|
|
|
strcat(buf, ((EuroDates) ? "European" : "US (NonEuropean)"));
|
|
|
|
strcat(buf, " conventions");
|
To: Thomas Lockhart <Thomas.G.Lockhart@jpl.nasa.gov>
Subject: Re: [PATCHES] SET DateStyle patches
On Tue, 22 Apr 1997, Thomas Lockhart wrote:
> Some more patches! These (try to) finish implementing SET variable TO value
> for "DateStyle" (changed the name from simply "date" to be more descriptive).
> This is based on code from Martin and Bruce (?), which was easy to modify.
> The syntax is
>
> SET DateStyle TO 'iso'
> SET DateStyle TO 'postgres'
> SET DateStyle TO 'sql'
> SET DateStyle TO 'european'
> SET DateStyle TO 'noneuropean'
> SET DateStyle TO 'us' (same as "noneuropean")
> SET DateStyle TO 'default' (current same as "postgres,us")
>
> ("european" is just compared for the first 4 characters, and "noneuropean"
> is compared for the first 7 to allow less typing).
>
> Multiple arguments are allowed, so SET datestyle TO 'sql,euro' is valid.
>
> My mods also try to implement "SHOW variable" and "RESET variable", but
> that part just core dumps at the moment. I would guess that my errors
> are obvious to someone who knows what they are doing with the parser stuff,
> so if someone (Bruce and/or Martin??) could have it do the right thing
> we will have a more complete set of what we need.
>
> Also, I would like to have a floating point precision global variable to
> implement "SET precision TO 10" and perhaps "SET precision TO 10,2" for
> float8 and float4, but I don't know how to do that for integer types rather
> than strings. If someone is fixing the SHOW and RESET code, perhaps they can
> add some hooks for me to do the floats while they are at it.
>
> I've left some remnants of variable structures in the source code which
> I did not use in the interests of getting something working for v6.1.
> We'll have time to clean things up for the next release...
1997-04-23 05:18:27 +02:00
|
|
|
|
2002-05-17 03:19:19 +02:00
|
|
|
return buf;
|
2000-02-19 23:10:47 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-05-17 03:19:19 +02:00
|
|
|
/*
|
|
|
|
* TIMEZONE
|
1997-11-10 16:24:56 +01:00
|
|
|
*/
|
|
|
|
|
2002-05-17 03:19:19 +02:00
|
|
|
/*
|
|
|
|
* Storage for TZ env var is allocated with an arbitrary size of 64 bytes.
|
|
|
|
*/
|
1997-11-10 16:24:56 +01:00
|
|
|
static char tzbuf[64];
|
1997-11-07 07:43:16 +01:00
|
|
|
|
1998-10-14 07:10:12 +02:00
|
|
|
/*
|
2002-05-17 03:19:19 +02:00
|
|
|
* assign_timezone: GUC assign_hook for timezone
|
1997-11-10 16:37:15 +01:00
|
|
|
*/
|
2002-05-17 03:19:19 +02:00
|
|
|
const char *
|
|
|
|
assign_timezone(const char *value, bool doit, bool interactive)
|
1997-10-30 17:52:11 +01:00
|
|
|
{
|
2002-05-17 03:19:19 +02:00
|
|
|
char *result;
|
|
|
|
char *endptr;
|
|
|
|
double hours;
|
1997-10-30 17:52:11 +01:00
|
|
|
|
2002-05-17 03:19:19 +02:00
|
|
|
/*
|
|
|
|
* Check for INTERVAL 'foo'
|
|
|
|
*/
|
|
|
|
if (strncasecmp(value, "interval", 8) == 0)
|
1997-10-30 17:52:11 +01:00
|
|
|
{
|
2002-05-17 03:19:19 +02:00
|
|
|
const char *valueptr = value;
|
|
|
|
char *val;
|
|
|
|
Interval *interval;
|
|
|
|
|
|
|
|
valueptr += 8;
|
|
|
|
while (isspace((unsigned char) *valueptr))
|
|
|
|
valueptr++;
|
|
|
|
if (*valueptr++ != '\'')
|
|
|
|
return NULL;
|
|
|
|
val = pstrdup(valueptr);
|
|
|
|
/* Check and remove trailing quote */
|
|
|
|
endptr = strchr(val, '\'');
|
|
|
|
if (!endptr || endptr[1] != '\0')
|
2001-10-18 19:30:21 +02:00
|
|
|
{
|
2002-05-17 03:19:19 +02:00
|
|
|
pfree(val);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
*endptr = '\0';
|
|
|
|
/*
|
|
|
|
* Try to parse it. XXX an invalid interval format will result in
|
|
|
|
* elog, which is not desirable for GUC. We did what we could to
|
|
|
|
* guard against this in flatten_set_variable_args, but a string
|
|
|
|
* coming in from postgresql.conf might contain anything.
|
|
|
|
*/
|
|
|
|
interval = DatumGetIntervalP(DirectFunctionCall3(interval_in,
|
|
|
|
CStringGetDatum(val),
|
|
|
|
ObjectIdGetDatum(InvalidOid),
|
|
|
|
Int32GetDatum(-1)));
|
|
|
|
pfree(val);
|
|
|
|
if (interval->month != 0)
|
|
|
|
{
|
|
|
|
if (interactive)
|
|
|
|
elog(ERROR, "SET TIME ZONE: illegal INTERVAL; month not allowed");
|
|
|
|
pfree(interval);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
if (doit)
|
|
|
|
{
|
|
|
|
CTimeZone = interval->time;
|
|
|
|
HasCTZSet = true;
|
|
|
|
}
|
|
|
|
pfree(interval);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Try it as a numeric number of hours (possibly fractional).
|
|
|
|
*/
|
|
|
|
hours = strtod(value, &endptr);
|
|
|
|
if (endptr != value && *endptr == '\0')
|
|
|
|
{
|
|
|
|
if (doit)
|
2001-10-18 19:30:21 +02:00
|
|
|
{
|
2002-05-17 03:19:19 +02:00
|
|
|
CTimeZone = hours * 3600;
|
|
|
|
HasCTZSet = true;
|
2001-10-18 19:30:21 +02:00
|
|
|
}
|
2002-05-17 03:19:19 +02:00
|
|
|
}
|
|
|
|
else if (strcasecmp(value, "UNKNOWN") == 0)
|
|
|
|
{
|
2001-10-25 07:50:21 +02:00
|
|
|
/*
|
2002-05-17 03:19:19 +02:00
|
|
|
* Clear any TZ value we may have established.
|
|
|
|
*
|
|
|
|
* unsetenv() works fine, but is BSD, not POSIX, and is not
|
|
|
|
* available under Solaris, among others. Apparently putenv()
|
|
|
|
* called as below clears the process-specific environment
|
|
|
|
* variables. Other reasonable arguments to putenv() (e.g.
|
|
|
|
* "TZ=", "TZ", "") result in a core dump (under Linux anyway).
|
|
|
|
* - thomas 1998-01-26
|
2001-10-25 07:50:21 +02:00
|
|
|
*/
|
2002-05-17 03:19:19 +02:00
|
|
|
if (doit)
|
2001-10-18 19:30:21 +02:00
|
|
|
{
|
2002-05-17 03:19:19 +02:00
|
|
|
if (tzbuf[0] == 'T')
|
|
|
|
{
|
|
|
|
strcpy(tzbuf, "=");
|
|
|
|
if (putenv(tzbuf) != 0)
|
|
|
|
elog(ERROR, "Unable to clear TZ environment variable");
|
|
|
|
tzset();
|
|
|
|
}
|
|
|
|
HasCTZSet = false;
|
2001-10-18 19:30:21 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2002-05-17 03:19:19 +02:00
|
|
|
/*
|
|
|
|
* Otherwise assume it is a timezone name.
|
|
|
|
*
|
|
|
|
* XXX unfortunately we have no reasonable way to check whether a
|
|
|
|
* timezone name is good, so we have to just assume that it is.
|
|
|
|
*/
|
|
|
|
if (doit)
|
2001-10-18 19:30:21 +02:00
|
|
|
{
|
|
|
|
strcpy(tzbuf, "TZ=");
|
2002-05-17 03:19:19 +02:00
|
|
|
strncat(tzbuf, value, sizeof(tzbuf)-4);
|
|
|
|
if (putenv(tzbuf) != 0) /* shouldn't happen? */
|
|
|
|
elog(LOG, "assign_timezone: putenv failed");
|
2001-10-18 19:30:21 +02:00
|
|
|
tzset();
|
2002-05-17 03:19:19 +02:00
|
|
|
HasCTZSet = false;
|
2001-10-18 19:30:21 +02:00
|
|
|
}
|
|
|
|
}
|
1997-10-30 17:52:11 +01:00
|
|
|
}
|
|
|
|
|
2002-05-17 03:19:19 +02:00
|
|
|
/*
|
|
|
|
* If we aren't going to do the assignment, just return OK indicator.
|
|
|
|
*/
|
|
|
|
if (!doit)
|
|
|
|
return value;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Prepare the canonical string to return. GUC wants it malloc'd.
|
|
|
|
*/
|
|
|
|
result = (char *) malloc(sizeof(tzbuf));
|
|
|
|
if (!result)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
if (HasCTZSet)
|
|
|
|
{
|
|
|
|
snprintf(result, sizeof(tzbuf), "%.5f",
|
|
|
|
(double) CTimeZone / 3600.0);
|
|
|
|
}
|
|
|
|
else if (tzbuf[0] == 'T')
|
|
|
|
{
|
|
|
|
strcpy(result, tzbuf + 3);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
strcpy(result, "UNKNOWN");
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
1997-10-30 17:52:11 +01:00
|
|
|
|
2002-05-17 03:19:19 +02:00
|
|
|
/*
|
|
|
|
* show_timezone: GUC show_hook for timezone
|
|
|
|
*/
|
|
|
|
const char *
|
2000-10-25 21:44:44 +02:00
|
|
|
show_timezone(void)
|
1997-10-30 17:52:11 +01:00
|
|
|
{
|
2001-10-25 07:50:21 +02:00
|
|
|
char *tzn;
|
2001-10-18 19:30:21 +02:00
|
|
|
|
|
|
|
if (HasCTZSet)
|
|
|
|
{
|
2001-10-25 07:50:21 +02:00
|
|
|
Interval interval;
|
1997-10-30 17:52:11 +01:00
|
|
|
|
2001-10-18 19:30:21 +02:00
|
|
|
interval.month = 0;
|
|
|
|
interval.time = CTimeZone;
|
|
|
|
|
2002-05-17 03:19:19 +02:00
|
|
|
tzn = DatumGetCString(DirectFunctionCall1(interval_out,
|
|
|
|
IntervalPGetDatum(&interval)));
|
2001-10-18 19:30:21 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
tzn = getenv("TZ");
|
1997-10-30 17:52:11 +01:00
|
|
|
|
2001-10-18 19:30:21 +02:00
|
|
|
if (tzn != NULL)
|
2002-05-17 03:19:19 +02:00
|
|
|
return tzn;
|
1997-10-30 17:52:11 +01:00
|
|
|
|
2002-05-17 03:19:19 +02:00
|
|
|
return "unknown";
|
|
|
|
}
|
2000-02-15 21:49:31 +01:00
|
|
|
|
2000-03-17 06:29:07 +01:00
|
|
|
|
2001-10-18 19:30:21 +02:00
|
|
|
/*
|
2002-05-17 03:19:19 +02:00
|
|
|
* SET TRANSACTION ISOLATION LEVEL
|
2001-10-18 19:30:21 +02:00
|
|
|
*/
|
2000-02-15 21:49:31 +01:00
|
|
|
|
2002-05-17 03:19:19 +02:00
|
|
|
const char *
|
|
|
|
assign_XactIsoLevel(const char *value, bool doit, bool interactive)
|
2000-02-15 21:49:31 +01:00
|
|
|
{
|
2002-05-17 03:19:19 +02:00
|
|
|
if (doit && interactive && SerializableSnapshot != NULL)
|
2000-02-15 21:49:31 +01:00
|
|
|
elog(ERROR, "SET TRANSACTION ISOLATION LEVEL must be called before any query");
|
|
|
|
|
2001-09-19 17:19:12 +02:00
|
|
|
if (strcmp(value, "serializable") == 0)
|
2002-05-17 03:19:19 +02:00
|
|
|
{ if (doit) XactIsoLevel = XACT_SERIALIZABLE; }
|
2001-09-19 17:19:12 +02:00
|
|
|
else if (strcmp(value, "read committed") == 0)
|
2002-05-17 03:19:19 +02:00
|
|
|
{ if (doit) XactIsoLevel = XACT_READ_COMMITTED; }
|
|
|
|
else if (strcmp(value, "default") == 0)
|
|
|
|
{ if (doit) XactIsoLevel = DefaultXactIsoLevel; }
|
2000-02-15 21:49:31 +01:00
|
|
|
else
|
2002-05-17 03:19:19 +02:00
|
|
|
return NULL;
|
2000-02-15 21:49:31 +01:00
|
|
|
|
2002-05-17 03:19:19 +02:00
|
|
|
return value;
|
2000-02-15 21:49:31 +01:00
|
|
|
}
|
|
|
|
|
2002-05-17 03:19:19 +02:00
|
|
|
const char *
|
2000-10-25 21:44:44 +02:00
|
|
|
show_XactIsoLevel(void)
|
2000-02-15 21:49:31 +01:00
|
|
|
{
|
|
|
|
if (XactIsoLevel == XACT_SERIALIZABLE)
|
2002-05-17 03:19:19 +02:00
|
|
|
return "SERIALIZABLE";
|
2000-02-15 21:49:31 +01:00
|
|
|
else
|
2002-05-17 03:19:19 +02:00
|
|
|
return "READ COMMITTED";
|
2000-02-15 21:49:31 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2000-04-07 15:40:45 +02:00
|
|
|
/*
|
|
|
|
* Random number seed
|
|
|
|
*/
|
2002-04-21 21:12:46 +02:00
|
|
|
|
2002-05-17 03:19:19 +02:00
|
|
|
bool
|
|
|
|
assign_random_seed(double value, bool doit, bool interactive)
|
2000-04-07 15:40:45 +02:00
|
|
|
{
|
2002-05-17 03:19:19 +02:00
|
|
|
/* Can't really roll back on error, so ignore non-interactive setting */
|
|
|
|
if (doit && interactive)
|
|
|
|
DirectFunctionCall1(setseed, Float8GetDatum(value));
|
|
|
|
return true;
|
2000-04-07 15:40:45 +02:00
|
|
|
}
|
|
|
|
|
2002-05-17 03:19:19 +02:00
|
|
|
const char *
|
|
|
|
show_random_seed(void)
|
2000-04-07 15:40:45 +02:00
|
|
|
{
|
2002-05-17 03:19:19 +02:00
|
|
|
return "unavailable";
|
2000-04-07 15:40:45 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2000-10-25 21:44:44 +02:00
|
|
|
/*
|
I have committed many support files for CREATE CONVERSION. Default
conversion procs and conversions are added in initdb. Currently
supported conversions are:
UTF-8(UNICODE) <--> SQL_ASCII, ISO-8859-1 to 16, EUC_JP, EUC_KR,
EUC_CN, EUC_TW, SJIS, BIG5, GBK, GB18030, UHC,
JOHAB, TCVN
EUC_JP <--> SJIS
EUC_TW <--> BIG5
MULE_INTERNAL <--> EUC_JP, SJIS, EUC_TW, BIG5
Note that initial contents of pg_conversion system catalog are created
in the initdb process. So doing initdb required is ideal, it's
possible to add them to your databases by hand, however. To accomplish
this:
psql -f your_postgresql_install_path/share/conversion_create.sql your_database
So I did not bump up the version in cataversion.h.
TODO:
Add more conversion procs
Add [CASCADE|RESTRICT] to DROP CONVERSION
Add tuples to pg_depend
Add regression tests
Write docs
Add SQL99 CONVERT command?
--
Tatsuo Ishii
2002-07-18 04:02:30 +02:00
|
|
|
* encoding handling functions
|
2000-10-25 21:44:44 +02:00
|
|
|
*/
|
|
|
|
|
2002-05-17 03:19:19 +02:00
|
|
|
const char *
|
|
|
|
assign_client_encoding(const char *value, bool doit, bool interactive)
|
2000-10-25 21:44:44 +02:00
|
|
|
{
|
2001-10-25 07:50:21 +02:00
|
|
|
int encoding;
|
2001-10-18 19:30:21 +02:00
|
|
|
|
2000-10-25 21:44:44 +02:00
|
|
|
encoding = pg_valid_client_encoding(value);
|
|
|
|
if (encoding < 0)
|
2002-05-17 03:19:19 +02:00
|
|
|
return NULL;
|
I have committed many support files for CREATE CONVERSION. Default
conversion procs and conversions are added in initdb. Currently
supported conversions are:
UTF-8(UNICODE) <--> SQL_ASCII, ISO-8859-1 to 16, EUC_JP, EUC_KR,
EUC_CN, EUC_TW, SJIS, BIG5, GBK, GB18030, UHC,
JOHAB, TCVN
EUC_JP <--> SJIS
EUC_TW <--> BIG5
MULE_INTERNAL <--> EUC_JP, SJIS, EUC_TW, BIG5
Note that initial contents of pg_conversion system catalog are created
in the initdb process. So doing initdb required is ideal, it's
possible to add them to your databases by hand, however. To accomplish
this:
psql -f your_postgresql_install_path/share/conversion_create.sql your_database
So I did not bump up the version in cataversion.h.
TODO:
Add more conversion procs
Add [CASCADE|RESTRICT] to DROP CONVERSION
Add tuples to pg_depend
Add regression tests
Write docs
Add SQL99 CONVERT command?
--
Tatsuo Ishii
2002-07-18 04:02:30 +02:00
|
|
|
|
|
|
|
/* XXX SetClientEncoding depends on namespace functions which are
|
|
|
|
* not available at startup time. So we accept requested client
|
|
|
|
* encoding anyway which might not be valid (e.g. no conversion
|
|
|
|
* procs available).
|
2002-05-17 03:19:19 +02:00
|
|
|
*/
|
I have committed many support files for CREATE CONVERSION. Default
conversion procs and conversions are added in initdb. Currently
supported conversions are:
UTF-8(UNICODE) <--> SQL_ASCII, ISO-8859-1 to 16, EUC_JP, EUC_KR,
EUC_CN, EUC_TW, SJIS, BIG5, GBK, GB18030, UHC,
JOHAB, TCVN
EUC_JP <--> SJIS
EUC_TW <--> BIG5
MULE_INTERNAL <--> EUC_JP, SJIS, EUC_TW, BIG5
Note that initial contents of pg_conversion system catalog are created
in the initdb process. So doing initdb required is ideal, it's
possible to add them to your databases by hand, however. To accomplish
this:
psql -f your_postgresql_install_path/share/conversion_create.sql your_database
So I did not bump up the version in cataversion.h.
TODO:
Add more conversion procs
Add [CASCADE|RESTRICT] to DROP CONVERSION
Add tuples to pg_depend
Add regression tests
Write docs
Add SQL99 CONVERT command?
--
Tatsuo Ishii
2002-07-18 04:02:30 +02:00
|
|
|
if (SetClientEncoding(encoding, doit) < 0)
|
2000-10-25 21:44:44 +02:00
|
|
|
{
|
2002-05-17 03:19:19 +02:00
|
|
|
if (interactive)
|
2000-10-25 21:44:44 +02:00
|
|
|
elog(ERROR, "Conversion between %s and %s is not supported",
|
Commit Karel's patch.
-------------------------------------------------------------------
Subject: Re: [PATCHES] encoding names
From: Karel Zak <zakkr@zf.jcu.cz>
To: Peter Eisentraut <peter_e@gmx.net>
Cc: pgsql-patches <pgsql-patches@postgresql.org>
Date: Fri, 31 Aug 2001 17:24:38 +0200
On Thu, Aug 30, 2001 at 01:30:40AM +0200, Peter Eisentraut wrote:
> > - convert encoding 'name' to 'id'
>
> I thought we decided not to add functions returning "new" names until we
> know exactly what the new names should be, and pending schema
Ok, the patch not to add functions.
> better
>
> ...(): encoding name too long
Fixed.
I found new bug in command/variable.c in parse_client_encoding(), nobody
probably never see this error:
if (pg_set_client_encoding(encoding))
{
elog(ERROR, "Conversion between %s and %s is not supported",
value, GetDatabaseEncodingName());
}
because pg_set_client_encoding() returns -1 for error and 0 as true.
It's fixed too.
IMHO it can be apply.
Karel
PS:
* following files are renamed:
src/utils/mb/Unicode/KOI8_to_utf8.map -->
src/utils/mb/Unicode/koi8r_to_utf8.map
src/utils/mb/Unicode/WIN_to_utf8.map -->
src/utils/mb/Unicode/win1251_to_utf8.map
src/utils/mb/Unicode/utf8_to_KOI8.map -->
src/utils/mb/Unicode/utf8_to_koi8r.map
src/utils/mb/Unicode/utf8_to_WIN.map -->
src/utils/mb/Unicode/utf8_to_win1251.map
* new file:
src/utils/mb/encname.c
* removed file:
src/utils/mb/common.c
--
Karel Zak <zakkr@zf.jcu.cz>
http://home.zf.jcu.cz/~zakkr/
C, PostgreSQL, PHP, WWW, http://docs.linux.cz, http://mape.jcu.cz
2001-09-06 06:57:30 +02:00
|
|
|
value, GetDatabaseEncodingName());
|
2002-05-17 03:19:19 +02:00
|
|
|
return NULL;
|
2000-10-25 21:44:44 +02:00
|
|
|
}
|
2002-05-17 03:19:19 +02:00
|
|
|
return value;
|
2000-10-26 19:31:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-05-17 03:19:19 +02:00
|
|
|
const char *
|
|
|
|
assign_server_encoding(const char *value, bool doit, bool interactive)
|
2000-10-25 21:44:44 +02:00
|
|
|
{
|
2002-05-17 03:19:19 +02:00
|
|
|
if (interactive)
|
|
|
|
elog(ERROR, "SET SERVER_ENCODING is not supported");
|
|
|
|
/* Pretend never to fail in noninteractive case */
|
|
|
|
return value;
|
2000-10-25 21:44:44 +02:00
|
|
|
}
|
|
|
|
|
2002-05-17 03:19:19 +02:00
|
|
|
const char *
|
2000-10-25 21:44:44 +02:00
|
|
|
show_server_encoding(void)
|
|
|
|
{
|
2002-05-17 03:19:19 +02:00
|
|
|
return GetDatabaseEncodingName();
|
2000-10-25 21:44:44 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-05-17 03:19:19 +02:00
|
|
|
/*
|
|
|
|
* SET SESSION AUTHORIZATION
|
|
|
|
*
|
|
|
|
* Note: when resetting session auth after an error, we can't expect to do
|
|
|
|
* catalog lookups. Hence, the stored form of the value is always a numeric
|
|
|
|
* userid that can be re-used directly.
|
|
|
|
*/
|
|
|
|
const char *
|
|
|
|
assign_session_authorization(const char *value, bool doit, bool interactive)
|
2002-05-06 21:47:30 +02:00
|
|
|
{
|
2002-05-17 03:19:19 +02:00
|
|
|
Oid usesysid;
|
|
|
|
char *endptr;
|
|
|
|
char *result;
|
2002-05-06 21:47:30 +02:00
|
|
|
|
2002-05-17 03:19:19 +02:00
|
|
|
usesysid = (Oid) strtoul(value, &endptr, 10);
|
2002-05-06 21:47:30 +02:00
|
|
|
|
2002-05-17 03:19:19 +02:00
|
|
|
if (endptr != value && *endptr == '\0' && OidIsValid(usesysid))
|
|
|
|
{
|
|
|
|
/* use the numeric user ID */
|
|
|
|
}
|
2001-03-22 05:01:46 +01:00
|
|
|
else
|
2001-10-18 19:30:21 +02:00
|
|
|
{
|
2002-05-17 03:19:19 +02:00
|
|
|
HeapTuple userTup;
|
2000-09-22 17:34:31 +02:00
|
|
|
|
2002-05-17 03:19:19 +02:00
|
|
|
userTup = SearchSysCache(SHADOWNAME,
|
|
|
|
PointerGetDatum(value),
|
|
|
|
0, 0, 0);
|
|
|
|
if (!HeapTupleIsValid(userTup))
|
2002-04-21 21:12:46 +02:00
|
|
|
{
|
2002-05-17 03:19:19 +02:00
|
|
|
if (interactive)
|
|
|
|
elog(ERROR, "user \"%s\" does not exist", value);
|
|
|
|
return NULL;
|
2002-04-21 21:12:46 +02:00
|
|
|
}
|
2001-10-18 19:30:21 +02:00
|
|
|
|
2002-05-17 03:19:19 +02:00
|
|
|
usesysid = ((Form_pg_shadow) GETSTRUCT(userTup))->usesysid;
|
1997-03-25 10:44:00 +01:00
|
|
|
|
2002-05-17 03:19:19 +02:00
|
|
|
ReleaseSysCache(userTup);
|
2001-10-18 19:30:21 +02:00
|
|
|
}
|
2001-03-22 05:01:46 +01:00
|
|
|
|
2002-05-17 03:19:19 +02:00
|
|
|
if (doit)
|
|
|
|
SetSessionAuthorization(usesysid);
|
|
|
|
|
|
|
|
result = (char *) malloc(32);
|
|
|
|
if (!result)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
snprintf(result, 32, "%lu", (unsigned long) usesysid);
|
|
|
|
|
|
|
|
return result;
|
2001-03-22 05:01:46 +01:00
|
|
|
}
|
1997-06-20 19:17:03 +02:00
|
|
|
|
2002-05-17 03:19:19 +02:00
|
|
|
const char *
|
|
|
|
show_session_authorization(void)
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
2002-06-11 15:40:53 +02:00
|
|
|
return GetUserNameFromId(GetSessionUserId());
|
2001-03-22 05:01:46 +01:00
|
|
|
}
|