Commit 09130e58 authored by Tom Lane's avatar Tom Lane

Fix plpython so that it again honors typmod while assigning to tuple fields.

This was broken in 9.0 while improving plpython's conversion behavior for
bytea and boolean.  Per bug report from maizi.
parent 4016bdef
...@@ -523,3 +523,29 @@ SELECT * FROM trigger_test; ...@@ -523,3 +523,29 @@ SELECT * FROM trigger_test;
0 | 0 |
(1 row) (1 row)
--
-- Test that triggers honor typmod when assigning to tuple fields,
-- as per an early 9.0 bug report
--
SET DateStyle = 'ISO';
CREATE FUNCTION set_modif_time() RETURNS trigger AS $$
TD['new']['modif_time'] = '2010-10-13 21:57:28.930486'
return 'MODIFY'
$$ LANGUAGE plpythonu;
CREATE TABLE pb (a TEXT, modif_time TIMESTAMP(0) WITHOUT TIME ZONE);
CREATE TRIGGER set_modif_time BEFORE UPDATE ON pb
FOR EACH ROW EXECUTE PROCEDURE set_modif_time();
INSERT INTO pb VALUES ('a', '2010-10-09 21:57:33.930486');
SELECT * FROM pb;
a | modif_time
---+---------------------
a | 2010-10-09 21:57:34
(1 row)
UPDATE pb SET a = 'b';
SELECT * FROM pb;
a | modif_time
---+---------------------
b | 2010-10-13 21:57:29
(1 row)
...@@ -153,10 +153,8 @@ typedef union PLyTypeInput ...@@ -153,10 +153,8 @@ typedef union PLyTypeInput
*/ */
struct PLyObToDatum; struct PLyObToDatum;
struct PLyTypeInfo; typedef Datum (*PLyObToDatumFunc) (struct PLyObToDatum *, int32 typmod,
typedef Datum (*PLyObToDatumFunc) (struct PLyTypeInfo *, PyObject *);
struct PLyObToDatum *,
PyObject *);
typedef struct PLyObToDatum typedef struct PLyObToDatum
{ {
...@@ -346,14 +344,10 @@ static PyObject *PLyList_FromArray(PLyDatumToOb *arg, Datum d); ...@@ -346,14 +344,10 @@ static PyObject *PLyList_FromArray(PLyDatumToOb *arg, Datum d);
static PyObject *PLyDict_FromTuple(PLyTypeInfo *, HeapTuple, TupleDesc); static PyObject *PLyDict_FromTuple(PLyTypeInfo *, HeapTuple, TupleDesc);
static Datum PLyObject_ToBool(PLyTypeInfo *, PLyObToDatum *, static Datum PLyObject_ToBool(PLyObToDatum *, int32, PyObject *);
PyObject *); static Datum PLyObject_ToBytea(PLyObToDatum *, int32, PyObject *);
static Datum PLyObject_ToBytea(PLyTypeInfo *, PLyObToDatum *, static Datum PLyObject_ToDatum(PLyObToDatum *, int32, PyObject *);
PyObject *); static Datum PLySequence_ToArray(PLyObToDatum *, int32, PyObject *);
static Datum PLyObject_ToDatum(PLyTypeInfo *, PLyObToDatum *,
PyObject *);
static Datum PLySequence_ToArray(PLyTypeInfo *, PLyObToDatum *,
PyObject *);
static HeapTuple PLyMapping_ToTuple(PLyTypeInfo *, PyObject *); static HeapTuple PLyMapping_ToTuple(PLyTypeInfo *, PyObject *);
static HeapTuple PLySequence_ToTuple(PLyTypeInfo *, PyObject *); static HeapTuple PLySequence_ToTuple(PLyTypeInfo *, PyObject *);
...@@ -421,7 +415,8 @@ static void ...@@ -421,7 +415,8 @@ static void
plpython_error_callback(void *arg) plpython_error_callback(void *arg)
{ {
if (PLy_curr_procedure) if (PLy_curr_procedure)
errcontext("PL/Python function \"%s\"", PLy_procedure_name(PLy_curr_procedure)); errcontext("PL/Python function \"%s\"",
PLy_procedure_name(PLy_curr_procedure));
} }
static void static void
...@@ -743,7 +738,9 @@ PLy_modify_tuple(PLyProcedure *proc, PyObject *pltd, TriggerData *tdata, ...@@ -743,7 +738,9 @@ PLy_modify_tuple(PLyProcedure *proc, PyObject *pltd, TriggerData *tdata,
{ {
PLyObToDatum *att = &proc->result.out.r.atts[atti]; PLyObToDatum *att = &proc->result.out.r.atts[atti];
modvalues[i] = (att->func) (&proc->result, att, plval); modvalues[i] = (att->func) (att,
tupdesc->attrs[atti]->atttypmod,
plval);
modnulls[i] = ' '; modnulls[i] = ' ';
} }
else else
...@@ -1132,9 +1129,7 @@ PLy_function_handler(FunctionCallInfo fcinfo, PLyProcedure *proc) ...@@ -1132,9 +1129,7 @@ PLy_function_handler(FunctionCallInfo fcinfo, PLyProcedure *proc)
else else
{ {
fcinfo->isnull = false; fcinfo->isnull = false;
rv = (proc->result.out.d.func) (&proc->result, rv = (proc->result.out.d.func) (&proc->result.out.d, -1, plrv);
&proc->result.out.d,
plrv);
} }
} }
PG_CATCH(); PG_CATCH();
...@@ -2099,9 +2094,7 @@ PLyDict_FromTuple(PLyTypeInfo *info, HeapTuple tuple, TupleDesc desc) ...@@ -2099,9 +2094,7 @@ PLyDict_FromTuple(PLyTypeInfo *info, HeapTuple tuple, TupleDesc desc)
* type can parse. * type can parse.
*/ */
static Datum static Datum
PLyObject_ToBool(PLyTypeInfo *info, PLyObject_ToBool(PLyObToDatum *arg, int32 typmod, PyObject *plrv)
PLyObToDatum *arg,
PyObject *plrv)
{ {
Datum rv; Datum rv;
...@@ -2120,9 +2113,7 @@ PLyObject_ToBool(PLyTypeInfo *info, ...@@ -2120,9 +2113,7 @@ PLyObject_ToBool(PLyTypeInfo *info,
* with embedded nulls. And it's faster this way. * with embedded nulls. And it's faster this way.
*/ */
static Datum static Datum
PLyObject_ToBytea(PLyTypeInfo *info, PLyObject_ToBytea(PLyObToDatum *arg, int32 typmod, PyObject *plrv)
PLyObToDatum *arg,
PyObject *plrv)
{ {
PyObject *volatile plrv_so = NULL; PyObject *volatile plrv_so = NULL;
Datum rv; Datum rv;
...@@ -2164,9 +2155,7 @@ PLyObject_ToBytea(PLyTypeInfo *info, ...@@ -2164,9 +2155,7 @@ PLyObject_ToBytea(PLyTypeInfo *info,
* cstring into PostgreSQL type. * cstring into PostgreSQL type.
*/ */
static Datum static Datum
PLyObject_ToDatum(PLyTypeInfo *info, PLyObject_ToDatum(PLyObToDatum *arg, int32 typmod, PyObject *plrv)
PLyObToDatum *arg,
PyObject *plrv)
{ {
PyObject *volatile plrv_bo = NULL; PyObject *volatile plrv_bo = NULL;
Datum rv; Datum rv;
...@@ -2202,7 +2191,10 @@ PLyObject_ToDatum(PLyTypeInfo *info, ...@@ -2202,7 +2191,10 @@ PLyObject_ToDatum(PLyTypeInfo *info,
else if (slen > plen) else if (slen > plen)
elog(ERROR, "could not convert Python object into cstring: Python string longer than reported length"); elog(ERROR, "could not convert Python object into cstring: Python string longer than reported length");
pg_verifymbstr(plrv_sc, slen, false); pg_verifymbstr(plrv_sc, slen, false);
rv = InputFunctionCall(&arg->typfunc, plrv_sc, arg->typioparam, -1); rv = InputFunctionCall(&arg->typfunc,
plrv_sc,
arg->typioparam,
typmod);
} }
PG_CATCH(); PG_CATCH();
{ {
...@@ -2217,9 +2209,7 @@ PLyObject_ToDatum(PLyTypeInfo *info, ...@@ -2217,9 +2209,7 @@ PLyObject_ToDatum(PLyTypeInfo *info,
} }
static Datum static Datum
PLySequence_ToArray(PLyTypeInfo *info, PLySequence_ToArray(PLyObToDatum *arg, int32 typmod, PyObject *plrv)
PLyObToDatum *arg,
PyObject *plrv)
{ {
ArrayType *array; ArrayType *array;
int i; int i;
...@@ -2251,7 +2241,7 @@ PLySequence_ToArray(PLyTypeInfo *info, ...@@ -2251,7 +2241,7 @@ PLySequence_ToArray(PLyTypeInfo *info,
* We don't support arrays of row types yet, so the first argument * We don't support arrays of row types yet, so the first argument
* can be NULL. * can be NULL.
*/ */
elems[i] = arg->elm->func(NULL, arg->elm, obj); elems[i] = arg->elm->func(arg->elm, -1, obj);
} }
Py_XDECREF(obj); Py_XDECREF(obj);
} }
...@@ -2300,7 +2290,7 @@ PLyMapping_ToTuple(PLyTypeInfo *info, PyObject *mapping) ...@@ -2300,7 +2290,7 @@ PLyMapping_ToTuple(PLyTypeInfo *info, PyObject *mapping)
} }
else if (value) else if (value)
{ {
values[i] = (att->func) (info, att, value); values[i] = (att->func) (att, -1, value);
nulls[i] = false; nulls[i] = false;
} }
else else
...@@ -2377,7 +2367,7 @@ PLySequence_ToTuple(PLyTypeInfo *info, PyObject *sequence) ...@@ -2377,7 +2367,7 @@ PLySequence_ToTuple(PLyTypeInfo *info, PyObject *sequence)
} }
else if (value) else if (value)
{ {
values[i] = (att->func) (info, att, value); values[i] = (att->func) (att, -1, value);
nulls[i] = false; nulls[i] = false;
} }
...@@ -2437,7 +2427,7 @@ PLyObject_ToTuple(PLyTypeInfo *info, PyObject *object) ...@@ -2437,7 +2427,7 @@ PLyObject_ToTuple(PLyTypeInfo *info, PyObject *object)
} }
else if (value) else if (value)
{ {
values[i] = (att->func) (info, att, value); values[i] = (att->func) (att, -1, value);
nulls[i] = false; nulls[i] = false;
} }
else else
...@@ -3019,7 +3009,9 @@ PLy_spi_execute_plan(PyObject *ob, PyObject *list, long limit) ...@@ -3019,7 +3009,9 @@ PLy_spi_execute_plan(PyObject *ob, PyObject *list, long limit)
PG_TRY(); PG_TRY();
{ {
plan->values[j] = plan->values[j] =
plan->args[j].out.d.func(NULL, &(plan->args[j].out.d), elem); plan->args[j].out.d.func(&(plan->args[j].out.d),
-1,
elem);
} }
PG_CATCH(); PG_CATCH();
{ {
......
...@@ -303,3 +303,26 @@ UPDATE trigger_test SET v = 'null' WHERE i = 0; ...@@ -303,3 +303,26 @@ UPDATE trigger_test SET v = 'null' WHERE i = 0;
DROP TRIGGER test_null_trigger ON trigger_test; DROP TRIGGER test_null_trigger ON trigger_test;
SELECT * FROM trigger_test; SELECT * FROM trigger_test;
--
-- Test that triggers honor typmod when assigning to tuple fields,
-- as per an early 9.0 bug report
--
SET DateStyle = 'ISO';
CREATE FUNCTION set_modif_time() RETURNS trigger AS $$
TD['new']['modif_time'] = '2010-10-13 21:57:28.930486'
return 'MODIFY'
$$ LANGUAGE plpythonu;
CREATE TABLE pb (a TEXT, modif_time TIMESTAMP(0) WITHOUT TIME ZONE);
CREATE TRIGGER set_modif_time BEFORE UPDATE ON pb
FOR EACH ROW EXECUTE PROCEDURE set_modif_time();
INSERT INTO pb VALUES ('a', '2010-10-09 21:57:33.930486');
SELECT * FROM pb;
UPDATE pb SET a = 'b';
SELECT * FROM pb;
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