Commit 147d4bf3 authored by Tom Lane's avatar Tom Lane

Modify all callers of datatype input and receive functions so that if these

functions are not strict, they will be called (passing a NULL first parameter)
during any attempt to input a NULL value of their datatype.  Currently, all
our input functions are strict and so this commit does not change any
behavior.  However, this will make it possible to build domain input functions
that centralize checking of domain constraints, thereby closing numerous holes
in our domain support, as per previous discussion.

While at it, I took the opportunity to introduce convenience functions
InputFunctionCall, OutputFunctionCall, etc to use in code that calls I/O
functions.  This eliminates a lot of grotty-looking casts, but the main
motivation is to make it easier to grep for these places if we ever need
to touch them again.
parent eaef1113
<!-- <!--
$PostgreSQL: pgsql/doc/src/sgml/ref/create_type.sgml,v 1.61 2006/02/28 22:37:25 tgl Exp $ $PostgreSQL: pgsql/doc/src/sgml/ref/create_type.sgml,v 1.62 2006/04/04 19:35:32 tgl Exp $
PostgreSQL documentation PostgreSQL documentation
--> -->
...@@ -97,8 +97,7 @@ CREATE TYPE <replaceable class="parameter">name</replaceable> ...@@ -97,8 +97,7 @@ CREATE TYPE <replaceable class="parameter">name</replaceable>
<para> <para>
The <replaceable class="parameter">input_function</replaceable> The <replaceable class="parameter">input_function</replaceable>
converts the type's external textual representation to the internal converts the type's external textual representation to the internal
representation used by the representation used by the operators and functions defined for the type.
operators and functions defined for the type.
<replaceable class="parameter">output_function</replaceable> <replaceable class="parameter">output_function</replaceable>
performs the reverse transformation. The input function may be performs the reverse transformation. The input function may be
declared as taking one argument of type <type>cstring</type>, declared as taking one argument of type <type>cstring</type>,
...@@ -110,9 +109,16 @@ CREATE TYPE <replaceable class="parameter">name</replaceable> ...@@ -110,9 +109,16 @@ CREATE TYPE <replaceable class="parameter">name</replaceable>
and the third is the <literal>typmod</> of the destination column, if known and the third is the <literal>typmod</> of the destination column, if known
(-1 will be passed if not). (-1 will be passed if not).
The input function must return a value of the data type itself. The input function must return a value of the data type itself.
Usually, an input function should be declared STRICT; if it is not,
it will be called with a NULL first parameter when reading a NULL
input value. The function must still return NULL in this case, unless
it raises an error.
(This case is mainly meant to support domain input functions, which
may need to reject NULL inputs.)
The output function must be The output function must be
declared as taking one argument of the new data type. declared as taking one argument of the new data type.
The output function must return type <type>cstring</type>. The output function must return type <type>cstring</type>.
Output functions are not invoked for NULL values.
</para> </para>
<para> <para>
...@@ -133,6 +139,12 @@ CREATE TYPE <replaceable class="parameter">name</replaceable> ...@@ -133,6 +139,12 @@ CREATE TYPE <replaceable class="parameter">name</replaceable>
holding the received byte string; the optional arguments are the holding the received byte string; the optional arguments are the
same as for the text input function. same as for the text input function.
The receive function must return a value of the data type itself. The receive function must return a value of the data type itself.
Usually, a receive function should be declared STRICT; if it is not,
it will be called with a NULL first parameter when reading a NULL
input value. The function must still return NULL in this case, unless
it raises an error.
(This case is mainly meant to support domain receive functions, which
may need to reject NULL inputs.)
Similarly, the optional Similarly, the optional
<replaceable class="parameter">send_function</replaceable> converts <replaceable class="parameter">send_function</replaceable> converts
from the internal representation to the external binary representation. from the internal representation to the external binary representation.
...@@ -140,6 +152,7 @@ CREATE TYPE <replaceable class="parameter">name</replaceable> ...@@ -140,6 +152,7 @@ CREATE TYPE <replaceable class="parameter">name</replaceable>
output. The send function must be output. The send function must be
declared as taking one argument of the new data type. declared as taking one argument of the new data type.
The send function must return type <type>bytea</type>. The send function must return type <type>bytea</type>.
Send functions are not invoked for NULL values.
</para> </para>
<para> <para>
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * 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) ...@@ -331,8 +331,7 @@ printtup(TupleTableSlot *slot, DestReceiver *self)
/* Text output */ /* Text output */
char *outputstr; char *outputstr;
outputstr = DatumGetCString(FunctionCall1(&thisState->finfo, outputstr = OutputFunctionCall(&thisState->finfo, attr);
attr));
pq_sendcountedtext(&buf, outputstr, strlen(outputstr), false); pq_sendcountedtext(&buf, outputstr, strlen(outputstr), false);
pfree(outputstr); pfree(outputstr);
} }
...@@ -341,9 +340,7 @@ printtup(TupleTableSlot *slot, DestReceiver *self) ...@@ -341,9 +340,7 @@ printtup(TupleTableSlot *slot, DestReceiver *self)
/* Binary output */ /* Binary output */
bytea *outputbytes; bytea *outputbytes;
outputbytes = DatumGetByteaP(FunctionCall1(&thisState->finfo, outputbytes = SendFunctionCall(&thisState->finfo, attr);
attr));
/* We assume the result will not have been toasted */
pq_sendint(&buf, VARSIZE(outputbytes) - VARHDRSZ, 4); pq_sendint(&buf, VARSIZE(outputbytes) - VARHDRSZ, 4);
pq_sendbytes(&buf, VARDATA(outputbytes), pq_sendbytes(&buf, VARDATA(outputbytes),
VARSIZE(outputbytes) - VARHDRSZ); VARSIZE(outputbytes) - VARHDRSZ);
...@@ -429,8 +426,7 @@ printtup_20(TupleTableSlot *slot, DestReceiver *self) ...@@ -429,8 +426,7 @@ printtup_20(TupleTableSlot *slot, DestReceiver *self)
else else
attr = origattr; attr = origattr;
outputstr = DatumGetCString(FunctionCall1(&thisState->finfo, outputstr = OutputFunctionCall(&thisState->finfo, attr);
attr));
pq_sendcountedtext(&buf, outputstr, strlen(outputstr), true); pq_sendcountedtext(&buf, outputstr, strlen(outputstr), true);
pfree(outputstr); pfree(outputstr);
...@@ -542,8 +538,7 @@ debugtup(TupleTableSlot *slot, DestReceiver *self) ...@@ -542,8 +538,7 @@ debugtup(TupleTableSlot *slot, DestReceiver *self)
else else
attr = origattr; attr = origattr;
value = DatumGetCString(OidFunctionCall1(typoutput, value = OidOutputFunctionCall(typoutput, attr);
attr));
printatt((unsigned) i + 1, typeinfo->attrs[i], value); printatt((unsigned) i + 1, typeinfo->attrs[i], value);
...@@ -632,8 +627,7 @@ printtup_internal_20(TupleTableSlot *slot, DestReceiver *self) ...@@ -632,8 +627,7 @@ printtup_internal_20(TupleTableSlot *slot, DestReceiver *self)
else else
attr = origattr; attr = origattr;
outputbytes = DatumGetByteaP(FunctionCall1(&thisState->finfo, outputbytes = SendFunctionCall(&thisState->finfo, attr);
attr));
/* We assume the result will not have been toasted */ /* We assume the result will not have been toasted */
pq_sendint(&buf, VARSIZE(outputbytes) - VARHDRSZ, 4); pq_sendint(&buf, VARSIZE(outputbytes) - VARHDRSZ, 4);
pq_sendbytes(&buf, VARDATA(outputbytes), pq_sendbytes(&buf, VARDATA(outputbytes),
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * 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) ...@@ -826,11 +826,11 @@ InsertOneValue(char *value, int i)
if (ap == NULL) if (ap == NULL)
elog(ERROR, "could not find atttypid %u in Typ list", typoid); elog(ERROR, "could not find atttypid %u in Typ list", typoid);
/* XXX this should match getTypeIOParam() */ /* XXX this logic should match getTypeIOParam() */
if (ap->am_typ.typtype == 'c') if (OidIsValid(ap->am_typ.typelem))
typioparam = typoid;
else
typioparam = ap->am_typ.typelem; typioparam = ap->am_typ.typelem;
else
typioparam = typoid;
typinput = ap->am_typ.typinput; typinput = ap->am_typ.typinput;
typoutput = ap->am_typ.typoutput; typoutput = ap->am_typ.typoutput;
...@@ -850,19 +850,18 @@ InsertOneValue(char *value, int i) ...@@ -850,19 +850,18 @@ InsertOneValue(char *value, int i)
elog(ERROR, "type oid %u not found", typoid); elog(ERROR, "type oid %u not found", typoid);
elog(DEBUG5, "Typ == NULL, typeindex = %u", typeindex); elog(DEBUG5, "Typ == NULL, typeindex = %u", typeindex);
/* XXX there are no composite types in TypInfo */ /* XXX this logic should match getTypeIOParam() */
if (OidIsValid(TypInfo[typeindex].elem))
typioparam = TypInfo[typeindex].elem; typioparam = TypInfo[typeindex].elem;
else
typioparam = typoid;
typinput = TypInfo[typeindex].inproc; typinput = TypInfo[typeindex].inproc;
typoutput = TypInfo[typeindex].outproc; typoutput = TypInfo[typeindex].outproc;
} }
values[i] = OidFunctionCall3(typinput, values[i] = OidInputFunctionCall(typinput, value, typioparam, -1);
CStringGetDatum(value), prt = OidOutputFunctionCall(typoutput, values[i]);
ObjectIdGetDatum(typioparam),
Int32GetDatum(-1));
prt = DatumGetCString(OidFunctionCall1(typoutput,
values[i]));
elog(DEBUG4, "inserted -> %s", prt); elog(DEBUG4, "inserted -> %s", prt);
pfree(prt); pfree(prt);
} }
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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) ...@@ -1382,8 +1382,8 @@ CopyTo(CopyState cstate)
{ {
if (!cstate->binary) if (!cstate->binary)
{ {
string = DatumGetCString(FunctionCall1(&out_functions[attnum - 1], string = OutputFunctionCall(&out_functions[attnum - 1],
value)); value);
if (cstate->csv_mode) if (cstate->csv_mode)
CopyAttributeOutCSV(cstate, string, CopyAttributeOutCSV(cstate, string,
force_quote[attnum - 1], force_quote[attnum - 1],
...@@ -1395,9 +1395,8 @@ CopyTo(CopyState cstate) ...@@ -1395,9 +1395,8 @@ CopyTo(CopyState cstate)
{ {
bytea *outputbytes; bytea *outputbytes;
outputbytes = DatumGetByteaP(FunctionCall1(&out_functions[attnum - 1], outputbytes = SendFunctionCall(&out_functions[attnum - 1],
value)); value);
/* We assume the result will not have been toasted */
CopySendInt32(cstate, VARSIZE(outputbytes) - VARHDRSZ); CopySendInt32(cstate, VARSIZE(outputbytes) - VARHDRSZ);
CopySendData(cstate, VARDATA(outputbytes), CopySendData(cstate, VARDATA(outputbytes),
VARSIZE(outputbytes) - VARHDRSZ); VARSIZE(outputbytes) - VARHDRSZ);
...@@ -1459,6 +1458,13 @@ copy_in_error_callback(void *arg) ...@@ -1459,6 +1458,13 @@ copy_in_error_callback(void *arg)
cstate->cur_attname, attval); cstate->cur_attname, attval);
pfree(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 else
{ {
/* error is relevant to a particular line */ /* error is relevant to a particular line */
...@@ -1854,20 +1860,17 @@ CopyFrom(CopyState cstate) ...@@ -1854,20 +1860,17 @@ CopyFrom(CopyState cstate)
string = cstate->null_print; string = cstate->null_print;
} }
/* If we read an SQL NULL, no need to do anything */
if (string != NULL)
{
cstate->cur_attname = NameStr(attr[m]->attname); cstate->cur_attname = NameStr(attr[m]->attname);
cstate->cur_attval = string; cstate->cur_attval = string;
values[m] = FunctionCall3(&in_functions[m], values[m] = InputFunctionCall(&in_functions[m],
CStringGetDatum(string), string,
ObjectIdGetDatum(typioparams[m]), typioparams[m],
Int32GetDatum(attr[m]->atttypmod)); attr[m]->atttypmod);
if (string != NULL)
nulls[m] = ' '; nulls[m] = ' ';
cstate->cur_attname = NULL; cstate->cur_attname = NULL;
cstate->cur_attval = NULL; cstate->cur_attval = NULL;
} }
}
Assert(fieldno == nfields); Assert(fieldno == nfields);
} }
...@@ -2900,7 +2903,7 @@ CopyReadBinaryAttribute(CopyState cstate, ...@@ -2900,7 +2903,7 @@ CopyReadBinaryAttribute(CopyState cstate,
if (fld_size == -1) if (fld_size == -1)
{ {
*isnull = true; *isnull = true;
return (Datum) 0; return ReceiveFunctionCall(flinfo, NULL, typioparam, typmod);
} }
if (fld_size < 0) if (fld_size < 0)
ereport(ERROR, ereport(ERROR,
...@@ -2924,10 +2927,8 @@ CopyReadBinaryAttribute(CopyState cstate, ...@@ -2924,10 +2927,8 @@ CopyReadBinaryAttribute(CopyState cstate,
cstate->attribute_buf.data[fld_size] = '\0'; cstate->attribute_buf.data[fld_size] = '\0';
/* Call the column type's binary input converter */ /* Call the column type's binary input converter */
result = FunctionCall3(flinfo, result = ReceiveFunctionCall(flinfo, &cstate->attribute_buf,
PointerGetDatum(&cstate->attribute_buf), typioparam, typmod);
ObjectIdGetDatum(typioparam),
Int32GetDatum(typmod));
/* Trouble if it didn't eat the whole buffer */ /* Trouble if it didn't eat the whole buffer */
if (cstate->attribute_buf.cursor != cstate->attribute_buf.len) if (cstate->attribute_buf.cursor != cstate->attribute_buf.len)
......
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
* *
* *
* IDENTIFICATION * 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) ...@@ -928,6 +928,7 @@ TupleDescGetAttInMetadata(TupleDesc tupdesc)
/* /*
* BuildTupleFromCStrings - build a HeapTuple given user data in C string form. * 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. * 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 HeapTuple
BuildTupleFromCStrings(AttInMetadata *attinmeta, char **values) BuildTupleFromCStrings(AttInMetadata *attinmeta, char **values)
...@@ -937,36 +938,26 @@ BuildTupleFromCStrings(AttInMetadata *attinmeta, char **values) ...@@ -937,36 +938,26 @@ BuildTupleFromCStrings(AttInMetadata *attinmeta, char **values)
Datum *dvalues; Datum *dvalues;
char *nulls; char *nulls;
int i; int i;
Oid attioparam;
int32 atttypmod;
HeapTuple tuple; HeapTuple tuple;
dvalues = (Datum *) palloc(natts * sizeof(Datum)); dvalues = (Datum *) palloc(natts * sizeof(Datum));
nulls = (char *) palloc(natts * sizeof(char)); 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++) for (i = 0; i < natts; i++)
{ {
if (!tupdesc->attrs[i]->attisdropped) if (!tupdesc->attrs[i]->attisdropped)
{ {
/* Non-dropped attributes */ /* Non-dropped attributes */
dvalues[i] = InputFunctionCall(&attinmeta->attinfuncs[i],
values[i],
attinmeta->attioparams[i],
attinmeta->atttypmods[i]);
if (values[i] != NULL) 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] = ' '; nulls[i] = ' ';
}
else else
{
dvalues[i] = (Datum) 0;
nulls[i] = 'n'; nulls[i] = 'n';
} }
}
else else
{ {
/* Handle dropped attributes by setting to NULL */ /* Handle dropped attributes by setting to NULL */
......
...@@ -61,7 +61,7 @@ ...@@ -61,7 +61,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * 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) ...@@ -1407,10 +1407,8 @@ GetAggInitVal(Datum textInitVal, Oid transtype)
getTypeInputInfo(transtype, &typinput, &typioparam); getTypeInputInfo(transtype, &typinput, &typioparam);
strInitVal = DatumGetCString(DirectFunctionCall1(textout, textInitVal)); strInitVal = DatumGetCString(DirectFunctionCall1(textout, textInitVal));
initVal = OidFunctionCall3(typinput, initVal = OidInputFunctionCall(typinput, strInitVal,
CStringGetDatum(strInitVal), typioparam, -1);
ObjectIdGetDatum(typioparam),
Int32GetDatum(-1));
pfree(strInitVal); pfree(strInitVal);
return initVal; return initVal;
} }
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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) ...@@ -629,9 +629,9 @@ SPI_fname(TupleDesc tupdesc, int fnumber)
char * char *
SPI_getvalue(HeapTuple tuple, TupleDesc tupdesc, int fnumber) SPI_getvalue(HeapTuple tuple, TupleDesc tupdesc, int fnumber)
{ {
char *result;
Datum origval, Datum origval,
val, val;
result;
bool isnull; bool isnull;
Oid typoid, Oid typoid,
foutoid; foutoid;
...@@ -666,14 +666,13 @@ SPI_getvalue(HeapTuple tuple, TupleDesc tupdesc, int fnumber) ...@@ -666,14 +666,13 @@ SPI_getvalue(HeapTuple tuple, TupleDesc tupdesc, int fnumber)
else else
val = origval; val = origval;
result = OidFunctionCall1(foutoid, result = OidOutputFunctionCall(foutoid, val);
val);
/* Clean up detoasted copy, if any */ /* Clean up detoasted copy, if any */
if (val != origval) if (val != origval)
pfree(DatumGetPointer(val)); pfree(DatumGetPointer(val));
return DatumGetCString(result); return result;
} }
Datum Datum
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 * HISTORY
* AUTHOR DATE MAJOR EVENT * AUTHOR DATE MAJOR EVENT
...@@ -357,8 +357,7 @@ print_expr(Node *expr, List *rtable) ...@@ -357,8 +357,7 @@ print_expr(Node *expr, List *rtable)
getTypeOutputInfo(c->consttype, getTypeOutputInfo(c->consttype,
&typoutput, &typIsVarlena); &typoutput, &typIsVarlena);
outputstr = DatumGetCString(OidFunctionCall1(typoutput, outputstr = OidOutputFunctionCall(typoutput, c->constvalue);
c->constvalue));
printf("%s", outputstr); printf("%s", outputstr);
pfree(outputstr); pfree(outputstr);
} }
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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, ...@@ -166,26 +166,21 @@ coerce_type(ParseState *pstate, Node *node,
newcon->constbyval = typeByVal(targetType); newcon->constbyval = typeByVal(targetType);
newcon->constisnull = con->constisnull; newcon->constisnull = con->constisnull;
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 * We pass typmod -1 to the input routine, primarily because
* existing input routines follow implicit-coercion semantics for * existing input routines follow implicit-coercion semantics for
* length checks, which is not always what we want here. Any * length checks, which is not always what we want here. Any
* length constraint will be applied later by our caller. * length constraint will be applied later by our caller.
* *
* Note that we call stringTypeDatum using the domain's pg_type * We assume here that UNKNOWN's internal representation is the
* row, if it's a domain. This works because the domain row has * same as CSTRING.
* the same typinput and typelem as the base type --- ugly...
*/ */
newcon->constvalue = stringTypeDatum(targetType, val, -1); if (!con->constisnull)
} newcon->constvalue = stringTypeDatum(targetType,
DatumGetCString(con->constvalue),
-1);
else
newcon->constvalue = stringTypeDatum(targetType, NULL, -1);
result = (Node *) newcon; result = (Node *) newcon;
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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) ...@@ -326,7 +326,8 @@ typeTypeRelid(Type typ)
/* /*
* Given a type structure and a string, returns the internal representation * 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 Datum
stringTypeDatum(Type tp, char *string, int32 atttypmod) stringTypeDatum(Type tp, char *string, int32 atttypmod)
...@@ -336,10 +337,8 @@ 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; typinput = ((Form_pg_type) GETSTRUCT(tp))->typinput;
typioparam = getTypeIOParam(tp); typioparam = getTypeIOParam(tp);
return OidFunctionCall3(typinput, return OidInputFunctionCall(typinput, string,
CStringGetDatum(string), typioparam, atttypmod);
ObjectIdGetDatum(typioparam),
Int32GetDatum(atttypmod));
} }
/* given a typeid, return the type's typrelid (associated relation, if any) */ /* given a typeid, return the type's typrelid (associated relation, if any) */
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 * NOTES
* This cruft is the server side of PQfn. * This cruft is the server side of PQfn.
...@@ -154,8 +154,7 @@ SendFunctionResult(Datum retval, bool isnull, Oid rettype, int16 format) ...@@ -154,8 +154,7 @@ SendFunctionResult(Datum retval, bool isnull, Oid rettype, int16 format)
char *outputstr; char *outputstr;
getTypeOutputInfo(rettype, &typoutput, &typisvarlena); getTypeOutputInfo(rettype, &typoutput, &typisvarlena);
outputstr = DatumGetCString(OidFunctionCall1(typoutput, outputstr = OidOutputFunctionCall(typoutput, retval);
retval));
pq_sendcountedtext(&buf, outputstr, strlen(outputstr), false); pq_sendcountedtext(&buf, outputstr, strlen(outputstr), false);
pfree(outputstr); pfree(outputstr);
} }
...@@ -166,9 +165,7 @@ SendFunctionResult(Datum retval, bool isnull, Oid rettype, int16 format) ...@@ -166,9 +165,7 @@ SendFunctionResult(Datum retval, bool isnull, Oid rettype, int16 format)
bytea *outputbytes; bytea *outputbytes;
getTypeBinaryOutputInfo(rettype, &typsend, &typisvarlena); getTypeBinaryOutputInfo(rettype, &typsend, &typisvarlena);
outputbytes = DatumGetByteaP(OidFunctionCall1(typsend, outputbytes = OidSendFunctionCall(typsend, retval);
retval));
/* We assume the result will not have been toasted */
pq_sendint(&buf, VARSIZE(outputbytes) - VARHDRSZ, 4); pq_sendint(&buf, VARSIZE(outputbytes) - VARHDRSZ, 4);
pq_sendbytes(&buf, VARDATA(outputbytes), pq_sendbytes(&buf, VARDATA(outputbytes),
VARSIZE(outputbytes) - VARHDRSZ); VARSIZE(outputbytes) - VARHDRSZ);
...@@ -433,8 +430,9 @@ parse_fcall_arguments(StringInfo msgBuf, struct fp_info * fip, ...@@ -433,8 +430,9 @@ parse_fcall_arguments(StringInfo msgBuf, struct fp_info * fip,
if (argsize == -1) if (argsize == -1)
{ {
fcinfo->argnull[i] = true; fcinfo->argnull[i] = true;
continue;
} }
else
{
fcinfo->argnull[i] = false; fcinfo->argnull[i] = false;
if (argsize < 0) if (argsize < 0)
ereport(ERROR, ereport(ERROR,
...@@ -450,6 +448,7 @@ parse_fcall_arguments(StringInfo msgBuf, struct fp_info * fip, ...@@ -450,6 +448,7 @@ parse_fcall_arguments(StringInfo msgBuf, struct fp_info * fip,
appendBinaryStringInfo(&abuf, appendBinaryStringInfo(&abuf,
pq_getmsgbytes(msgBuf, argsize), pq_getmsgbytes(msgBuf, argsize),
argsize); argsize);
}
if (numAFormats > 1) if (numAFormats > 1)
aformat = aformats[i]; aformat = aformats[i];
...@@ -472,31 +471,36 @@ parse_fcall_arguments(StringInfo msgBuf, struct fp_info * fip, ...@@ -472,31 +471,36 @@ parse_fcall_arguments(StringInfo msgBuf, struct fp_info * fip,
* have to do encoding conversion before calling the typinput * have to do encoding conversion before calling the typinput
* routine, though. * routine, though.
*/ */
if (argsize == -1)
pstring = NULL;
else
pstring = pg_client_to_server(abuf.data, argsize); pstring = pg_client_to_server(abuf.data, argsize);
fcinfo->arg[i] =
OidFunctionCall3(typinput, fcinfo->arg[i] = OidInputFunctionCall(typinput, pstring,
CStringGetDatum(pstring), typioparam, -1);
ObjectIdGetDatum(typioparam),
Int32GetDatum(-1));
/* Free result of encoding conversion, if any */ /* Free result of encoding conversion, if any */
if (pstring != abuf.data) if (pstring && pstring != abuf.data)
pfree(pstring); pfree(pstring);
} }
else if (aformat == 1) else if (aformat == 1)
{ {
Oid typreceive; Oid typreceive;
Oid typioparam; Oid typioparam;
StringInfo bufptr;
/* Call the argument type's binary input converter */ /* Call the argument type's binary input converter */
getTypeBinaryInputInfo(fip->argtypes[i], &typreceive, &typioparam); getTypeBinaryInputInfo(fip->argtypes[i], &typreceive, &typioparam);
fcinfo->arg[i] = OidFunctionCall3(typreceive, if (argsize == -1)
PointerGetDatum(&abuf), bufptr = NULL;
ObjectIdGetDatum(typioparam), else
Int32GetDatum(-1)); bufptr = &abuf;
fcinfo->arg[i] = OidReceiveFunctionCall(typreceive, bufptr,
typioparam, -1);
/* Trouble if it didn't eat the whole buffer */ /* Trouble if it didn't eat the whole buffer */
if (abuf.cursor != abuf.len) if (argsize != -1 && abuf.cursor != abuf.len)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_INVALID_BINARY_REPRESENTATION), (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
errmsg("incorrect binary data format in function argument %d", errmsg("incorrect binary data format in function argument %d",
...@@ -552,10 +556,14 @@ parse_fcall_arguments_20(StringInfo msgBuf, struct fp_info * fip, ...@@ -552,10 +556,14 @@ parse_fcall_arguments_20(StringInfo msgBuf, struct fp_info * fip,
Oid typreceive; Oid typreceive;
Oid typioparam; Oid typioparam;
getTypeBinaryInputInfo(fip->argtypes[i], &typreceive, &typioparam);
argsize = pq_getmsgint(msgBuf, 4); argsize = pq_getmsgint(msgBuf, 4);
if (argsize == -1) if (argsize == -1)
{ {
fcinfo->argnull[i] = true; fcinfo->argnull[i] = true;
fcinfo->arg[i] = OidReceiveFunctionCall(typreceive, NULL,
typioparam, -1);
continue; continue;
} }
fcinfo->argnull[i] = false; fcinfo->argnull[i] = false;
...@@ -574,13 +582,8 @@ parse_fcall_arguments_20(StringInfo msgBuf, struct fp_info * fip, ...@@ -574,13 +582,8 @@ parse_fcall_arguments_20(StringInfo msgBuf, struct fp_info * fip,
pq_getmsgbytes(msgBuf, argsize), pq_getmsgbytes(msgBuf, argsize),
argsize); argsize);
/* Call the argument type's binary input converter */ fcinfo->arg[i] = OidReceiveFunctionCall(typreceive, &abuf,
getTypeBinaryInputInfo(fip->argtypes[i], &typreceive, &typioparam); typioparam, -1);
fcinfo->arg[i] = OidFunctionCall3(typreceive,
PointerGetDatum(&abuf),
ObjectIdGetDatum(typioparam),
Int32GetDatum(-1));
/* Trouble if it didn't eat the whole buffer */ /* Trouble if it didn't eat the whole buffer */
if (abuf.cursor != abuf.len) if (abuf.cursor != abuf.len)
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 * NOTES
* this is the "main" module of the postgres backend and * this is the "main" module of the postgres backend and
...@@ -1486,6 +1486,9 @@ exec_bind_message(StringInfo input_message) ...@@ -1486,6 +1486,9 @@ exec_bind_message(StringInfo input_message)
Oid ptype = lfirst_oid(l); Oid ptype = lfirst_oid(l);
int32 plength; int32 plength;
bool isNull; bool isNull;
StringInfoData pbuf;
char csave;
int16 pformat;
plength = pq_getmsgint(input_message, 4); plength = pq_getmsgint(input_message, 4);
isNull = (plength == -1); isNull = (plength == -1);
...@@ -1493,16 +1496,6 @@ exec_bind_message(StringInfo input_message) ...@@ -1493,16 +1496,6 @@ exec_bind_message(StringInfo input_message)
if (!isNull) if (!isNull)
{ {
const char *pvalue = pq_getmsgbytes(input_message, plength); 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 * Rather than copying data around, we just set up a phony
...@@ -1519,6 +1512,19 @@ exec_bind_message(StringInfo input_message) ...@@ -1519,6 +1512,19 @@ exec_bind_message(StringInfo input_message)
csave = pbuf.data[plength]; csave = pbuf.data[plength];
pbuf.data[plength] = '\0'; pbuf.data[plength] = '\0';
}
else
{
pbuf.data = NULL; /* keep compiler quiet */
csave = 0;
}
if (numPFormats > 1)
pformat = pformats[i];
else if (numPFormats > 0)
pformat = pformats[0];
else
pformat = 0; /* default = text */
if (pformat == 0) if (pformat == 0)
{ {
...@@ -1532,34 +1538,38 @@ exec_bind_message(StringInfo input_message) ...@@ -1532,34 +1538,38 @@ exec_bind_message(StringInfo input_message)
* We have to do encoding conversion before calling the * We have to do encoding conversion before calling the
* typinput routine. * typinput routine.
*/ */
if (isNull)
pstring = NULL;
else
pstring = pg_client_to_server(pbuf.data, plength); pstring = pg_client_to_server(pbuf.data, plength);
params[i].value =
OidFunctionCall3(typinput, params[i].value = OidInputFunctionCall(typinput, pstring,
CStringGetDatum(pstring), typioparam, -1);
ObjectIdGetDatum(typioparam),
Int32GetDatum(-1));
/* Free result of encoding conversion, if any */ /* Free result of encoding conversion, if any */
if (pstring != pbuf.data) if (pstring && pstring != pbuf.data)
pfree(pstring); pfree(pstring);
} }
else if (pformat == 1) else if (pformat == 1)
{ {
Oid typreceive; Oid typreceive;
Oid typioparam; Oid typioparam;
StringInfo bufptr;
/* /*
* Call the parameter type's binary input converter * Call the parameter type's binary input converter
*/ */
getTypeBinaryInputInfo(ptype, &typreceive, &typioparam); getTypeBinaryInputInfo(ptype, &typreceive, &typioparam);
params[i].value = if (isNull)
OidFunctionCall3(typreceive, bufptr = NULL;
PointerGetDatum(&pbuf), else
ObjectIdGetDatum(typioparam), bufptr = &pbuf;
Int32GetDatum(-1));
params[i].value = OidReceiveFunctionCall(typreceive, bufptr,
typioparam, -1);
/* Trouble if it didn't eat the whole buffer */ /* Trouble if it didn't eat the whole buffer */
if (pbuf.cursor != pbuf.len) if (!isNull && pbuf.cursor != pbuf.len)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_INVALID_BINARY_REPRESENTATION), (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
errmsg("incorrect binary data format in bind parameter %d", errmsg("incorrect binary data format in bind parameter %d",
...@@ -1574,8 +1584,8 @@ exec_bind_message(StringInfo input_message) ...@@ -1574,8 +1584,8 @@ exec_bind_message(StringInfo input_message)
} }
/* Restore message buffer contents */ /* Restore message buffer contents */
if (!isNull)
pbuf.data[plength] = csave; pbuf.data[plength] = csave;
}
params[i].kind = PARAM_NUM; params[i].kind = PARAM_NUM;
params[i].id = i + 1; params[i].id = i + 1;
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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, ...@@ -787,14 +787,14 @@ ReadArrayStr(char *arrayStr,
pg_strcasecmp(itemstart, "NULL") == 0) pg_strcasecmp(itemstart, "NULL") == 0)
{ {
/* it's a NULL item */ /* it's a NULL item */
values[i] = InputFunctionCall(inputproc, NULL,
typioparam, typmod);
nulls[i] = true; nulls[i] = true;
} }
else else
{ {
values[i] = FunctionCall3(inputproc, values[i] = InputFunctionCall(inputproc, itemstart,
CStringGetDatum(itemstart), typioparam, typmod);
ObjectIdGetDatum(typioparam),
Int32GetDatum(typmod));
nulls[i] = false; nulls[i] = false;
} }
} }
...@@ -1018,8 +1018,7 @@ array_out(PG_FUNCTION_ARGS) ...@@ -1018,8 +1018,7 @@ array_out(PG_FUNCTION_ARGS)
Datum itemvalue; Datum itemvalue;
itemvalue = fetch_att(p, typbyval, typlen); itemvalue = fetch_att(p, typbyval, typlen);
values[i] = DatumGetCString(FunctionCall1(&my_extra->proc, values[i] = OutputFunctionCall(&my_extra->proc, itemvalue);
itemvalue));
p = att_addlength(p, typlen, PointerGetDatum(p)); p = att_addlength(p, typlen, PointerGetDatum(p));
p = (char *) att_align(p, typalign); p = (char *) att_align(p, typalign);
...@@ -1357,6 +1356,8 @@ ReadArrayBinary(StringInfo buf, ...@@ -1357,6 +1356,8 @@ ReadArrayBinary(StringInfo buf,
if (itemlen == -1) if (itemlen == -1)
{ {
/* -1 length means NULL */ /* -1 length means NULL */
values[i] = ReceiveFunctionCall(receiveproc, NULL,
typioparam, typmod);
nulls[i] = true; nulls[i] = true;
continue; continue;
} }
...@@ -1378,10 +1379,8 @@ ReadArrayBinary(StringInfo buf, ...@@ -1378,10 +1379,8 @@ ReadArrayBinary(StringInfo buf,
buf->data[buf->cursor] = '\0'; buf->data[buf->cursor] = '\0';
/* Now call the element's receiveproc */ /* Now call the element's receiveproc */
values[i] = FunctionCall3(receiveproc, values[i] = ReceiveFunctionCall(receiveproc, &elem_buf,
PointerGetDatum(&elem_buf), typioparam, typmod);
ObjectIdGetDatum(typioparam),
Int32GetDatum(typmod));
nulls[i] = false; nulls[i] = false;
/* Trouble if it didn't eat the whole buffer */ /* Trouble if it didn't eat the whole buffer */
...@@ -1515,10 +1514,7 @@ array_send(PG_FUNCTION_ARGS) ...@@ -1515,10 +1514,7 @@ array_send(PG_FUNCTION_ARGS)
bytea *outputbytes; bytea *outputbytes;
itemvalue = fetch_att(p, typbyval, typlen); itemvalue = fetch_att(p, typbyval, typlen);
outputbytes = SendFunctionCall(&my_extra->proc, itemvalue);
outputbytes = DatumGetByteaP(FunctionCall1(&my_extra->proc,
itemvalue));
/* We assume the result will not have been toasted */
pq_sendint(&buf, VARSIZE(outputbytes) - VARHDRSZ, 4); pq_sendint(&buf, VARSIZE(outputbytes) - VARHDRSZ, 4);
pq_sendbytes(&buf, VARDATA(outputbytes), pq_sendbytes(&buf, VARDATA(outputbytes),
VARSIZE(outputbytes) - VARHDRSZ); VARSIZE(outputbytes) - VARHDRSZ);
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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) ...@@ -136,6 +136,7 @@ record_in(PG_FUNCTION_ARGS)
{ {
ColumnIOData *column_info = &my_extra->columns[i]; ColumnIOData *column_info = &my_extra->columns[i];
Oid column_type = tupdesc->attrs[i]->atttypid; Oid column_type = tupdesc->attrs[i]->atttypid;
char *column_data;
/* Ignore dropped columns in datatype, but fill with nulls */ /* Ignore dropped columns in datatype, but fill with nulls */
if (tupdesc->attrs[i]->attisdropped) if (tupdesc->attrs[i]->attisdropped)
...@@ -161,7 +162,7 @@ record_in(PG_FUNCTION_ARGS) ...@@ -161,7 +162,7 @@ record_in(PG_FUNCTION_ARGS)
/* Check for null: completely empty input means null */ /* Check for null: completely empty input means null */
if (*ptr == ',' || *ptr == ')') if (*ptr == ',' || *ptr == ')')
{ {
values[i] = (Datum) 0; column_data = NULL;
nulls[i] = 'n'; nulls[i] = 'n';
} }
else else
...@@ -207,6 +208,10 @@ record_in(PG_FUNCTION_ARGS) ...@@ -207,6 +208,10 @@ record_in(PG_FUNCTION_ARGS)
appendStringInfoChar(&buf, ch); appendStringInfoChar(&buf, ch);
} }
column_data = buf.data;
nulls[i] = ' ';
}
/* /*
* Convert the column value * Convert the column value
*/ */
...@@ -220,12 +225,10 @@ record_in(PG_FUNCTION_ARGS) ...@@ -220,12 +225,10 @@ record_in(PG_FUNCTION_ARGS)
column_info->column_type = column_type; column_info->column_type = column_type;
} }
values[i] = FunctionCall3(&column_info->proc, values[i] = InputFunctionCall(&column_info->proc,
CStringGetDatum(buf.data), column_data,
ObjectIdGetDatum(column_info->typioparam), column_info->typioparam,
Int32GetDatum(tupdesc->attrs[i]->atttypmod)); tupdesc->attrs[i]->atttypmod);
nulls[i] = ' ';
}
/* /*
* Prep for next column * Prep for next column
...@@ -372,8 +375,7 @@ record_out(PG_FUNCTION_ARGS) ...@@ -372,8 +375,7 @@ record_out(PG_FUNCTION_ARGS)
column_info->column_type = column_type; column_info->column_type = column_type;
} }
value = DatumGetCString(FunctionCall1(&column_info->proc, value = OutputFunctionCall(&column_info->proc, values[i]);
values[i]));
/* Detect whether we need double quotes for this value */ /* Detect whether we need double quotes for this value */
nq = (value[0] == '\0'); /* force quotes for empty string */ nq = (value[0] == '\0'); /* force quotes for empty string */
...@@ -505,6 +507,9 @@ record_recv(PG_FUNCTION_ARGS) ...@@ -505,6 +507,9 @@ record_recv(PG_FUNCTION_ARGS)
Oid column_type = tupdesc->attrs[i]->atttypid; Oid column_type = tupdesc->attrs[i]->atttypid;
Oid coltypoid; Oid coltypoid;
int itemlen; int itemlen;
StringInfoData item_buf;
StringInfo bufptr;
char csave;
/* Ignore dropped columns in datatype, but fill with nulls */ /* Ignore dropped columns in datatype, but fill with nulls */
if (tupdesc->attrs[i]->attisdropped) if (tupdesc->attrs[i]->attisdropped)
...@@ -532,8 +537,9 @@ record_recv(PG_FUNCTION_ARGS) ...@@ -532,8 +537,9 @@ record_recv(PG_FUNCTION_ARGS)
if (itemlen == -1) if (itemlen == -1)
{ {
/* -1 length means NULL */ /* -1 length means NULL */
values[i] = (Datum) 0; bufptr = NULL;
nulls[i] = 'n'; nulls[i] = 'n';
csave = 0; /* keep compiler quiet */
} }
else else
{ {
...@@ -543,9 +549,6 @@ record_recv(PG_FUNCTION_ARGS) ...@@ -543,9 +549,6 @@ record_recv(PG_FUNCTION_ARGS)
* We assume we can scribble on the input buffer so as to maintain * We assume we can scribble on the input buffer so as to maintain
* the convention that StringInfos have a trailing null. * the convention that StringInfos have a trailing null.
*/ */
StringInfoData item_buf;
char csave;
item_buf.data = &buf->data[buf->cursor]; item_buf.data = &buf->data[buf->cursor];
item_buf.maxlen = itemlen + 1; item_buf.maxlen = itemlen + 1;
item_buf.len = itemlen; item_buf.len = itemlen;
...@@ -556,6 +559,10 @@ record_recv(PG_FUNCTION_ARGS) ...@@ -556,6 +559,10 @@ record_recv(PG_FUNCTION_ARGS)
csave = buf->data[buf->cursor]; csave = buf->data[buf->cursor];
buf->data[buf->cursor] = '\0'; buf->data[buf->cursor] = '\0';
bufptr = &item_buf;
nulls[i] = ' ';
}
/* Now call the column's receiveproc */ /* Now call the column's receiveproc */
if (column_info->column_type != column_type) if (column_info->column_type != column_type)
{ {
...@@ -567,12 +574,13 @@ record_recv(PG_FUNCTION_ARGS) ...@@ -567,12 +574,13 @@ record_recv(PG_FUNCTION_ARGS)
column_info->column_type = column_type; column_info->column_type = column_type;
} }
values[i] = FunctionCall3(&column_info->proc, values[i] = ReceiveFunctionCall(&column_info->proc,
PointerGetDatum(&item_buf), bufptr,
ObjectIdGetDatum(column_info->typioparam), column_info->typioparam,
Int32GetDatum(tupdesc->attrs[i]->atttypmod)); tupdesc->attrs[i]->atttypmod);
nulls[i] = ' ';
if (bufptr)
{
/* Trouble if it didn't eat the whole buffer */ /* Trouble if it didn't eat the whole buffer */
if (item_buf.cursor != itemlen) if (item_buf.cursor != itemlen)
ereport(ERROR, ereport(ERROR,
...@@ -712,8 +720,7 @@ record_send(PG_FUNCTION_ARGS) ...@@ -712,8 +720,7 @@ record_send(PG_FUNCTION_ARGS)
column_info->column_type = column_type; column_info->column_type = column_type;
} }
outputbytes = DatumGetByteaP(FunctionCall1(&column_info->proc, outputbytes = SendFunctionCall(&column_info->proc, values[i]);
values[i]));
/* We assume the result will not have been toasted */ /* We assume the result will not have been toasted */
pq_sendint(&buf, VARSIZE(outputbytes) - VARHDRSZ, 4); pq_sendint(&buf, VARSIZE(outputbytes) - VARHDRSZ, 4);
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
* ruleutils.c - Functions to convert stored expressions/querytrees * ruleutils.c - Functions to convert stored expressions/querytrees
* back to source text * 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" #include "postgres.h"
...@@ -3921,8 +3921,7 @@ get_const_expr(Const *constval, deparse_context *context) ...@@ -3921,8 +3921,7 @@ get_const_expr(Const *constval, deparse_context *context)
getTypeOutputInfo(constval->consttype, getTypeOutputInfo(constval->consttype,
&typoutput, &typIsVarlena); &typoutput, &typIsVarlena);
extval = DatumGetCString(OidFunctionCall1(typoutput, extval = OidOutputFunctionCall(typoutput, constval->constvalue);
constval->constvalue));
switch (constval->consttype) switch (constval->consttype)
{ {
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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) ...@@ -2580,8 +2580,7 @@ array_to_text(PG_FUNCTION_ARGS)
{ {
itemvalue = fetch_att(p, typbyval, typlen); itemvalue = fetch_att(p, typbyval, typlen);
value = DatumGetCString(FunctionCall1(&my_extra->proc, value = OutputFunctionCall(&my_extra->proc, itemvalue);
itemvalue));
if (printed) if (printed)
appendStringInfo(&buf, "%s%s", fldsep, value); appendStringInfo(&buf, "%s%s", fldsep, value);
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * 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 * NOTES
* Eventually, the index information should go through here, too. * Eventually, the index information should go through here, too.
...@@ -1554,10 +1554,8 @@ get_typdefault(Oid typid) ...@@ -1554,10 +1554,8 @@ get_typdefault(Oid typid)
strDefaultVal = DatumGetCString(DirectFunctionCall1(textout, strDefaultVal = DatumGetCString(DirectFunctionCall1(textout,
datum)); datum));
/* Convert C string to a value of the given type */ /* Convert C string to a value of the given type */
datum = OidFunctionCall3(type->typinput, datum = OidInputFunctionCall(type->typinput, strDefaultVal,
CStringGetDatum(strDefaultVal), getTypeIOParam(typeTuple), -1);
ObjectIdGetDatum(getTypeIOParam(typeTuple)),
Int32GetDatum(-1));
/* Build a Const node containing the value */ /* Build a Const node containing the value */
expr = (Node *) makeConst(typid, expr = (Node *) makeConst(typid,
type->typlen, type->typlen,
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -1682,6 +1682,172 @@ OidFunctionCall9(Oid functionId, Datum arg1, Datum arg2, ...@@ -1682,6 +1682,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 !!! * !!! OLD INTERFACE !!!
* *
......
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * 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 @@ ...@@ -20,6 +20,8 @@
/* We don't want to include primnodes.h here, so make a stub reference */ /* We don't want to include primnodes.h here, so make a stub reference */
typedef struct Node *fmNodePtr; 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, ...@@ -394,6 +396,20 @@ extern Datum OidFunctionCall9(Oid functionId, Datum arg1, Datum arg2,
Datum arg6, Datum arg7, Datum arg8, Datum arg6, Datum arg7, Datum arg8,
Datum arg9); 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 * Routines in fmgr.c
......
/********************************************************************** /**********************************************************************
* plperl.c - perl as a procedural language for PostgreSQL * 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) ...@@ -585,31 +585,35 @@ plperl_modify_tuple(HV *hvTD, TriggerData *tdata, HeapTuple otup)
while ((val = hv_iternextsv(hvNew, &key, &klen))) while ((val = hv_iternextsv(hvNew, &key, &klen)))
{ {
int attn = SPI_fnumber(tupdesc, key); int attn = SPI_fnumber(tupdesc, key);
Oid typinput;
Oid typioparam;
int32 atttypmod;
FmgrInfo finfo;
if (attn <= 0 || tupdesc->attrs[attn - 1]->attisdropped) if (attn <= 0 || tupdesc->attrs[attn - 1]->attisdropped)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_COLUMN), (errcode(ERRCODE_UNDEFINED_COLUMN),
errmsg("Perl hash contains nonexistent column \"%s\"", errmsg("Perl hash contains nonexistent column \"%s\"",
key))); key)));
if (SvOK(val) && SvTYPE(val) != SVt_NULL)
{
Oid typinput;
Oid typioparam;
FmgrInfo finfo;
/* XXX would be better to cache these lookups */ /* XXX would be better to cache these lookups */
getTypeInputInfo(tupdesc->attrs[attn - 1]->atttypid, getTypeInputInfo(tupdesc->attrs[attn - 1]->atttypid,
&typinput, &typioparam); &typinput, &typioparam);
fmgr_info(typinput, &finfo); fmgr_info(typinput, &finfo);
modvalues[slotsused] = FunctionCall3(&finfo, atttypmod = tupdesc->attrs[attn - 1]->atttypmod;
CStringGetDatum(SvPV(val, PL_na)), if (SvOK(val) && SvTYPE(val) != SVt_NULL)
ObjectIdGetDatum(typioparam), {
Int32GetDatum(tupdesc->attrs[attn - 1]->atttypmod)); modvalues[slotsused] = InputFunctionCall(&finfo,
SvPV(val, PL_na),
typioparam,
atttypmod);
modnulls[slotsused] = ' '; modnulls[slotsused] = ' ';
} }
else else
{ {
modvalues[slotsused] = (Datum) 0; modvalues[slotsused] = InputFunctionCall(&finfo,
NULL,
typioparam,
atttypmod);
modnulls[slotsused] = 'n'; modnulls[slotsused] = 'n';
} }
modattrs[slotsused] = attn; modattrs[slotsused] = attn;
...@@ -897,8 +901,8 @@ plperl_call_perl_func(plperl_proc_desc *desc, FunctionCallInfo fcinfo) ...@@ -897,8 +901,8 @@ plperl_call_perl_func(plperl_proc_desc *desc, FunctionCallInfo fcinfo)
{ {
char *tmp; char *tmp;
tmp = DatumGetCString(FunctionCall1(&(desc->arg_out_func[i]), tmp = OutputFunctionCall(&(desc->arg_out_func[i]),
fcinfo->arg[i])); fcinfo->arg[i]);
sv = newSVpv(tmp, 0); sv = newSVpv(tmp, 0);
#if PERL_BCDVERSION >= 0x5006000L #if PERL_BCDVERSION >= 0x5006000L
if (GetDatabaseEncoding() == PG_UTF8) if (GetDatabaseEncoding() == PG_UTF8)
...@@ -1091,8 +1095,9 @@ plperl_func_handler(PG_FUNCTION_ARGS) ...@@ -1091,8 +1095,9 @@ plperl_func_handler(PG_FUNCTION_ARGS)
/* Return NULL if Perl code returned undef */ /* Return NULL if Perl code returned undef */
if (rsi && IsA(rsi, ReturnSetInfo)) if (rsi && IsA(rsi, ReturnSetInfo))
rsi->isDone = ExprEndResult; rsi->isDone = ExprEndResult;
retval = InputFunctionCall(&prodesc->result_in_func, NULL,
prodesc->result_typioparam, -1);
fcinfo->isnull = true; fcinfo->isnull = true;
retval = (Datum) 0;
} }
else if (prodesc->fn_retistuple) else if (prodesc->fn_retistuple)
{ {
...@@ -1138,10 +1143,8 @@ plperl_func_handler(PG_FUNCTION_ARGS) ...@@ -1138,10 +1143,8 @@ plperl_func_handler(PG_FUNCTION_ARGS)
val = SvPV(perlret, PL_na); val = SvPV(perlret, PL_na);
retval = FunctionCall3(&prodesc->result_in_func, retval = InputFunctionCall(&prodesc->result_in_func, val,
CStringGetDatum(val), prodesc->result_typioparam, -1);
ObjectIdGetDatum(prodesc->result_typioparam),
Int32GetDatum(-1));
} }
if (array_ret == NULL) if (array_ret == NULL)
...@@ -1534,7 +1537,7 @@ plperl_hash_from_tuple(HeapTuple tuple, TupleDesc tupdesc) ...@@ -1534,7 +1537,7 @@ plperl_hash_from_tuple(HeapTuple tuple, TupleDesc tupdesc)
getTypeOutputInfo(tupdesc->attrs[i]->atttypid, getTypeOutputInfo(tupdesc->attrs[i]->atttypid,
&typoutput, &typisvarlena); &typoutput, &typisvarlena);
outputstr = DatumGetCString(OidFunctionCall1(typoutput, attr)); outputstr = OidOutputFunctionCall(typoutput, attr);
sv = newSVpv(outputstr, 0); sv = newSVpv(outputstr, 0);
#if PERL_BCDVERSION >= 0x5006000L #if PERL_BCDVERSION >= 0x5006000L
...@@ -1750,19 +1753,23 @@ plperl_return_next(SV *sv) ...@@ -1750,19 +1753,23 @@ plperl_return_next(SV *sv)
} }
else else
{ {
Datum ret = (Datum) 0; Datum ret;
bool isNull = true; bool isNull;
if (SvOK(sv) && SvTYPE(sv) != SVt_NULL) if (SvOK(sv) && SvTYPE(sv) != SVt_NULL)
{ {
char *val = SvPV(sv, PL_na); char *val = SvPV(sv, PL_na);
ret = FunctionCall3(&prodesc->result_in_func, ret = InputFunctionCall(&prodesc->result_in_func, val,
PointerGetDatum(val), prodesc->result_typioparam, -1);
ObjectIdGetDatum(prodesc->result_typioparam),
Int32GetDatum(-1));
isNull = false; 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); 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) ...@@ -2118,9 +2125,9 @@ plperl_spi_exec_prepared(char* query, HV * attr, int argc, SV ** argv)
/************************************************************ /************************************************************
* Set up arguments * Set up arguments
************************************************************/ ************************************************************/
if ( argc > 0) if (argc > 0)
{ {
nulls = (char *)palloc( argc); nulls = (char *) palloc(argc);
argvalues = (Datum *) palloc(argc * sizeof(Datum)); argvalues = (Datum *) palloc(argc * sizeof(Datum));
} }
else else
...@@ -2129,21 +2136,22 @@ plperl_spi_exec_prepared(char* query, HV * attr, int argc, SV ** argv) ...@@ -2129,21 +2136,22 @@ plperl_spi_exec_prepared(char* query, HV * attr, int argc, SV ** argv)
argvalues = NULL; 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] = argvalues[i] = InputFunctionCall(&qdesc->arginfuncs[i],
FunctionCall3( &qdesc->arginfuncs[i], SvPV(argv[i], PL_na),
CStringGetDatum( SvPV( argv[i], PL_na)), qdesc->argtypioparams[i],
ObjectIdGetDatum( qdesc->argtypioparams[i]), -1);
Int32GetDatum(-1)
);
nulls[i] = ' '; nulls[i] = ' ';
} }
else else
{ {
argvalues[i] = (Datum) 0; argvalues[i] = InputFunctionCall(&qdesc->arginfuncs[i],
NULL,
qdesc->argtypioparams[i],
-1);
nulls[i] = 'n'; nulls[i] = 'n';
} }
} }
...@@ -2247,9 +2255,9 @@ plperl_spi_query_prepared(char* query, int argc, SV ** argv) ...@@ -2247,9 +2255,9 @@ plperl_spi_query_prepared(char* query, int argc, SV ** argv)
/************************************************************ /************************************************************
* Set up arguments * Set up arguments
************************************************************/ ************************************************************/
if ( argc > 0) if (argc > 0)
{ {
nulls = (char *)palloc( argc); nulls = (char *) palloc(argc);
argvalues = (Datum *) palloc(argc * sizeof(Datum)); argvalues = (Datum *) palloc(argc * sizeof(Datum));
} }
else else
...@@ -2258,21 +2266,22 @@ plperl_spi_query_prepared(char* query, int argc, SV ** argv) ...@@ -2258,21 +2266,22 @@ plperl_spi_query_prepared(char* query, int argc, SV ** argv)
argvalues = NULL; 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] = argvalues[i] = InputFunctionCall(&qdesc->arginfuncs[i],
FunctionCall3( &qdesc->arginfuncs[i], SvPV(argv[i], PL_na),
CStringGetDatum( SvPV( argv[i], PL_na)), qdesc->argtypioparams[i],
ObjectIdGetDatum( qdesc->argtypioparams[i]), -1);
Int32GetDatum(-1)
);
nulls[i] = ' '; nulls[i] = ' ';
} }
else else
{ {
argvalues[i] = (Datum) 0; argvalues[i] = InputFunctionCall(&qdesc->arginfuncs[i],
NULL,
qdesc->argtypioparams[i],
-1);
nulls[i] = 'n'; nulls[i] = 'n';
} }
} }
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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, ...@@ -4043,6 +4043,8 @@ make_tuple_from_row(PLpgSQL_execstate *estate,
* *
* Note: callers generally assume that the result is a palloc'd string and * 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 ... * 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 * static char *
...@@ -4053,7 +4055,7 @@ convert_value_to_string(Datum value, Oid valtype) ...@@ -4053,7 +4055,7 @@ convert_value_to_string(Datum value, Oid valtype)
getTypeOutputInfo(valtype, &typoutput, &typIsVarlena); getTypeOutputInfo(valtype, &typoutput, &typIsVarlena);
return DatumGetCString(OidFunctionCall1(typoutput, value)); return OidOutputFunctionCall(typoutput, value);
} }
/* ---------- /* ----------
...@@ -4068,23 +4070,26 @@ exec_cast_value(Datum value, Oid valtype, ...@@ -4068,23 +4070,26 @@ exec_cast_value(Datum value, Oid valtype,
int32 reqtypmod, int32 reqtypmod,
bool isnull) bool isnull)
{ {
if (!isnull)
{
/* /*
* If the type of the queries return value isn't that of the variable, * If the type of the queries return value isn't that of the variable,
* convert it. * convert it.
*/ */
if (valtype != reqtype || reqtypmod != -1) if (valtype != reqtype || reqtypmod != -1)
{
if (!isnull)
{ {
char *extval; char *extval;
extval = convert_value_to_string(value, valtype); extval = convert_value_to_string(value, valtype);
value = FunctionCall3(reqinput, value = InputFunctionCall(reqinput, extval,
CStringGetDatum(extval), reqtypioparam, reqtypmod);
ObjectIdGetDatum(reqtypioparam),
Int32GetDatum(reqtypmod));
pfree(extval); pfree(extval);
} }
else
{
value = InputFunctionCall(reqinput, NULL,
reqtypioparam, reqtypmod);
}
} }
return value; return value;
......
/********************************************************************** /**********************************************************************
* plpython.c - python as a procedural language for PostgreSQL * 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, ...@@ -482,17 +482,24 @@ PLy_modify_tuple(PLyProcedure * proc, PyObject * pltd, TriggerData *tdata,
modattrs[i] = attn; 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); plstr = PyObject_Str(plval);
if (!plstr) 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); src = PyString_AsString(plstr);
modvalues[i] = FunctionCall3(&proc->result.out.r.atts[atti].typfunc, modvalues[i] =
CStringGetDatum(src), InputFunctionCall(&proc->result.out.r.atts[atti].typfunc,
ObjectIdGetDatum(proc->result.out.r.atts[atti].typioparam), src,
Int32GetDatum(tupdesc->attrs[atti]->atttypmod)); proc->result.out.r.atts[atti].typioparam,
tupdesc->attrs[atti]->atttypmod);
modnulls[i] = ' '; modnulls[i] = ' ';
Py_DECREF(plstr); Py_DECREF(plstr);
...@@ -500,7 +507,11 @@ PLy_modify_tuple(PLyProcedure * proc, PyObject * pltd, TriggerData *tdata, ...@@ -500,7 +507,11 @@ PLy_modify_tuple(PLyProcedure * proc, PyObject * pltd, TriggerData *tdata,
} }
else 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'; modnulls[i] = 'n';
} }
...@@ -751,7 +762,10 @@ PLy_function_handler(FunctionCallInfo fcinfo, PLyProcedure * proc) ...@@ -751,7 +762,10 @@ PLy_function_handler(FunctionCallInfo fcinfo, PLyProcedure * proc)
else if (plrv == Py_None) else if (plrv == Py_None)
{ {
fcinfo->isnull = true; fcinfo->isnull = true;
rv = PointerGetDatum(NULL); rv = InputFunctionCall(&proc->result.out.d.typfunc,
NULL,
proc->result.out.d.typioparam,
-1);
} }
else else
{ {
...@@ -760,10 +774,10 @@ PLy_function_handler(FunctionCallInfo fcinfo, PLyProcedure * proc) ...@@ -760,10 +774,10 @@ PLy_function_handler(FunctionCallInfo fcinfo, PLyProcedure * proc)
if (!plrv_so) if (!plrv_so)
PLy_elog(ERROR, "function \"%s\" could not create return value", proc->proname); PLy_elog(ERROR, "function \"%s\" could not create return value", proc->proname);
plrv_sc = PyString_AsString(plrv_so); plrv_sc = PyString_AsString(plrv_so);
rv = FunctionCall3(&proc->result.out.d.typfunc, rv = InputFunctionCall(&proc->result.out.d.typfunc,
PointerGetDatum(plrv_sc), plrv_sc,
ObjectIdGetDatum(proc->result.out.d.typioparam), proc->result.out.d.typioparam,
Int32GetDatum(-1)); -1);
} }
} }
PG_CATCH(); PG_CATCH();
...@@ -861,13 +875,9 @@ PLy_function_build_args(FunctionCallInfo fcinfo, PLyProcedure * proc) ...@@ -861,13 +875,9 @@ PLy_function_build_args(FunctionCallInfo fcinfo, PLyProcedure * proc)
else else
{ {
char *ct; char *ct;
Datum dt;
dt = FunctionCall3(&(proc->args[i].in.d.typfunc), ct = OutputFunctionCall(&(proc->args[i].in.d.typfunc),
fcinfo->arg[i], fcinfo->arg[i]);
ObjectIdGetDatum(proc->args[i].in.d.typioparam),
Int32GetDatum(-1));
ct = DatumGetCString(dt);
arg = (proc->args[i].in.d.func) (ct); arg = (proc->args[i].in.d.func) (ct);
pfree(ct); pfree(ct);
} }
...@@ -1454,8 +1464,7 @@ PLyDict_FromTuple(PLyTypeInfo * info, HeapTuple tuple, TupleDesc desc) ...@@ -1454,8 +1464,7 @@ PLyDict_FromTuple(PLyTypeInfo * info, HeapTuple tuple, TupleDesc desc)
{ {
char *key, char *key,
*vsrc; *vsrc;
Datum vattr, Datum vattr;
vdat;
bool is_null; bool is_null;
PyObject *value; PyObject *value;
...@@ -1469,11 +1478,8 @@ PLyDict_FromTuple(PLyTypeInfo * info, HeapTuple tuple, TupleDesc desc) ...@@ -1469,11 +1478,8 @@ PLyDict_FromTuple(PLyTypeInfo * info, HeapTuple tuple, TupleDesc desc)
PyDict_SetItemString(dict, key, Py_None); PyDict_SetItemString(dict, key, Py_None);
else else
{ {
vdat = FunctionCall3(&info->in.r.atts[i].typfunc, vsrc = OutputFunctionCall(&info->in.r.atts[i].typfunc,
vattr, vattr);
ObjectIdGetDatum(info->in.r.atts[i].typioparam),
Int32GetDatum(desc->attrs[i]->atttypmod));
vsrc = DatumGetCString(vdat);
/* /*
* no exceptions allowed * no exceptions allowed
...@@ -2035,10 +2041,10 @@ PLy_spi_execute_plan(PyObject * ob, PyObject * list, long limit) ...@@ -2035,10 +2041,10 @@ PLy_spi_execute_plan(PyObject * ob, PyObject * list, long limit)
char *sv = PyString_AsString(so); char *sv = PyString_AsString(so);
plan->values[i] = plan->values[i] =
FunctionCall3(&(plan->args[i].out.d.typfunc), InputFunctionCall(&(plan->args[i].out.d.typfunc),
CStringGetDatum(sv), sv,
ObjectIdGetDatum(plan->args[i].out.d.typioparam), plan->args[i].out.d.typioparam,
Int32GetDatum(-1)); -1);
} }
PG_CATCH(); PG_CATCH();
{ {
...@@ -2053,7 +2059,11 @@ PLy_spi_execute_plan(PyObject * ob, PyObject * list, long limit) ...@@ -2053,7 +2059,11 @@ PLy_spi_execute_plan(PyObject * ob, PyObject * list, long limit)
else else
{ {
Py_DECREF(elem); 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'; nulls[i] = 'n';
} }
} }
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
* pltcl.c - PostgreSQL support for Tcl as * pltcl.c - PostgreSQL support for Tcl as
* procedural language (PL) * 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) ...@@ -524,8 +524,8 @@ pltcl_func_handler(PG_FUNCTION_ARGS)
{ {
char *tmp; char *tmp;
tmp = DatumGetCString(FunctionCall1(&prodesc->arg_out_func[i], tmp = OutputFunctionCall(&prodesc->arg_out_func[i],
fcinfo->arg[i])); fcinfo->arg[i]);
UTF_BEGIN; UTF_BEGIN;
Tcl_DStringAppendElement(&tcl_cmd, UTF_E2U(tmp)); Tcl_DStringAppendElement(&tcl_cmd, UTF_E2U(tmp));
UTF_END; UTF_END;
...@@ -578,14 +578,17 @@ pltcl_func_handler(PG_FUNCTION_ARGS) ...@@ -578,14 +578,17 @@ pltcl_func_handler(PG_FUNCTION_ARGS)
elog(ERROR, "SPI_finish() failed"); elog(ERROR, "SPI_finish() failed");
if (fcinfo->isnull) if (fcinfo->isnull)
retval = (Datum) 0; retval = InputFunctionCall(&prodesc->result_in_func,
NULL,
prodesc->result_typioparam,
-1);
else else
{ {
UTF_BEGIN; UTF_BEGIN;
retval = FunctionCall3(&prodesc->result_in_func, retval = InputFunctionCall(&prodesc->result_in_func,
PointerGetDatum(UTF_U2E(interp->result)), UTF_U2E(interp->result),
ObjectIdGetDatum(prodesc->result_typioparam), prodesc->result_typioparam,
Int32GetDatum(-1)); -1);
UTF_END; UTF_END;
} }
...@@ -805,7 +808,6 @@ pltcl_trigger_handler(PG_FUNCTION_ARGS) ...@@ -805,7 +808,6 @@ pltcl_trigger_handler(PG_FUNCTION_ARGS)
/* Use a TRY to ensure ret_values will get freed */ /* Use a TRY to ensure ret_values will get freed */
PG_TRY(); PG_TRY();
{ {
if (ret_numvals % 2 != 0) if (ret_numvals % 2 != 0)
elog(ERROR, "invalid return list from trigger - must have even # of elements"); elog(ERROR, "invalid return list from trigger - must have even # of elements");
...@@ -871,11 +873,10 @@ pltcl_trigger_handler(PG_FUNCTION_ARGS) ...@@ -871,11 +873,10 @@ pltcl_trigger_handler(PG_FUNCTION_ARGS)
modnulls[attnum - 1] = ' '; modnulls[attnum - 1] = ' ';
fmgr_info(typinput, &finfo); fmgr_info(typinput, &finfo);
UTF_BEGIN; UTF_BEGIN;
modvalues[attnum - 1] = modvalues[attnum - 1] = InputFunctionCall(&finfo,
FunctionCall3(&finfo, (char *) UTF_U2E(ret_value),
CStringGetDatum(UTF_U2E(ret_value)), typioparam,
ObjectIdGetDatum(typioparam), tupdesc->attrs[attnum - 1]->atttypmod);
Int32GetDatum(tupdesc->attrs[attnum - 1]->atttypmod));
UTF_END; UTF_END;
} }
...@@ -2041,17 +2042,18 @@ pltcl_SPI_execute_plan(ClientData cdata, Tcl_Interp *interp, ...@@ -2041,17 +2042,18 @@ pltcl_SPI_execute_plan(ClientData cdata, Tcl_Interp *interp,
{ {
if (nulls && nulls[j] == 'n') if (nulls && nulls[j] == 'n')
{ {
/* don't try to convert the input for a null */ argvalues[j] = InputFunctionCall(&qdesc->arginfuncs[j],
argvalues[j] = (Datum) 0; NULL,
qdesc->argtypioparams[j],
-1);
} }
else else
{ {
UTF_BEGIN; UTF_BEGIN;
argvalues[j] = argvalues[j] = InputFunctionCall(&qdesc->arginfuncs[j],
FunctionCall3(&qdesc->arginfuncs[j], (char *) UTF_U2E(callargs[j]),
CStringGetDatum(UTF_U2E(callargs[j])), qdesc->argtypioparams[j],
ObjectIdGetDatum(qdesc->argtypioparams[j]), -1);
Int32GetDatum(-1));
UTF_END; UTF_END;
} }
} }
...@@ -2185,8 +2187,7 @@ pltcl_set_tuple_values(Tcl_Interp *interp, CONST84 char *arrayname, ...@@ -2185,8 +2187,7 @@ pltcl_set_tuple_values(Tcl_Interp *interp, CONST84 char *arrayname,
************************************************************/ ************************************************************/
if (!isnull && OidIsValid(typoutput)) if (!isnull && OidIsValid(typoutput))
{ {
outputstr = DatumGetCString(OidFunctionCall1(typoutput, outputstr = OidOutputFunctionCall(typoutput, attr);
attr));
UTF_BEGIN; UTF_BEGIN;
Tcl_SetVar2(interp, *arrptr, *nameptr, UTF_E2U(outputstr), 0); Tcl_SetVar2(interp, *arrptr, *nameptr, UTF_E2U(outputstr), 0);
UTF_END; UTF_END;
...@@ -2255,8 +2256,7 @@ pltcl_build_tuple_argument(HeapTuple tuple, TupleDesc tupdesc, ...@@ -2255,8 +2256,7 @@ pltcl_build_tuple_argument(HeapTuple tuple, TupleDesc tupdesc,
************************************************************/ ************************************************************/
if (!isnull && OidIsValid(typoutput)) if (!isnull && OidIsValid(typoutput))
{ {
outputstr = DatumGetCString(OidFunctionCall1(typoutput, outputstr = OidOutputFunctionCall(typoutput, attr);
attr));
Tcl_DStringAppendElement(retval, attname); Tcl_DStringAppendElement(retval, attname);
UTF_BEGIN; UTF_BEGIN;
Tcl_DStringAppendElement(retval, UTF_E2U(outputstr)); Tcl_DStringAppendElement(retval, UTF_E2U(outputstr));
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment