summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/pl/plpython/expected/plpython_trigger.out26
-rw-r--r--src/pl/plpython/plpython.c62
-rw-r--r--src/pl/plpython/sql/plpython_trigger.sql23
3 files changed, 76 insertions, 35 deletions
diff --git a/src/pl/plpython/expected/plpython_trigger.out b/src/pl/plpython/expected/plpython_trigger.out
index 275d0f74399..a78e96e4a16 100644
--- a/src/pl/plpython/expected/plpython_trigger.out
+++ b/src/pl/plpython/expected/plpython_trigger.out
@@ -523,3 +523,29 @@ SELECT * FROM trigger_test;
0 |
(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)
+
diff --git a/src/pl/plpython/plpython.c b/src/pl/plpython/plpython.c
index c468cf00d07..f3352b3bc6f 100644
--- a/src/pl/plpython/plpython.c
+++ b/src/pl/plpython/plpython.c
@@ -153,10 +153,8 @@ typedef union PLyTypeInput
*/
struct PLyObToDatum;
-struct PLyTypeInfo;
-typedef Datum (*PLyObToDatumFunc) (struct PLyTypeInfo *,
- struct PLyObToDatum *,
- PyObject *);
+typedef Datum (*PLyObToDatumFunc) (struct PLyObToDatum *, int32 typmod,
+ PyObject *);
typedef struct PLyObToDatum
{
@@ -346,14 +344,10 @@ static PyObject *PLyList_FromArray(PLyDatumToOb *arg, Datum d);
static PyObject *PLyDict_FromTuple(PLyTypeInfo *, HeapTuple, TupleDesc);
-static Datum PLyObject_ToBool(PLyTypeInfo *, PLyObToDatum *,
- PyObject *);
-static Datum PLyObject_ToBytea(PLyTypeInfo *, PLyObToDatum *,
- PyObject *);
-static Datum PLyObject_ToDatum(PLyTypeInfo *, PLyObToDatum *,
- PyObject *);
-static Datum PLySequence_ToArray(PLyTypeInfo *, PLyObToDatum *,
- PyObject *);
+static Datum PLyObject_ToBool(PLyObToDatum *, int32, PyObject *);
+static Datum PLyObject_ToBytea(PLyObToDatum *, int32, PyObject *);
+static Datum PLyObject_ToDatum(PLyObToDatum *, int32, PyObject *);
+static Datum PLySequence_ToArray(PLyObToDatum *, int32, PyObject *);
static HeapTuple PLyMapping_ToTuple(PLyTypeInfo *, PyObject *);
static HeapTuple PLySequence_ToTuple(PLyTypeInfo *, PyObject *);
@@ -421,7 +415,8 @@ static void
plpython_error_callback(void *arg)
{
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
@@ -743,7 +738,9 @@ PLy_modify_tuple(PLyProcedure *proc, PyObject *pltd, TriggerData *tdata,
{
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] = ' ';
}
else
@@ -1132,9 +1129,7 @@ PLy_function_handler(FunctionCallInfo fcinfo, PLyProcedure *proc)
else
{
fcinfo->isnull = false;
- rv = (proc->result.out.d.func) (&proc->result,
- &proc->result.out.d,
- plrv);
+ rv = (proc->result.out.d.func) (&proc->result.out.d, -1, plrv);
}
}
PG_CATCH();
@@ -2099,9 +2094,7 @@ PLyDict_FromTuple(PLyTypeInfo *info, HeapTuple tuple, TupleDesc desc)
* type can parse.
*/
static Datum
-PLyObject_ToBool(PLyTypeInfo *info,
- PLyObToDatum *arg,
- PyObject *plrv)
+PLyObject_ToBool(PLyObToDatum *arg, int32 typmod, PyObject *plrv)
{
Datum rv;
@@ -2120,9 +2113,7 @@ PLyObject_ToBool(PLyTypeInfo *info,
* with embedded nulls. And it's faster this way.
*/
static Datum
-PLyObject_ToBytea(PLyTypeInfo *info,
- PLyObToDatum *arg,
- PyObject *plrv)
+PLyObject_ToBytea(PLyObToDatum *arg, int32 typmod, PyObject *plrv)
{
PyObject *volatile plrv_so = NULL;
Datum rv;
@@ -2164,9 +2155,7 @@ PLyObject_ToBytea(PLyTypeInfo *info,
* cstring into PostgreSQL type.
*/
static Datum
-PLyObject_ToDatum(PLyTypeInfo *info,
- PLyObToDatum *arg,
- PyObject *plrv)
+PLyObject_ToDatum(PLyObToDatum *arg, int32 typmod, PyObject *plrv)
{
PyObject *volatile plrv_bo = NULL;
Datum rv;
@@ -2202,7 +2191,10 @@ PLyObject_ToDatum(PLyTypeInfo *info,
else if (slen > plen)
elog(ERROR, "could not convert Python object into cstring: Python string longer than reported length");
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();
{
@@ -2217,9 +2209,7 @@ PLyObject_ToDatum(PLyTypeInfo *info,
}
static Datum
-PLySequence_ToArray(PLyTypeInfo *info,
- PLyObToDatum *arg,
- PyObject *plrv)
+PLySequence_ToArray(PLyObToDatum *arg, int32 typmod, PyObject *plrv)
{
ArrayType *array;
int i;
@@ -2251,7 +2241,7 @@ PLySequence_ToArray(PLyTypeInfo *info,
* We don't support arrays of row types yet, so the first argument
* can be NULL.
*/
- elems[i] = arg->elm->func(NULL, arg->elm, obj);
+ elems[i] = arg->elm->func(arg->elm, -1, obj);
}
Py_XDECREF(obj);
}
@@ -2300,7 +2290,7 @@ PLyMapping_ToTuple(PLyTypeInfo *info, PyObject *mapping)
}
else if (value)
{
- values[i] = (att->func) (info, att, value);
+ values[i] = (att->func) (att, -1, value);
nulls[i] = false;
}
else
@@ -2377,7 +2367,7 @@ PLySequence_ToTuple(PLyTypeInfo *info, PyObject *sequence)
}
else if (value)
{
- values[i] = (att->func) (info, att, value);
+ values[i] = (att->func) (att, -1, value);
nulls[i] = false;
}
@@ -2437,7 +2427,7 @@ PLyObject_ToTuple(PLyTypeInfo *info, PyObject *object)
}
else if (value)
{
- values[i] = (att->func) (info, att, value);
+ values[i] = (att->func) (att, -1, value);
nulls[i] = false;
}
else
@@ -3019,7 +3009,9 @@ PLy_spi_execute_plan(PyObject *ob, PyObject *list, long limit)
PG_TRY();
{
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();
{
diff --git a/src/pl/plpython/sql/plpython_trigger.sql b/src/pl/plpython/sql/plpython_trigger.sql
index c3af5c211e6..7520c79db58 100644
--- a/src/pl/plpython/sql/plpython_trigger.sql
+++ b/src/pl/plpython/sql/plpython_trigger.sql
@@ -303,3 +303,26 @@ UPDATE trigger_test SET v = 'null' WHERE i = 0;
DROP TRIGGER test_null_trigger ON 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;