aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backend/access/common/printtup.c18
-rw-r--r--src/backend/bootstrap/bootstrap.c25
-rw-r--r--src/backend/commands/copy.c45
-rw-r--r--src/backend/executor/execTuples.c23
-rw-r--r--src/backend/executor/nodeAgg.c8
-rw-r--r--src/backend/executor/spi.c11
-rw-r--r--src/backend/nodes/print.c5
-rw-r--r--src/backend/parser/parse_coerce.c35
-rw-r--r--src/backend/parser/parse_type.c11
-rw-r--r--src/backend/tcop/fastpath.c89
-rw-r--r--src/backend/tcop/postgres.c128
-rw-r--r--src/backend/utils/adt/arrayfuncs.c26
-rw-r--r--src/backend/utils/adt/rowtypes.c91
-rw-r--r--src/backend/utils/adt/ruleutils.c5
-rw-r--r--src/backend/utils/adt/varlena.c5
-rw-r--r--src/backend/utils/cache/lsyscache.c8
-rw-r--r--src/backend/utils/fmgr/fmgr.c168
-rw-r--r--src/include/fmgr.h18
-rw-r--r--src/pl/plperl/plperl.c109
-rw-r--r--src/pl/plpgsql/src/pl_exec.c29
-rw-r--r--src/pl/plpython/plpython.c72
-rw-r--r--src/pl/tcl/pltcl.c50
22 files changed, 586 insertions, 393 deletions
diff --git a/src/backend/access/common/printtup.c b/src/backend/access/common/printtup.c
index 3ba606dfaf1..ba5793b0e7e 100644
--- a/src/backend/access/common/printtup.c
+++ b/src/backend/access/common/printtup.c
@@ -9,7 +9,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/access/common/printtup.c,v 1.94 2006/03/05 15:58:20 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/access/common/printtup.c,v 1.95 2006/04/04 19:35:33 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -331,8 +331,7 @@ printtup(TupleTableSlot *slot, DestReceiver *self)
/* Text output */
char *outputstr;
- outputstr = DatumGetCString(FunctionCall1(&thisState->finfo,
- attr));
+ outputstr = OutputFunctionCall(&thisState->finfo, attr);
pq_sendcountedtext(&buf, outputstr, strlen(outputstr), false);
pfree(outputstr);
}
@@ -341,9 +340,7 @@ printtup(TupleTableSlot *slot, DestReceiver *self)
/* Binary output */
bytea *outputbytes;
- outputbytes = DatumGetByteaP(FunctionCall1(&thisState->finfo,
- attr));
- /* We assume the result will not have been toasted */
+ outputbytes = SendFunctionCall(&thisState->finfo, attr);
pq_sendint(&buf, VARSIZE(outputbytes) - VARHDRSZ, 4);
pq_sendbytes(&buf, VARDATA(outputbytes),
VARSIZE(outputbytes) - VARHDRSZ);
@@ -429,8 +426,7 @@ printtup_20(TupleTableSlot *slot, DestReceiver *self)
else
attr = origattr;
- outputstr = DatumGetCString(FunctionCall1(&thisState->finfo,
- attr));
+ outputstr = OutputFunctionCall(&thisState->finfo, attr);
pq_sendcountedtext(&buf, outputstr, strlen(outputstr), true);
pfree(outputstr);
@@ -542,8 +538,7 @@ debugtup(TupleTableSlot *slot, DestReceiver *self)
else
attr = origattr;
- value = DatumGetCString(OidFunctionCall1(typoutput,
- attr));
+ value = OidOutputFunctionCall(typoutput, attr);
printatt((unsigned) i + 1, typeinfo->attrs[i], value);
@@ -632,8 +627,7 @@ printtup_internal_20(TupleTableSlot *slot, DestReceiver *self)
else
attr = origattr;
- outputbytes = DatumGetByteaP(FunctionCall1(&thisState->finfo,
- attr));
+ outputbytes = SendFunctionCall(&thisState->finfo, attr);
/* We assume the result will not have been toasted */
pq_sendint(&buf, VARSIZE(outputbytes) - VARHDRSZ, 4);
pq_sendbytes(&buf, VARDATA(outputbytes),
diff --git a/src/backend/bootstrap/bootstrap.c b/src/backend/bootstrap/bootstrap.c
index 1d48fc44e18..c1d16b0e8fc 100644
--- a/src/backend/bootstrap/bootstrap.c
+++ b/src/backend/bootstrap/bootstrap.c
@@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/bootstrap/bootstrap.c,v 1.213 2006/03/07 01:03:12 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/bootstrap/bootstrap.c,v 1.214 2006/04/04 19:35:33 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -826,11 +826,11 @@ InsertOneValue(char *value, int i)
if (ap == NULL)
elog(ERROR, "could not find atttypid %u in Typ list", typoid);
- /* XXX this should match getTypeIOParam() */
- if (ap->am_typ.typtype == 'c')
- typioparam = typoid;
- else
+ /* XXX this logic should match getTypeIOParam() */
+ if (OidIsValid(ap->am_typ.typelem))
typioparam = ap->am_typ.typelem;
+ else
+ typioparam = typoid;
typinput = ap->am_typ.typinput;
typoutput = ap->am_typ.typoutput;
@@ -850,19 +850,18 @@ InsertOneValue(char *value, int i)
elog(ERROR, "type oid %u not found", typoid);
elog(DEBUG5, "Typ == NULL, typeindex = %u", typeindex);
- /* XXX there are no composite types in TypInfo */
- typioparam = TypInfo[typeindex].elem;
+ /* XXX this logic should match getTypeIOParam() */
+ if (OidIsValid(TypInfo[typeindex].elem))
+ typioparam = TypInfo[typeindex].elem;
+ else
+ typioparam = typoid;
typinput = TypInfo[typeindex].inproc;
typoutput = TypInfo[typeindex].outproc;
}
- values[i] = OidFunctionCall3(typinput,
- CStringGetDatum(value),
- ObjectIdGetDatum(typioparam),
- Int32GetDatum(-1));
- prt = DatumGetCString(OidFunctionCall1(typoutput,
- values[i]));
+ values[i] = OidInputFunctionCall(typinput, value, typioparam, -1);
+ prt = OidOutputFunctionCall(typoutput, values[i]);
elog(DEBUG4, "inserted -> %s", prt);
pfree(prt);
}
diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index 23c057af8e0..af21d565f17 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.261 2006/03/23 00:19:29 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/copy.c,v 1.262 2006/04/04 19:35:33 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -1382,8 +1382,8 @@ CopyTo(CopyState cstate)
{
if (!cstate->binary)
{
- string = DatumGetCString(FunctionCall1(&out_functions[attnum - 1],
- value));
+ string = OutputFunctionCall(&out_functions[attnum - 1],
+ value);
if (cstate->csv_mode)
CopyAttributeOutCSV(cstate, string,
force_quote[attnum - 1],
@@ -1395,9 +1395,8 @@ CopyTo(CopyState cstate)
{
bytea *outputbytes;
- outputbytes = DatumGetByteaP(FunctionCall1(&out_functions[attnum - 1],
- value));
- /* We assume the result will not have been toasted */
+ outputbytes = SendFunctionCall(&out_functions[attnum - 1],
+ value);
CopySendInt32(cstate, VARSIZE(outputbytes) - VARHDRSZ);
CopySendData(cstate, VARDATA(outputbytes),
VARSIZE(outputbytes) - VARHDRSZ);
@@ -1459,6 +1458,13 @@ copy_in_error_callback(void *arg)
cstate->cur_attname, attval);
pfree(attval);
}
+ else if (cstate->cur_attname)
+ {
+ /* error is relevant to a particular column, value is NULL */
+ errcontext("COPY %s, line %d, column %s: NULL input",
+ cstate->cur_relname, cstate->cur_lineno,
+ cstate->cur_attname);
+ }
else
{
/* error is relevant to a particular line */
@@ -1854,19 +1860,16 @@ CopyFrom(CopyState cstate)
string = cstate->null_print;
}
- /* If we read an SQL NULL, no need to do anything */
+ cstate->cur_attname = NameStr(attr[m]->attname);
+ cstate->cur_attval = string;
+ values[m] = InputFunctionCall(&in_functions[m],
+ string,
+ typioparams[m],
+ attr[m]->atttypmod);
if (string != NULL)
- {
- cstate->cur_attname = NameStr(attr[m]->attname);
- cstate->cur_attval = string;
- values[m] = FunctionCall3(&in_functions[m],
- CStringGetDatum(string),
- ObjectIdGetDatum(typioparams[m]),
- Int32GetDatum(attr[m]->atttypmod));
nulls[m] = ' ';
- cstate->cur_attname = NULL;
- cstate->cur_attval = NULL;
- }
+ cstate->cur_attname = NULL;
+ cstate->cur_attval = NULL;
}
Assert(fieldno == nfields);
@@ -2900,7 +2903,7 @@ CopyReadBinaryAttribute(CopyState cstate,
if (fld_size == -1)
{
*isnull = true;
- return (Datum) 0;
+ return ReceiveFunctionCall(flinfo, NULL, typioparam, typmod);
}
if (fld_size < 0)
ereport(ERROR,
@@ -2924,10 +2927,8 @@ CopyReadBinaryAttribute(CopyState cstate,
cstate->attribute_buf.data[fld_size] = '\0';
/* Call the column type's binary input converter */
- result = FunctionCall3(flinfo,
- PointerGetDatum(&cstate->attribute_buf),
- ObjectIdGetDatum(typioparam),
- Int32GetDatum(typmod));
+ result = ReceiveFunctionCall(flinfo, &cstate->attribute_buf,
+ typioparam, typmod);
/* Trouble if it didn't eat the whole buffer */
if (cstate->attribute_buf.cursor != cstate->attribute_buf.len)
diff --git a/src/backend/executor/execTuples.c b/src/backend/executor/execTuples.c
index bd50027f776..81f589fd44b 100644
--- a/src/backend/executor/execTuples.c
+++ b/src/backend/executor/execTuples.c
@@ -15,7 +15,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/executor/execTuples.c,v 1.92 2006/03/05 15:58:26 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/executor/execTuples.c,v 1.93 2006/04/04 19:35:34 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -928,6 +928,7 @@ TupleDescGetAttInMetadata(TupleDesc tupdesc)
/*
* BuildTupleFromCStrings - build a HeapTuple given user data in C string form.
* values is an array of C strings, one for each attribute of the return tuple.
+ * A NULL string pointer indicates we want to create a NULL field.
*/
HeapTuple
BuildTupleFromCStrings(AttInMetadata *attinmeta, char **values)
@@ -937,35 +938,25 @@ BuildTupleFromCStrings(AttInMetadata *attinmeta, char **values)
Datum *dvalues;
char *nulls;
int i;
- Oid attioparam;
- int32 atttypmod;
HeapTuple tuple;
dvalues = (Datum *) palloc(natts * sizeof(Datum));
nulls = (char *) palloc(natts * sizeof(char));
- /* Call the "in" function for each non-null, non-dropped attribute */
+ /* Call the "in" function for each non-dropped attribute */
for (i = 0; i < natts; i++)
{
if (!tupdesc->attrs[i]->attisdropped)
{
/* Non-dropped attributes */
+ dvalues[i] = InputFunctionCall(&attinmeta->attinfuncs[i],
+ values[i],
+ attinmeta->attioparams[i],
+ attinmeta->atttypmods[i]);
if (values[i] != NULL)
- {
- attioparam = attinmeta->attioparams[i];
- atttypmod = attinmeta->atttypmods[i];
-
- dvalues[i] = FunctionCall3(&attinmeta->attinfuncs[i],
- CStringGetDatum(values[i]),
- ObjectIdGetDatum(attioparam),
- Int32GetDatum(atttypmod));
nulls[i] = ' ';
- }
else
- {
- dvalues[i] = (Datum) 0;
nulls[i] = 'n';
- }
}
else
{
diff --git a/src/backend/executor/nodeAgg.c b/src/backend/executor/nodeAgg.c
index 5b48545aac9..a242d53968e 100644
--- a/src/backend/executor/nodeAgg.c
+++ b/src/backend/executor/nodeAgg.c
@@ -61,7 +61,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/executor/nodeAgg.c,v 1.138 2006/03/05 15:58:26 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/executor/nodeAgg.c,v 1.139 2006/04/04 19:35:34 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -1407,10 +1407,8 @@ GetAggInitVal(Datum textInitVal, Oid transtype)
getTypeInputInfo(transtype, &typinput, &typioparam);
strInitVal = DatumGetCString(DirectFunctionCall1(textout, textInitVal));
- initVal = OidFunctionCall3(typinput,
- CStringGetDatum(strInitVal),
- ObjectIdGetDatum(typioparam),
- Int32GetDatum(-1));
+ initVal = OidInputFunctionCall(typinput, strInitVal,
+ typioparam, -1);
pfree(strInitVal);
return initVal;
}
diff --git a/src/backend/executor/spi.c b/src/backend/executor/spi.c
index 183bc89b020..3563ba23d3a 100644
--- a/src/backend/executor/spi.c
+++ b/src/backend/executor/spi.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/executor/spi.c,v 1.149 2006/03/14 22:48:19 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/executor/spi.c,v 1.150 2006/04/04 19:35:34 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -629,9 +629,9 @@ SPI_fname(TupleDesc tupdesc, int fnumber)
char *
SPI_getvalue(HeapTuple tuple, TupleDesc tupdesc, int fnumber)
{
+ char *result;
Datum origval,
- val,
- result;
+ val;
bool isnull;
Oid typoid,
foutoid;
@@ -666,14 +666,13 @@ SPI_getvalue(HeapTuple tuple, TupleDesc tupdesc, int fnumber)
else
val = origval;
- result = OidFunctionCall1(foutoid,
- val);
+ result = OidOutputFunctionCall(foutoid, val);
/* Clean up detoasted copy, if any */
if (val != origval)
pfree(DatumGetPointer(val));
- return DatumGetCString(result);
+ return result;
}
Datum
diff --git a/src/backend/nodes/print.c b/src/backend/nodes/print.c
index 18b7535cd06..c3fbdf242d0 100644
--- a/src/backend/nodes/print.c
+++ b/src/backend/nodes/print.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/nodes/print.c,v 1.78 2006/03/05 15:58:28 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/nodes/print.c,v 1.79 2006/04/04 19:35:34 tgl Exp $
*
* HISTORY
* AUTHOR DATE MAJOR EVENT
@@ -357,8 +357,7 @@ print_expr(Node *expr, List *rtable)
getTypeOutputInfo(c->consttype,
&typoutput, &typIsVarlena);
- outputstr = DatumGetCString(OidFunctionCall1(typoutput,
- c->constvalue));
+ outputstr = OidOutputFunctionCall(typoutput, c->constvalue);
printf("%s", outputstr);
pfree(outputstr);
}
diff --git a/src/backend/parser/parse_coerce.c b/src/backend/parser/parse_coerce.c
index bcb8e0016df..5a343e768dd 100644
--- a/src/backend/parser/parse_coerce.c
+++ b/src/backend/parser/parse_coerce.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/parser/parse_coerce.c,v 2.135 2006/03/05 15:58:33 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/parser/parse_coerce.c,v 2.136 2006/04/04 19:35:34 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -166,26 +166,21 @@ coerce_type(ParseState *pstate, Node *node,
newcon->constbyval = typeByVal(targetType);
newcon->constisnull = con->constisnull;
+ /*
+ * We pass typmod -1 to the input routine, primarily because
+ * existing input routines follow implicit-coercion semantics for
+ * length checks, which is not always what we want here. Any
+ * length constraint will be applied later by our caller.
+ *
+ * We assume here that UNKNOWN's internal representation is the
+ * same as CSTRING.
+ */
if (!con->constisnull)
- {
- /*
- * We assume here that UNKNOWN's internal representation is the
- * same as CSTRING
- */
- char *val = DatumGetCString(con->constvalue);
-
- /*
- * We pass typmod -1 to the input routine, primarily because
- * existing input routines follow implicit-coercion semantics for
- * length checks, which is not always what we want here. Any
- * length constraint will be applied later by our caller.
- *
- * Note that we call stringTypeDatum using the domain's pg_type
- * row, if it's a domain. This works because the domain row has
- * the same typinput and typelem as the base type --- ugly...
- */
- newcon->constvalue = stringTypeDatum(targetType, val, -1);
- }
+ newcon->constvalue = stringTypeDatum(targetType,
+ DatumGetCString(con->constvalue),
+ -1);
+ else
+ newcon->constvalue = stringTypeDatum(targetType, NULL, -1);
result = (Node *) newcon;
diff --git a/src/backend/parser/parse_type.c b/src/backend/parser/parse_type.c
index e88e6c37c1e..fec4552c9c4 100644
--- a/src/backend/parser/parse_type.c
+++ b/src/backend/parser/parse_type.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/parser/parse_type.c,v 1.79 2006/03/14 22:48:21 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/parser/parse_type.c,v 1.80 2006/04/04 19:35:35 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -326,7 +326,8 @@ typeTypeRelid(Type typ)
/*
* Given a type structure and a string, returns the internal representation
- * of that string
+ * of that string. The "string" can be NULL to perform conversion of a NULL
+ * (which might result in failure, if the input function rejects NULLs).
*/
Datum
stringTypeDatum(Type tp, char *string, int32 atttypmod)
@@ -336,10 +337,8 @@ stringTypeDatum(Type tp, char *string, int32 atttypmod)
typinput = ((Form_pg_type) GETSTRUCT(tp))->typinput;
typioparam = getTypeIOParam(tp);
- return OidFunctionCall3(typinput,
- CStringGetDatum(string),
- ObjectIdGetDatum(typioparam),
- Int32GetDatum(atttypmod));
+ return OidInputFunctionCall(typinput, string,
+ typioparam, atttypmod);
}
/* given a typeid, return the type's typrelid (associated relation, if any) */
diff --git a/src/backend/tcop/fastpath.c b/src/backend/tcop/fastpath.c
index f9a5d7116b1..c9fa715600f 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.85 2006/03/05 15:58:40 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/tcop/fastpath.c,v 1.86 2006/04/04 19:35:35 tgl Exp $
*
* NOTES
* This cruft is the server side of PQfn.
@@ -154,8 +154,7 @@ SendFunctionResult(Datum retval, bool isnull, Oid rettype, int16 format)
char *outputstr;
getTypeOutputInfo(rettype, &typoutput, &typisvarlena);
- outputstr = DatumGetCString(OidFunctionCall1(typoutput,
- retval));
+ outputstr = OidOutputFunctionCall(typoutput, retval);
pq_sendcountedtext(&buf, outputstr, strlen(outputstr), false);
pfree(outputstr);
}
@@ -166,9 +165,7 @@ SendFunctionResult(Datum retval, bool isnull, Oid rettype, int16 format)
bytea *outputbytes;
getTypeBinaryOutputInfo(rettype, &typsend, &typisvarlena);
- outputbytes = DatumGetByteaP(OidFunctionCall1(typsend,
- retval));
- /* We assume the result will not have been toasted */
+ outputbytes = OidSendFunctionCall(typsend, retval);
pq_sendint(&buf, VARSIZE(outputbytes) - VARHDRSZ, 4);
pq_sendbytes(&buf, VARDATA(outputbytes),
VARSIZE(outputbytes) - VARHDRSZ);
@@ -433,23 +430,25 @@ parse_fcall_arguments(StringInfo msgBuf, struct fp_info * fip,
if (argsize == -1)
{
fcinfo->argnull[i] = true;
- continue;
}
- fcinfo->argnull[i] = false;
- if (argsize < 0)
- ereport(ERROR,
- (errcode(ERRCODE_PROTOCOL_VIOLATION),
- errmsg("invalid argument size %d in function call message",
- argsize)));
-
- /* Reset abuf to empty, and insert raw data into it */
- abuf.len = 0;
- abuf.data[0] = '\0';
- abuf.cursor = 0;
-
- appendBinaryStringInfo(&abuf,
- pq_getmsgbytes(msgBuf, argsize),
- argsize);
+ else
+ {
+ fcinfo->argnull[i] = false;
+ if (argsize < 0)
+ ereport(ERROR,
+ (errcode(ERRCODE_PROTOCOL_VIOLATION),
+ errmsg("invalid argument size %d in function call message",
+ argsize)));
+
+ /* Reset abuf to empty, and insert raw data into it */
+ abuf.len = 0;
+ abuf.data[0] = '\0';
+ abuf.cursor = 0;
+
+ appendBinaryStringInfo(&abuf,
+ pq_getmsgbytes(msgBuf, argsize),
+ argsize);
+ }
if (numAFormats > 1)
aformat = aformats[i];
@@ -472,31 +471,36 @@ parse_fcall_arguments(StringInfo msgBuf, struct fp_info * fip,
* have to do encoding conversion before calling the typinput
* routine, though.
*/
- pstring = pg_client_to_server(abuf.data, argsize);
- fcinfo->arg[i] =
- OidFunctionCall3(typinput,
- CStringGetDatum(pstring),
- ObjectIdGetDatum(typioparam),
- Int32GetDatum(-1));
+ if (argsize == -1)
+ pstring = NULL;
+ else
+ pstring = pg_client_to_server(abuf.data, argsize);
+
+ fcinfo->arg[i] = OidInputFunctionCall(typinput, pstring,
+ typioparam, -1);
/* Free result of encoding conversion, if any */
- if (pstring != abuf.data)
+ if (pstring && pstring != abuf.data)
pfree(pstring);
}
else if (aformat == 1)
{
Oid typreceive;
Oid typioparam;
+ StringInfo bufptr;
/* Call the argument type's binary input converter */
getTypeBinaryInputInfo(fip->argtypes[i], &typreceive, &typioparam);
- fcinfo->arg[i] = OidFunctionCall3(typreceive,
- PointerGetDatum(&abuf),
- ObjectIdGetDatum(typioparam),
- Int32GetDatum(-1));
+ if (argsize == -1)
+ bufptr = NULL;
+ else
+ bufptr = &abuf;
+
+ fcinfo->arg[i] = OidReceiveFunctionCall(typreceive, bufptr,
+ typioparam, -1);
/* Trouble if it didn't eat the whole buffer */
- if (abuf.cursor != abuf.len)
+ if (argsize != -1 && abuf.cursor != abuf.len)
ereport(ERROR,
(errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
errmsg("incorrect binary data format in function argument %d",
@@ -552,18 +556,22 @@ parse_fcall_arguments_20(StringInfo msgBuf, struct fp_info * fip,
Oid typreceive;
Oid typioparam;
+ getTypeBinaryInputInfo(fip->argtypes[i], &typreceive, &typioparam);
+
argsize = pq_getmsgint(msgBuf, 4);
if (argsize == -1)
{
fcinfo->argnull[i] = true;
+ fcinfo->arg[i] = OidReceiveFunctionCall(typreceive, NULL,
+ typioparam, -1);
continue;
}
fcinfo->argnull[i] = false;
if (argsize < 0)
ereport(ERROR,
(errcode(ERRCODE_PROTOCOL_VIOLATION),
- errmsg("invalid argument size %d in function call message",
- argsize)));
+ errmsg("invalid argument size %d in function call message",
+ argsize)));
/* Reset abuf to empty, and insert raw data into it */
abuf.len = 0;
@@ -574,13 +582,8 @@ parse_fcall_arguments_20(StringInfo msgBuf, struct fp_info * fip,
pq_getmsgbytes(msgBuf, argsize),
argsize);
- /* Call the argument type's binary input converter */
- getTypeBinaryInputInfo(fip->argtypes[i], &typreceive, &typioparam);
-
- fcinfo->arg[i] = OidFunctionCall3(typreceive,
- PointerGetDatum(&abuf),
- ObjectIdGetDatum(typioparam),
- Int32GetDatum(-1));
+ fcinfo->arg[i] = OidReceiveFunctionCall(typreceive, &abuf,
+ typioparam, -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 78cb8c3f811..df9ef8983a0 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.482 2006/03/14 22:48:21 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/tcop/postgres.c,v 1.483 2006/04/04 19:35:35 tgl Exp $
*
* NOTES
* this is the "main" module of the postgres backend and
@@ -1486,6 +1486,9 @@ exec_bind_message(StringInfo input_message)
Oid ptype = lfirst_oid(l);
int32 plength;
bool isNull;
+ StringInfoData pbuf;
+ char csave;
+ int16 pformat;
plength = pq_getmsgint(input_message, 4);
isNull = (plength == -1);
@@ -1493,16 +1496,6 @@ exec_bind_message(StringInfo input_message)
if (!isNull)
{
const char *pvalue = pq_getmsgbytes(input_message, plength);
- int16 pformat;
- StringInfoData pbuf;
- char csave;
-
- if (numPFormats > 1)
- pformat = pformats[i];
- else if (numPFormats > 0)
- pformat = pformats[0];
- else
- pformat = 0; /* default = text */
/*
* Rather than copying data around, we just set up a phony
@@ -1519,63 +1512,80 @@ exec_bind_message(StringInfo input_message)
csave = pbuf.data[plength];
pbuf.data[plength] = '\0';
+ }
+ else
+ {
+ pbuf.data = NULL; /* keep compiler quiet */
+ csave = 0;
+ }
- if (pformat == 0)
- {
- Oid typinput;
- Oid typioparam;
- char *pstring;
+ if (numPFormats > 1)
+ pformat = pformats[i];
+ else if (numPFormats > 0)
+ pformat = pformats[0];
+ else
+ pformat = 0; /* default = text */
- getTypeInputInfo(ptype, &typinput, &typioparam);
+ if (pformat == 0)
+ {
+ Oid typinput;
+ Oid typioparam;
+ char *pstring;
- /*
- * We have to do encoding conversion before calling the
- * typinput routine.
- */
+ getTypeInputInfo(ptype, &typinput, &typioparam);
+
+ /*
+ * We have to do encoding conversion before calling the
+ * typinput routine.
+ */
+ if (isNull)
+ pstring = NULL;
+ else
pstring = pg_client_to_server(pbuf.data, plength);
- params[i].value =
- OidFunctionCall3(typinput,
- CStringGetDatum(pstring),
- ObjectIdGetDatum(typioparam),
- Int32GetDatum(-1));
- /* Free result of encoding conversion, if any */
- if (pstring != pbuf.data)
- pfree(pstring);
- }
- else if (pformat == 1)
- {
- Oid typreceive;
- Oid typioparam;
- /*
- * Call the parameter type's binary input converter
- */
- getTypeBinaryInputInfo(ptype, &typreceive, &typioparam);
-
- params[i].value =
- OidFunctionCall3(typreceive,
- PointerGetDatum(&pbuf),
- ObjectIdGetDatum(typioparam),
- Int32GetDatum(-1));
-
- /* Trouble if it didn't eat the whole buffer */
- if (pbuf.cursor != pbuf.len)
- ereport(ERROR,
- (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
- errmsg("incorrect binary data format in bind parameter %d",
- i + 1)));
- }
+ params[i].value = OidInputFunctionCall(typinput, pstring,
+ typioparam, -1);
+ /* Free result of encoding conversion, if any */
+ if (pstring && pstring != pbuf.data)
+ pfree(pstring);
+ }
+ else if (pformat == 1)
+ {
+ Oid typreceive;
+ Oid typioparam;
+ StringInfo bufptr;
+
+ /*
+ * Call the parameter type's binary input converter
+ */
+ getTypeBinaryInputInfo(ptype, &typreceive, &typioparam);
+
+ if (isNull)
+ bufptr = NULL;
else
- {
+ bufptr = &pbuf;
+
+ params[i].value = OidReceiveFunctionCall(typreceive, bufptr,
+ typioparam, -1);
+
+ /* Trouble if it didn't eat the whole buffer */
+ if (!isNull && pbuf.cursor != pbuf.len)
ereport(ERROR,
- (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
- errmsg("unsupported format code: %d",
- pformat)));
- }
+ (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
+ errmsg("incorrect binary data format in bind parameter %d",
+ i + 1)));
+ }
+ else
+ {
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("unsupported format code: %d",
+ pformat)));
+ }
- /* Restore message buffer contents */
+ /* Restore message buffer contents */
+ if (!isNull)
pbuf.data[plength] = csave;
- }
params[i].kind = PARAM_NUM;
params[i].id = i + 1;
diff --git a/src/backend/utils/adt/arrayfuncs.c b/src/backend/utils/adt/arrayfuncs.c
index 1de3ff13a7d..dba7353ba58 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.127 2006/03/05 15:58:41 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/adt/arrayfuncs.c,v 1.128 2006/04/04 19:35:35 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -787,14 +787,14 @@ ReadArrayStr(char *arrayStr,
pg_strcasecmp(itemstart, "NULL") == 0)
{
/* it's a NULL item */
+ values[i] = InputFunctionCall(inputproc, NULL,
+ typioparam, typmod);
nulls[i] = true;
}
else
{
- values[i] = FunctionCall3(inputproc,
- CStringGetDatum(itemstart),
- ObjectIdGetDatum(typioparam),
- Int32GetDatum(typmod));
+ values[i] = InputFunctionCall(inputproc, itemstart,
+ typioparam, typmod);
nulls[i] = false;
}
}
@@ -1018,8 +1018,7 @@ array_out(PG_FUNCTION_ARGS)
Datum itemvalue;
itemvalue = fetch_att(p, typbyval, typlen);
- values[i] = DatumGetCString(FunctionCall1(&my_extra->proc,
- itemvalue));
+ values[i] = OutputFunctionCall(&my_extra->proc, itemvalue);
p = att_addlength(p, typlen, PointerGetDatum(p));
p = (char *) att_align(p, typalign);
@@ -1357,6 +1356,8 @@ ReadArrayBinary(StringInfo buf,
if (itemlen == -1)
{
/* -1 length means NULL */
+ values[i] = ReceiveFunctionCall(receiveproc, NULL,
+ typioparam, typmod);
nulls[i] = true;
continue;
}
@@ -1378,10 +1379,8 @@ ReadArrayBinary(StringInfo buf,
buf->data[buf->cursor] = '\0';
/* Now call the element's receiveproc */
- values[i] = FunctionCall3(receiveproc,
- PointerGetDatum(&elem_buf),
- ObjectIdGetDatum(typioparam),
- Int32GetDatum(typmod));
+ values[i] = ReceiveFunctionCall(receiveproc, &elem_buf,
+ typioparam, typmod);
nulls[i] = false;
/* Trouble if it didn't eat the whole buffer */
@@ -1515,10 +1514,7 @@ array_send(PG_FUNCTION_ARGS)
bytea *outputbytes;
itemvalue = fetch_att(p, typbyval, typlen);
-
- outputbytes = DatumGetByteaP(FunctionCall1(&my_extra->proc,
- itemvalue));
- /* We assume the result will not have been toasted */
+ outputbytes = SendFunctionCall(&my_extra->proc, itemvalue);
pq_sendint(&buf, VARSIZE(outputbytes) - VARHDRSZ, 4);
pq_sendbytes(&buf, VARDATA(outputbytes),
VARSIZE(outputbytes) - VARHDRSZ);
diff --git a/src/backend/utils/adt/rowtypes.c b/src/backend/utils/adt/rowtypes.c
index 9d7fcaa413a..bb61dc29568 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.14 2006/03/05 15:58:43 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/adt/rowtypes.c,v 1.15 2006/04/04 19:35:36 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -136,6 +136,7 @@ record_in(PG_FUNCTION_ARGS)
{
ColumnIOData *column_info = &my_extra->columns[i];
Oid column_type = tupdesc->attrs[i]->atttypid;
+ char *column_data;
/* Ignore dropped columns in datatype, but fill with nulls */
if (tupdesc->attrs[i]->attisdropped)
@@ -161,7 +162,7 @@ record_in(PG_FUNCTION_ARGS)
/* Check for null: completely empty input means null */
if (*ptr == ',' || *ptr == ')')
{
- values[i] = (Datum) 0;
+ column_data = NULL;
nulls[i] = 'n';
}
else
@@ -207,27 +208,29 @@ record_in(PG_FUNCTION_ARGS)
appendStringInfoChar(&buf, ch);
}
- /*
- * Convert the column value
- */
- if (column_info->column_type != column_type)
- {
- getTypeInputInfo(column_type,
- &column_info->typiofunc,
- &column_info->typioparam);
- fmgr_info_cxt(column_info->typiofunc, &column_info->proc,
- fcinfo->flinfo->fn_mcxt);
- column_info->column_type = column_type;
- }
-
- values[i] = FunctionCall3(&column_info->proc,
- CStringGetDatum(buf.data),
- ObjectIdGetDatum(column_info->typioparam),
- Int32GetDatum(tupdesc->attrs[i]->atttypmod));
+ column_data = buf.data;
nulls[i] = ' ';
}
/*
+ * Convert the column value
+ */
+ if (column_info->column_type != column_type)
+ {
+ getTypeInputInfo(column_type,
+ &column_info->typiofunc,
+ &column_info->typioparam);
+ fmgr_info_cxt(column_info->typiofunc, &column_info->proc,
+ fcinfo->flinfo->fn_mcxt);
+ column_info->column_type = column_type;
+ }
+
+ values[i] = InputFunctionCall(&column_info->proc,
+ column_data,
+ column_info->typioparam,
+ tupdesc->attrs[i]->atttypmod);
+
+ /*
* Prep for next column
*/
needComma = true;
@@ -372,8 +375,7 @@ record_out(PG_FUNCTION_ARGS)
column_info->column_type = column_type;
}
- value = DatumGetCString(FunctionCall1(&column_info->proc,
- values[i]));
+ value = OutputFunctionCall(&column_info->proc, values[i]);
/* Detect whether we need double quotes for this value */
nq = (value[0] == '\0'); /* force quotes for empty string */
@@ -505,6 +507,9 @@ record_recv(PG_FUNCTION_ARGS)
Oid column_type = tupdesc->attrs[i]->atttypid;
Oid coltypoid;
int itemlen;
+ StringInfoData item_buf;
+ StringInfo bufptr;
+ char csave;
/* Ignore dropped columns in datatype, but fill with nulls */
if (tupdesc->attrs[i]->attisdropped)
@@ -532,8 +537,9 @@ record_recv(PG_FUNCTION_ARGS)
if (itemlen == -1)
{
/* -1 length means NULL */
- values[i] = (Datum) 0;
+ bufptr = NULL;
nulls[i] = 'n';
+ csave = 0; /* keep compiler quiet */
}
else
{
@@ -543,9 +549,6 @@ record_recv(PG_FUNCTION_ARGS)
* We assume we can scribble on the input buffer so as to maintain
* the convention that StringInfos have a trailing null.
*/
- StringInfoData item_buf;
- char csave;
-
item_buf.data = &buf->data[buf->cursor];
item_buf.maxlen = itemlen + 1;
item_buf.len = itemlen;
@@ -556,23 +559,28 @@ record_recv(PG_FUNCTION_ARGS)
csave = buf->data[buf->cursor];
buf->data[buf->cursor] = '\0';
- /* Now call the column's receiveproc */
- if (column_info->column_type != column_type)
- {
- getTypeBinaryInputInfo(column_type,
- &column_info->typiofunc,
- &column_info->typioparam);
- fmgr_info_cxt(column_info->typiofunc, &column_info->proc,
- fcinfo->flinfo->fn_mcxt);
- column_info->column_type = column_type;
- }
-
- values[i] = FunctionCall3(&column_info->proc,
- PointerGetDatum(&item_buf),
- ObjectIdGetDatum(column_info->typioparam),
- Int32GetDatum(tupdesc->attrs[i]->atttypmod));
+ bufptr = &item_buf;
nulls[i] = ' ';
+ }
+ /* Now call the column's receiveproc */
+ if (column_info->column_type != column_type)
+ {
+ getTypeBinaryInputInfo(column_type,
+ &column_info->typiofunc,
+ &column_info->typioparam);
+ fmgr_info_cxt(column_info->typiofunc, &column_info->proc,
+ fcinfo->flinfo->fn_mcxt);
+ column_info->column_type = column_type;
+ }
+
+ values[i] = ReceiveFunctionCall(&column_info->proc,
+ bufptr,
+ column_info->typioparam,
+ tupdesc->attrs[i]->atttypmod);
+
+ if (bufptr)
+ {
/* Trouble if it didn't eat the whole buffer */
if (item_buf.cursor != itemlen)
ereport(ERROR,
@@ -712,8 +720,7 @@ record_send(PG_FUNCTION_ARGS)
column_info->column_type = column_type;
}
- outputbytes = DatumGetByteaP(FunctionCall1(&column_info->proc,
- values[i]));
+ outputbytes = SendFunctionCall(&column_info->proc, values[i]);
/* We assume the result will not have been toasted */
pq_sendint(&buf, VARSIZE(outputbytes) - VARHDRSZ, 4);
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index 714140e0617..f8daab6eeaf 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -2,7 +2,7 @@
* ruleutils.c - Functions to convert stored expressions/querytrees
* back to source text
*
- * $PostgreSQL: pgsql/src/backend/utils/adt/ruleutils.c,v 1.217 2006/03/16 00:31:55 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/adt/ruleutils.c,v 1.218 2006/04/04 19:35:36 tgl Exp $
**********************************************************************/
#include "postgres.h"
@@ -3921,8 +3921,7 @@ get_const_expr(Const *constval, deparse_context *context)
getTypeOutputInfo(constval->consttype,
&typoutput, &typIsVarlena);
- extval = DatumGetCString(OidFunctionCall1(typoutput,
- constval->constvalue));
+ extval = OidOutputFunctionCall(typoutput, constval->constvalue);
switch (constval->consttype)
{
diff --git a/src/backend/utils/adt/varlena.c b/src/backend/utils/adt/varlena.c
index b936b8219dd..79dc0178a80 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.145 2006/03/05 15:58:44 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/adt/varlena.c,v 1.146 2006/04/04 19:35:36 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -2580,8 +2580,7 @@ array_to_text(PG_FUNCTION_ARGS)
{
itemvalue = fetch_att(p, typbyval, typlen);
- value = DatumGetCString(FunctionCall1(&my_extra->proc,
- itemvalue));
+ value = OutputFunctionCall(&my_extra->proc, itemvalue);
if (printed)
appendStringInfo(&buf, "%s%s", fldsep, value);
diff --git a/src/backend/utils/cache/lsyscache.c b/src/backend/utils/cache/lsyscache.c
index 6eb6ea802bf..fb24cc62366 100644
--- a/src/backend/utils/cache/lsyscache.c
+++ b/src/backend/utils/cache/lsyscache.c
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/utils/cache/lsyscache.c,v 1.132 2006/03/05 15:58:45 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/cache/lsyscache.c,v 1.133 2006/04/04 19:35:36 tgl Exp $
*
* NOTES
* Eventually, the index information should go through here, too.
@@ -1554,10 +1554,8 @@ get_typdefault(Oid typid)
strDefaultVal = DatumGetCString(DirectFunctionCall1(textout,
datum));
/* Convert C string to a value of the given type */
- datum = OidFunctionCall3(type->typinput,
- CStringGetDatum(strDefaultVal),
- ObjectIdGetDatum(getTypeIOParam(typeTuple)),
- Int32GetDatum(-1));
+ datum = OidInputFunctionCall(type->typinput, strDefaultVal,
+ getTypeIOParam(typeTuple), -1);
/* Build a Const node containing the value */
expr = (Node *) makeConst(typid,
type->typlen,
diff --git a/src/backend/utils/fmgr/fmgr.c b/src/backend/utils/fmgr/fmgr.c
index e64ede6f566..4a663135dcb 100644
--- a/src/backend/utils/fmgr/fmgr.c
+++ b/src/backend/utils/fmgr/fmgr.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/utils/fmgr/fmgr.c,v 1.99 2006/03/05 15:58:46 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/fmgr/fmgr.c,v 1.100 2006/04/04 19:35:36 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -1683,6 +1683,172 @@ OidFunctionCall9(Oid functionId, Datum arg1, Datum arg2,
/*
+ * Special cases for convenient invocation of datatype I/O functions.
+ */
+
+/*
+ * Call a previously-looked-up datatype input function.
+ *
+ * "str" may be NULL to indicate we are reading a NULL. In this case
+ * the caller should assume the result is NULL, but we'll call the input
+ * function anyway if it's not strict. So this is almost but not quite
+ * the same as FunctionCall3.
+ */
+Datum
+InputFunctionCall(FmgrInfo *flinfo, char *str, Oid typioparam, int32 typmod)
+{
+ FunctionCallInfoData fcinfo;
+ Datum result;
+
+ if (str == NULL && flinfo->fn_strict)
+ return (Datum) 0; /* just return null result */
+
+ InitFunctionCallInfoData(fcinfo, flinfo, 3, NULL, NULL);
+
+ fcinfo.arg[0] = CStringGetDatum(str);
+ fcinfo.arg[1] = ObjectIdGetDatum(typioparam);
+ fcinfo.arg[2] = Int32GetDatum(typmod);
+ fcinfo.argnull[0] = (str == NULL);
+ fcinfo.argnull[1] = false;
+ fcinfo.argnull[2] = false;
+
+ result = FunctionCallInvoke(&fcinfo);
+
+ /* Should get null result if and only if str is NULL */
+ if (str == NULL)
+ {
+ if (!fcinfo.isnull)
+ elog(ERROR, "input function %u returned non-NULL",
+ fcinfo.flinfo->fn_oid);
+ }
+ else
+ {
+ if (fcinfo.isnull)
+ elog(ERROR, "input function %u returned NULL",
+ fcinfo.flinfo->fn_oid);
+ }
+
+ return result;
+}
+
+/*
+ * Call a previously-looked-up datatype output function.
+ *
+ * Do not call this on NULL datums.
+ *
+ * This is mere window dressing for FunctionCall1, but its use is recommended
+ * anyway so that code invoking output functions can be identified easily.
+ */
+char *
+OutputFunctionCall(FmgrInfo *flinfo, Datum val)
+{
+ return DatumGetCString(FunctionCall1(flinfo, val));
+}
+
+/*
+ * Call a previously-looked-up datatype binary-input function.
+ *
+ * "buf" may be NULL to indicate we are reading a NULL. In this case
+ * the caller should assume the result is NULL, but we'll call the receive
+ * function anyway if it's not strict. So this is almost but not quite
+ * the same as FunctionCall3.
+ */
+Datum
+ReceiveFunctionCall(FmgrInfo *flinfo, StringInfo buf,
+ Oid typioparam, int32 typmod)
+{
+ FunctionCallInfoData fcinfo;
+ Datum result;
+
+ if (buf == NULL && flinfo->fn_strict)
+ return (Datum) 0; /* just return null result */
+
+ InitFunctionCallInfoData(fcinfo, flinfo, 3, NULL, NULL);
+
+ fcinfo.arg[0] = PointerGetDatum(buf);
+ fcinfo.arg[1] = ObjectIdGetDatum(typioparam);
+ fcinfo.arg[2] = Int32GetDatum(typmod);
+ fcinfo.argnull[0] = (buf == NULL);
+ fcinfo.argnull[1] = false;
+ fcinfo.argnull[2] = false;
+
+ result = FunctionCallInvoke(&fcinfo);
+
+ /* Should get null result if and only if buf is NULL */
+ if (buf == NULL)
+ {
+ if (!fcinfo.isnull)
+ elog(ERROR, "receive function %u returned non-NULL",
+ fcinfo.flinfo->fn_oid);
+ }
+ else
+ {
+ if (fcinfo.isnull)
+ elog(ERROR, "receive function %u returned NULL",
+ fcinfo.flinfo->fn_oid);
+ }
+
+ return result;
+}
+
+/*
+ * Call a previously-looked-up datatype binary-output function.
+ *
+ * Do not call this on NULL datums.
+ *
+ * This is little more than window dressing for FunctionCall1, but its use is
+ * recommended anyway so that code invoking output functions can be identified
+ * easily. Note however that it does guarantee a non-toasted result.
+ */
+bytea *
+SendFunctionCall(FmgrInfo *flinfo, Datum val)
+{
+ return DatumGetByteaP(FunctionCall1(flinfo, val));
+}
+
+/*
+ * As above, for I/O functions identified by OID. These are only to be used
+ * in seldom-executed code paths. They are not only slow but leak memory.
+ */
+Datum
+OidInputFunctionCall(Oid functionId, char *str, Oid typioparam, int32 typmod)
+{
+ FmgrInfo flinfo;
+
+ fmgr_info(functionId, &flinfo);
+ return InputFunctionCall(&flinfo, str, typioparam, typmod);
+}
+
+char *
+OidOutputFunctionCall(Oid functionId, Datum val)
+{
+ FmgrInfo flinfo;
+
+ fmgr_info(functionId, &flinfo);
+ return OutputFunctionCall(&flinfo, val);
+}
+
+Datum
+OidReceiveFunctionCall(Oid functionId, StringInfo buf,
+ Oid typioparam, int32 typmod)
+{
+ FmgrInfo flinfo;
+
+ fmgr_info(functionId, &flinfo);
+ return ReceiveFunctionCall(&flinfo, buf, typioparam, typmod);
+}
+
+bytea *
+OidSendFunctionCall(Oid functionId, Datum val)
+{
+ FmgrInfo flinfo;
+
+ fmgr_info(functionId, &flinfo);
+ return SendFunctionCall(&flinfo, val);
+}
+
+
+/*
* !!! OLD INTERFACE !!!
*
* fmgr() is the only remaining vestige of the old-style caller support
diff --git a/src/include/fmgr.h b/src/include/fmgr.h
index 9f17a24357d..0d6e72594d2 100644
--- a/src/include/fmgr.h
+++ b/src/include/fmgr.h
@@ -11,7 +11,7 @@
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/fmgr.h,v 1.42 2006/03/05 15:58:52 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/fmgr.h,v 1.43 2006/04/04 19:35:37 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -20,6 +20,8 @@
/* We don't want to include primnodes.h here, so make a stub reference */
typedef struct Node *fmNodePtr;
+/* Likewise, avoid including stringinfo.h here */
+typedef struct StringInfoData *fmStringInfo;
/*
@@ -394,6 +396,20 @@ extern Datum OidFunctionCall9(Oid functionId, Datum arg1, Datum arg2,
Datum arg6, Datum arg7, Datum arg8,
Datum arg9);
+/* Special cases for convenient invocation of datatype I/O functions. */
+extern Datum InputFunctionCall(FmgrInfo *flinfo, char *str,
+ Oid typioparam, int32 typmod);
+extern Datum OidInputFunctionCall(Oid functionId, char *str,
+ Oid typioparam, int32 typmod);
+extern char *OutputFunctionCall(FmgrInfo *flinfo, Datum val);
+extern char *OidOutputFunctionCall(Oid functionId, Datum val);
+extern Datum ReceiveFunctionCall(FmgrInfo *flinfo, fmStringInfo buf,
+ Oid typioparam, int32 typmod);
+extern Datum OidReceiveFunctionCall(Oid functionId, fmStringInfo buf,
+ Oid typioparam, int32 typmod);
+extern bytea *SendFunctionCall(FmgrInfo *flinfo, Datum val);
+extern bytea *OidSendFunctionCall(Oid functionId, Datum val);
+
/*
* Routines in fmgr.c
diff --git a/src/pl/plperl/plperl.c b/src/pl/plperl/plperl.c
index 0524d9ebe4e..310df025706 100644
--- a/src/pl/plperl/plperl.c
+++ b/src/pl/plperl/plperl.c
@@ -1,7 +1,7 @@
/**********************************************************************
* plperl.c - perl as a procedural language for PostgreSQL
*
- * $PostgreSQL: pgsql/src/pl/plperl/plperl.c,v 1.107 2006/03/19 22:22:56 neilc Exp $
+ * $PostgreSQL: pgsql/src/pl/plperl/plperl.c,v 1.108 2006/04/04 19:35:37 tgl Exp $
*
**********************************************************************/
@@ -585,31 +585,35 @@ plperl_modify_tuple(HV *hvTD, TriggerData *tdata, HeapTuple otup)
while ((val = hv_iternextsv(hvNew, &key, &klen)))
{
int attn = SPI_fnumber(tupdesc, key);
+ Oid typinput;
+ Oid typioparam;
+ int32 atttypmod;
+ FmgrInfo finfo;
if (attn <= 0 || tupdesc->attrs[attn - 1]->attisdropped)
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_COLUMN),
errmsg("Perl hash contains nonexistent column \"%s\"",
key)));
+ /* XXX would be better to cache these lookups */
+ getTypeInputInfo(tupdesc->attrs[attn - 1]->atttypid,
+ &typinput, &typioparam);
+ fmgr_info(typinput, &finfo);
+ atttypmod = tupdesc->attrs[attn - 1]->atttypmod;
if (SvOK(val) && SvTYPE(val) != SVt_NULL)
{
- Oid typinput;
- Oid typioparam;
- FmgrInfo finfo;
-
- /* XXX would be better to cache these lookups */
- getTypeInputInfo(tupdesc->attrs[attn - 1]->atttypid,
- &typinput, &typioparam);
- fmgr_info(typinput, &finfo);
- modvalues[slotsused] = FunctionCall3(&finfo,
- CStringGetDatum(SvPV(val, PL_na)),
- ObjectIdGetDatum(typioparam),
- Int32GetDatum(tupdesc->attrs[attn - 1]->atttypmod));
+ modvalues[slotsused] = InputFunctionCall(&finfo,
+ SvPV(val, PL_na),
+ typioparam,
+ atttypmod);
modnulls[slotsused] = ' ';
}
else
{
- modvalues[slotsused] = (Datum) 0;
+ modvalues[slotsused] = InputFunctionCall(&finfo,
+ NULL,
+ typioparam,
+ atttypmod);
modnulls[slotsused] = 'n';
}
modattrs[slotsused] = attn;
@@ -897,8 +901,8 @@ plperl_call_perl_func(plperl_proc_desc *desc, FunctionCallInfo fcinfo)
{
char *tmp;
- tmp = DatumGetCString(FunctionCall1(&(desc->arg_out_func[i]),
- fcinfo->arg[i]));
+ tmp = OutputFunctionCall(&(desc->arg_out_func[i]),
+ fcinfo->arg[i]);
sv = newSVpv(tmp, 0);
#if PERL_BCDVERSION >= 0x5006000L
if (GetDatabaseEncoding() == PG_UTF8)
@@ -1091,8 +1095,9 @@ plperl_func_handler(PG_FUNCTION_ARGS)
/* Return NULL if Perl code returned undef */
if (rsi && IsA(rsi, ReturnSetInfo))
rsi->isDone = ExprEndResult;
+ retval = InputFunctionCall(&prodesc->result_in_func, NULL,
+ prodesc->result_typioparam, -1);
fcinfo->isnull = true;
- retval = (Datum) 0;
}
else if (prodesc->fn_retistuple)
{
@@ -1138,10 +1143,8 @@ plperl_func_handler(PG_FUNCTION_ARGS)
val = SvPV(perlret, PL_na);
- retval = FunctionCall3(&prodesc->result_in_func,
- CStringGetDatum(val),
- ObjectIdGetDatum(prodesc->result_typioparam),
- Int32GetDatum(-1));
+ retval = InputFunctionCall(&prodesc->result_in_func, val,
+ prodesc->result_typioparam, -1);
}
if (array_ret == NULL)
@@ -1534,7 +1537,7 @@ plperl_hash_from_tuple(HeapTuple tuple, TupleDesc tupdesc)
getTypeOutputInfo(tupdesc->attrs[i]->atttypid,
&typoutput, &typisvarlena);
- outputstr = DatumGetCString(OidFunctionCall1(typoutput, attr));
+ outputstr = OidOutputFunctionCall(typoutput, attr);
sv = newSVpv(outputstr, 0);
#if PERL_BCDVERSION >= 0x5006000L
@@ -1750,19 +1753,23 @@ plperl_return_next(SV *sv)
}
else
{
- Datum ret = (Datum) 0;
- bool isNull = true;
+ Datum ret;
+ bool isNull;
if (SvOK(sv) && SvTYPE(sv) != SVt_NULL)
{
char *val = SvPV(sv, PL_na);
- ret = FunctionCall3(&prodesc->result_in_func,
- PointerGetDatum(val),
- ObjectIdGetDatum(prodesc->result_typioparam),
- Int32GetDatum(-1));
+ ret = InputFunctionCall(&prodesc->result_in_func, val,
+ prodesc->result_typioparam, -1);
isNull = false;
}
+ else
+ {
+ ret = InputFunctionCall(&prodesc->result_in_func, NULL,
+ prodesc->result_typioparam, -1);
+ isNull = true;
+ }
tuple = heap_form_tuple(current_call_data->ret_tdesc, &ret, &isNull);
}
@@ -2118,9 +2125,9 @@ plperl_spi_exec_prepared(char* query, HV * attr, int argc, SV ** argv)
/************************************************************
* Set up arguments
************************************************************/
- if ( argc > 0)
+ if (argc > 0)
{
- nulls = (char *)palloc( argc);
+ nulls = (char *) palloc(argc);
argvalues = (Datum *) palloc(argc * sizeof(Datum));
}
else
@@ -2129,21 +2136,22 @@ plperl_spi_exec_prepared(char* query, HV * attr, int argc, SV ** argv)
argvalues = NULL;
}
- for ( i = 0; i < argc; i++)
+ for (i = 0; i < argc; i++)
{
- if ( SvTYPE( argv[i]) != SVt_NULL)
+ if (SvTYPE(argv[i]) != SVt_NULL)
{
- argvalues[i] =
- FunctionCall3( &qdesc->arginfuncs[i],
- CStringGetDatum( SvPV( argv[i], PL_na)),
- ObjectIdGetDatum( qdesc->argtypioparams[i]),
- Int32GetDatum(-1)
- );
+ argvalues[i] = InputFunctionCall(&qdesc->arginfuncs[i],
+ SvPV(argv[i], PL_na),
+ qdesc->argtypioparams[i],
+ -1);
nulls[i] = ' ';
}
else
{
- argvalues[i] = (Datum) 0;
+ argvalues[i] = InputFunctionCall(&qdesc->arginfuncs[i],
+ NULL,
+ qdesc->argtypioparams[i],
+ -1);
nulls[i] = 'n';
}
}
@@ -2247,9 +2255,9 @@ plperl_spi_query_prepared(char* query, int argc, SV ** argv)
/************************************************************
* Set up arguments
************************************************************/
- if ( argc > 0)
+ if (argc > 0)
{
- nulls = (char *)palloc( argc);
+ nulls = (char *) palloc(argc);
argvalues = (Datum *) palloc(argc * sizeof(Datum));
}
else
@@ -2258,21 +2266,22 @@ plperl_spi_query_prepared(char* query, int argc, SV ** argv)
argvalues = NULL;
}
- for ( i = 0; i < argc; i++)
+ for (i = 0; i < argc; i++)
{
- if ( SvTYPE( argv[i]) != SVt_NULL)
+ if (SvTYPE(argv[i]) != SVt_NULL)
{
- argvalues[i] =
- FunctionCall3( &qdesc->arginfuncs[i],
- CStringGetDatum( SvPV( argv[i], PL_na)),
- ObjectIdGetDatum( qdesc->argtypioparams[i]),
- Int32GetDatum(-1)
- );
+ argvalues[i] = InputFunctionCall(&qdesc->arginfuncs[i],
+ SvPV(argv[i], PL_na),
+ qdesc->argtypioparams[i],
+ -1);
nulls[i] = ' ';
}
else
{
- argvalues[i] = (Datum) 0;
+ argvalues[i] = InputFunctionCall(&qdesc->arginfuncs[i],
+ NULL,
+ qdesc->argtypioparams[i],
+ -1);
nulls[i] = 'n';
}
}
diff --git a/src/pl/plpgsql/src/pl_exec.c b/src/pl/plpgsql/src/pl_exec.c
index e4fa7003a7c..8a82a42fbe6 100644
--- a/src/pl/plpgsql/src/pl_exec.c
+++ b/src/pl/plpgsql/src/pl_exec.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.162 2006/03/09 21:29:36 momjian Exp $
+ * $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.163 2006/04/04 19:35:37 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -4043,6 +4043,8 @@ make_tuple_from_row(PLpgSQL_execstate *estate,
*
* Note: callers generally assume that the result is a palloc'd string and
* should be pfree'd. This is not all that safe an assumption ...
+ *
+ * Note: not caching the conversion function lookup is bad for performance.
* ----------
*/
static char *
@@ -4053,7 +4055,7 @@ convert_value_to_string(Datum value, Oid valtype)
getTypeOutputInfo(valtype, &typoutput, &typIsVarlena);
- return DatumGetCString(OidFunctionCall1(typoutput, value));
+ return OidOutputFunctionCall(typoutput, value);
}
/* ----------
@@ -4068,23 +4070,26 @@ exec_cast_value(Datum value, Oid valtype,
int32 reqtypmod,
bool isnull)
{
- if (!isnull)
+ /*
+ * If the type of the queries return value isn't that of the variable,
+ * convert it.
+ */
+ if (valtype != reqtype || reqtypmod != -1)
{
- /*
- * If the type of the queries return value isn't that of the variable,
- * convert it.
- */
- if (valtype != reqtype || reqtypmod != -1)
+ if (!isnull)
{
char *extval;
extval = convert_value_to_string(value, valtype);
- value = FunctionCall3(reqinput,
- CStringGetDatum(extval),
- ObjectIdGetDatum(reqtypioparam),
- Int32GetDatum(reqtypmod));
+ value = InputFunctionCall(reqinput, extval,
+ reqtypioparam, reqtypmod);
pfree(extval);
}
+ else
+ {
+ value = InputFunctionCall(reqinput, NULL,
+ reqtypioparam, reqtypmod);
+ }
}
return value;
diff --git a/src/pl/plpython/plpython.c b/src/pl/plpython/plpython.c
index d20a5f72f13..bf96db1776d 100644
--- a/src/pl/plpython/plpython.c
+++ b/src/pl/plpython/plpython.c
@@ -1,7 +1,7 @@
/**********************************************************************
* plpython.c - python as a procedural language for PostgreSQL
*
- * $PostgreSQL: pgsql/src/pl/plpython/plpython.c,v 1.76 2006/03/14 22:48:24 tgl Exp $
+ * $PostgreSQL: pgsql/src/pl/plpython/plpython.c,v 1.77 2006/04/04 19:35:37 tgl Exp $
*
*********************************************************************
*/
@@ -482,17 +482,24 @@ PLy_modify_tuple(PLyProcedure * proc, PyObject * pltd, TriggerData *tdata,
modattrs[i] = attn;
- if (plval != Py_None && !tupdesc->attrs[atti]->attisdropped)
+ if (tupdesc->attrs[atti]->attisdropped)
+ {
+ modvalues[i] = (Datum) 0;
+ modnulls[i] = 'n';
+ }
+ else if (plval != Py_None)
{
plstr = PyObject_Str(plval);
if (!plstr)
- PLy_elog(ERROR, "function \"%s\" could not modify tuple", proc->proname);
+ PLy_elog(ERROR, "function \"%s\" could not modify tuple",
+ proc->proname);
src = PyString_AsString(plstr);
- modvalues[i] = FunctionCall3(&proc->result.out.r.atts[atti].typfunc,
- CStringGetDatum(src),
- ObjectIdGetDatum(proc->result.out.r.atts[atti].typioparam),
- Int32GetDatum(tupdesc->attrs[atti]->atttypmod));
+ modvalues[i] =
+ InputFunctionCall(&proc->result.out.r.atts[atti].typfunc,
+ src,
+ proc->result.out.r.atts[atti].typioparam,
+ tupdesc->attrs[atti]->atttypmod);
modnulls[i] = ' ';
Py_DECREF(plstr);
@@ -500,7 +507,11 @@ PLy_modify_tuple(PLyProcedure * proc, PyObject * pltd, TriggerData *tdata,
}
else
{
- modvalues[i] = PointerGetDatum(NULL);
+ modvalues[i] =
+ InputFunctionCall(&proc->result.out.r.atts[atti].typfunc,
+ NULL,
+ proc->result.out.r.atts[atti].typioparam,
+ tupdesc->attrs[atti]->atttypmod);
modnulls[i] = 'n';
}
@@ -751,7 +762,10 @@ PLy_function_handler(FunctionCallInfo fcinfo, PLyProcedure * proc)
else if (plrv == Py_None)
{
fcinfo->isnull = true;
- rv = PointerGetDatum(NULL);
+ rv = InputFunctionCall(&proc->result.out.d.typfunc,
+ NULL,
+ proc->result.out.d.typioparam,
+ -1);
}
else
{
@@ -760,10 +774,10 @@ PLy_function_handler(FunctionCallInfo fcinfo, PLyProcedure * proc)
if (!plrv_so)
PLy_elog(ERROR, "function \"%s\" could not create return value", proc->proname);
plrv_sc = PyString_AsString(plrv_so);
- rv = FunctionCall3(&proc->result.out.d.typfunc,
- PointerGetDatum(plrv_sc),
- ObjectIdGetDatum(proc->result.out.d.typioparam),
- Int32GetDatum(-1));
+ rv = InputFunctionCall(&proc->result.out.d.typfunc,
+ plrv_sc,
+ proc->result.out.d.typioparam,
+ -1);
}
}
PG_CATCH();
@@ -861,13 +875,9 @@ PLy_function_build_args(FunctionCallInfo fcinfo, PLyProcedure * proc)
else
{
char *ct;
- Datum dt;
- dt = FunctionCall3(&(proc->args[i].in.d.typfunc),
- fcinfo->arg[i],
- ObjectIdGetDatum(proc->args[i].in.d.typioparam),
- Int32GetDatum(-1));
- ct = DatumGetCString(dt);
+ ct = OutputFunctionCall(&(proc->args[i].in.d.typfunc),
+ fcinfo->arg[i]);
arg = (proc->args[i].in.d.func) (ct);
pfree(ct);
}
@@ -1454,8 +1464,7 @@ PLyDict_FromTuple(PLyTypeInfo * info, HeapTuple tuple, TupleDesc desc)
{
char *key,
*vsrc;
- Datum vattr,
- vdat;
+ Datum vattr;
bool is_null;
PyObject *value;
@@ -1469,11 +1478,8 @@ PLyDict_FromTuple(PLyTypeInfo * info, HeapTuple tuple, TupleDesc desc)
PyDict_SetItemString(dict, key, Py_None);
else
{
- vdat = FunctionCall3(&info->in.r.atts[i].typfunc,
- vattr,
- ObjectIdGetDatum(info->in.r.atts[i].typioparam),
- Int32GetDatum(desc->attrs[i]->atttypmod));
- vsrc = DatumGetCString(vdat);
+ vsrc = OutputFunctionCall(&info->in.r.atts[i].typfunc,
+ vattr);
/*
* no exceptions allowed
@@ -2035,10 +2041,10 @@ PLy_spi_execute_plan(PyObject * ob, PyObject * list, long limit)
char *sv = PyString_AsString(so);
plan->values[i] =
- FunctionCall3(&(plan->args[i].out.d.typfunc),
- CStringGetDatum(sv),
- ObjectIdGetDatum(plan->args[i].out.d.typioparam),
- Int32GetDatum(-1));
+ InputFunctionCall(&(plan->args[i].out.d.typfunc),
+ sv,
+ plan->args[i].out.d.typioparam,
+ -1);
}
PG_CATCH();
{
@@ -2053,7 +2059,11 @@ PLy_spi_execute_plan(PyObject * ob, PyObject * list, long limit)
else
{
Py_DECREF(elem);
- plan->values[i] = PointerGetDatum(NULL);
+ plan->values[i] =
+ InputFunctionCall(&(plan->args[i].out.d.typfunc),
+ NULL,
+ plan->args[i].out.d.typioparam,
+ -1);
nulls[i] = 'n';
}
}
diff --git a/src/pl/tcl/pltcl.c b/src/pl/tcl/pltcl.c
index e1f21109bc5..07cbcc2eb31 100644
--- a/src/pl/tcl/pltcl.c
+++ b/src/pl/tcl/pltcl.c
@@ -2,7 +2,7 @@
* pltcl.c - PostgreSQL support for Tcl as
* procedural language (PL)
*
- * $PostgreSQL: pgsql/src/pl/tcl/pltcl.c,v 1.101 2006/03/14 22:48:24 tgl Exp $
+ * $PostgreSQL: pgsql/src/pl/tcl/pltcl.c,v 1.102 2006/04/04 19:35:37 tgl Exp $
*
**********************************************************************/
@@ -524,8 +524,8 @@ pltcl_func_handler(PG_FUNCTION_ARGS)
{
char *tmp;
- tmp = DatumGetCString(FunctionCall1(&prodesc->arg_out_func[i],
- fcinfo->arg[i]));
+ tmp = OutputFunctionCall(&prodesc->arg_out_func[i],
+ fcinfo->arg[i]);
UTF_BEGIN;
Tcl_DStringAppendElement(&tcl_cmd, UTF_E2U(tmp));
UTF_END;
@@ -578,14 +578,17 @@ pltcl_func_handler(PG_FUNCTION_ARGS)
elog(ERROR, "SPI_finish() failed");
if (fcinfo->isnull)
- retval = (Datum) 0;
+ retval = InputFunctionCall(&prodesc->result_in_func,
+ NULL,
+ prodesc->result_typioparam,
+ -1);
else
{
UTF_BEGIN;
- retval = FunctionCall3(&prodesc->result_in_func,
- PointerGetDatum(UTF_U2E(interp->result)),
- ObjectIdGetDatum(prodesc->result_typioparam),
- Int32GetDatum(-1));
+ retval = InputFunctionCall(&prodesc->result_in_func,
+ UTF_U2E(interp->result),
+ prodesc->result_typioparam,
+ -1);
UTF_END;
}
@@ -805,7 +808,6 @@ pltcl_trigger_handler(PG_FUNCTION_ARGS)
/* Use a TRY to ensure ret_values will get freed */
PG_TRY();
{
-
if (ret_numvals % 2 != 0)
elog(ERROR, "invalid return list from trigger - must have even # of elements");
@@ -871,11 +873,10 @@ pltcl_trigger_handler(PG_FUNCTION_ARGS)
modnulls[attnum - 1] = ' ';
fmgr_info(typinput, &finfo);
UTF_BEGIN;
- modvalues[attnum - 1] =
- FunctionCall3(&finfo,
- CStringGetDatum(UTF_U2E(ret_value)),
- ObjectIdGetDatum(typioparam),
- Int32GetDatum(tupdesc->attrs[attnum - 1]->atttypmod));
+ modvalues[attnum - 1] = InputFunctionCall(&finfo,
+ (char *) UTF_U2E(ret_value),
+ typioparam,
+ tupdesc->attrs[attnum - 1]->atttypmod);
UTF_END;
}
@@ -2041,17 +2042,18 @@ pltcl_SPI_execute_plan(ClientData cdata, Tcl_Interp *interp,
{
if (nulls && nulls[j] == 'n')
{
- /* don't try to convert the input for a null */
- argvalues[j] = (Datum) 0;
+ argvalues[j] = InputFunctionCall(&qdesc->arginfuncs[j],
+ NULL,
+ qdesc->argtypioparams[j],
+ -1);
}
else
{
UTF_BEGIN;
- argvalues[j] =
- FunctionCall3(&qdesc->arginfuncs[j],
- CStringGetDatum(UTF_U2E(callargs[j])),
- ObjectIdGetDatum(qdesc->argtypioparams[j]),
- Int32GetDatum(-1));
+ argvalues[j] = InputFunctionCall(&qdesc->arginfuncs[j],
+ (char *) UTF_U2E(callargs[j]),
+ qdesc->argtypioparams[j],
+ -1);
UTF_END;
}
}
@@ -2185,8 +2187,7 @@ pltcl_set_tuple_values(Tcl_Interp *interp, CONST84 char *arrayname,
************************************************************/
if (!isnull && OidIsValid(typoutput))
{
- outputstr = DatumGetCString(OidFunctionCall1(typoutput,
- attr));
+ outputstr = OidOutputFunctionCall(typoutput, attr);
UTF_BEGIN;
Tcl_SetVar2(interp, *arrptr, *nameptr, UTF_E2U(outputstr), 0);
UTF_END;
@@ -2255,8 +2256,7 @@ pltcl_build_tuple_argument(HeapTuple tuple, TupleDesc tupdesc,
************************************************************/
if (!isnull && OidIsValid(typoutput))
{
- outputstr = DatumGetCString(OidFunctionCall1(typoutput,
- attr));
+ outputstr = OidOutputFunctionCall(typoutput, attr);
Tcl_DStringAppendElement(retval, attname);
UTF_BEGIN;
Tcl_DStringAppendElement(retval, UTF_E2U(outputstr));