Skip to content

Commit 09130e5

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 4016bde commit 09130e5

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
@@ -523,3 +523,29 @@ SELECT * FROM trigger_test;
523523
0 |
524524
(1 row)
525525

526+
--
527+
-- Test that triggers honor typmod when assigning to tuple fields,
528+
-- as per an early 9.0 bug report
529+
--
530+
SET DateStyle = 'ISO';
531+
CREATE FUNCTION set_modif_time() RETURNS trigger AS $$
532+
TD['new']['modif_time'] = '2010-10-13 21:57:28.930486'
533+
return 'MODIFY'
534+
$$ LANGUAGE plpythonu;
535+
CREATE TABLE pb (a TEXT, modif_time TIMESTAMP(0) WITHOUT TIME ZONE);
536+
CREATE TRIGGER set_modif_time BEFORE UPDATE ON pb
537+
FOR EACH ROW EXECUTE PROCEDURE set_modif_time();
538+
INSERT INTO pb VALUES ('a', '2010-10-09 21:57:33.930486');
539+
SELECT * FROM pb;
540+
a | modif_time
541+
---+---------------------
542+
a | 2010-10-09 21:57:34
543+
(1 row)
544+
545+
UPDATE pb SET a = 'b';
546+
SELECT * FROM pb;
547+
a | modif_time
548+
---+---------------------
549+
b | 2010-10-13 21:57:29
550+
(1 row)
551+

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
@@ -1132,9 +1129,7 @@ PLy_function_handler(FunctionCallInfo fcinfo, PLyProcedure *proc)
11321129
else
11331130
{
11341131
fcinfo->isnull = false;
1135-
rv = (proc->result.out.d.func) (&proc->result,
1136-
&proc->result.out.d,
1137-
plrv);
1132+
rv = (proc->result.out.d.func) (&proc->result.out.d, -1, plrv);
11381133
}
11391134
}
11401135
PG_CATCH();
@@ -2099,9 +2094,7 @@ PLyDict_FromTuple(PLyTypeInfo *info, HeapTuple tuple, TupleDesc desc)
20992094
* type can parse.
21002095
*/
21012096
static Datum
2102-
PLyObject_ToBool(PLyTypeInfo *info,
2103-
PLyObToDatum *arg,
2104-
PyObject *plrv)
2097+
PLyObject_ToBool(PLyObToDatum *arg, int32 typmod, PyObject *plrv)
21052098
{
21062099
Datum rv;
21072100

@@ -2120,9 +2113,7 @@ PLyObject_ToBool(PLyTypeInfo *info,
21202113
* with embedded nulls. And it's faster this way.
21212114
*/
21222115
static Datum
2123-
PLyObject_ToBytea(PLyTypeInfo *info,
2124-
PLyObToDatum *arg,
2125-
PyObject *plrv)
2116+
PLyObject_ToBytea(PLyObToDatum *arg, int32 typmod, PyObject *plrv)
21262117
{
21272118
PyObject *volatile plrv_so = NULL;
21282119
Datum rv;
@@ -2164,9 +2155,7 @@ PLyObject_ToBytea(PLyTypeInfo *info,
21642155
* cstring into PostgreSQL type.
21652156
*/
21662157
static Datum
2167-
PLyObject_ToDatum(PLyTypeInfo *info,
2168-
PLyObToDatum *arg,
2169-
PyObject *plrv)
2158+
PLyObject_ToDatum(PLyObToDatum *arg, int32 typmod, PyObject *plrv)
21702159
{
21712160
PyObject *volatile plrv_bo = NULL;
21722161
Datum rv;
@@ -2202,7 +2191,10 @@ PLyObject_ToDatum(PLyTypeInfo *info,
22022191
else if (slen > plen)
22032192
elog(ERROR, "could not convert Python object into cstring: Python string longer than reported length");
22042193
pg_verifymbstr(plrv_sc, slen, false);
2205-
rv = InputFunctionCall(&arg->typfunc, plrv_sc, arg->typioparam, -1);
2194+
rv = InputFunctionCall(&arg->typfunc,
2195+
plrv_sc,
2196+
arg->typioparam,
2197+
typmod);
22062198
}
22072199
PG_CATCH();
22082200
{
@@ -2217,9 +2209,7 @@ PLyObject_ToDatum(PLyTypeInfo *info,
22172209
}
22182210

22192211
static Datum
2220-
PLySequence_ToArray(PLyTypeInfo *info,
2221-
PLyObToDatum *arg,
2222-
PyObject *plrv)
2212+
PLySequence_ToArray(PLyObToDatum *arg, int32 typmod, PyObject *plrv)
22232213
{
22242214
ArrayType *array;
22252215
int i;
@@ -2251,7 +2241,7 @@ PLySequence_ToArray(PLyTypeInfo *info,
22512241
* We don't support arrays of row types yet, so the first argument
22522242
* can be NULL.
22532243
*/
2254-
elems[i] = arg->elm->func(NULL, arg->elm, obj);
2244+
elems[i] = arg->elm->func(arg->elm, -1, obj);
22552245
}
22562246
Py_XDECREF(obj);
22572247
}
@@ -2300,7 +2290,7 @@ PLyMapping_ToTuple(PLyTypeInfo *info, PyObject *mapping)
23002290
}
23012291
else if (value)
23022292
{
2303-
values[i] = (att->func) (info, att, value);
2293+
values[i] = (att->func) (att, -1, value);
23042294
nulls[i] = false;
23052295
}
23062296
else
@@ -2377,7 +2367,7 @@ PLySequence_ToTuple(PLyTypeInfo *info, PyObject *sequence)
23772367
}
23782368
else if (value)
23792369
{
2380-
values[i] = (att->func) (info, att, value);
2370+
values[i] = (att->func) (att, -1, value);
23812371
nulls[i] = false;
23822372
}
23832373

@@ -2437,7 +2427,7 @@ PLyObject_ToTuple(PLyTypeInfo *info, PyObject *object)
24372427
}
24382428
else if (value)
24392429
{
2440-
values[i] = (att->func) (info, att, value);
2430+
values[i] = (att->func) (att, -1, value);
24412431
nulls[i] = false;
24422432
}
24432433
else
@@ -3019,7 +3009,9 @@ PLy_spi_execute_plan(PyObject *ob, PyObject *list, long limit)
30193009
PG_TRY();
30203010
{
30213011
plan->values[j] =
3022-
plan->args[j].out.d.func(NULL, &(plan->args[j].out.d), elem);
3012+
plan->args[j].out.d.func(&(plan->args[j].out.d),
3013+
-1,
3014+
elem);
30233015
}
30243016
PG_CATCH();
30253017
{

src/pl/plpython/sql/plpython_trigger.sql

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

305305
SELECT * FROM trigger_test;
306+
307+
308+
--
309+
-- Test that triggers honor typmod when assigning to tuple fields,
310+
-- as per an early 9.0 bug report
311+
--
312+
313+
SET DateStyle = 'ISO';
314+
315+
CREATE FUNCTION set_modif_time() RETURNS trigger AS $$
316+
TD['new']['modif_time'] = '2010-10-13 21:57:28.930486'
317+
return 'MODIFY'
318+
$$ LANGUAGE plpythonu;
319+
320+
CREATE TABLE pb (a TEXT, modif_time TIMESTAMP(0) WITHOUT TIME ZONE);
321+
322+
CREATE TRIGGER set_modif_time BEFORE UPDATE ON pb
323+
FOR EACH ROW EXECUTE PROCEDURE set_modif_time();
324+
325+
INSERT INTO pb VALUES ('a', '2010-10-09 21:57:33.930486');
326+
SELECT * FROM pb;
327+
UPDATE pb SET a = 'b';
328+
SELECT * FROM pb;

0 commit comments

Comments
 (0)