mirror of
https://github.com/postgres/postgres.git
synced 2025-11-29 23:43:17 +03:00
Support type modifiers for user-defined types, and pull most knowledge
about typmod representation for standard types out into type-specific typmod I/O functions. Teodor Sigaev, with some editorialization by Tom Lane.
This commit is contained in:
@@ -8,13 +8,14 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/utils/adt/arrayutils.c,v 1.21 2006/03/05 15:58:41 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/utils/adt/arrayutils.c,v 1.22 2006/12/30 21:21:54 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#include "postgres.h"
|
||||
|
||||
#include "catalog/pg_type.h"
|
||||
#include "utils/array.h"
|
||||
#include "utils/memutils.h"
|
||||
|
||||
@@ -188,3 +189,30 @@ mda_next_tuple(int n, int *curr, const int *span)
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* ArrayGetTypmods: verify that argument is a 1-D integer array,
|
||||
* return its length and a pointer to the first contained integer.
|
||||
*/
|
||||
int32 *
|
||||
ArrayGetTypmods(ArrayType *arr, int *n)
|
||||
{
|
||||
if (ARR_ELEMTYPE(arr) != INT4OID)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_ARRAY_ELEMENT_ERROR),
|
||||
errmsg("typmod array must be type integer[]")));
|
||||
|
||||
if (ARR_NDIM(arr) != 1)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
|
||||
errmsg("typmod array must be one-dimensional")));
|
||||
|
||||
if (ARR_HASNULL(arr))
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
|
||||
errmsg("typmod array must not contain nulls")));
|
||||
|
||||
*n = ArrayGetNItems(ARR_NDIM(arr), ARR_DIMS(arr));
|
||||
|
||||
return (int32 *) ARR_DATA_PTR(arr);
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/utils/adt/date.c,v 1.125 2006/07/14 14:52:23 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/utils/adt/date.c,v 1.126 2006/12/30 21:21:54 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -24,6 +24,7 @@
|
||||
#include "libpq/pqformat.h"
|
||||
#include "miscadmin.h"
|
||||
#include "parser/scansup.h"
|
||||
#include "utils/array.h"
|
||||
#include "utils/builtins.h"
|
||||
#include "utils/date.h"
|
||||
#include "utils/nabstime.h"
|
||||
@@ -43,6 +44,60 @@ static int tm2time(struct pg_tm * tm, fsec_t fsec, TimeADT *result);
|
||||
static int tm2timetz(struct pg_tm * tm, fsec_t fsec, int tz, TimeTzADT *result);
|
||||
static void AdjustTimeForTypmod(TimeADT *time, int32 typmod);
|
||||
|
||||
|
||||
/* common code for timetypmodin and timetztypmodin */
|
||||
static int32
|
||||
anytime_typmodin(bool istz, ArrayType *ta)
|
||||
{
|
||||
int32 typmod;
|
||||
int32 *tl;
|
||||
int n;
|
||||
|
||||
tl = ArrayGetTypmods(ta, &n);
|
||||
|
||||
/*
|
||||
* we're not too tense about good error message here because grammar
|
||||
* shouldn't allow wrong number of modifiers for TIME
|
||||
*/
|
||||
if (n != 1)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
||||
errmsg("invalid type modifier")));
|
||||
|
||||
if (*tl < 0)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
||||
errmsg("TIME(%d)%s precision must not be negative",
|
||||
*tl, (istz ? " WITH TIME ZONE" : ""))));
|
||||
if (*tl > MAX_TIME_PRECISION)
|
||||
{
|
||||
ereport(WARNING,
|
||||
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
||||
errmsg("TIME(%d)%s precision reduced to maximum allowed, %d",
|
||||
*tl, (istz ? " WITH TIME ZONE" : "" ),
|
||||
MAX_TIME_PRECISION)));
|
||||
typmod = MAX_TIME_PRECISION;
|
||||
} else
|
||||
typmod = *tl;
|
||||
|
||||
return typmod;
|
||||
}
|
||||
|
||||
/* common code for timetypmodout and timetztypmodout */
|
||||
static char *
|
||||
anytime_typmodout(bool istz, int32 typmod)
|
||||
{
|
||||
char *res = (char *) palloc(64);
|
||||
const char *tz = istz ? " with time zone" : " without time zone";
|
||||
|
||||
if (typmod >= 0)
|
||||
snprintf(res, 64, "(%d)%s", (int) typmod, tz);
|
||||
else
|
||||
snprintf(res, 64, "%s", tz);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
* Date ADT
|
||||
*****************************************************************************/
|
||||
@@ -1029,6 +1084,22 @@ time_send(PG_FUNCTION_ARGS)
|
||||
PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
|
||||
}
|
||||
|
||||
Datum
|
||||
timetypmodin(PG_FUNCTION_ARGS)
|
||||
{
|
||||
ArrayType *ta = PG_GETARG_ARRAYTYPE_P(0);
|
||||
|
||||
PG_RETURN_INT32(anytime_typmodin(false, ta));
|
||||
}
|
||||
|
||||
Datum
|
||||
timetypmodout(PG_FUNCTION_ARGS)
|
||||
{
|
||||
int32 typmod = PG_GETARG_INT32(0);
|
||||
|
||||
PG_RETURN_CSTRING(anytime_typmodout(false, typmod));
|
||||
}
|
||||
|
||||
|
||||
/* time_scale()
|
||||
* Adjust time type for specified scale factor.
|
||||
@@ -1830,6 +1901,22 @@ timetz_send(PG_FUNCTION_ARGS)
|
||||
PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
|
||||
}
|
||||
|
||||
Datum
|
||||
timetztypmodin(PG_FUNCTION_ARGS)
|
||||
{
|
||||
ArrayType *ta = PG_GETARG_ARRAYTYPE_P(0);
|
||||
|
||||
PG_RETURN_INT32(anytime_typmodin(true, ta));
|
||||
}
|
||||
|
||||
Datum
|
||||
timetztypmodout(PG_FUNCTION_ARGS)
|
||||
{
|
||||
int32 typmod = PG_GETARG_INT32(0);
|
||||
|
||||
PG_RETURN_CSTRING(anytime_typmodout(true, typmod));
|
||||
}
|
||||
|
||||
|
||||
/* timetz2tm()
|
||||
* Convert TIME WITH TIME ZONE data type to POSIX time structure.
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/utils/adt/format_type.c,v 1.44 2006/07/14 14:52:24 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/utils/adt/format_type.c,v 1.45 2006/12/30 21:21:54 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -20,7 +20,6 @@
|
||||
#include "catalog/namespace.h"
|
||||
#include "catalog/pg_type.h"
|
||||
#include "utils/builtins.h"
|
||||
#include "utils/datetime.h"
|
||||
#include "utils/lsyscache.h"
|
||||
#include "utils/numeric.h"
|
||||
#include "utils/syscache.h"
|
||||
@@ -31,6 +30,7 @@
|
||||
|
||||
static char *format_type_internal(Oid type_oid, int32 typemod,
|
||||
bool typemod_given, bool allow_invalid);
|
||||
static char *printTypmod(const char *typname, int32 typmod, Oid typmodout);
|
||||
static char *
|
||||
psnprintf(size_t len, const char *fmt,...)
|
||||
/* This lets gcc check the format string for consistency. */
|
||||
@@ -186,8 +186,7 @@ format_type_internal(Oid type_oid, int32 typemod,
|
||||
{
|
||||
case BITOID:
|
||||
if (with_typemod)
|
||||
buf = psnprintf(5 + MAX_INT32_LEN + 1, "bit(%d)",
|
||||
(int) typemod);
|
||||
buf = printTypmod("bit", typemod, typeform->typmodout);
|
||||
else if (typemod_given)
|
||||
{
|
||||
/*
|
||||
@@ -206,8 +205,7 @@ format_type_internal(Oid type_oid, int32 typemod,
|
||||
|
||||
case BPCHAROID:
|
||||
if (with_typemod)
|
||||
buf = psnprintf(11 + MAX_INT32_LEN + 1, "character(%d)",
|
||||
(int) (typemod - VARHDRSZ));
|
||||
buf = printTypmod("character", typemod, typeform->typmodout);
|
||||
else if (typemod_given)
|
||||
{
|
||||
/*
|
||||
@@ -242,136 +240,56 @@ format_type_internal(Oid type_oid, int32 typemod,
|
||||
|
||||
case NUMERICOID:
|
||||
if (with_typemod)
|
||||
buf = psnprintf(10 + 2 * MAX_INT32_LEN + 1, "numeric(%d,%d)",
|
||||
((typemod - VARHDRSZ) >> 16) & 0xffff,
|
||||
(typemod - VARHDRSZ) & 0xffff);
|
||||
buf = printTypmod("numeric", typemod, typeform->typmodout);
|
||||
else
|
||||
buf = pstrdup("numeric");
|
||||
break;
|
||||
|
||||
case INTERVALOID:
|
||||
if (with_typemod)
|
||||
{
|
||||
int fields = INTERVAL_RANGE(typemod);
|
||||
int precision = INTERVAL_PRECISION(typemod);
|
||||
const char *fieldstr;
|
||||
|
||||
switch (fields)
|
||||
{
|
||||
case INTERVAL_MASK(YEAR):
|
||||
fieldstr = " year";
|
||||
break;
|
||||
case INTERVAL_MASK(MONTH):
|
||||
fieldstr = " month";
|
||||
break;
|
||||
case INTERVAL_MASK(DAY):
|
||||
fieldstr = " day";
|
||||
break;
|
||||
case INTERVAL_MASK(HOUR):
|
||||
fieldstr = " hour";
|
||||
break;
|
||||
case INTERVAL_MASK(MINUTE):
|
||||
fieldstr = " minute";
|
||||
break;
|
||||
case INTERVAL_MASK(SECOND):
|
||||
fieldstr = " second";
|
||||
break;
|
||||
case INTERVAL_MASK(YEAR)
|
||||
| INTERVAL_MASK(MONTH):
|
||||
fieldstr = " year to month";
|
||||
break;
|
||||
case INTERVAL_MASK(DAY)
|
||||
| INTERVAL_MASK(HOUR):
|
||||
fieldstr = " day to hour";
|
||||
break;
|
||||
case INTERVAL_MASK(DAY)
|
||||
| INTERVAL_MASK(HOUR)
|
||||
| INTERVAL_MASK(MINUTE):
|
||||
fieldstr = " day to minute";
|
||||
break;
|
||||
case INTERVAL_MASK(DAY)
|
||||
| INTERVAL_MASK(HOUR)
|
||||
| INTERVAL_MASK(MINUTE)
|
||||
| INTERVAL_MASK(SECOND):
|
||||
fieldstr = " day to second";
|
||||
break;
|
||||
case INTERVAL_MASK(HOUR)
|
||||
| INTERVAL_MASK(MINUTE):
|
||||
fieldstr = " hour to minute";
|
||||
break;
|
||||
case INTERVAL_MASK(HOUR)
|
||||
| INTERVAL_MASK(MINUTE)
|
||||
| INTERVAL_MASK(SECOND):
|
||||
fieldstr = " hour to second";
|
||||
break;
|
||||
case INTERVAL_MASK(MINUTE)
|
||||
| INTERVAL_MASK(SECOND):
|
||||
fieldstr = " minute to second";
|
||||
break;
|
||||
case INTERVAL_FULL_RANGE:
|
||||
fieldstr = "";
|
||||
break;
|
||||
default:
|
||||
elog(ERROR, "invalid INTERVAL typmod: 0x%x", typemod);
|
||||
fieldstr = "";
|
||||
break;
|
||||
}
|
||||
if (precision != INTERVAL_FULL_PRECISION)
|
||||
buf = psnprintf(100, "interval(%d)%s",
|
||||
precision, fieldstr);
|
||||
else
|
||||
buf = psnprintf(100, "interval%s",
|
||||
fieldstr);
|
||||
}
|
||||
buf = printTypmod("interval", typemod, typeform->typmodout);
|
||||
else
|
||||
buf = pstrdup("interval");
|
||||
break;
|
||||
|
||||
case TIMEOID:
|
||||
if (with_typemod)
|
||||
buf = psnprintf(50, "time(%d) without time zone",
|
||||
typemod);
|
||||
buf = printTypmod("time", typemod, typeform->typmodout);
|
||||
else
|
||||
buf = pstrdup("time without time zone");
|
||||
break;
|
||||
|
||||
case TIMETZOID:
|
||||
if (with_typemod)
|
||||
buf = psnprintf(50, "time(%d) with time zone",
|
||||
typemod);
|
||||
buf = printTypmod("time", typemod, typeform->typmodout);
|
||||
else
|
||||
buf = pstrdup("time with time zone");
|
||||
break;
|
||||
|
||||
case TIMESTAMPOID:
|
||||
if (with_typemod)
|
||||
buf = psnprintf(50, "timestamp(%d) without time zone",
|
||||
typemod);
|
||||
buf = printTypmod("timestamp", typemod, typeform->typmodout);
|
||||
else
|
||||
buf = pstrdup("timestamp without time zone");
|
||||
break;
|
||||
|
||||
case TIMESTAMPTZOID:
|
||||
if (with_typemod)
|
||||
buf = psnprintf(50, "timestamp(%d) with time zone",
|
||||
typemod);
|
||||
buf = printTypmod("timestamp", typemod, typeform->typmodout);
|
||||
else
|
||||
buf = pstrdup("timestamp with time zone");
|
||||
break;
|
||||
|
||||
case VARBITOID:
|
||||
if (with_typemod)
|
||||
buf = psnprintf(13 + MAX_INT32_LEN + 1, "bit varying(%d)",
|
||||
(int) typemod);
|
||||
buf = printTypmod("bit varying", typemod, typeform->typmodout);
|
||||
else
|
||||
buf = pstrdup("bit varying");
|
||||
break;
|
||||
|
||||
case VARCHAROID:
|
||||
if (with_typemod)
|
||||
buf = psnprintf(19 + MAX_INT32_LEN + 1,
|
||||
"character varying(%d)",
|
||||
(int) (typemod - VARHDRSZ));
|
||||
buf = printTypmod("character varying", typemod, typeform->typmodout);
|
||||
else
|
||||
buf = pstrdup("character varying");
|
||||
break;
|
||||
@@ -396,6 +314,9 @@ format_type_internal(Oid type_oid, int32 typemod,
|
||||
typname = NameStr(typeform->typname);
|
||||
|
||||
buf = quote_qualified_identifier(nspname, typname);
|
||||
|
||||
if (with_typemod)
|
||||
buf = printTypmod(buf, typemod, typeform->typmodout);
|
||||
}
|
||||
|
||||
if (is_array)
|
||||
@@ -407,6 +328,38 @@ format_type_internal(Oid type_oid, int32 typemod,
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Add typmod decoration to the basic type name
|
||||
*/
|
||||
static char *
|
||||
printTypmod(const char *typname, int32 typmod, Oid typmodout)
|
||||
{
|
||||
char *res;
|
||||
|
||||
/* Shouldn't be called if typmod is -1 */
|
||||
Assert(typmod >= 0);
|
||||
|
||||
if (typmodout == InvalidOid)
|
||||
{
|
||||
/* Default behavior: just print the integer typmod with parens */
|
||||
res = psnprintf(strlen(typname) + MAX_INT32_LEN + 3, "%s(%d)",
|
||||
typname, (int) typmod);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Use the type-specific typmodout procedure */
|
||||
char *tmstr;
|
||||
|
||||
tmstr = DatumGetCString(OidFunctionCall1(typmodout,
|
||||
Int32GetDatum(typmod)));
|
||||
res = psnprintf(strlen(typname) + strlen(tmstr) + 1, "%s%s",
|
||||
typname, tmstr);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* type_maximum_size --- determine maximum width of a variable-width column
|
||||
*
|
||||
@@ -417,7 +370,9 @@ format_type_internal(Oid type_oid, int32 typemod,
|
||||
*
|
||||
* This may appear unrelated to format_type(), but in fact the two routines
|
||||
* share knowledge of the encoding of typmod for different types, so it's
|
||||
* convenient to keep them together.
|
||||
* convenient to keep them together. (XXX now that most of this knowledge
|
||||
* has been pushed out of format_type into the typmodout functions, it's
|
||||
* interesting to wonder if it's worth trying to factor this code too...)
|
||||
*/
|
||||
int32
|
||||
type_maximum_size(Oid type_oid, int32 typemod)
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
* Copyright (c) 1998-2006, PostgreSQL Global Development Group
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/utils/adt/numeric.c,v 1.96 2006/10/04 00:29:59 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/utils/adt/numeric.c,v 1.97 2006/12/30 21:21:54 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -470,7 +470,7 @@ numeric_send(PG_FUNCTION_ARGS)
|
||||
* scale of the attribute have to be applied on the value.
|
||||
*/
|
||||
Datum
|
||||
numeric (PG_FUNCTION_ARGS)
|
||||
numeric(PG_FUNCTION_ARGS)
|
||||
{
|
||||
Numeric num = PG_GETARG_NUMERIC(0);
|
||||
int32 typmod = PG_GETARG_INT32(1);
|
||||
@@ -537,6 +537,67 @@ numeric (PG_FUNCTION_ARGS)
|
||||
PG_RETURN_NUMERIC(new);
|
||||
}
|
||||
|
||||
Datum
|
||||
numerictypmodin(PG_FUNCTION_ARGS)
|
||||
{
|
||||
ArrayType *ta = PG_GETARG_ARRAYTYPE_P(0);
|
||||
int32 *tl;
|
||||
int n;
|
||||
int32 typmod;
|
||||
|
||||
tl = ArrayGetTypmods(ta, &n);
|
||||
|
||||
if (n == 2)
|
||||
{
|
||||
if (tl[0] < 1 || tl[0] > NUMERIC_MAX_PRECISION)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
||||
errmsg("NUMERIC precision %d must be between 1 and %d",
|
||||
tl[0], NUMERIC_MAX_PRECISION)));
|
||||
if (tl[1] < 0 || tl[1] > tl[0])
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
||||
errmsg("NUMERIC scale %d must be between 0 and precision %d",
|
||||
tl[1], tl[0])));
|
||||
typmod = ((tl[0] << 16) | tl[1]) + VARHDRSZ;
|
||||
}
|
||||
else if (n == 1)
|
||||
{
|
||||
if (tl[0] < 1 || tl[0] > NUMERIC_MAX_PRECISION)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
||||
errmsg("NUMERIC precision %d must be between 1 and %d",
|
||||
tl[0], NUMERIC_MAX_PRECISION)));
|
||||
/* scale defaults to zero */
|
||||
typmod = (tl[0] << 16) + VARHDRSZ;
|
||||
}
|
||||
else
|
||||
{
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
||||
errmsg("invalid NUMERIC type modifier")));
|
||||
typmod = 0; /* keep compiler quiet */
|
||||
}
|
||||
|
||||
PG_RETURN_INT32(typmod);
|
||||
}
|
||||
|
||||
Datum
|
||||
numerictypmodout(PG_FUNCTION_ARGS)
|
||||
{
|
||||
int32 typmod = PG_GETARG_INT32(0);
|
||||
char *res = (char *) palloc(64);
|
||||
|
||||
if (typmod >= 0)
|
||||
snprintf(res, 64, "(%d,%d)",
|
||||
((typmod - VARHDRSZ) >> 16) & 0xffff,
|
||||
(typmod - VARHDRSZ) & 0xffff);
|
||||
else
|
||||
*res = '\0';
|
||||
|
||||
PG_RETURN_CSTRING(res);
|
||||
}
|
||||
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
*
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/utils/adt/timestamp.c,v 1.169 2006/11/11 01:14:19 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/utils/adt/timestamp.c,v 1.170 2006/12/30 21:21:54 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -56,6 +56,60 @@ static void AdjustIntervalForTypmod(Interval *interval, int32 typmod);
|
||||
static TimestampTz timestamp2timestamptz(Timestamp timestamp);
|
||||
|
||||
|
||||
/* common code for timestamptypmodin and timestamptztypmodin */
|
||||
static int32
|
||||
anytimestamp_typmodin(bool istz, ArrayType *ta)
|
||||
{
|
||||
int32 typmod;
|
||||
int32 *tl;
|
||||
int n;
|
||||
|
||||
tl = ArrayGetTypmods(ta, &n);
|
||||
|
||||
/*
|
||||
* we're not too tense about good error message here because grammar
|
||||
* shouldn't allow wrong number of modifiers for TIMESTAMP
|
||||
*/
|
||||
if (n != 1)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
||||
errmsg("invalid type modifier")));
|
||||
|
||||
if (*tl < 0)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
||||
errmsg("TIMESTAMP(%d)%s precision must not be negative",
|
||||
*tl, (istz ? " WITH TIME ZONE" : ""))));
|
||||
if (*tl > MAX_TIMESTAMP_PRECISION)
|
||||
{
|
||||
ereport(WARNING,
|
||||
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
||||
errmsg("TIMESTAMP(%d)%s precision reduced to maximum allowed, %d",
|
||||
*tl, (istz ? " WITH TIME ZONE" : ""),
|
||||
MAX_TIMESTAMP_PRECISION)));
|
||||
typmod = MAX_TIMESTAMP_PRECISION;
|
||||
} else
|
||||
typmod = *tl;
|
||||
|
||||
return typmod;
|
||||
}
|
||||
|
||||
/* common code for timestamptypmodout and timestamptztypmodout */
|
||||
static char *
|
||||
anytimestamp_typmodout(bool istz, int32 typmod)
|
||||
{
|
||||
char *res = (char *) palloc(64);
|
||||
const char *tz = istz ? " with time zone" : " without time zone";
|
||||
|
||||
if (typmod >= 0)
|
||||
snprintf(res, 64, "(%d)%s", (int) typmod, tz);
|
||||
else
|
||||
snprintf(res, 64, "%s", tz);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
* USER I/O ROUTINES *
|
||||
*****************************************************************************/
|
||||
@@ -215,6 +269,22 @@ timestamp_send(PG_FUNCTION_ARGS)
|
||||
PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
|
||||
}
|
||||
|
||||
Datum
|
||||
timestamptypmodin(PG_FUNCTION_ARGS)
|
||||
{
|
||||
ArrayType *ta = PG_GETARG_ARRAYTYPE_P(0);
|
||||
|
||||
PG_RETURN_INT32(anytimestamp_typmodin(false, ta));
|
||||
}
|
||||
|
||||
Datum
|
||||
timestamptypmodout(PG_FUNCTION_ARGS)
|
||||
{
|
||||
int32 typmod = PG_GETARG_INT32(0);
|
||||
|
||||
PG_RETURN_CSTRING(anytimestamp_typmodout(false, typmod));
|
||||
}
|
||||
|
||||
|
||||
/* timestamp_scale()
|
||||
* Adjust time type for specified scale factor.
|
||||
@@ -461,6 +531,22 @@ timestamptz_send(PG_FUNCTION_ARGS)
|
||||
PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
|
||||
}
|
||||
|
||||
Datum
|
||||
timestamptztypmodin(PG_FUNCTION_ARGS)
|
||||
{
|
||||
ArrayType *ta = PG_GETARG_ARRAYTYPE_P(0);
|
||||
|
||||
PG_RETURN_INT32(anytimestamp_typmodin(true, ta));
|
||||
}
|
||||
|
||||
Datum
|
||||
timestamptztypmodout(PG_FUNCTION_ARGS)
|
||||
{
|
||||
int32 typmod = PG_GETARG_INT32(0);
|
||||
|
||||
PG_RETURN_CSTRING(anytimestamp_typmodout(true, typmod));
|
||||
}
|
||||
|
||||
|
||||
/* timestamptz_scale()
|
||||
* Adjust time type for specified scale factor.
|
||||
@@ -625,6 +711,162 @@ interval_send(PG_FUNCTION_ARGS)
|
||||
PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
|
||||
}
|
||||
|
||||
Datum
|
||||
intervaltypmodin(PG_FUNCTION_ARGS)
|
||||
{
|
||||
ArrayType *ta = PG_GETARG_ARRAYTYPE_P(0);
|
||||
int32 *tl;
|
||||
int n;
|
||||
int32 typmod;
|
||||
|
||||
tl = ArrayGetTypmods(ta, &n);
|
||||
|
||||
/*
|
||||
* tl[0] - opt_interval
|
||||
* tl[1] - Iconst (optional)
|
||||
*
|
||||
* Note we must validate tl[0] even though it's normally guaranteed
|
||||
* correct by the grammar --- consider SELECT 'foo'::"interval"(1000).
|
||||
*/
|
||||
if (n > 0)
|
||||
{
|
||||
switch (tl[0])
|
||||
{
|
||||
case INTERVAL_MASK(YEAR):
|
||||
case INTERVAL_MASK(MONTH):
|
||||
case INTERVAL_MASK(DAY):
|
||||
case INTERVAL_MASK(HOUR):
|
||||
case INTERVAL_MASK(MINUTE):
|
||||
case INTERVAL_MASK(SECOND):
|
||||
case INTERVAL_MASK(YEAR) | INTERVAL_MASK(MONTH):
|
||||
case INTERVAL_MASK(DAY) | INTERVAL_MASK(HOUR):
|
||||
case INTERVAL_MASK(DAY) | INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE):
|
||||
case INTERVAL_MASK(DAY) | INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE) | INTERVAL_MASK(SECOND):
|
||||
case INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE):
|
||||
case INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE) | INTERVAL_MASK(SECOND):
|
||||
case INTERVAL_MASK(MINUTE) | INTERVAL_MASK(SECOND):
|
||||
case INTERVAL_FULL_RANGE:
|
||||
/* all OK */
|
||||
break;
|
||||
default:
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
||||
errmsg("invalid INTERVAL type modifier")));
|
||||
}
|
||||
}
|
||||
|
||||
if (n == 1)
|
||||
{
|
||||
if (tl[0] != INTERVAL_FULL_RANGE)
|
||||
typmod = INTERVAL_TYPMOD(INTERVAL_FULL_PRECISION, tl[0]);
|
||||
else
|
||||
typmod = -1;
|
||||
}
|
||||
else if (n == 2)
|
||||
{
|
||||
if (tl[1] < 0)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
||||
errmsg("INTERVAL(%d) precision must not be negative",
|
||||
tl[1])));
|
||||
if (tl[1] > MAX_INTERVAL_PRECISION)
|
||||
{
|
||||
ereport(WARNING,
|
||||
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
||||
errmsg("INTERVAL(%d) precision reduced to maximum allowed, %d",
|
||||
tl[1], MAX_INTERVAL_PRECISION)));
|
||||
typmod = INTERVAL_TYPMOD(MAX_INTERVAL_PRECISION, tl[0]);
|
||||
}
|
||||
else
|
||||
typmod = INTERVAL_TYPMOD(tl[1], tl[0]);
|
||||
}
|
||||
else
|
||||
{
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
||||
errmsg("invalid INTERVAL type modifier")));
|
||||
typmod = 0; /* keep compiler quiet */
|
||||
}
|
||||
|
||||
PG_RETURN_INT32(typmod);
|
||||
}
|
||||
|
||||
Datum
|
||||
intervaltypmodout(PG_FUNCTION_ARGS)
|
||||
{
|
||||
int32 typmod = PG_GETARG_INT32(0);
|
||||
char *res = (char *) palloc(64);
|
||||
int fields;
|
||||
int precision;
|
||||
const char *fieldstr;
|
||||
|
||||
if (typmod < 0)
|
||||
{
|
||||
*res = '\0';
|
||||
PG_RETURN_CSTRING(res);
|
||||
}
|
||||
|
||||
fields = INTERVAL_RANGE(typmod);
|
||||
precision = INTERVAL_PRECISION(typmod);
|
||||
|
||||
switch (fields)
|
||||
{
|
||||
case INTERVAL_MASK(YEAR):
|
||||
fieldstr = " year";
|
||||
break;
|
||||
case INTERVAL_MASK(MONTH):
|
||||
fieldstr = " month";
|
||||
break;
|
||||
case INTERVAL_MASK(DAY):
|
||||
fieldstr = " day";
|
||||
break;
|
||||
case INTERVAL_MASK(HOUR):
|
||||
fieldstr = " hour";
|
||||
break;
|
||||
case INTERVAL_MASK(MINUTE):
|
||||
fieldstr = " minute";
|
||||
break;
|
||||
case INTERVAL_MASK(SECOND):
|
||||
fieldstr = " second";
|
||||
break;
|
||||
case INTERVAL_MASK(YEAR) | INTERVAL_MASK(MONTH):
|
||||
fieldstr = " year to month";
|
||||
break;
|
||||
case INTERVAL_MASK(DAY) | INTERVAL_MASK(HOUR):
|
||||
fieldstr = " day to hour";
|
||||
break;
|
||||
case INTERVAL_MASK(DAY) | INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE):
|
||||
fieldstr = " day to minute";
|
||||
break;
|
||||
case INTERVAL_MASK(DAY) | INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE) | INTERVAL_MASK(SECOND):
|
||||
fieldstr = " day to second";
|
||||
break;
|
||||
case INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE):
|
||||
fieldstr = " hour to minute";
|
||||
break;
|
||||
case INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE) | INTERVAL_MASK(SECOND):
|
||||
fieldstr = " hour to second";
|
||||
break;
|
||||
case INTERVAL_MASK(MINUTE) | INTERVAL_MASK(SECOND):
|
||||
fieldstr = " minute to second";
|
||||
break;
|
||||
case INTERVAL_FULL_RANGE:
|
||||
fieldstr = "";
|
||||
break;
|
||||
default:
|
||||
elog(ERROR, "invalid INTERVAL typmod: 0x%x", typmod);
|
||||
fieldstr = "";
|
||||
break;
|
||||
}
|
||||
|
||||
if (precision != INTERVAL_FULL_PRECISION)
|
||||
snprintf(res, 64, "(%d)%s", precision, fieldstr);
|
||||
else
|
||||
snprintf(res, 64, "%s", fieldstr);
|
||||
|
||||
PG_RETURN_CSTRING(res);
|
||||
}
|
||||
|
||||
|
||||
/* interval_scale()
|
||||
* Adjust interval type for specified fields.
|
||||
|
||||
@@ -9,19 +9,71 @@
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/utils/adt/varbit.c,v 1.50 2006/07/14 14:52:24 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/utils/adt/varbit.c,v 1.51 2006/12/30 21:21:54 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#include "postgres.h"
|
||||
|
||||
#include "access/htup.h"
|
||||
#include "libpq/pqformat.h"
|
||||
#include "utils/array.h"
|
||||
#include "utils/varbit.h"
|
||||
|
||||
#define HEXDIG(z) ((z)<10 ? ((z)+'0') : ((z)-10+'A'))
|
||||
|
||||
|
||||
/* common code for bittypmodin and varbittypmodin */
|
||||
static int32
|
||||
anybit_typmodin(ArrayType *ta, const char *typename)
|
||||
{
|
||||
int32 typmod;
|
||||
int32 *tl;
|
||||
int n;
|
||||
|
||||
tl = ArrayGetTypmods(ta, &n);
|
||||
|
||||
/*
|
||||
* we're not too tense about good error message here because grammar
|
||||
* shouldn't allow wrong number of modifiers for BIT
|
||||
*/
|
||||
if (n != 1)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
||||
errmsg("invalid type modifier")));
|
||||
|
||||
if (*tl < 1)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
||||
errmsg("length for type %s must be at least 1",
|
||||
typename)));
|
||||
if (*tl > (MaxAttrSize * BITS_PER_BYTE))
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
||||
errmsg("length for type %s cannot exceed %d",
|
||||
typename, MaxAttrSize * BITS_PER_BYTE)));
|
||||
|
||||
typmod = *tl;
|
||||
|
||||
return typmod;
|
||||
}
|
||||
|
||||
/* common code for bittypmodout and varbittypmodout */
|
||||
static char *
|
||||
anybit_typmodout(int32 typmod)
|
||||
{
|
||||
char *res = (char *) palloc(64);
|
||||
|
||||
if (typmod >= 0)
|
||||
snprintf(res, 64, "(%d)", typmod);
|
||||
else
|
||||
*res = '\0';
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
/*----------
|
||||
* attypmod -- contains the length of the bit string in bits, or for
|
||||
* varying bits the maximum length.
|
||||
@@ -325,6 +377,23 @@ bit(PG_FUNCTION_ARGS)
|
||||
PG_RETURN_VARBIT_P(result);
|
||||
}
|
||||
|
||||
Datum
|
||||
bittypmodin(PG_FUNCTION_ARGS)
|
||||
{
|
||||
ArrayType *ta = PG_GETARG_ARRAYTYPE_P(0);
|
||||
|
||||
PG_RETURN_INT32(anybit_typmodin(ta, "bit"));
|
||||
}
|
||||
|
||||
Datum
|
||||
bittypmodout(PG_FUNCTION_ARGS)
|
||||
{
|
||||
int32 typmod = PG_GETARG_INT32(0);
|
||||
|
||||
PG_RETURN_CSTRING(anybit_typmodout(typmod));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* varbit_in -
|
||||
* converts a string to the internal representation of a bitstring.
|
||||
@@ -603,6 +672,22 @@ varbit(PG_FUNCTION_ARGS)
|
||||
PG_RETURN_VARBIT_P(result);
|
||||
}
|
||||
|
||||
Datum
|
||||
varbittypmodin(PG_FUNCTION_ARGS)
|
||||
{
|
||||
ArrayType *ta = PG_GETARG_ARRAYTYPE_P(0);
|
||||
|
||||
PG_RETURN_INT32(anybit_typmodin(ta, "varbit"));
|
||||
}
|
||||
|
||||
Datum
|
||||
varbittypmodout(PG_FUNCTION_ARGS)
|
||||
{
|
||||
int32 typmod = PG_GETARG_INT32(0);
|
||||
|
||||
PG_RETURN_CSTRING(anybit_typmodout(typmod));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Comparison operators
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/utils/adt/varchar.c,v 1.119 2006/10/04 00:30:00 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/utils/adt/varchar.c,v 1.120 2006/12/30 21:21:54 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -17,10 +17,65 @@
|
||||
|
||||
#include "access/hash.h"
|
||||
#include "libpq/pqformat.h"
|
||||
#include "utils/array.h"
|
||||
#include "utils/builtins.h"
|
||||
#include "mb/pg_wchar.h"
|
||||
|
||||
|
||||
/* common code for bpchartypmodin and varchartypmodin */
|
||||
static int32
|
||||
anychar_typmodin(ArrayType *ta, const char *typename)
|
||||
{
|
||||
int32 typmod;
|
||||
int32 *tl;
|
||||
int n;
|
||||
|
||||
tl = ArrayGetTypmods(ta, &n);
|
||||
|
||||
/*
|
||||
* we're not too tense about good error message here because grammar
|
||||
* shouldn't allow wrong number of modifiers for CHAR
|
||||
*/
|
||||
if (n != 1)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
||||
errmsg("invalid type modifier")));
|
||||
|
||||
if (*tl < 1)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
||||
errmsg("length for type %s must be at least 1", typename)));
|
||||
if (*tl > MaxAttrSize)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
||||
errmsg("length for type %s cannot exceed %d",
|
||||
typename, MaxAttrSize)));
|
||||
|
||||
/*
|
||||
* For largely historical reasons, the typmod is VARHDRSZ plus the
|
||||
* number of characters; there is enough client-side code that knows
|
||||
* about that that we'd better not change it.
|
||||
*/
|
||||
typmod = VARHDRSZ + *tl;
|
||||
|
||||
return typmod;
|
||||
}
|
||||
|
||||
/* common code for bpchartypmodout and varchartypmodout */
|
||||
static char *
|
||||
anychar_typmodout(int32 typmod)
|
||||
{
|
||||
char *res = (char *) palloc(64);
|
||||
|
||||
if (typmod > VARHDRSZ)
|
||||
snprintf(res, 64, "(%d)", (int) (typmod - VARHDRSZ));
|
||||
else
|
||||
*res = '\0';
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* CHAR() and VARCHAR() types are part of the ANSI SQL standard. CHAR()
|
||||
* is for blank-padded string whose length is specified in CREATE TABLE.
|
||||
@@ -359,6 +414,22 @@ name_bpchar(PG_FUNCTION_ARGS)
|
||||
PG_RETURN_BPCHAR_P(result);
|
||||
}
|
||||
|
||||
Datum
|
||||
bpchartypmodin(PG_FUNCTION_ARGS)
|
||||
{
|
||||
ArrayType *ta = PG_GETARG_ARRAYTYPE_P(0);
|
||||
|
||||
PG_RETURN_INT32(anychar_typmodin(ta, "char"));
|
||||
}
|
||||
|
||||
Datum
|
||||
bpchartypmodout(PG_FUNCTION_ARGS)
|
||||
{
|
||||
int32 typmod = PG_GETARG_INT32(0);
|
||||
|
||||
PG_RETURN_CSTRING(anychar_typmodout(typmod));
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
* varchar - varchar(n)
|
||||
@@ -536,6 +607,22 @@ varchar(PG_FUNCTION_ARGS)
|
||||
PG_RETURN_VARCHAR_P(result);
|
||||
}
|
||||
|
||||
Datum
|
||||
varchartypmodin(PG_FUNCTION_ARGS)
|
||||
{
|
||||
ArrayType *ta = PG_GETARG_ARRAYTYPE_P(0);
|
||||
|
||||
PG_RETURN_INT32(anychar_typmodin(ta, "varchar"));
|
||||
}
|
||||
|
||||
Datum
|
||||
varchartypmodout(PG_FUNCTION_ARGS)
|
||||
{
|
||||
int32 typmod = PG_GETARG_INT32(0);
|
||||
|
||||
PG_RETURN_CSTRING(anychar_typmodout(typmod));
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
* Exported functions
|
||||
|
||||
Reference in New Issue
Block a user