diff --git a/doc/src/sgml/ref/create_type.sgml b/doc/src/sgml/ref/create_type.sgml index 69899d84f53d7b94ab45db3fa04077837d256433..4f002b65194974bbb4ee7e776ea937b0b5cf3e69 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 10e68684b8e6e62f3e141b6a05da72f4eb8e1637..d25189d0ac34174ef23f75a2cfa60e6eb7cd11cc 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 e5f2a2f762bc7281827c5b51c58d023bd3752548..7406e15376abd7d76b4ff8e3e37df93d974a4d4e 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 bd9b490378592d113fcc90991b31d61aecd8727c..a870f2c9c883c59a6efa940b11f8292259f8b277 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 6973e9d3b3cb48fd566ead7ecbb23425b04de60c..038a482239f0c4a4dad63da2b60b7ee2bcd6bbb7 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 794b95e22975d2be4b786789348ffcf1a0f8f76a..07edd7014da341c0233046af9342164624fc573b 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 abc6155594f137f242268fb8deff5d36c26da894..4f8f96075d92448683ce5a1f6c2feab61213039c 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)); + + AdjustTimeForTypmod(&(result->time), typmod); - PG_RETURN_TIMETZADT_P(time); + PG_RETURN_TIMETZADT_P(result); } /* diff --git a/src/backend/utils/adt/numeric.c b/src/backend/utils/adt/numeric.c index 8b39bb4248cc97caf4ce421b8db9d8ee180e0041..4aa631ee5778df3b4726c804e3effd27e3ca12bf 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 d3a151a8ab14778f3184c21bfa6549e88c1614dc..07a5cf54eeaab3e93446104c37f5f8bee3e540cb 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 8b64711e63548e9493bc82b5ca59a916fab1513b..0f928ef57494d7494d4c043bca20682467bb084c 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 bdbf43c8993b3cd919278c2a06f9803ffc59c0af..1996638d28ea9f23503e4aaecbfcfcd8eb9eb616 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 6d89b3df2f70b9ed488d080804ba7984623eaeea..5c5c1075c71a0a9d4fab6b7a3e64674ddb6dbf13 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 + * + * s is the input text of length len (may not be null-terminated) + * atttypmod is the typmod value to apply * - * If the C string is too long, raise an error, unless the extra + * 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 + * + * s is the input text of length len (may not be null-terminated) + * atttypmod is the typmod value to apply * - * Note that atttypmod is regarded as the number of characters, which + * 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 ba40747df41c4a0c3bbcaa6bbd1f0e73c9f06432..9b57a497a1d713169dbbe09ab356fb6f8c9777c2 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 541f9c2a5d302a6e1611bca9c9aade540d63cc26..a670bcce624c975825b8806c2bd31d8de4dd5dc3 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 3452b246d17537adfb02e56891ccd7ea5178d805..5ce6b4724e12f905e57a4f761f7671a07a4a385d 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 9ea413a6f541c3bf59e652c0015e594d1c241a8a..f0ecaa9d9baebeefbb1ff2d3a12f8fc2e092036c 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 0eb6bb8e9613c53af17562842b5f0609c86ba866..73d51925c2ffaab57d4327dba2819f1fbf9f2d16 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 20f6a75ffae9f5ad6af61a775cce828f0f0f104b..3969b4cce2ef4808dcfeac26d294cf6a30d13f5a 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