diff options
| author | Tom Lane | 2006-04-04 19:35:37 +0000 |
|---|---|---|
| committer | Tom Lane | 2006-04-04 19:35:37 +0000 |
| commit | 147d4bf3e5e3da2ee0f0cc132718ab1c4912a877 (patch) | |
| tree | e02e6a191197edb5224ab5f831146854fde7d460 /src/pl | |
| parent | eaef111396ef7e70c88979c7a82f6a8f918d9651 (diff) | |
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.
Diffstat (limited to 'src/pl')
| -rw-r--r-- | src/pl/plperl/plperl.c | 109 | ||||
| -rw-r--r-- | src/pl/plpgsql/src/pl_exec.c | 29 | ||||
| -rw-r--r-- | src/pl/plpython/plpython.c | 72 | ||||
| -rw-r--r-- | src/pl/tcl/pltcl.c | 50 |
4 files changed, 142 insertions, 118 deletions
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)); |
