<!--
-$PostgreSQL: pgsql/doc/src/sgml/ref/create_type.sgml,v 1.55 2005/05/01 18:56:17 tgl Exp $
+$PostgreSQL: pgsql/doc/src/sgml/ref/create_type.sgml,v 1.56 2005/07/10 21:13:57 tgl Exp $
PostgreSQL documentation
-->
function should perform adequate checking to ensure that the value is
valid.
The receive function may be declared as taking one argument of type
- <type>internal</type>, or two arguments of types <type>internal</type>
- and <type>oid</type>. It must return a value of the data type itself.
- (The first argument is a pointer to a <type>StringInfo</type> 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
+ <type>internal</type>, or as taking three arguments of types
+ <type>internal</type>, <type>oid</type>, <type>integer</type>.
+ The first argument is a pointer to a <type>StringInfo</type> 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
<replaceable class="parameter">send_function</replaceable> converts
from the internal representation to the external binary representation.
If this function is not supplied, the type cannot participate in binary
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
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);
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,
values[m] = CopyReadBinaryAttribute(i,
&in_functions[m],
typioparams[m],
+ attr[m]->atttypmod,
&isnull);
nulls[m] = isnull ? 'n' : ' ';
copy_attname = NULL;
* 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;
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)
*
*
* 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
/*
* 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.
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;
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;
*
*
* 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.
/* 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)
/* 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)
*
*
* 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
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)
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
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,
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;
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);
int nitems,
FmgrInfo *receiveproc,
Oid typioparam,
+ int32 typmod,
int typlen,
bool typbyval,
char typalign,
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)
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
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);
}
/*
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);
}
/*
* 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 $
*
*-------------------------------------------------------------------------
*/
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,
value.digits[i] = d;
}
+ apply_typmod(&value, typmod);
+
res = make_result(&value);
free_var(&value);
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
{
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;
{
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;
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 */
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
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;
#ifdef HAVE_INT64_TIMESTAMP
timestamp = (Timestamp) pq_getmsgint64(buf);
-
#else
timestamp = (Timestamp) pq_getmsgfloat8(buf);
#endif
/* 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);
}
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,
#ifdef HAVE_INT64_TIMESTAMP
timestamp = (TimestampTz) pq_getmsgint64(buf);
-
#else
timestamp = (TimestampTz) pq_getmsgfloat8(buf);
#endif
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
errmsg("timestamp out of range")));
+ AdjustTimestampForTypmod(×tamp, typmod);
+
PG_RETURN_TIMESTAMPTZ(timestamp);
}
ereport(ERROR,
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
errmsg("interval out of range")));
- AdjustIntervalForTypmod(result, typmod);
break;
case DTK_INVALID:
dtype, str);
}
+ AdjustIntervalForTypmod(result, typmod);
+
PG_RETURN_INTERVAL_P(result);
}
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);
}
* 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 $
*
*-------------------------------------------------------------------------
*/
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);
}
/*
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;
(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;
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
#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"
*****************************************************************************/
/*
- * 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 */
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
{
}
}
- result = palloc(maxlen + VARHDRSZ);
+ result = (BpChar *) palloc(maxlen + VARHDRSZ);
VARATT_SIZEP(result) = maxlen + VARHDRSZ;
r = VARDATA(result);
memcpy(r, s, len);
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);
}
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);
}
/*
*****************************************************************************/
/*
- * 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;
{
/* 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);
}
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);
}
/*
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
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);
* (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"
}
/* 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++;
* 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 $
*
*-------------------------------------------------------------------------
*/
*/
/* yyyymmddN */
-#define CATALOG_VERSION_NO 200507101
+#define CATALOG_VERSION_NO 200507102
#endif
* 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
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");
/* 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");
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");
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");
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");
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)
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));
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)
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
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
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));
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
(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