diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/Makefile.global.in | 42 | ||||
-rw-r--r-- | src/backend/utils/adt/oracle_compat.c | 190 | ||||
-rw-r--r-- | src/include/pg_config.h.in | 12 |
3 files changed, 240 insertions, 4 deletions
diff --git a/src/Makefile.global.in b/src/Makefile.global.in index ecbd7d6f0b4..7a9183eed37 100644 --- a/src/Makefile.global.in +++ b/src/Makefile.global.in @@ -1,5 +1,5 @@ # -*-makefile-*- -# $PostgreSQL: pgsql/src/Makefile.global.in,v 1.186 2004/05/21 20:56:48 tgl Exp $ +# $PostgreSQL: pgsql/src/Makefile.global.in,v 1.187 2004/05/22 00:34:49 tgl Exp $ #------------------------------------------------------------------------------ # All PostgreSQL makefiles include this file and use the variables it sets, @@ -51,22 +51,53 @@ configure_args = @configure_args@ ########################################################################## # # Installation directories +# +# These are set by the equivalent --xxxdir configure options. We +# append "postgresql" to some of them, if the string does not already +# contain "pgsql" or "postgres", in order to avoid directory clutter. prefix := @prefix@ exec_prefix := @exec_prefix@ bindir := @bindir@ sbindir := @sbindir@ + libexecdir := @libexecdir@ +ifeq "$(findstring pgsql, $(libexecdir))" "" +ifeq "$(findstring postgres, $(libexecdir))" "" +override libexecdir := $(libexecdir)/postgresql +endif +endif datadir := @datadir@ +ifeq "$(findstring pgsql, $(datadir))" "" +ifeq "$(findstring postgres, $(datadir))" "" +override datadir := $(datadir)/postgresql +endif +endif + sysconfdir := @sysconfdir@ +ifeq "$(findstring pgsql, $(sysconfdir))" "" +ifeq "$(findstring postgres, $(sysconfdir))" "" +override sysconfdir := $(sysconfdir)/postgresql +endif +endif libdir := @libdir@ -pkglibdir := @pkglibdir@ +pkglibdir = $(libdir) +ifeq "$(findstring pgsql, $(pkglibdir))" "" +ifeq "$(findstring postgres, $(pkglibdir))" "" +override pkglibdir := $(pkglibdir)/postgresql +endif +endif includedir := @includedir@ -pkgincludedir := @pkgincludedir@ +pkgincludedir = $(includedir) +ifeq "$(findstring pgsql, $(pkgincludedir))" "" +ifeq "$(findstring postgres, $(pkgincludedir))" "" +override pkgincludedir := $(pkgincludedir)/postgresql +endif +endif includedir_server = $(pkgincludedir)/server includedir_internal = $(pkgincludedir)/internal @@ -74,6 +105,11 @@ mandir := @mandir@ sqlmansect_dummy = l docdir := @docdir@ +ifeq "$(findstring pgsql, $(docdir))" "" +ifeq "$(findstring postgres, $(docdir))" "" +override docdir := $(docdir)/postgresql +endif +endif localedir := @localedir@ diff --git a/src/backend/utils/adt/oracle_compat.c b/src/backend/utils/adt/oracle_compat.c index eca71de6fc6..7f381438ed2 100644 --- a/src/backend/utils/adt/oracle_compat.c +++ b/src/backend/utils/adt/oracle_compat.c @@ -9,23 +9,144 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/adt/oracle_compat.c,v 1.50 2004/02/27 03:59:23 neilc Exp $ + * $PostgreSQL: pgsql/src/backend/utils/adt/oracle_compat.c,v 1.51 2004/05/22 00:34:50 tgl Exp $ * *------------------------------------------------------------------------- */ #include "postgres.h" +/* + * towlower() and friends should be in <wctype.h>, but some pre-C99 systems + * declare them in <wchar.h>. + */ #include <ctype.h> +#ifdef HAVE_WCHAR_H +#include <wchar.h> +#endif +#ifdef HAVE_WCTYPE_H +#include <wctype.h> +#endif #include "utils/builtins.h" #include "mb/pg_wchar.h" +/* + * If the system provides the needed functions for wide-character manipulation + * (which are all standardized by C99), then we implement upper/lower/initcap + * using wide-character functions. Otherwise we use the traditional <ctype.h> + * functions, which of course will not work as desired in multibyte character + * sets. Note that in either case we are effectively assuming that the + * database character encoding matches the encoding implied by LC_CTYPE. + * + * We assume if we have these two functions, we have their friends too, and + * can use the wide-character method. + */ +#if defined(HAVE_WCSTOMBS) && defined(HAVE_TOWLOWER) +#define USE_WIDE_UPPER_LOWER +#endif + static text *dotrim(const char *string, int stringlen, const char *set, int setlen, bool doltrim, bool dortrim); +#ifdef USE_WIDE_UPPER_LOWER + +/* + * Convert a TEXT value into a palloc'd wchar string. + */ +static wchar_t * +texttowcs(const text *txt) +{ + int nbytes = VARSIZE(txt) - VARHDRSZ; + char *workstr; + wchar_t *result; + size_t ncodes; + + /* Overflow paranoia */ + if (nbytes < 0 || + nbytes > (int) (INT_MAX / sizeof(wchar_t)) - 1) + ereport(ERROR, + (errcode(ERRCODE_OUT_OF_MEMORY), + errmsg("out of memory"))); + + /* Need a null-terminated version of the input */ + workstr = (char *) palloc(nbytes + 1); + memcpy(workstr, VARDATA(txt), nbytes); + workstr[nbytes] = '\0'; + + /* Output workspace cannot have more codes than input bytes */ + result = (wchar_t *) palloc((nbytes + 1) * sizeof(wchar_t)); + + /* Do the conversion */ + ncodes = mbstowcs(result, workstr, nbytes + 1); + + if (ncodes == (size_t) -1) + { + /* + * Invalid multibyte character encountered. We try to give a useful + * error message by letting pg_verifymbstr check the string. But + * it's possible that the string is OK to us, and not OK to mbstowcs + * --- this suggests that the LC_CTYPE locale is different from the + * database encoding. Give a generic error message if verifymbstr + * can't find anything wrong. + */ + pg_verifymbstr(workstr, nbytes, false); + ereport(ERROR, + (errcode(ERRCODE_CHARACTER_NOT_IN_REPERTOIRE), + errmsg("invalid multibyte character for locale"))); + } + + Assert(ncodes <= (size_t) nbytes); + + return result; +} + + +/* + * Convert a wchar string into a palloc'd TEXT value. The wchar string + * must be zero-terminated, but we also require the caller to pass the string + * length, since it will know it anyway in current uses. + */ +static text * +wcstotext(const wchar_t *str, int ncodes) +{ + text *result; + size_t nbytes; + + /* Overflow paranoia */ + if (ncodes < 0 || + ncodes > (int) ((INT_MAX - VARHDRSZ) / MB_CUR_MAX) - 1) + ereport(ERROR, + (errcode(ERRCODE_OUT_OF_MEMORY), + errmsg("out of memory"))); + + /* Make workspace certainly large enough for result */ + result = (text *) palloc((ncodes + 1) * MB_CUR_MAX + VARHDRSZ); + + /* Do the conversion */ + nbytes = wcstombs((char *) VARDATA(result), str, + (ncodes + 1) * MB_CUR_MAX); + + if (nbytes == (size_t) -1) + { + /* Invalid multibyte character encountered ... shouldn't happen */ + ereport(ERROR, + (errcode(ERRCODE_CHARACTER_NOT_IN_REPERTOIRE), + errmsg("invalid multibyte character for locale"))); + } + + Assert(nbytes <= (size_t) (ncodes * MB_CUR_MAX)); + + VARATT_SIZEP(result) = nbytes + VARHDRSZ; + + return result; +} + +#endif /* USE_WIDE_UPPER_LOWER */ + + /******************************************************************** * * lower @@ -43,6 +164,25 @@ static text *dotrim(const char *string, int stringlen, Datum lower(PG_FUNCTION_ARGS) { +#ifdef USE_WIDE_UPPER_LOWER + text *string = PG_GETARG_TEXT_P(0); + text *result; + wchar_t *workspace; + int i; + + workspace = texttowcs(string); + + for (i = 0; workspace[i] != 0; i++) + workspace[i] = towlower(workspace[i]); + + result = wcstotext(workspace, i); + + pfree(workspace); + + PG_RETURN_TEXT_P(result); + +#else /* !USE_WIDE_UPPER_LOWER */ + text *string = PG_GETARG_TEXT_P_COPY(0); char *ptr; int m; @@ -58,6 +198,7 @@ lower(PG_FUNCTION_ARGS) } PG_RETURN_TEXT_P(string); +#endif /* USE_WIDE_UPPER_LOWER */ } @@ -78,6 +219,25 @@ lower(PG_FUNCTION_ARGS) Datum upper(PG_FUNCTION_ARGS) { +#ifdef USE_WIDE_UPPER_LOWER + text *string = PG_GETARG_TEXT_P(0); + text *result; + wchar_t *workspace; + int i; + + workspace = texttowcs(string); + + for (i = 0; workspace[i] != 0; i++) + workspace[i] = towupper(workspace[i]); + + result = wcstotext(workspace, i); + + pfree(workspace); + + PG_RETURN_TEXT_P(result); + +#else /* !USE_WIDE_UPPER_LOWER */ + text *string = PG_GETARG_TEXT_P_COPY(0); char *ptr; int m; @@ -93,6 +253,7 @@ upper(PG_FUNCTION_ARGS) } PG_RETURN_TEXT_P(string); +#endif /* USE_WIDE_UPPER_LOWER */ } @@ -116,6 +277,32 @@ upper(PG_FUNCTION_ARGS) Datum initcap(PG_FUNCTION_ARGS) { +#ifdef USE_WIDE_UPPER_LOWER + text *string = PG_GETARG_TEXT_P(0); + text *result; + wchar_t *workspace; + int wasalnum = 0; + int i; + + workspace = texttowcs(string); + + for (i = 0; workspace[i] != 0; i++) + { + if (wasalnum) + workspace[i] = towlower(workspace[i]); + else + workspace[i] = towupper(workspace[i]); + wasalnum = iswalnum(workspace[i]); + } + + result = wcstotext(workspace, i); + + pfree(workspace); + + PG_RETURN_TEXT_P(result); + +#else /* !USE_WIDE_UPPER_LOWER */ + text *string = PG_GETARG_TEXT_P_COPY(0); char *ptr; int m; @@ -142,6 +329,7 @@ initcap(PG_FUNCTION_ARGS) } PG_RETURN_TEXT_P(string); +#endif /* USE_WIDE_UPPER_LOWER */ } diff --git a/src/include/pg_config.h.in b/src/include/pg_config.h.in index 69aee085f8c..f9c3d5ade7f 100644 --- a/src/include/pg_config.h.in +++ b/src/include/pg_config.h.in @@ -509,6 +509,9 @@ `HAVE_STRUCT_TM_TM_ZONE' instead. */ #undef HAVE_TM_ZONE +/* Define to 1 if you have the `towlower' function. */ +#undef HAVE_TOWLOWER + /* Define to 1 if you have the external array `tzname'. */ #undef HAVE_TZNAME @@ -545,6 +548,15 @@ /* Define to 1 if you have the `waitpid' function. */ #undef HAVE_WAITPID +/* Define to 1 if you have the <wchar.h> header file. */ +#undef HAVE_WCHAR_H + +/* Define to 1 if you have the `wcstombs' function. */ +#undef HAVE_WCSTOMBS + +/* Define to 1 if you have the <wctype.h> header file. */ +#undef HAVE_WCTYPE_H + /* Define to the appropriate snprintf format for 64-bit ints, if any. */ #undef INT64_FORMAT |