Skip to content

Commit 2178cbf

Browse files
committed
Modernize result-tuple construction in pltcl_trigger_handler().
Use Tcl_ListObjGetElements instead of Tcl_SplitList. Aside from being possibly more efficient in its own right, this means we are no longer responsible for freeing a malloc'd result array, so we can get rid of a PG_TRY/PG_CATCH block. Use heap_form_tuple instead of SPI_modifytuple. We don't need the extra generality of the latter, since we're always replacing all columns. Nor do we need its memory-context-munging, since at this point we're already out of the SPI environment. Per comparison of this code to tuple-building code submitted by Jim Nasby. I've abandoned the thought of merging the two cases into a single routine, but we may as well make the older code simpler and faster where we can.
1 parent fd2664d commit 2178cbf

File tree

1 file changed

+73
-94
lines changed

1 file changed

+73
-94
lines changed

src/pl/tcl/pltcl.c

Lines changed: 73 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -870,12 +870,11 @@ pltcl_trigger_handler(PG_FUNCTION_ARGS, bool pltrusted)
870870
Tcl_Obj *tcl_newtup;
871871
int tcl_rc;
872872
int i;
873-
int *modattrs;
874-
Datum *modvalues;
875-
char *modnulls;
876-
int ret_numvals;
877873
const char *result;
878-
const char **ret_values;
874+
int result_Objc;
875+
Tcl_Obj **result_Objv;
876+
Datum *values;
877+
bool *nulls;
879878

880879
/* Connect to SPI manager */
881880
if (SPI_connect() != SPI_OK_CONNECT)
@@ -1065,13 +1064,16 @@ pltcl_trigger_handler(PG_FUNCTION_ARGS, bool pltrusted)
10651064
throw_tcl_error(interp, prodesc->user_proname);
10661065

10671066
/************************************************************
1068-
* The return value from the procedure might be one of
1069-
* the magic strings OK or SKIP or a list from array get.
1070-
* We can check for OK or SKIP without worrying about encoding.
1067+
* Exit SPI environment.
10711068
************************************************************/
10721069
if (SPI_finish() != SPI_OK_FINISH)
10731070
elog(ERROR, "SPI_finish() failed");
10741071

1072+
/************************************************************
1073+
* The return value from the procedure might be one of
1074+
* the magic strings OK or SKIP, or a list from array get.
1075+
* We can check for OK or SKIP without worrying about encoding.
1076+
************************************************************/
10751077
result = Tcl_GetStringResult(interp);
10761078

10771079
if (strcmp(result, "OK") == 0)
@@ -1080,108 +1082,85 @@ pltcl_trigger_handler(PG_FUNCTION_ARGS, bool pltrusted)
10801082
return (HeapTuple) NULL;
10811083

10821084
/************************************************************
1083-
* Convert the result value from the Tcl interpreter
1084-
* and setup structures for SPI_modifytuple();
1085+
* Otherwise, the return value should be a column name/value list
1086+
* specifying the modified tuple to return.
10851087
************************************************************/
1086-
if (Tcl_SplitList(interp, result,
1087-
&ret_numvals, &ret_values) != TCL_OK)
1088+
if (Tcl_ListObjGetElements(interp, Tcl_GetObjResult(interp),
1089+
&result_Objc, &result_Objv) != TCL_OK)
10881090
ereport(ERROR,
10891091
(errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED),
10901092
errmsg("could not split return value from trigger: %s",
10911093
utf_u2e(Tcl_GetStringResult(interp)))));
10921094

1093-
/* Use a TRY to ensure ret_values will get freed */
1094-
PG_TRY();
1095-
{
1096-
if (ret_numvals % 2 != 0)
1097-
ereport(ERROR,
1098-
(errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED),
1099-
errmsg("trigger's return list must have even number of elements")));
1095+
if (result_Objc % 2 != 0)
1096+
ereport(ERROR,
1097+
(errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED),
1098+
errmsg("trigger's return list must have even number of elements")));
11001099

1101-
modattrs = (int *) palloc(tupdesc->natts * sizeof(int));
1102-
modvalues = (Datum *) palloc(tupdesc->natts * sizeof(Datum));
1103-
for (i = 0; i < tupdesc->natts; i++)
1104-
{
1105-
modattrs[i] = i + 1;
1106-
modvalues[i] = (Datum) NULL;
1107-
}
1100+
values = (Datum *) palloc0(tupdesc->natts * sizeof(Datum));
1101+
nulls = (bool *) palloc(tupdesc->natts * sizeof(bool));
1102+
memset(nulls, true, tupdesc->natts * sizeof(bool));
11081103

1109-
modnulls = palloc(tupdesc->natts);
1110-
memset(modnulls, 'n', tupdesc->natts);
1104+
for (i = 0; i < result_Objc; i += 2)
1105+
{
1106+
char *ret_name = utf_u2e(Tcl_GetString(result_Objv[i]));
1107+
char *ret_value = utf_u2e(Tcl_GetString(result_Objv[i + 1]));
1108+
int attnum;
1109+
Oid typinput;
1110+
Oid typioparam;
1111+
FmgrInfo finfo;
11111112

1112-
for (i = 0; i < ret_numvals; i += 2)
1113+
/************************************************************
1114+
* Get the attribute number
1115+
*
1116+
* We silently ignore ".tupno", if it's present but doesn't match
1117+
* any actual output column. This allows direct use of a row
1118+
* returned by pltcl_set_tuple_values().
1119+
************************************************************/
1120+
attnum = SPI_fnumber(tupdesc, ret_name);
1121+
if (attnum == SPI_ERROR_NOATTRIBUTE)
11131122
{
1114-
char *ret_name = utf_u2e(ret_values[i]);
1115-
char *ret_value = utf_u2e(ret_values[i + 1]);
1116-
int attnum;
1117-
Oid typinput;
1118-
Oid typioparam;
1119-
FmgrInfo finfo;
1120-
1121-
/************************************************************
1122-
* Get the attribute number
1123-
*
1124-
* We silently ignore ".tupno", if it's present but doesn't match
1125-
* any actual output column. This allows direct use of a row
1126-
* returned by pltcl_set_tuple_values().
1127-
************************************************************/
1128-
attnum = SPI_fnumber(tupdesc, ret_name);
1129-
if (attnum == SPI_ERROR_NOATTRIBUTE)
1130-
{
1131-
if (strcmp(ret_name, ".tupno") == 0)
1132-
continue;
1133-
ereport(ERROR,
1134-
(errcode(ERRCODE_UNDEFINED_COLUMN),
1135-
errmsg("unrecognized attribute \"%s\"",
1136-
ret_name)));
1137-
}
1138-
if (attnum <= 0)
1139-
ereport(ERROR,
1140-
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1141-
errmsg("cannot set system attribute \"%s\"",
1142-
ret_name)));
1143-
1144-
/************************************************************
1145-
* Ignore dropped columns
1146-
************************************************************/
1147-
if (tupdesc->attrs[attnum - 1]->attisdropped)
1123+
if (strcmp(ret_name, ".tupno") == 0)
11481124
continue;
1149-
1150-
/************************************************************
1151-
* Lookup the attribute type in the syscache
1152-
* for the input function
1153-
************************************************************/
1154-
getTypeInputInfo(tupdesc->attrs[attnum - 1]->atttypid,
1155-
&typinput, &typioparam);
1156-
fmgr_info(typinput, &finfo);
1157-
1158-
/************************************************************
1159-
* Set the attribute to NOT NULL and convert the contents
1160-
************************************************************/
1161-
modvalues[attnum - 1] = InputFunctionCall(&finfo,
1162-
ret_value,
1163-
typioparam,
1164-
tupdesc->attrs[attnum - 1]->atttypmod);
1165-
modnulls[attnum - 1] = ' ';
1125+
ereport(ERROR,
1126+
(errcode(ERRCODE_UNDEFINED_COLUMN),
1127+
errmsg("unrecognized attribute \"%s\"",
1128+
ret_name)));
11661129
}
1130+
if (attnum <= 0)
1131+
ereport(ERROR,
1132+
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1133+
errmsg("cannot set system attribute \"%s\"",
1134+
ret_name)));
11671135

1168-
rettup = SPI_modifytuple(trigdata->tg_relation, rettup, tupdesc->natts,
1169-
modattrs, modvalues, modnulls);
1136+
/************************************************************
1137+
* Ignore dropped columns
1138+
************************************************************/
1139+
if (tupdesc->attrs[attnum - 1]->attisdropped)
1140+
continue;
11701141

1171-
pfree(modattrs);
1172-
pfree(modvalues);
1173-
pfree(modnulls);
1142+
/************************************************************
1143+
* Lookup the attribute type's input function
1144+
************************************************************/
1145+
getTypeInputInfo(tupdesc->attrs[attnum - 1]->atttypid,
1146+
&typinput, &typioparam);
1147+
fmgr_info(typinput, &finfo);
11741148

1175-
if (rettup == NULL)
1176-
elog(ERROR, "SPI_modifytuple() failed - RC = %d", SPI_result);
1177-
}
1178-
PG_CATCH();
1179-
{
1180-
ckfree((char *) ret_values);
1181-
PG_RE_THROW();
1149+
/************************************************************
1150+
* Set the attribute to NOT NULL and convert the contents
1151+
************************************************************/
1152+
values[attnum - 1] = InputFunctionCall(&finfo,
1153+
ret_value,
1154+
typioparam,
1155+
tupdesc->attrs[attnum - 1]->atttypmod);
1156+
nulls[attnum - 1] = false;
11821157
}
1183-
PG_END_TRY();
1184-
ckfree((char *) ret_values);
1158+
1159+
/* Build the modified tuple to return */
1160+
rettup = heap_form_tuple(tupdesc, values, nulls);
1161+
1162+
pfree(values);
1163+
pfree(nulls);
11851164

11861165
return rettup;
11871166
}

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy