Skip to content

Commit dc1c1ae

Browse files
committed
Don't capture hard errors for old cagg format
If an error occurs inside the deserialization function for continuous aggregates, we are using the old numeric format and this was captured inside `inner_agg_deserialize` and the format was "repaired". However, this captured hard errors as well, which can cause cascading errors if execution continues after the error. This commit fixes that by capturing data exception errors, internal error (which is the default for elog()) and protocol error (c.f. `pq_getmsgint64` used by `numeric_deserialize`), but re-throwing all other errors.
1 parent 4653c72 commit dc1c1ae

File tree

1 file changed

+33
-6
lines changed

1 file changed

+33
-6
lines changed

tsl/src/partialize_finalize.c

+33-6
Original file line numberDiff line numberDiff line change
@@ -260,24 +260,51 @@ inner_agg_deserialize(FACombineFnMeta *combine_meta, bytea *volatile serialized_
260260
deser_fcinfo->isnull = false;
261261

262262
/*
263-
* When an exception is thrown and longjmp() is called, CurrentMemoryContext is potentially
264-
* different than what it was inside the PG_TRY() block below.
263+
* When an exception is thrown and longjmp() is called,
264+
* CurrentMemoryContext is potentially different than what it was
265+
* inside the PG_TRY() block below.
265266
*
266-
* Restore it to the old value so that the code in the subsequent PG_CATCH() block does not
267-
* corrupt the memory.
267+
* Restore it to the old value so that the code in the subsequent
268+
* PG_CATCH() block does not corrupt the memory.
268269
*
269-
* No need for volatile variables since we don't modify any of this function's stack frame
270-
* inside the PG_TRY() block.
270+
* No need for volatile variables since we don't modify any of this
271+
* function's stack frame inside the PG_TRY() block.
272+
*
273+
* We create a subtransaction to run the functions below, in case they
274+
* abort.
271275
*/
272276
MemoryContext oldcontext = CurrentMemoryContext;
277+
BeginInternalSubTransaction(NULL);
273278
PG_TRY();
274279
{
275280
deserialized = FunctionCallInvoke(deser_fcinfo);
281+
ReleaseCurrentSubTransaction();
276282
}
277283
PG_CATCH();
278284
{
285+
const int sqlerrcode = geterrcode();
279286
CurrentMemoryContext = oldcontext;
287+
288+
/*
289+
* If we get a data exception category error or a protocol
290+
* violation or an internal error (which is generated by default
291+
* when using elog()), the format is wrong and we can attempt to
292+
* repair it by switching to a different function for
293+
* deserializing.
294+
*
295+
* If the error is an insufficient resources category we should
296+
* *not* continue executing.
297+
*
298+
* Errors in other categories are not expected, but we cannot do
299+
* anything with them anyway, so just re-throw them too.
300+
*/
301+
if (ERRCODE_TO_CATEGORY(sqlerrcode) != ERRCODE_DATA_EXCEPTION &&
302+
sqlerrcode != ERRCODE_PROTOCOL_VIOLATION && sqlerrcode != ERRCODE_INTERNAL_ERROR)
303+
{
304+
PG_RE_THROW();
305+
}
280306
FlushErrorState();
307+
RollbackAndReleaseCurrentSubTransaction();
281308
/* attempt to repair the serialized partial */
282309
serialized_partial =
283310
sanitize_serialized_partial(combine_meta->deserialfnoid, serialized_partial);

0 commit comments

Comments
 (0)