From d78397d301172cccce14d5d789f296c47dd47c5e Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Sun, 10 Jul 2005 21:14:00 +0000 Subject: [PATCH] Change typreceive function API so that receive functions get the same optional arguments as text input functions, ie, typioparam OID and atttypmod. Make all the datatypes that use typmod enforce it the same way in typreceive as they do in typinput. This fixes a problem with failure to enforce length restrictions during COPY FROM BINARY. --- doc/src/sgml/ref/create_type.sgml | 15 +- src/backend/commands/copy.c | 18 ++- src/backend/commands/typecmds.c | 11 +- src/backend/tcop/fastpath.c | 12 +- src/backend/tcop/postgres.c | 7 +- src/backend/utils/adt/arrayfuncs.c | 15 +- src/backend/utils/adt/date.c | 33 +++-- src/backend/utils/adt/numeric.c | 8 +- src/backend/utils/adt/rowtypes.c | 14 +- src/backend/utils/adt/timestamp.c | 28 +++- src/backend/utils/adt/varbit.c | 61 +++++++- src/backend/utils/adt/varchar.c | 165 +++++++++++++++------- src/backend/utils/adt/varlena.c | 6 +- src/backend/utils/mb/mbutils.c | 13 +- src/include/catalog/catversion.h | 4 +- src/include/catalog/pg_proc.h | 28 ++-- src/test/regress/expected/type_sanity.out | 21 ++- src/test/regress/sql/type_sanity.sql | 18 ++- 18 files changed, 333 insertions(+), 144 deletions(-) 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