Skip to content

Commit 4dc601c

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 4dc601c

File tree

1 file changed

+38
-7
lines changed

1 file changed

+38
-7
lines changed

tsl/src/partialize_finalize.c

+38-7
Original file line numberDiff line numberDiff line change
@@ -260,24 +260,55 @@ 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+
ResourceOwner oldowner = CurrentResourceOwner;
278+
BeginInternalSubTransaction(NULL);
273279
PG_TRY();
274280
{
275281
deserialized = FunctionCallInvoke(deser_fcinfo);
282+
ReleaseCurrentSubTransaction();
283+
MemoryContextSwitchTo(oldcontext);
284+
CurrentResourceOwner = oldowner;
276285
}
277286
PG_CATCH();
278287
{
279-
CurrentMemoryContext = oldcontext;
288+
const int sqlerrcode = geterrcode();
289+
290+
/*
291+
* If we get a data exception category error or a protocol
292+
* violation or an internal error (which is generated by default
293+
* when using elog()), the format is wrong and we can attempt to
294+
* repair it by switching to a different function for
295+
* deserializing.
296+
*
297+
* If the error is an insufficient resources category we should
298+
* *not* continue executing.
299+
*
300+
* Errors in other categories are not expected, but we cannot do
301+
* anything with them anyway, so just re-throw them too.
302+
*/
303+
if (ERRCODE_TO_CATEGORY(sqlerrcode) != ERRCODE_DATA_EXCEPTION &&
304+
sqlerrcode != ERRCODE_PROTOCOL_VIOLATION && sqlerrcode != ERRCODE_INTERNAL_ERROR)
305+
{
306+
PG_RE_THROW();
307+
}
280308
FlushErrorState();
309+
RollbackAndReleaseCurrentSubTransaction();
310+
MemoryContextSwitchTo(oldcontext);
311+
CurrentResourceOwner = oldowner;
281312
/* attempt to repair the serialized partial */
282313
serialized_partial =
283314
sanitize_serialized_partial(combine_meta->deserialfnoid, serialized_partial);

0 commit comments

Comments
 (0)