@@ -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