On 11/8/16 8:33 AM, Tom Lane wrote:
As things stand in HEAD, the behavior is about the same, but the error
messages are not --- in one case they mention triggers and of course the
other doesn't.  There are a couple of other minor things in the way of
unifying the two hunks of code, so I concluded it probably wasn't worth
the trouble.  But feel free to take another look if it bugs you.

I had to add a bit of cruft to pltcl_build_tuple_result but it's not that bad. tg_tupdesc could potentially be eliminated, but I don't know if it's really worth it.

Note that this does change some of the trigger error messages, but I don't think that's really an issue?
--
Jim Nasby, Data Architect, Blue Treble Consulting, Austin TX
Experts in Analytics, Data Architecture and PostgreSQL
Data in Trouble? Get it in Treble! http://BlueTreble.com
855-TREBLE2 (855-873-2532)   mobile: 512-569-9461
diff --git a/src/pl/tcl/pltcl.c b/src/pl/tcl/pltcl.c
index b0d9e41..25d959e 100644
--- a/src/pl/tcl/pltcl.c
+++ b/src/pl/tcl/pltcl.c
@@ -301,7 +301,8 @@ static void pltcl_set_tuple_values(Tcl_Interp *interp, 
const char *arrayname,
 static Tcl_Obj *pltcl_build_tuple_argument(HeapTuple tuple, TupleDesc tupdesc);
 static HeapTuple pltcl_build_tuple_result(Tcl_Interp *interp,
                                                 Tcl_Obj **kvObjv, int kvObjc,
-                                                pltcl_call_state *call_state);
+                                                pltcl_call_state *call_state,
+                                                TupleDesc tg_tupdesc);
 static void pltcl_init_tuple_store(pltcl_call_state *call_state);
 
 
@@ -966,7 +967,7 @@ pltcl_func_handler(PG_FUNCTION_ARGS, pltcl_call_state 
*call_state,
                        throw_tcl_error(interp, prodesc->user_proname);
 
                tup = pltcl_build_tuple_result(interp, resultObjv, resultObjc,
-                                                                          
call_state);
+                                                                          
call_state, NULL);
                retval = HeapTupleGetDatum(tup);
        }
        else
@@ -1000,8 +1001,6 @@ pltcl_trigger_handler(PG_FUNCTION_ARGS, pltcl_call_state 
*call_state,
        const char *result;
        int                     result_Objc;
        Tcl_Obj   **result_Objv;
-       Datum      *values;
-       bool       *nulls;
 
        /* Connect to SPI manager */
        if (SPI_connect() != SPI_OK_CONNECT)
@@ -1219,70 +1218,9 @@ pltcl_trigger_handler(PG_FUNCTION_ARGS, pltcl_call_state 
*call_state,
                                 errmsg("could not split return value from 
trigger: %s",
                                                
utf_u2e(Tcl_GetStringResult(interp)))));
 
-       if (result_Objc % 2 != 0)
-               ereport(ERROR,
-                               
(errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED),
-                errmsg("trigger's return list must have even number of 
elements")));
-
-       values = (Datum *) palloc0(tupdesc->natts * sizeof(Datum));
-       nulls = (bool *) palloc(tupdesc->natts * sizeof(bool));
-       memset(nulls, true, tupdesc->natts * sizeof(bool));
-
-       for (i = 0; i < result_Objc; i += 2)
-       {
-               char       *ret_name = utf_u2e(Tcl_GetString(result_Objv[i]));
-               char       *ret_value = utf_u2e(Tcl_GetString(result_Objv[i + 
1]));
-               int                     attnum;
-               Oid                     typinput;
-               Oid                     typioparam;
-               FmgrInfo        finfo;
-
-               /************************************************************
-                * Get the attribute number
-                *
-                * We silently ignore ".tupno", if it's present but doesn't 
match
-                * any actual output column.  This allows direct use of a row
-                * returned by pltcl_set_tuple_values().
-                ************************************************************/
-               attnum = SPI_fnumber(tupdesc, ret_name);
-               if (attnum == SPI_ERROR_NOATTRIBUTE)
-               {
-                       if (strcmp(ret_name, ".tupno") == 0)
-                               continue;
-                       ereport(ERROR,
-                                       (errcode(ERRCODE_UNDEFINED_COLUMN),
-                                        errmsg("unrecognized attribute \"%s\"",
-                                                       ret_name)));
-               }
-               if (attnum <= 0)
-                       ereport(ERROR,
-                                       (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-                                        errmsg("cannot set system attribute 
\"%s\"",
-                                                       ret_name)));
-
-               /************************************************************
-                * Lookup the attribute type's input function
-                ************************************************************/
-               getTypeInputInfo(tupdesc->attrs[attnum - 1]->atttypid,
-                                                &typinput, &typioparam);
-               fmgr_info(typinput, &finfo);
-
-               /************************************************************
-                * Set the attribute to NOT NULL and convert the contents
-                ************************************************************/
-               values[attnum - 1] = InputFunctionCall(&finfo,
-                                                                               
           ret_value,
-                                                                               
           typioparam,
-                                                                         
tupdesc->attrs[attnum - 1]->atttypmod);
-               nulls[attnum - 1] = false;
-       }
-
-       /* Build the modified tuple to return */
-       rettup = heap_form_tuple(tupdesc, values, nulls);
-
-       pfree(values);
-       pfree(nulls);
-
+       /* Convert function result to tuple */
+       rettup = pltcl_build_tuple_result(interp, result_Objv, result_Objc,
+                                                                  call_state, 
tupdesc);
        return rettup;
 }
 
@@ -2183,7 +2121,7 @@ pltcl_returnnext(ClientData cdata, Tcl_Interp *interp,
                        HeapTuple       tuple;
 
                        tuple = pltcl_build_tuple_result(interp, rowObjv, 
rowObjc,
-                                                                               
         call_state);
+                                                                               
         call_state, NULL);
                        tuplestore_puttuple(call_state->tuple_store, tuple);
                }
        }
@@ -3010,6 +2948,8 @@ pltcl_build_tuple_argument(HeapTuple tuple, TupleDesc 
tupdesc)
  * pltcl_build_tuple_result() - Build a tuple of function's result rowtype
  *                               from a Tcl list of column names and values
  *
+ * If not called from the trigger handler, tg_tupdesc must be NULL!
+ *
  * Note: this function leaks memory.  Even if we made it clean up its own
  * mess, there's no way to prevent the datatype input functions it calls
  * from leaking.  Run it in a short-lived context, unless we're about to
@@ -3017,8 +2957,9 @@ pltcl_build_tuple_argument(HeapTuple tuple, TupleDesc 
tupdesc)
  **********************************************************************/
 static HeapTuple
 pltcl_build_tuple_result(Tcl_Interp *interp, Tcl_Obj **kvObjv, int kvObjc,
-                                                pltcl_call_state *call_state)
+                                                pltcl_call_state *call_state, 
TupleDesc tg_tupdesc)
 {
+       TupleDesc       tupdesc;
        char      **values;
        int                     i;
 
@@ -3027,12 +2968,17 @@ pltcl_build_tuple_result(Tcl_Interp *interp, Tcl_Obj 
**kvObjv, int kvObjc,
                                (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                errmsg("column name/value list must have even number of 
elements")));
 
-       values = (char **) palloc0(call_state->ret_tupdesc->natts * sizeof(char 
*));
+       if (tg_tupdesc)
+               tupdesc = tg_tupdesc;
+       else
+               tupdesc = call_state->ret_tupdesc;
+
+       values = (char **) palloc0(tupdesc->natts * sizeof(char *));
 
        for (i = 0; i < kvObjc; i += 2)
        {
                char       *fieldName = utf_e2u(Tcl_GetString(kvObjv[i]));
-               int                     attn = 
SPI_fnumber(call_state->ret_tupdesc, fieldName);
+               int                     attn = SPI_fnumber(tupdesc, fieldName);
 
                /*
                 * As in pltcl_trigger_handler, silently ignore ".tupno" if 
it's in
@@ -3057,7 +3003,10 @@ pltcl_build_tuple_result(Tcl_Interp *interp, Tcl_Obj 
**kvObjv, int kvObjc,
                values[attn - 1] = utf_e2u(Tcl_GetString(kvObjv[i + 1]));
        }
 
-       return BuildTupleFromCStrings(call_state->attinmeta, values);
+       if (tg_tupdesc)
+               return 
BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupdesc), values);
+       else
+               return BuildTupleFromCStrings(call_state->attinmeta, values);
 }
 
 /**********************************************************************
-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Reply via email to