Skip to content

Commit 67120d3

Browse files
committed
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.
1 parent 3b6eb75 commit 67120d3

File tree

3 files changed

+76
-35
lines changed

3 files changed

+76
-35
lines changed

src/pl/plpython/expected/plpython_trigger.out

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -453,3 +453,29 @@ SELECT * FROM trigger_test;
453453
0 |
454454
(1 row)
455455

456+
--
457+
-- Test that triggers honor typmod when assigning to tuple fields,
458+
-- as per an early 9.0 bug report
459+
--
460+
SET DateStyle = 'ISO';
461+
CREATE FUNCTION set_modif_time() RETURNS trigger AS $$
462+
TD['new']['modif_time'] = '2010-10-13 21:57:28.930486'
463+
return 'MODIFY'
464+
$$ LANGUAGE plpythonu;
465+
CREATE TABLE pb (a TEXT, modif_time TIMESTAMP(0) WITHOUT TIME ZONE);
466+
CREATE TRIGGER set_modif_time BEFORE UPDATE ON pb
467+
FOR EACH ROW EXECUTE PROCEDURE set_modif_time();
468+
INSERT INTO pb VALUES ('a', '2010-10-09 21:57:33.930486');
469+
SELECT * FROM pb;
470+
a | modif_time
471+
---+---------------------
472+
a | 2010-10-09 21:57:34
473+
(1 row)
474+
475+
UPDATE pb SET a = 'b';
476+
SELECT * FROM pb;
477+
a | modif_time
478+
---+---------------------
479+
b | 2010-10-13 21:57:29
480+
(1 row)
481+

src/pl/plpython/plpython.c

Lines changed: 27 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -153,10 +153,8 @@ typedef union PLyTypeInput
153153
*/
154154

155155
struct PLyObToDatum;
156-
struct PLyTypeInfo;
157-
typedef Datum (*PLyObToDatumFunc) (struct PLyTypeInfo *,
158-
struct PLyObToDatum *,
159-
PyObject *);
156+
typedef Datum (*PLyObToDatumFunc) (struct PLyObToDatum *, int32 typmod,
157+
PyObject *);
160158

161159
typedef struct PLyObToDatum
162160
{
@@ -346,14 +344,10 @@ static PyObject *PLyList_FromArray(PLyDatumToOb *arg, Datum d);
346344

347345
static PyObject *PLyDict_FromTuple(PLyTypeInfo *, HeapTuple, TupleDesc);
348346

349-
static Datum PLyObject_ToBool(PLyTypeInfo *, PLyObToDatum *,
350-
PyObject *);
351-
static Datum PLyObject_ToBytea(PLyTypeInfo *, PLyObToDatum *,
352-
PyObject *);
353-
static Datum PLyObject_ToDatum(PLyTypeInfo *, PLyObToDatum *,
354-
PyObject *);
355-
static Datum PLySequence_ToArray(PLyTypeInfo *, PLyObToDatum *,
356-
PyObject *);
347+
static Datum PLyObject_ToBool(PLyObToDatum *, int32, PyObject *);
348+
static Datum PLyObject_ToBytea(PLyObToDatum *, int32, PyObject *);
349+
static Datum PLyObject_ToDatum(PLyObToDatum *, int32, PyObject *);
350+
static Datum PLySequence_ToArray(PLyObToDatum *, int32, PyObject *);
357351

358352
static HeapTuple PLyMapping_ToTuple(PLyTypeInfo *, PyObject *);
359353
static HeapTuple PLySequence_ToTuple(PLyTypeInfo *, PyObject *);
@@ -421,7 +415,8 @@ static void
421415
plpython_error_callback(void *arg)
422416
{
423417
if (PLy_curr_procedure)
424-
errcontext("PL/Python function \"%s\"", PLy_procedure_name(PLy_curr_procedure));
418+
errcontext("PL/Python function \"%s\"",
419+
PLy_procedure_name(PLy_curr_procedure));
425420
}
426421

427422
static void
@@ -743,7 +738,9 @@ PLy_modify_tuple(PLyProcedure *proc, PyObject *pltd, TriggerData *tdata,
743738
{
744739
PLyObToDatum *att = &proc->result.out.r.atts[atti];
745740

746-
modvalues[i] = (att->func) (&proc->result, att, plval);
741+
modvalues[i] = (att->func) (att,
742+
tupdesc->attrs[atti]->atttypmod,
743+
plval);
747744
modnulls[i] = ' ';
748745
}
749746
else
@@ -1131,9 +1128,7 @@ PLy_function_handler(FunctionCallInfo fcinfo, PLyProcedure *proc)
11311128
else
11321129
{
11331130
fcinfo->isnull = false;
1134-
rv = (proc->result.out.d.func) (&proc->result,
1135-
&proc->result.out.d,
1136-
plrv);
1131+
rv = (proc->result.out.d.func) (&proc->result.out.d, -1, plrv);
11371132
}
11381133
}
11391134
PG_CATCH();
@@ -2098,9 +2093,7 @@ PLyDict_FromTuple(PLyTypeInfo *info, HeapTuple tuple, TupleDesc desc)
20982093
* type can parse.
20992094
*/
21002095
static Datum
2101-
PLyObject_ToBool(PLyTypeInfo *info,
2102-
PLyObToDatum *arg,
2103-
PyObject *plrv)
2096+
PLyObject_ToBool(PLyObToDatum *arg, int32 typmod, PyObject *plrv)
21042097
{
21052098
Datum rv;
21062099

@@ -2119,9 +2112,7 @@ PLyObject_ToBool(PLyTypeInfo *info,
21192112
* with embedded nulls. And it's faster this way.
21202113
*/
21212114
static Datum
2122-
PLyObject_ToBytea(PLyTypeInfo *info,
2123-
PLyObToDatum *arg,
2124-
PyObject *plrv)
2115+
PLyObject_ToBytea(PLyObToDatum *arg, int32 typmod, PyObject *plrv)
21252116
{
21262117
PyObject *volatile plrv_so = NULL;
21272118
Datum rv;
@@ -2163,9 +2154,7 @@ PLyObject_ToBytea(PLyTypeInfo *info,
21632154
* cstring into PostgreSQL type.
21642155
*/
21652156
static Datum
2166-
PLyObject_ToDatum(PLyTypeInfo *info,
2167-
PLyObToDatum *arg,
2168-
PyObject *plrv)
2157+
PLyObject_ToDatum(PLyObToDatum *arg, int32 typmod, PyObject *plrv)
21692158
{
21702159
PyObject *volatile plrv_bo = NULL;
21712160
Datum rv;
@@ -2201,7 +2190,10 @@ PLyObject_ToDatum(PLyTypeInfo *info,
22012190
else if (slen > plen)
22022191
elog(ERROR, "could not convert Python object into cstring: Python string longer than reported length");
22032192
pg_verifymbstr(plrv_sc, slen, false);
2204-
rv = InputFunctionCall(&arg->typfunc, plrv_sc, arg->typioparam, -1);
2193+
rv = InputFunctionCall(&arg->typfunc,
2194+
plrv_sc,
2195+
arg->typioparam,
2196+
typmod);
22052197
}
22062198
PG_CATCH();
22072199
{
@@ -2216,9 +2208,7 @@ PLyObject_ToDatum(PLyTypeInfo *info,
22162208
}
22172209

22182210
static Datum
2219-
PLySequence_ToArray(PLyTypeInfo *info,
2220-
PLyObToDatum *arg,
2221-
PyObject *plrv)
2211+
PLySequence_ToArray(PLyObToDatum *arg, int32 typmod, PyObject *plrv)
22222212
{
22232213
ArrayType *array;
22242214
int i;
@@ -2250,7 +2240,7 @@ PLySequence_ToArray(PLyTypeInfo *info,
22502240
* We don't support arrays of row types yet, so the first argument
22512241
* can be NULL.
22522242
*/
2253-
elems[i] = arg->elm->func(NULL, arg->elm, obj);
2243+
elems[i] = arg->elm->func(arg->elm, -1, obj);
22542244
}
22552245
Py_XDECREF(obj);
22562246
}
@@ -2299,7 +2289,7 @@ PLyMapping_ToTuple(PLyTypeInfo *info, PyObject *mapping)
22992289
}
23002290
else if (value)
23012291
{
2302-
values[i] = (att->func) (info, att, value);
2292+
values[i] = (att->func) (att, -1, value);
23032293
nulls[i] = false;
23042294
}
23052295
else
@@ -2376,7 +2366,7 @@ PLySequence_ToTuple(PLyTypeInfo *info, PyObject *sequence)
23762366
}
23772367
else if (value)
23782368
{
2379-
values[i] = (att->func) (info, att, value);
2369+
values[i] = (att->func) (att, -1, value);
23802370
nulls[i] = false;
23812371
}
23822372

@@ -2436,7 +2426,7 @@ PLyObject_ToTuple(PLyTypeInfo *info, PyObject *object)
24362426
}
24372427
else if (value)
24382428
{
2439-
values[i] = (att->func) (info, att, value);
2429+
values[i] = (att->func) (att, -1, value);
24402430
nulls[i] = false;
24412431
}
24422432
else
@@ -3018,7 +3008,9 @@ PLy_spi_execute_plan(PyObject *ob, PyObject *list, long limit)
30183008
PG_TRY();
30193009
{
30203010
plan->values[j] =
3021-
plan->args[j].out.d.func(NULL, &(plan->args[j].out.d), elem);
3011+
plan->args[j].out.d.func(&(plan->args[j].out.d),
3012+
-1,
3013+
elem);
30223014
}
30233015
PG_CATCH();
30243016
{

src/pl/plpython/sql/plpython_trigger.sql

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -286,3 +286,26 @@ UPDATE trigger_test SET v = 'null' WHERE i = 0;
286286
DROP TRIGGER test_null_trigger ON trigger_test;
287287

288288
SELECT * FROM trigger_test;
289+
290+
291+
--
292+
-- Test that triggers honor typmod when assigning to tuple fields,
293+
-- as per an early 9.0 bug report
294+
--
295+
296+
SET DateStyle = 'ISO';
297+
298+
CREATE FUNCTION set_modif_time() RETURNS trigger AS $$
299+
TD['new']['modif_time'] = '2010-10-13 21:57:28.930486'
300+
return 'MODIFY'
301+
$$ LANGUAGE plpythonu;
302+
303+
CREATE TABLE pb (a TEXT, modif_time TIMESTAMP(0) WITHOUT TIME ZONE);
304+
305+
CREATE TRIGGER set_modif_time BEFORE UPDATE ON pb
306+
FOR EACH ROW EXECUTE PROCEDURE set_modif_time();
307+
308+
INSERT INTO pb VALUES ('a', '2010-10-09 21:57:33.930486');
309+
SELECT * FROM pb;
310+
UPDATE pb SET a = 'b';
311+
SELECT * FROM pb;

0 commit comments

Comments
 (0)