mirror of
https://github.com/postgres/postgres.git
synced 2025-12-01 12:18:01 +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
|
||||
|
||||
56
src/backend/utils/cache/lsyscache.c
vendored
56
src/backend/utils/cache/lsyscache.c
vendored
@@ -7,7 +7,7 @@
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/utils/cache/lsyscache.c,v 1.139 2006/12/23 00:43:11 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/utils/cache/lsyscache.c,v 1.140 2006/12/30 21:21:54 tgl Exp $
|
||||
*
|
||||
* NOTES
|
||||
* Eventually, the index information should go through here, too.
|
||||
@@ -2016,6 +2016,60 @@ getTypeBinaryOutputInfo(Oid type, Oid *typSend, bool *typIsVarlena)
|
||||
ReleaseSysCache(typeTuple);
|
||||
}
|
||||
|
||||
/*
|
||||
* get_typmodin
|
||||
*
|
||||
* Given the type OID, return the type's typmodin procedure, if any.
|
||||
*/
|
||||
Oid
|
||||
get_typmodin(Oid typid)
|
||||
{
|
||||
HeapTuple tp;
|
||||
|
||||
tp = SearchSysCache(TYPEOID,
|
||||
ObjectIdGetDatum(typid),
|
||||
0, 0, 0);
|
||||
if (HeapTupleIsValid(tp))
|
||||
{
|
||||
Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
|
||||
Oid result;
|
||||
|
||||
result = typtup->typmodin;
|
||||
ReleaseSysCache(tp);
|
||||
return result;
|
||||
}
|
||||
else
|
||||
return InvalidOid;
|
||||
}
|
||||
|
||||
#ifdef NOT_USED
|
||||
/*
|
||||
* get_typmodout
|
||||
*
|
||||
* Given the type OID, return the type's typmodout procedure, if any.
|
||||
*/
|
||||
Oid
|
||||
get_typmodout(Oid typid)
|
||||
{
|
||||
HeapTuple tp;
|
||||
|
||||
tp = SearchSysCache(TYPEOID,
|
||||
ObjectIdGetDatum(typid),
|
||||
0, 0, 0);
|
||||
if (HeapTupleIsValid(tp))
|
||||
{
|
||||
Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
|
||||
Oid result;
|
||||
|
||||
result = typtup->typmodout;
|
||||
ReleaseSysCache(tp);
|
||||
return result;
|
||||
}
|
||||
else
|
||||
return InvalidOid;
|
||||
}
|
||||
#endif /* NOT_USED */
|
||||
|
||||
|
||||
/* ---------- STATISTICS CACHE ---------- */
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
* Written by Peter Eisentraut <peter_e@gmx.net>.
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.363 2006/12/23 00:52:40 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.364 2006/12/30 21:21:54 tgl Exp $
|
||||
*
|
||||
*--------------------------------------------------------------------
|
||||
*/
|
||||
@@ -45,6 +45,7 @@
|
||||
#include "parser/gramparse.h"
|
||||
#include "parser/parse_expr.h"
|
||||
#include "parser/parse_relation.h"
|
||||
#include "parser/parse_type.h"
|
||||
#include "parser/scansup.h"
|
||||
#include "pgstat.h"
|
||||
#include "postmaster/autovacuum.h"
|
||||
@@ -4523,14 +4524,17 @@ flatten_set_variable_args(const char *name, List *args)
|
||||
* to interval and back to normalize the value and account
|
||||
* for any typmod.
|
||||
*/
|
||||
int32 typmod;
|
||||
Datum interval;
|
||||
char *intervalout;
|
||||
|
||||
typmod = typenameTypeMod(NULL, arg->typename, INTERVALOID);
|
||||
|
||||
interval =
|
||||
DirectFunctionCall3(interval_in,
|
||||
CStringGetDatum(val),
|
||||
ObjectIdGetDatum(InvalidOid),
|
||||
Int32GetDatum(arg->typename->typmod));
|
||||
Int32GetDatum(typmod));
|
||||
|
||||
intervalout =
|
||||
DatumGetCString(DirectFunctionCall1(interval_out,
|
||||
|
||||
Reference in New Issue
Block a user