diff --git a/doc/src/sgml/ref/create_type.sgml b/doc/src/sgml/ref/create_type.sgml
index 69899d84f5..4f002b6519 100644
--- a/doc/src/sgml/ref/create_type.sgml
+++ b/doc/src/sgml/ref/create_type.sgml
@@ -1,5 +1,5 @@
@@ -125,12 +125,13 @@ CREATE TYPE name (
function should perform adequate checking to ensure that the value is
valid.
The receive function may be declared as taking one argument of type
- internal, or two arguments of types internal
- and oid. It must return a value of the data type itself.
- (The first argument is a pointer to a StringInfo buffer
- holding the received byte string; the optional second argument is the
- element type OID in case this is an array type, or the type's own OID for a
- composite type.) Similarly, the optional
+ internal, or as taking three arguments of types
+ internal, oid, integer.
+ The first argument is a pointer to a StringInfo buffer
+ holding the received byte string; the optional arguments are the
+ same as for the text input function.
+ The receive function must return a value of the data type itself.
+ Similarly, the optional
send_function converts
from the internal representation to the external binary representation.
If this function is not supplied, the type cannot participate in binary
diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index 10e68684b8..d25189d0ac 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/copy.c,v 1.246 2005/06/28 05:08:53 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/copy.c,v 1.247 2005/07/10 21:13:58 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -144,7 +144,7 @@ static char *CopyReadAttributeCSV(const char *delim, const char *null_print,
char *quote, char *escape,
CopyReadResult *result, bool *isnull);
static Datum CopyReadBinaryAttribute(int column_no, FmgrInfo *flinfo,
- Oid typioparam, bool *isnull);
+ Oid typioparam, int32 typmod, bool *isnull);
static void CopyAttributeOut(char *string, char *delim);
static void CopyAttributeOutCSV(char *string, char *delim, char *quote,
char *escape, bool force_quote);
@@ -1843,8 +1843,9 @@ CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids,
copy_attname = "oid";
loaded_oid =
DatumGetObjectId(CopyReadBinaryAttribute(0,
- &oid_in_function,
- oid_typioparam,
+ &oid_in_function,
+ oid_typioparam,
+ -1,
&isnull));
if (isnull || loaded_oid == InvalidOid)
ereport(ERROR,
@@ -1864,6 +1865,7 @@ CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids,
values[m] = CopyReadBinaryAttribute(i,
&in_functions[m],
typioparams[m],
+ attr[m]->atttypmod,
&isnull);
nulls[m] = isnull ? 'n' : ' ';
copy_attname = NULL;
@@ -2556,7 +2558,8 @@ CopyReadAttributeCSV(const char *delim, const char *null_print, char *quote,
* Read a binary attribute
*/
static Datum
-CopyReadBinaryAttribute(int column_no, FmgrInfo *flinfo, Oid typioparam,
+CopyReadBinaryAttribute(int column_no, FmgrInfo *flinfo,
+ Oid typioparam, int32 typmod,
bool *isnull)
{
int32 fld_size;
@@ -2594,9 +2597,10 @@ CopyReadBinaryAttribute(int column_no, FmgrInfo *flinfo, Oid typioparam,
attribute_buf.data[fld_size] = '\0';
/* Call the column type's binary input converter */
- result = FunctionCall2(flinfo,
+ result = FunctionCall3(flinfo,
PointerGetDatum(&attribute_buf),
- ObjectIdGetDatum(typioparam));
+ ObjectIdGetDatum(typioparam),
+ Int32GetDatum(typmod));
/* Trouble if it didn't eat the whole buffer */
if (attribute_buf.cursor != attribute_buf.len)
diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c
index e5f2a2f762..7406e15376 100644
--- a/src/backend/commands/typecmds.c
+++ b/src/backend/commands/typecmds.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/typecmds.c,v 1.74 2005/07/07 20:39:58 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/typecmds.c,v 1.75 2005/07/10 21:13:58 tgl Exp $
*
* DESCRIPTION
* The "DefineFoo" routines take the parse tree and pick out the
@@ -859,7 +859,7 @@ findTypeInputFunction(List *procname, Oid typeOid)
/*
* Input functions can take a single argument of type CSTRING, or
- * three arguments (string, element OID, typmod).
+ * three arguments (string, typioparam OID, typmod).
*
* For backwards compatibility we allow OPAQUE in place of CSTRING; if we
* see this, we issue a warning and fix up the pg_proc entry.
@@ -973,12 +973,12 @@ findTypeOutputFunction(List *procname, Oid typeOid)
static Oid
findTypeReceiveFunction(List *procname, Oid typeOid)
{
- Oid argList[2];
+ Oid argList[3];
Oid procOid;
/*
* Receive functions can take a single argument of type INTERNAL, or
- * two arguments (internal, oid).
+ * three arguments (internal, typioparam OID, typmod).
*/
argList[0] = INTERNALOID;
@@ -987,8 +987,9 @@ findTypeReceiveFunction(List *procname, Oid typeOid)
return procOid;
argList[1] = OIDOID;
+ argList[2] = INT4OID;
- procOid = LookupFuncName(procname, 2, argList, true);
+ procOid = LookupFuncName(procname, 3, argList, true);
if (OidIsValid(procOid))
return procOid;
diff --git a/src/backend/tcop/fastpath.c b/src/backend/tcop/fastpath.c
index bd9b490378..a870f2c9c8 100644
--- a/src/backend/tcop/fastpath.c
+++ b/src/backend/tcop/fastpath.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/tcop/fastpath.c,v 1.80 2005/05/01 18:56:18 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/tcop/fastpath.c,v 1.81 2005/07/10 21:13:58 tgl Exp $
*
* NOTES
* This cruft is the server side of PQfn.
@@ -493,9 +493,10 @@ parse_fcall_arguments(StringInfo msgBuf, struct fp_info * fip,
/* Call the argument type's binary input converter */
getTypeBinaryInputInfo(fip->argtypes[i], &typreceive, &typioparam);
- fcinfo->arg[i] = OidFunctionCall2(typreceive,
+ fcinfo->arg[i] = OidFunctionCall3(typreceive,
PointerGetDatum(&abuf),
- ObjectIdGetDatum(typioparam));
+ ObjectIdGetDatum(typioparam),
+ Int32GetDatum(-1));
/* Trouble if it didn't eat the whole buffer */
if (abuf.cursor != abuf.len)
@@ -579,9 +580,10 @@ parse_fcall_arguments_20(StringInfo msgBuf, struct fp_info * fip,
/* Call the argument type's binary input converter */
getTypeBinaryInputInfo(fip->argtypes[i], &typreceive, &typioparam);
- fcinfo->arg[i] = OidFunctionCall2(typreceive,
+ fcinfo->arg[i] = OidFunctionCall3(typreceive,
PointerGetDatum(&abuf),
- ObjectIdGetDatum(typioparam));
+ ObjectIdGetDatum(typioparam),
+ Int32GetDatum(-1));
/* Trouble if it didn't eat the whole buffer */
if (abuf.cursor != abuf.len)
diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c
index 6973e9d3b3..038a482239 100644
--- a/src/backend/tcop/postgres.c
+++ b/src/backend/tcop/postgres.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/tcop/postgres.c,v 1.452 2005/07/04 04:51:49 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/tcop/postgres.c,v 1.453 2005/07/10 21:13:58 tgl Exp $
*
* NOTES
* this is the "main" module of the postgres backend and
@@ -1571,9 +1571,10 @@ exec_bind_message(StringInfo input_message)
getTypeBinaryInputInfo(ptype, &typreceive, &typioparam);
params[i].value =
- OidFunctionCall2(typreceive,
+ OidFunctionCall3(typreceive,
PointerGetDatum(&pbuf),
- ObjectIdGetDatum(typioparam));
+ ObjectIdGetDatum(typioparam),
+ Int32GetDatum(-1));
/* Trouble if it didn't eat the whole buffer */
if (pbuf.cursor != pbuf.len)
diff --git a/src/backend/utils/adt/arrayfuncs.c b/src/backend/utils/adt/arrayfuncs.c
index 794b95e229..07edd7014d 100644
--- a/src/backend/utils/adt/arrayfuncs.c
+++ b/src/backend/utils/adt/arrayfuncs.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/utils/adt/arrayfuncs.c,v 1.120 2005/05/01 18:56:18 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/adt/arrayfuncs.c,v 1.121 2005/07/10 21:13:58 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -81,7 +81,7 @@ static Datum *ReadArrayStr(char *arrayStr, const char *origStr,
int typlen, bool typbyval, char typalign,
int *nbytes);
static Datum *ReadArrayBinary(StringInfo buf, int nitems,
- FmgrInfo *receiveproc, Oid typioparam,
+ FmgrInfo *receiveproc, Oid typioparam, int32 typmod,
int typlen, bool typbyval, char typalign,
int *nbytes);
static void CopyArrayEls(char *p, Datum *values, int nitems,
@@ -1121,6 +1121,8 @@ array_recv(PG_FUNCTION_ARGS)
StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
Oid spec_element_type = PG_GETARG_OID(1); /* type of an array
* element */
+ int32 typmod = PG_GETARG_INT32(2); /* typmod for array
+ * elements */
Oid element_type;
int typlen;
bool typbyval;
@@ -1215,7 +1217,8 @@ array_recv(PG_FUNCTION_ARGS)
typalign = my_extra->typalign;
typioparam = my_extra->typioparam;
- dataPtr = ReadArrayBinary(buf, nitems, &my_extra->proc, typioparam,
+ dataPtr = ReadArrayBinary(buf, nitems, &my_extra->proc,
+ typioparam, typmod,
typlen, typbyval, typalign,
&nbytes);
nbytes += ARR_OVERHEAD(ndim);
@@ -1249,6 +1252,7 @@ ReadArrayBinary(StringInfo buf,
int nitems,
FmgrInfo *receiveproc,
Oid typioparam,
+ int32 typmod,
int typlen,
bool typbyval,
char typalign,
@@ -1289,9 +1293,10 @@ ReadArrayBinary(StringInfo buf,
buf->data[buf->cursor] = '\0';
/* Now call the element's receiveproc */
- values[i] = FunctionCall2(receiveproc,
+ values[i] = FunctionCall3(receiveproc,
PointerGetDatum(&elem_buf),
- ObjectIdGetDatum(typioparam));
+ ObjectIdGetDatum(typioparam),
+ Int32GetDatum(typmod));
/* Trouble if it didn't eat the whole buffer */
if (elem_buf.cursor != itemlen)
diff --git a/src/backend/utils/adt/date.c b/src/backend/utils/adt/date.c
index abc6155594..4f8f96075d 100644
--- a/src/backend/utils/adt/date.c
+++ b/src/backend/utils/adt/date.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/utils/adt/date.c,v 1.110 2005/06/15 00:34:08 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/adt/date.c,v 1.111 2005/07/10 21:13:59 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -982,12 +982,21 @@ Datum
time_recv(PG_FUNCTION_ARGS)
{
StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
+#ifdef NOT_USED
+ Oid typelem = PG_GETARG_OID(1);
+#endif
+ int32 typmod = PG_GETARG_INT32(2);
+ TimeADT result;
#ifdef HAVE_INT64_TIMESTAMP
- PG_RETURN_TIMEADT((TimeADT) pq_getmsgint64(buf));
+ result = pq_getmsgint64(buf);
#else
- PG_RETURN_TIMEADT((TimeADT) pq_getmsgfloat8(buf));
+ result = pq_getmsgfloat8(buf);
#endif
+
+ AdjustTimeForTypmod(&result, typmod);
+
+ PG_RETURN_TIMEADT(result);
}
/*
@@ -1774,18 +1783,24 @@ Datum
timetz_recv(PG_FUNCTION_ARGS)
{
StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
- TimeTzADT *time;
+#ifdef NOT_USED
+ Oid typelem = PG_GETARG_OID(1);
+#endif
+ int32 typmod = PG_GETARG_INT32(2);
+ TimeTzADT *result;
- time = (TimeTzADT *) palloc(sizeof(TimeTzADT));
+ result = (TimeTzADT *) palloc(sizeof(TimeTzADT));
#ifdef HAVE_INT64_TIMESTAMP
- time->time = pq_getmsgint64(buf);
+ result->time = pq_getmsgint64(buf);
#else
- time->time = pq_getmsgfloat8(buf);
+ result->time = pq_getmsgfloat8(buf);
#endif
- time->zone = pq_getmsgint(buf, sizeof(time->zone));
+ result->zone = pq_getmsgint(buf, sizeof(result->zone));
- PG_RETURN_TIMETZADT_P(time);
+ AdjustTimeForTypmod(&(result->time), typmod);
+
+ PG_RETURN_TIMETZADT_P(result);
}
/*
diff --git a/src/backend/utils/adt/numeric.c b/src/backend/utils/adt/numeric.c
index 8b39bb4248..4aa631ee57 100644
--- a/src/backend/utils/adt/numeric.c
+++ b/src/backend/utils/adt/numeric.c
@@ -14,7 +14,7 @@
* Copyright (c) 1998-2005, PostgreSQL Global Development Group
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/utils/adt/numeric.c,v 1.84 2005/06/04 14:12:50 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/adt/numeric.c,v 1.85 2005/07/10 21:13:59 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -383,6 +383,10 @@ Datum
numeric_recv(PG_FUNCTION_ARGS)
{
StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
+#ifdef NOT_USED
+ Oid typelem = PG_GETARG_OID(1);
+#endif
+ int32 typmod = PG_GETARG_INT32(2);
NumericVar value;
Numeric res;
int len,
@@ -419,6 +423,8 @@ numeric_recv(PG_FUNCTION_ARGS)
value.digits[i] = d;
}
+ apply_typmod(&value, typmod);
+
res = make_result(&value);
free_var(&value);
diff --git a/src/backend/utils/adt/rowtypes.c b/src/backend/utils/adt/rowtypes.c
index d3a151a8ab..07a5cf54ee 100644
--- a/src/backend/utils/adt/rowtypes.c
+++ b/src/backend/utils/adt/rowtypes.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/utils/adt/rowtypes.c,v 1.11 2005/05/01 18:56:18 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/adt/rowtypes.c,v 1.12 2005/07/10 21:13:59 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -54,6 +54,9 @@ record_in(PG_FUNCTION_ARGS)
{
char *string = PG_GETARG_CSTRING(0);
Oid tupType = PG_GETARG_OID(1);
+#ifdef NOT_USED
+ int32 typmod = PG_GETARG_INT32(2);
+#endif
HeapTupleHeader result;
int32 tupTypmod;
TupleDesc tupdesc;
@@ -417,6 +420,9 @@ record_recv(PG_FUNCTION_ARGS)
{
StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
Oid tupType = PG_GETARG_OID(1);
+#ifdef NOT_USED
+ int32 typmod = PG_GETARG_INT32(2);
+#endif
HeapTupleHeader result;
int32 tupTypmod;
TupleDesc tupdesc;
@@ -560,10 +566,10 @@ record_recv(PG_FUNCTION_ARGS)
column_info->column_type = column_type;
}
- values[i] = FunctionCall2(&column_info->proc,
+ values[i] = FunctionCall3(&column_info->proc,
PointerGetDatum(&item_buf),
- ObjectIdGetDatum(column_info->typioparam));
-
+ ObjectIdGetDatum(column_info->typioparam),
+ Int32GetDatum(tupdesc->attrs[i]->atttypmod));
nulls[i] = ' ';
/* Trouble if it didn't eat the whole buffer */
diff --git a/src/backend/utils/adt/timestamp.c b/src/backend/utils/adt/timestamp.c
index 8b64711e63..0f928ef574 100644
--- a/src/backend/utils/adt/timestamp.c
+++ b/src/backend/utils/adt/timestamp.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/utils/adt/timestamp.c,v 1.129 2005/07/04 14:38:31 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/adt/timestamp.c,v 1.130 2005/07/10 21:13:59 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -170,6 +170,10 @@ Datum
timestamp_recv(PG_FUNCTION_ARGS)
{
StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
+#ifdef NOT_USED
+ Oid typelem = PG_GETARG_OID(1);
+#endif
+ int32 typmod = PG_GETARG_INT32(2);
Timestamp timestamp;
struct pg_tm tt,
*tm = &tt;
@@ -177,7 +181,6 @@ timestamp_recv(PG_FUNCTION_ARGS)
#ifdef HAVE_INT64_TIMESTAMP
timestamp = (Timestamp) pq_getmsgint64(buf);
-
#else
timestamp = (Timestamp) pq_getmsgfloat8(buf);
#endif
@@ -185,11 +188,13 @@ timestamp_recv(PG_FUNCTION_ARGS)
/* rangecheck: see if timestamp_out would like it */
if (TIMESTAMP_NOT_FINITE(timestamp))
/* ok */ ;
- else if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) !=0)
+ else if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) != 0)
ereport(ERROR,
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
errmsg("timestamp out of range")));
+ AdjustTimestampForTypmod(×tamp, typmod);
+
PG_RETURN_TIMESTAMP(timestamp);
}
@@ -409,6 +414,10 @@ Datum
timestamptz_recv(PG_FUNCTION_ARGS)
{
StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
+#ifdef NOT_USED
+ Oid typelem = PG_GETARG_OID(1);
+#endif
+ int32 typmod = PG_GETARG_INT32(2);
TimestampTz timestamp;
int tz;
struct pg_tm tt,
@@ -418,7 +427,6 @@ timestamptz_recv(PG_FUNCTION_ARGS)
#ifdef HAVE_INT64_TIMESTAMP
timestamp = (TimestampTz) pq_getmsgint64(buf);
-
#else
timestamp = (TimestampTz) pq_getmsgfloat8(buf);
#endif
@@ -431,6 +439,8 @@ timestamptz_recv(PG_FUNCTION_ARGS)
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
errmsg("timestamp out of range")));
+ AdjustTimestampForTypmod(×tamp, typmod);
+
PG_RETURN_TIMESTAMPTZ(timestamp);
}
@@ -526,7 +536,6 @@ interval_in(PG_FUNCTION_ARGS)
ereport(ERROR,
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
errmsg("interval out of range")));
- AdjustIntervalForTypmod(result, typmod);
break;
case DTK_INVALID:
@@ -540,6 +549,8 @@ interval_in(PG_FUNCTION_ARGS)
dtype, str);
}
+ AdjustIntervalForTypmod(result, typmod);
+
PG_RETURN_INTERVAL_P(result);
}
@@ -573,18 +584,23 @@ Datum
interval_recv(PG_FUNCTION_ARGS)
{
StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
+#ifdef NOT_USED
+ Oid typelem = PG_GETARG_OID(1);
+#endif
+ int32 typmod = PG_GETARG_INT32(2);
Interval *interval;
interval = (Interval *) palloc(sizeof(Interval));
#ifdef HAVE_INT64_TIMESTAMP
interval->time = pq_getmsgint64(buf);
-
#else
interval->time = pq_getmsgfloat8(buf);
#endif
interval->month = pq_getmsgint(buf, sizeof(interval->month));
+ AdjustIntervalForTypmod(interval, typmod);
+
PG_RETURN_INTERVAL_P(interval);
}
diff --git a/src/backend/utils/adt/varbit.c b/src/backend/utils/adt/varbit.c
index bdbf43c899..1996638d28 100644
--- a/src/backend/utils/adt/varbit.c
+++ b/src/backend/utils/adt/varbit.c
@@ -9,7 +9,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/utils/adt/varbit.c,v 1.44 2004/12/31 22:01:22 pgsql Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/adt/varbit.c,v 1.45 2005/07/10 21:13:59 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -221,8 +221,49 @@ bit_out(PG_FUNCTION_ARGS)
Datum
bit_recv(PG_FUNCTION_ARGS)
{
- /* Exactly the same as varbit_recv, so share code */
- return varbit_recv(fcinfo);
+ StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
+#ifdef NOT_USED
+ Oid typelem = PG_GETARG_OID(1);
+#endif
+ int32 atttypmod = PG_GETARG_INT32(2);
+ VarBit *result;
+ int len,
+ bitlen;
+ int ipad;
+ bits8 mask;
+
+ bitlen = pq_getmsgint(buf, sizeof(int32));
+ if (bitlen < 0)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
+ errmsg("invalid length in external bit string")));
+
+ /*
+ * Sometimes atttypmod is not supplied. If it is supplied we need to
+ * make sure that the bitstring fits.
+ */
+ if (atttypmod > 0 && bitlen != atttypmod)
+ ereport(ERROR,
+ (errcode(ERRCODE_STRING_DATA_LENGTH_MISMATCH),
+ errmsg("bit string length %d does not match type bit(%d)",
+ bitlen, atttypmod)));
+
+ len = VARBITTOTALLEN(bitlen);
+ result = (VarBit *) palloc(len);
+ VARATT_SIZEP(result) = len;
+ VARBITLEN(result) = bitlen;
+
+ pq_copymsgbytes(buf, (char *) VARBITS(result), VARBITBYTES(result));
+
+ /* Make sure last byte is zero-padded if needed */
+ ipad = VARBITPAD(result);
+ if (ipad > 0)
+ {
+ mask = BITMASK << ipad;
+ *(VARBITS(result) + VARBITBYTES(result) - 1) &= mask;
+ }
+
+ PG_RETURN_VARBIT_P(result);
}
/*
@@ -459,6 +500,10 @@ Datum
varbit_recv(PG_FUNCTION_ARGS)
{
StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
+#ifdef NOT_USED
+ Oid typelem = PG_GETARG_OID(1);
+#endif
+ int32 atttypmod = PG_GETARG_INT32(2);
VarBit *result;
int len,
bitlen;
@@ -471,6 +516,16 @@ varbit_recv(PG_FUNCTION_ARGS)
(errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
errmsg("invalid length in external bit string")));
+ /*
+ * Sometimes atttypmod is not supplied. If it is supplied we need to
+ * make sure that the bitstring fits.
+ */
+ if (atttypmod > 0 && bitlen > atttypmod)
+ ereport(ERROR,
+ (errcode(ERRCODE_STRING_DATA_RIGHT_TRUNCATION),
+ errmsg("bit string too long for type bit varying(%d)",
+ atttypmod)));
+
len = VARBITTOTALLEN(bitlen);
result = (VarBit *) palloc(len);
VARATT_SIZEP(result) = len;
diff --git a/src/backend/utils/adt/varchar.c b/src/backend/utils/adt/varchar.c
index 6d89b3df2f..5c5c1075c7 100644
--- a/src/backend/utils/adt/varchar.c
+++ b/src/backend/utils/adt/varchar.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/utils/adt/varchar.c,v 1.110 2005/05/29 20:15:59 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/adt/varchar.c,v 1.111 2005/07/10 21:13:59 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -16,6 +16,8 @@
#include "access/hash.h"
#include "catalog/pg_type.h"
+#include "lib/stringinfo.h"
+#include "libpq/pqformat.h"
#include "miscadmin.h"
#include "utils/array.h"
#include "utils/builtins.h"
@@ -53,28 +55,25 @@
*****************************************************************************/
/*
- * Convert a C string to CHARACTER internal representation. atttypmod
- * is the declared length of the type plus VARHDRSZ.
+ * bpchar_input -- common guts of bpcharin and bpcharrecv
*
- * If the C string is too long, raise an error, unless the extra
+ * s is the input text of length len (may not be null-terminated)
+ * atttypmod is the typmod value to apply
+ *
+ * Note that atttypmod is measured in characters, which
+ * is not necessarily the same as the number of bytes.
+ *
+ * If the input string is too long, raise an error, unless the extra
* characters are spaces, in which case they're truncated. (per SQL)
*/
-Datum
-bpcharin(PG_FUNCTION_ARGS)
+static BpChar *
+bpchar_input(const char *s, size_t len, int32 atttypmod)
{
- char *s = PG_GETARG_CSTRING(0);
-
-#ifdef NOT_USED
- Oid typelem = PG_GETARG_OID(1);
-#endif
- int32 atttypmod = PG_GETARG_INT32(2);
BpChar *result;
char *r;
- size_t len,
- maxlen;
+ size_t maxlen;
/* verify encoding */
- len = strlen(s);
pg_verifymbstr(s, len, false);
/* If typmod is -1 (or invalid), use the actual string length */
@@ -85,30 +84,32 @@ bpcharin(PG_FUNCTION_ARGS)
size_t charlen; /* number of CHARACTERS in the input */
maxlen = atttypmod - VARHDRSZ;
- charlen = pg_mbstrlen(s);
+ charlen = pg_mbstrlen_with_len(s, len);
if (charlen > maxlen)
{
/* Verify that extra characters are spaces, and clip them off */
size_t mbmaxlen = pg_mbcharcliplen(s, len, maxlen);
+ size_t j;
/*
* at this point, len is the actual BYTE length of the input
* string, maxlen is the max number of CHARACTERS allowed for this
- * bpchar type.
+ * bpchar type, mbmaxlen is the length in BYTES of those chars.
*/
- if (strspn(s + mbmaxlen, " ") == len - mbmaxlen)
- len = mbmaxlen;
- else
- ereport(ERROR,
- (errcode(ERRCODE_STRING_DATA_RIGHT_TRUNCATION),
- errmsg("value too long for type character(%d)",
- (int) maxlen)));
+ for (j = mbmaxlen; j < len; j++)
+ {
+ if (s[j] != ' ')
+ ereport(ERROR,
+ (errcode(ERRCODE_STRING_DATA_RIGHT_TRUNCATION),
+ errmsg("value too long for type character(%d)",
+ (int) maxlen)));
+ }
/*
* Now we set maxlen to the necessary byte length, not
* the number of CHARACTERS!
*/
- maxlen = len;
+ maxlen = len = mbmaxlen;
}
else
{
@@ -120,7 +121,7 @@ bpcharin(PG_FUNCTION_ARGS)
}
}
- result = palloc(maxlen + VARHDRSZ);
+ result = (BpChar *) palloc(maxlen + VARHDRSZ);
VARATT_SIZEP(result) = maxlen + VARHDRSZ;
r = VARDATA(result);
memcpy(r, s, len);
@@ -129,6 +130,24 @@ bpcharin(PG_FUNCTION_ARGS)
if (maxlen > len)
memset(r + len, ' ', maxlen - len);
+ return result;
+}
+
+/*
+ * Convert a C string to CHARACTER internal representation. atttypmod
+ * is the declared length of the type plus VARHDRSZ.
+ */
+Datum
+bpcharin(PG_FUNCTION_ARGS)
+{
+ char *s = PG_GETARG_CSTRING(0);
+#ifdef NOT_USED
+ Oid typelem = PG_GETARG_OID(1);
+#endif
+ int32 atttypmod = PG_GETARG_INT32(2);
+ BpChar *result;
+
+ result = bpchar_input(s, strlen(s), atttypmod);
PG_RETURN_BPCHAR_P(result);
}
@@ -158,8 +177,19 @@ bpcharout(PG_FUNCTION_ARGS)
Datum
bpcharrecv(PG_FUNCTION_ARGS)
{
- /* Exactly the same as textrecv, so share code */
- return textrecv(fcinfo);
+ StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
+#ifdef NOT_USED
+ Oid typelem = PG_GETARG_OID(1);
+#endif
+ int32 atttypmod = PG_GETARG_INT32(2);
+ BpChar *result;
+ char *str;
+ int nbytes;
+
+ str = pq_getmsgtext(buf, buf->len - buf->cursor, &nbytes);
+ result = bpchar_input(str, nbytes, atttypmod);
+ pfree(str);
+ PG_RETURN_BPCHAR_P(result);
}
/*
@@ -344,30 +374,24 @@ name_bpchar(PG_FUNCTION_ARGS)
*****************************************************************************/
/*
- * Convert a C string to VARCHAR internal representation. atttypmod
- * is the declared length of the type plus VARHDRSZ.
+ * varchar_input -- common guts of varcharin and varcharrecv
*
- * Note that atttypmod is regarded as the number of characters, which
+ * s is the input text of length len (may not be null-terminated)
+ * atttypmod is the typmod value to apply
+ *
+ * Note that atttypmod is measured in characters, which
* is not necessarily the same as the number of bytes.
*
- * If the C string is too long, raise an error, unless the extra characters
- * are spaces, in which case they're truncated. (per SQL)
+ * If the input string is too long, raise an error, unless the extra
+ * characters are spaces, in which case they're truncated. (per SQL)
*/
-Datum
-varcharin(PG_FUNCTION_ARGS)
+static VarChar *
+varchar_input(const char *s, size_t len, int32 atttypmod)
{
- char *s = PG_GETARG_CSTRING(0);
-
-#ifdef NOT_USED
- Oid typelem = PG_GETARG_OID(1);
-#endif
- int32 atttypmod = PG_GETARG_INT32(2);
VarChar *result;
- size_t len,
- maxlen;
+ size_t maxlen;
/* verify encoding */
- len = strlen(s);
pg_verifymbstr(s, len, false);
maxlen = atttypmod - VARHDRSZ;
@@ -376,20 +400,42 @@ varcharin(PG_FUNCTION_ARGS)
{
/* Verify that extra characters are spaces, and clip them off */
size_t mbmaxlen = pg_mbcharcliplen(s, len, maxlen);
+ size_t j;
- if (strspn(s + mbmaxlen, " ") == len - mbmaxlen)
- len = mbmaxlen;
- else
- ereport(ERROR,
- (errcode(ERRCODE_STRING_DATA_RIGHT_TRUNCATION),
- errmsg("value too long for type character varying(%d)",
- (int) maxlen)));
+ for (j = mbmaxlen; j < len; j++)
+ {
+ if (s[j] != ' ')
+ ereport(ERROR,
+ (errcode(ERRCODE_STRING_DATA_RIGHT_TRUNCATION),
+ errmsg("value too long for type character varying(%d)",
+ (int) maxlen)));
+ }
+
+ len = mbmaxlen;
}
- result = palloc(len + VARHDRSZ);
+ result = (VarChar *) palloc(len + VARHDRSZ);
VARATT_SIZEP(result) = len + VARHDRSZ;
memcpy(VARDATA(result), s, len);
+ return result;
+}
+
+/*
+ * Convert a C string to VARCHAR internal representation. atttypmod
+ * is the declared length of the type plus VARHDRSZ.
+ */
+Datum
+varcharin(PG_FUNCTION_ARGS)
+{
+ char *s = PG_GETARG_CSTRING(0);
+#ifdef NOT_USED
+ Oid typelem = PG_GETARG_OID(1);
+#endif
+ int32 atttypmod = PG_GETARG_INT32(2);
+ VarChar *result;
+
+ result = varchar_input(s, strlen(s), atttypmod);
PG_RETURN_VARCHAR_P(result);
}
@@ -419,8 +465,19 @@ varcharout(PG_FUNCTION_ARGS)
Datum
varcharrecv(PG_FUNCTION_ARGS)
{
- /* Exactly the same as textrecv, so share code */
- return textrecv(fcinfo);
+ StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
+#ifdef NOT_USED
+ Oid typelem = PG_GETARG_OID(1);
+#endif
+ int32 atttypmod = PG_GETARG_INT32(2);
+ VarChar *result;
+ char *str;
+ int nbytes;
+
+ str = pq_getmsgtext(buf, buf->len - buf->cursor, &nbytes);
+ result = varchar_input(str, nbytes, atttypmod);
+ pfree(str);
+ PG_RETURN_VARCHAR_P(result);
}
/*
diff --git a/src/backend/utils/adt/varlena.c b/src/backend/utils/adt/varlena.c
index ba40747df4..9b57a497a1 100644
--- a/src/backend/utils/adt/varlena.c
+++ b/src/backend/utils/adt/varlena.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/utils/adt/varlena.c,v 1.127 2005/07/10 04:54:30 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/adt/varlena.c,v 1.128 2005/07/10 21:13:59 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -299,6 +299,10 @@ textrecv(PG_FUNCTION_ARGS)
int nbytes;
str = pq_getmsgtext(buf, buf->len - buf->cursor, &nbytes);
+
+ /* verify encoding */
+ pg_verifymbstr(str, nbytes, false);
+
result = (text *) palloc(nbytes + VARHDRSZ);
VARATT_SIZEP(result) = nbytes + VARHDRSZ;
memcpy(VARDATA(result), str, nbytes);
diff --git a/src/backend/utils/mb/mbutils.c b/src/backend/utils/mb/mbutils.c
index 541f9c2a5d..a670bcce62 100644
--- a/src/backend/utils/mb/mbutils.c
+++ b/src/backend/utils/mb/mbutils.c
@@ -4,7 +4,7 @@
* (currently mule internal code (mic) is used)
* Tatsuo Ishii
*
- * $PostgreSQL: pgsql/src/backend/utils/mb/mbutils.c,v 1.49 2005/03/07 04:30:52 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/mb/mbutils.c,v 1.50 2005/07/10 21:13:59 tgl Exp $
*/
#include "postgres.h"
@@ -489,16 +489,21 @@ pg_mbstrlen(const unsigned char *mbstr)
}
/* returns the length (counted as a wchar) of a multibyte string
- (not necessarily NULL terminated) */
+ * (not necessarily NULL terminated)
+ */
int
pg_mbstrlen_with_len(const unsigned char *mbstr, int limit)
{
int len = 0;
- int l;
+
+ /* optimization for single byte encoding */
+ if (pg_database_encoding_max_length() == 1)
+ return limit;
while (limit > 0 && *mbstr)
{
- l = pg_mblen(mbstr);
+ int l = pg_mblen(mbstr);
+
limit -= l;
mbstr += l;
len++;
diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h
index 3452b246d1..5ce6b4724e 100644
--- a/src/include/catalog/catversion.h
+++ b/src/include/catalog/catversion.h
@@ -37,7 +37,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.287 2005/07/10 04:54:31 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.288 2005/07/10 21:13:59 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -53,6 +53,6 @@
*/
/* yyyymmddN */
-#define CATALOG_VERSION_NO 200507101
+#define CATALOG_VERSION_NO 200507102
#endif
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index 9ea413a6f5..f0ecaa9d9b 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.375 2005/07/10 04:54:31 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.376 2005/07/10 21:13:59 tgl Exp $
*
* NOTES
* The script catalog/genbki.sh reads this file and generates .bki
@@ -3236,7 +3236,7 @@ DESCR("current user privilege on tablespace by tablespace name");
DATA(insert OID = 2395 ( has_tablespace_privilege PGNSP PGUID 12 f f t f s 2 16 "26 25" _null_ _null_ _null_ has_tablespace_privilege_id - _null_ ));
DESCR("current user privilege on tablespace by tablespace oid");
-DATA(insert OID = 2290 ( record_in PGNSP PGUID 12 f f t f v 2 2249 "2275 26" _null_ _null_ _null_ record_in - _null_ ));
+DATA(insert OID = 2290 ( record_in PGNSP PGUID 12 f f t f v 3 2249 "2275 26 23" _null_ _null_ _null_ record_in - _null_ ));
DESCR("I/O");
DATA(insert OID = 2291 ( record_out PGNSP PGUID 12 f f t f v 1 2275 "2249" _null_ _null_ _null_ record_out - _null_ ));
DESCR("I/O");
@@ -3377,11 +3377,11 @@ DESCR("less-equal-greater");
/* send/receive functions */
-DATA(insert OID = 2400 ( array_recv PGNSP PGUID 12 f f t f s 2 2277 "2281 26" _null_ _null_ _null_ array_recv - _null_ ));
+DATA(insert OID = 2400 ( array_recv PGNSP PGUID 12 f f t f s 3 2277 "2281 26 23" _null_ _null_ _null_ array_recv - _null_ ));
DESCR("I/O");
DATA(insert OID = 2401 ( array_send PGNSP PGUID 12 f f t f s 1 17 "2277" _null_ _null_ _null_ array_send - _null_ ));
DESCR("I/O");
-DATA(insert OID = 2402 ( record_recv PGNSP PGUID 12 f f t f v 2 2249 "2281 26" _null_ _null_ _null_ record_recv - _null_ ));
+DATA(insert OID = 2402 ( record_recv PGNSP PGUID 12 f f t f v 3 2249 "2281 26 23" _null_ _null_ _null_ record_recv - _null_ ));
DESCR("I/O");
DATA(insert OID = 2403 ( record_send PGNSP PGUID 12 f f t f v 1 17 "2249" _null_ _null_ _null_ record_send - _null_ ));
DESCR("I/O");
@@ -3437,11 +3437,11 @@ DATA(insert OID = 2428 ( point_recv PGNSP PGUID 12 f f t f i 1 600 "2281" _
DESCR("I/O");
DATA(insert OID = 2429 ( point_send PGNSP PGUID 12 f f t f i 1 17 "600" _null_ _null_ _null_ point_send - _null_ ));
DESCR("I/O");
-DATA(insert OID = 2430 ( bpcharrecv PGNSP PGUID 12 f f t f s 1 1042 "2281" _null_ _null_ _null_ bpcharrecv - _null_ ));
+DATA(insert OID = 2430 ( bpcharrecv PGNSP PGUID 12 f f t f s 3 1042 "2281 26 23" _null_ _null_ _null_ bpcharrecv - _null_ ));
DESCR("I/O");
DATA(insert OID = 2431 ( bpcharsend PGNSP PGUID 12 f f t f s 1 17 "1042" _null_ _null_ _null_ bpcharsend - _null_ ));
DESCR("I/O");
-DATA(insert OID = 2432 ( varcharrecv PGNSP PGUID 12 f f t f s 1 1043 "2281" _null_ _null_ _null_ varcharrecv - _null_ ));
+DATA(insert OID = 2432 ( varcharrecv PGNSP PGUID 12 f f t f s 3 1043 "2281 26 23" _null_ _null_ _null_ varcharrecv - _null_ ));
DESCR("I/O");
DATA(insert OID = 2433 ( varcharsend PGNSP PGUID 12 f f t f s 1 17 "1043" _null_ _null_ _null_ varcharsend - _null_ ));
DESCR("I/O");
@@ -3489,15 +3489,15 @@ DATA(insert OID = 2454 ( regtyperecv PGNSP PGUID 12 f f t f i 1 2206 "2281"
DESCR("I/O");
DATA(insert OID = 2455 ( regtypesend PGNSP PGUID 12 f f t f i 1 17 "2206" _null_ _null_ _null_ regtypesend - _null_ ));
DESCR("I/O");
-DATA(insert OID = 2456 ( bit_recv PGNSP PGUID 12 f f t f i 1 1560 "2281" _null_ _null_ _null_ bit_recv - _null_ ));
+DATA(insert OID = 2456 ( bit_recv PGNSP PGUID 12 f f t f i 3 1560 "2281 26 23" _null_ _null_ _null_ bit_recv - _null_ ));
DESCR("I/O");
DATA(insert OID = 2457 ( bit_send PGNSP PGUID 12 f f t f i 1 17 "1560" _null_ _null_ _null_ bit_send - _null_ ));
DESCR("I/O");
-DATA(insert OID = 2458 ( varbit_recv PGNSP PGUID 12 f f t f i 1 1562 "2281" _null_ _null_ _null_ varbit_recv - _null_ ));
+DATA(insert OID = 2458 ( varbit_recv PGNSP PGUID 12 f f t f i 3 1562 "2281 26 23" _null_ _null_ _null_ varbit_recv - _null_ ));
DESCR("I/O");
DATA(insert OID = 2459 ( varbit_send PGNSP PGUID 12 f f t f i 1 17 "1562" _null_ _null_ _null_ varbit_send - _null_ ));
DESCR("I/O");
-DATA(insert OID = 2460 ( numeric_recv PGNSP PGUID 12 f f t f i 1 1700 "2281" _null_ _null_ _null_ numeric_recv - _null_ ));
+DATA(insert OID = 2460 ( numeric_recv PGNSP PGUID 12 f f t f i 3 1700 "2281 26 23" _null_ _null_ _null_ numeric_recv - _null_ ));
DESCR("I/O");
DATA(insert OID = 2461 ( numeric_send PGNSP PGUID 12 f f t f i 1 17 "1700" _null_ _null_ _null_ numeric_send - _null_ ));
DESCR("I/O");
@@ -3517,23 +3517,23 @@ DATA(insert OID = 2468 ( date_recv PGNSP PGUID 12 f f t f i 1 1082 "2281"
DESCR("I/O");
DATA(insert OID = 2469 ( date_send PGNSP PGUID 12 f f t f i 1 17 "1082" _null_ _null_ _null_ date_send - _null_ ));
DESCR("I/O");
-DATA(insert OID = 2470 ( time_recv PGNSP PGUID 12 f f t f i 1 1083 "2281" _null_ _null_ _null_ time_recv - _null_ ));
+DATA(insert OID = 2470 ( time_recv PGNSP PGUID 12 f f t f i 3 1083 "2281 26 23" _null_ _null_ _null_ time_recv - _null_ ));
DESCR("I/O");
DATA(insert OID = 2471 ( time_send PGNSP PGUID 12 f f t f i 1 17 "1083" _null_ _null_ _null_ time_send - _null_ ));
DESCR("I/O");
-DATA(insert OID = 2472 ( timetz_recv PGNSP PGUID 12 f f t f i 1 1266 "2281" _null_ _null_ _null_ timetz_recv - _null_ ));
+DATA(insert OID = 2472 ( timetz_recv PGNSP PGUID 12 f f t f i 3 1266 "2281 26 23" _null_ _null_ _null_ timetz_recv - _null_ ));
DESCR("I/O");
DATA(insert OID = 2473 ( timetz_send PGNSP PGUID 12 f f t f i 1 17 "1266" _null_ _null_ _null_ timetz_send - _null_ ));
DESCR("I/O");
-DATA(insert OID = 2474 ( timestamp_recv PGNSP PGUID 12 f f t f i 1 1114 "2281" _null_ _null_ _null_ timestamp_recv - _null_ ));
+DATA(insert OID = 2474 ( timestamp_recv PGNSP PGUID 12 f f t f i 3 1114 "2281 26 23" _null_ _null_ _null_ timestamp_recv - _null_ ));
DESCR("I/O");
DATA(insert OID = 2475 ( timestamp_send PGNSP PGUID 12 f f t f i 1 17 "1114" _null_ _null_ _null_ timestamp_send - _null_ ));
DESCR("I/O");
-DATA(insert OID = 2476 ( timestamptz_recv PGNSP PGUID 12 f f t f i 1 1184 "2281" _null_ _null_ _null_ timestamptz_recv - _null_ ));
+DATA(insert OID = 2476 ( timestamptz_recv PGNSP PGUID 12 f f t f i 3 1184 "2281 26 23" _null_ _null_ _null_ timestamptz_recv - _null_ ));
DESCR("I/O");
DATA(insert OID = 2477 ( timestamptz_send PGNSP PGUID 12 f f t f i 1 17 "1184" _null_ _null_ _null_ timestamptz_send - _null_ ));
DESCR("I/O");
-DATA(insert OID = 2478 ( interval_recv PGNSP PGUID 12 f f t f i 1 1186 "2281" _null_ _null_ _null_ interval_recv - _null_ ));
+DATA(insert OID = 2478 ( interval_recv PGNSP PGUID 12 f f t f i 3 1186 "2281 26 23" _null_ _null_ _null_ interval_recv - _null_ ));
DESCR("I/O");
DATA(insert OID = 2479 ( interval_send PGNSP PGUID 12 f f t f i 1 17 "1186" _null_ _null_ _null_ interval_send - _null_ ));
DESCR("I/O");
diff --git a/src/test/regress/expected/type_sanity.out b/src/test/regress/expected/type_sanity.out
index 0eb6bb8e96..73d51925c2 100644
--- a/src/test/regress/expected/type_sanity.out
+++ b/src/test/regress/expected/type_sanity.out
@@ -69,11 +69,10 @@ WHERE p1.typtype in ('b') AND p1.typname NOT LIKE E'\\_%' AND NOT EXISTS
705 | unknown
(2 rows)
--- Conversion routines must be provided except in 'c' entries.
+-- Text conversion routines must be provided.
SELECT p1.oid, p1.typname
FROM pg_type as p1
-WHERE p1.typtype != 'c' AND
- (p1.typinput = 0 OR p1.typoutput = 0);
+WHERE (p1.typinput = 0 OR p1.typoutput = 0);
oid | typname
-----+---------
(0 rows)
@@ -83,8 +82,6 @@ SELECT p1.oid, p1.typname, p2.oid, p2.proname
FROM pg_type AS p1, pg_proc AS p2
WHERE p1.typinput = p2.oid AND p1.typtype in ('b', 'p') AND NOT
((p2.pronargs = 1 AND p2.proargtypes[0] = 'cstring'::regtype) OR
- (p2.pronargs = 2 AND p2.proargtypes[0] = 'cstring'::regtype AND
- p2.proargtypes[1] = 'oid'::regtype) OR
(p2.pronargs = 3 AND p2.proargtypes[0] = 'cstring'::regtype AND
p2.proargtypes[1] = 'oid'::regtype AND
p2.proargtypes[2] = 'int4'::regtype));
@@ -148,8 +145,9 @@ SELECT p1.oid, p1.typname, p2.oid, p2.proname
FROM pg_type AS p1, pg_proc AS p2
WHERE p1.typreceive = p2.oid AND p1.typtype in ('b', 'p') AND NOT
((p2.pronargs = 1 AND p2.proargtypes[0] = 'internal'::regtype) OR
- (p2.pronargs = 2 AND p2.proargtypes[0] = 'internal'::regtype AND
- p2.proargtypes[1] = 'oid'::regtype));
+ (p2.pronargs = 3 AND p2.proargtypes[0] = 'internal'::regtype AND
+ p2.proargtypes[1] = 'oid'::regtype AND
+ p2.proargtypes[2] = 'int4'::regtype));
oid | typname | oid | proname
-----+---------+-----+---------
(0 rows)
@@ -181,6 +179,15 @@ ORDER BY 1;
30 | oidvector | 2420 | oidvectorrecv
(2 rows)
+-- Suspicious if typreceive doesn't take same number of args as typinput
+SELECT p1.oid, p1.typname, p2.oid, p2.proname, p3.oid, p3.proname
+FROM pg_type AS p1, pg_proc AS p2, pg_proc AS p3
+WHERE p1.typinput = p2.oid AND p1.typreceive = p3.oid AND
+ p2.pronargs != p3.pronargs;
+ oid | typname | oid | proname | oid | proname
+-----+---------+-----+---------+-----+---------
+(0 rows)
+
-- Check for bogus typsend routines
-- As of 7.4, this check finds refcursor, which is borrowing
-- other types' I/O routines
diff --git a/src/test/regress/sql/type_sanity.sql b/src/test/regress/sql/type_sanity.sql
index 20f6a75ffa..3969b4cce2 100644
--- a/src/test/regress/sql/type_sanity.sql
+++ b/src/test/regress/sql/type_sanity.sql
@@ -59,12 +59,11 @@ WHERE p1.typtype in ('b') AND p1.typname NOT LIKE E'\\_%' AND NOT EXISTS
WHERE p2.typname = ('_' || p1.typname)::name AND
p2.typelem = p1.oid);
--- Conversion routines must be provided except in 'c' entries.
+-- Text conversion routines must be provided.
SELECT p1.oid, p1.typname
FROM pg_type as p1
-WHERE p1.typtype != 'c' AND
- (p1.typinput = 0 OR p1.typoutput = 0);
+WHERE (p1.typinput = 0 OR p1.typoutput = 0);
-- Check for bogus typinput routines
@@ -72,8 +71,6 @@ SELECT p1.oid, p1.typname, p2.oid, p2.proname
FROM pg_type AS p1, pg_proc AS p2
WHERE p1.typinput = p2.oid AND p1.typtype in ('b', 'p') AND NOT
((p2.pronargs = 1 AND p2.proargtypes[0] = 'cstring'::regtype) OR
- (p2.pronargs = 2 AND p2.proargtypes[0] = 'cstring'::regtype AND
- p2.proargtypes[1] = 'oid'::regtype) OR
(p2.pronargs = 3 AND p2.proargtypes[0] = 'cstring'::regtype AND
p2.proargtypes[1] = 'oid'::regtype AND
p2.proargtypes[2] = 'int4'::regtype));
@@ -120,8 +117,9 @@ SELECT p1.oid, p1.typname, p2.oid, p2.proname
FROM pg_type AS p1, pg_proc AS p2
WHERE p1.typreceive = p2.oid AND p1.typtype in ('b', 'p') AND NOT
((p2.pronargs = 1 AND p2.proargtypes[0] = 'internal'::regtype) OR
- (p2.pronargs = 2 AND p2.proargtypes[0] = 'internal'::regtype AND
- p2.proargtypes[1] = 'oid'::regtype));
+ (p2.pronargs = 3 AND p2.proargtypes[0] = 'internal'::regtype AND
+ p2.proargtypes[1] = 'oid'::regtype AND
+ p2.proargtypes[2] = 'int4'::regtype));
-- As of 7.4, this check finds refcursor, which is borrowing
-- other types' I/O routines
@@ -141,6 +139,12 @@ WHERE p1.typreceive = p2.oid AND p1.typtype in ('b', 'p') AND
(p2.oid = 'array_recv'::regproc)
ORDER BY 1;
+-- Suspicious if typreceive doesn't take same number of args as typinput
+SELECT p1.oid, p1.typname, p2.oid, p2.proname, p3.oid, p3.proname
+FROM pg_type AS p1, pg_proc AS p2, pg_proc AS p3
+WHERE p1.typinput = p2.oid AND p1.typreceive = p3.oid AND
+ p2.pronargs != p3.pronargs;
+
-- Check for bogus typsend routines
-- As of 7.4, this check finds refcursor, which is borrowing