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 ([email protected])
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers