Fix plpython so that it again honors typmod while assigning to tuple fields.
authorTom Lane <tgl@sss.pgh.pa.us>
Tue, 12 Oct 2010 02:16:40 +0000 (22:16 -0400)
committerTom Lane <tgl@sss.pgh.pa.us>
Tue, 12 Oct 2010 02:16:40 +0000 (22:16 -0400)
This was broken in 9.0 while improving plpython's conversion behavior for
bytea and boolean.  Per bug report from maizi.

src/pl/plpython/expected/plpython_trigger.out
src/pl/plpython/plpython.c
src/pl/plpython/sql/plpython_trigger.sql

index 275d0f7439998552cfe5bbb87d68d86c4dbdb982..a78e96e4a16ba9d0a416f282ba1d870a5ca6f82d 100644 (file)
@@ -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)
+
index c468cf00d07fdf4a10b0e3177a77226d8066db5f..f3352b3bc6fe21d1c0ebfbb4c9fa6ea26ec9ff90 100644 (file)
@@ -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();
                {
index c3af5c211e6954f73be8abf002c8d63de1045f04..7520c79db58cca5dea8f18bfacca2d6962da91e8 100644 (file)
@@ -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;