|
16 | 16 | #include <utils/builtins.h>
|
17 | 17 | #include <utils/datum.h>
|
18 | 18 | #include <utils/fmgroids.h>
|
| 19 | +#include <utils/resowner.h> |
19 | 20 | #include <utils/syscache.h>
|
20 | 21 |
|
21 | 22 | #include "partialize_finalize.h"
|
@@ -260,24 +261,55 @@ inner_agg_deserialize(FACombineFnMeta *combine_meta, bytea *volatile serialized_
|
260 | 261 | deser_fcinfo->isnull = false;
|
261 | 262 |
|
262 | 263 | /*
|
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. |
| 264 | + * When an exception is thrown and longjmp() is called, |
| 265 | + * CurrentMemoryContext is potentially different than what it was |
| 266 | + * inside the PG_TRY() block below. |
265 | 267 | *
|
266 |
| - * Restore it to the old value so that the code in the subsequent PG_CATCH() block does not |
267 |
| - * corrupt the memory. |
| 268 | + * Restore it to the old value so that the code in the subsequent |
| 269 | + * PG_CATCH() block does not corrupt the memory. |
268 | 270 | *
|
269 |
| - * No need for volatile variables since we don't modify any of this function's stack frame |
270 |
| - * inside the PG_TRY() block. |
| 271 | + * No need for volatile variables since we don't modify any of this |
| 272 | + * function's stack frame inside the PG_TRY() block. |
| 273 | + * |
| 274 | + * We create a subtransaction to run the functions below, in case they |
| 275 | + * abort. |
271 | 276 | */
|
272 | 277 | MemoryContext oldcontext = CurrentMemoryContext;
|
| 278 | + ResourceOwner oldowner = CurrentResourceOwner; |
| 279 | + BeginInternalSubTransaction(NULL); |
273 | 280 | PG_TRY();
|
274 | 281 | {
|
275 | 282 | deserialized = FunctionCallInvoke(deser_fcinfo);
|
| 283 | + ReleaseCurrentSubTransaction(); |
| 284 | + MemoryContextSwitchTo(oldcontext); |
| 285 | + CurrentResourceOwner = oldowner; |
276 | 286 | }
|
277 | 287 | PG_CATCH();
|
278 | 288 | {
|
279 |
| - CurrentMemoryContext = oldcontext; |
| 289 | + const int sqlerrcode = geterrcode(); |
| 290 | + |
| 291 | + /* |
| 292 | + * If we get a data exception category error or a protocol |
| 293 | + * violation or an internal error (which is generated by default |
| 294 | + * when using elog()), the format is wrong and we can attempt to |
| 295 | + * repair it by switching to a different function for |
| 296 | + * deserializing. |
| 297 | + * |
| 298 | + * If the error is an insufficient resources category we should |
| 299 | + * *not* continue executing. |
| 300 | + * |
| 301 | + * Errors in other categories are not expected, but we cannot do |
| 302 | + * anything with them anyway, so just re-throw them too. |
| 303 | + */ |
| 304 | + if (ERRCODE_TO_CATEGORY(sqlerrcode) != ERRCODE_DATA_EXCEPTION && |
| 305 | + sqlerrcode != ERRCODE_PROTOCOL_VIOLATION && sqlerrcode != ERRCODE_INTERNAL_ERROR) |
| 306 | + { |
| 307 | + PG_RE_THROW(); |
| 308 | + } |
280 | 309 | FlushErrorState();
|
| 310 | + RollbackAndReleaseCurrentSubTransaction(); |
| 311 | + MemoryContextSwitchTo(oldcontext); |
| 312 | + CurrentResourceOwner = oldowner; |
281 | 313 | /* attempt to repair the serialized partial */
|
282 | 314 | serialized_partial =
|
283 | 315 | sanitize_serialized_partial(combine_meta->deserialfnoid, serialized_partial);
|
|
0 commit comments