Hi,
> >
> >> The following plpgsql function errors out with cvs head:
> >>
> >> CREATE function test_assign() returns void
> >> AS
> >> $$ declare x int;
> >> BEGIN
> >> x := 9E3/2;
> >> END
> >> $$ LANGUAGE 'plpgsql';
> >>
> >> postgres=# select test_assign();
> >> ERROR: invalid input syntax for integer: "4500.0000000000000000"
> >> CONTEXT: PL/pgSQL function "test_assign" line 3 at assignment
> >>
> >> We do have an existing cast from numeric to type integer. But here
> >> basically we convert the value to string in exec_cast_value before
> calling
> >> int4in. And then use of strtol in pg_atoi leads to this complaint. Guess
> >> converting the value to string is not always a good strategy.
> >
> > PFA, patch which uses find_coercion_pathway to find a direct
> > COERCION_PATH_FUNC function and uses that if it is available. Or is there
> a
> > better approach? Seems to handle the above issue with this patch.
>
> +1
>
> I thing, so some values should by cached, current patch could by slow.
Agreed, it can slow things down a bit especially since we are only
interested in the COERCION_PATH_FUNC case. What we need is a much simpler
pathway function which searches in the SysCache and returns back with the
valid/invalid castfunc immediately.
PFA, version 2.0 of this patch with these changes in place. I could have
added a generic function in parse_coerce.c, but thought the use case was
restricted to plpgsql and hence I have kept it within pl_exec.c for now.
Regards,
Nikhils
--
http://www.enterprisedb.com
Index: src/pl/plpgsql/src/pl_exec.c
===================================================================
RCS file: /repositories/postgreshome/cvs/pgsql/src/pl/plpgsql/src/pl_exec.c,v
retrieving revision 1.225
diff -c -r1.225 pl_exec.c
*** src/pl/plpgsql/src/pl_exec.c 20 Nov 2008 15:36:22 -0000 1.225
--- src/pl/plpgsql/src/pl_exec.c 30 Dec 2008 07:31:36 -0000
***************
*** 20,29 ****
--- 20,31 ----
#include "access/transam.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_type.h"
+ #include "catalog/pg_cast.h"
#include "executor/spi_priv.h"
#include "funcapi.h"
#include "nodes/nodeFuncs.h"
#include "parser/scansup.h"
+ #include "parser/parse_coerce.h"
#include "tcop/tcopprot.h"
#include "utils/array.h"
#include "utils/builtins.h"
***************
*** 199,204 ****
--- 201,208 ----
static void free_params_data(PreparedParamsData *ppd);
static Portal exec_dynquery_with_params(PLpgSQL_execstate *estate,
PLpgSQL_expr *query, List *params);
+ static CoercionPathType find_assignment_coercion_pathway(Oid targetTypeId,
+ Oid sourceTypeId, Oid *funcid);
/* ----------
***************
*** 4732,4750 ****
{
if (!isnull)
{
! char *extval;
! extval = convert_value_to_string(value, valtype);
! /* Allow input function to use SPI ... see notes above */
! SPI_push();
! value = InputFunctionCall(reqinput, extval,
! reqtypioparam, reqtypmod);
! SPI_pop();
! pfree(extval);
}
else
{
--- 4736,4779 ----
{
if (!isnull)
{
! /*
! * find out if there is a coercion pathway via a function
! */
! CoercionPathType pathtype;
! Oid castfunc;
! pathtype = find_assignment_coercion_pathway(reqtype, valtype,
! &castfunc);
! if (pathtype == COERCION_PATH_FUNC)
! {
! FmgrInfo cast_func_finfo;
!
! fmgr_info_cxt(castfunc, &cast_func_finfo,
! CurrentMemoryContext);
! cast_func_finfo.fn_oid = InvalidOid;
!
! /* do we need reqtypmod for cast functions? */
! value = FunctionCall2(&cast_func_finfo,
! value,
! reqtypmod);
! }
! else
! {
! char *extval;
! extval = convert_value_to_string(value, valtype);
! /* Allow input function to use SPI ... see notes above */
! SPI_push();
! value = InputFunctionCall(reqinput, extval,
! reqtypioparam, reqtypmod);
!
! SPI_pop();
!
! pfree(extval);
! }
}
else
{
***************
*** 5456,5458 ****
--- 5485,5513 ----
return portal;
}
+
+ static CoercionPathType
+ find_assignment_coercion_pathway(Oid targetTypeId, Oid sourceTypeId, Oid *funcid)
+ {
+ CoercionPathType result = COERCION_PATH_NONE;
+ HeapTuple tuple;
+
+ /* Look in pg_cast */
+ tuple = SearchSysCache(CASTSOURCETARGET,
+ ObjectIdGetDatum(sourceTypeId),
+ ObjectIdGetDatum(targetTypeId),
+ 0, 0);
+
+ if (HeapTupleIsValid(tuple))
+ {
+ Form_pg_cast castForm = (Form_pg_cast) GETSTRUCT(tuple);
+
+ *funcid = castForm->castfunc;
+ ReleaseSysCache(tuple);
+ }
+
+ if (OidIsValid(*funcid))
+ result = COERCION_PATH_FUNC;
+
+ return result;
+ }
--
Sent via pgsql-hackers mailing list ([email protected])
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers