@@ -870,12 +870,11 @@ pltcl_trigger_handler(PG_FUNCTION_ARGS, bool pltrusted)
870
870
Tcl_Obj * tcl_newtup ;
871
871
int tcl_rc ;
872
872
int i ;
873
- int * modattrs ;
874
- Datum * modvalues ;
875
- char * modnulls ;
876
- int ret_numvals ;
877
873
const char * result ;
878
- const char * * ret_values ;
874
+ int result_Objc ;
875
+ Tcl_Obj * * result_Objv ;
876
+ Datum * values ;
877
+ bool * nulls ;
879
878
880
879
/* Connect to SPI manager */
881
880
if (SPI_connect () != SPI_OK_CONNECT )
@@ -1065,13 +1064,16 @@ pltcl_trigger_handler(PG_FUNCTION_ARGS, bool pltrusted)
1065
1064
throw_tcl_error (interp , prodesc -> user_proname );
1066
1065
1067
1066
/************************************************************
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.
1071
1068
************************************************************/
1072
1069
if (SPI_finish () != SPI_OK_FINISH )
1073
1070
elog (ERROR , "SPI_finish() failed" );
1074
1071
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
+ ************************************************************/
1075
1077
result = Tcl_GetStringResult (interp );
1076
1078
1077
1079
if (strcmp (result , "OK" ) == 0 )
@@ -1080,108 +1082,85 @@ pltcl_trigger_handler(PG_FUNCTION_ARGS, bool pltrusted)
1080
1082
return (HeapTuple ) NULL ;
1081
1083
1082
1084
/************************************************************
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.
1085
1087
************************************************************/
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 )
1088
1090
ereport (ERROR ,
1089
1091
(errcode (ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED ),
1090
1092
errmsg ("could not split return value from trigger: %s" ,
1091
1093
utf_u2e (Tcl_GetStringResult (interp )))));
1092
1094
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" )));
1100
1099
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 ));
1108
1103
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 ;
1111
1112
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 )
1113
1122
{
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 )
1148
1124
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 )));
1166
1129
}
1130
+ if (attnum <= 0 )
1131
+ ereport (ERROR ,
1132
+ (errcode (ERRCODE_FEATURE_NOT_SUPPORTED ),
1133
+ errmsg ("cannot set system attribute \"%s\"" ,
1134
+ ret_name )));
1167
1135
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 ;
1170
1141
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 );
1174
1148
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;
1182
1157
}
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 );
1185
1164
1186
1165
return rettup ;
1187
1166
}
0 commit comments