|
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"
|
| 23 | +#include "utils.h" |
22 | 24 |
|
23 | 25 | /*
|
24 | 26 | * This file implements functions to split the calculation of partial and final
|
@@ -223,12 +225,15 @@ static bytea *
|
223 | 225 | sanitize_serialized_partial(Oid deserialfnoid, bytea *serialized_partial)
|
224 | 226 | {
|
225 | 227 | if ((deserialfnoid == F_NUMERIC_DESERIALIZE) || (deserialfnoid == F_NUMERIC_AVG_DESERIALIZE))
|
| 228 | + { |
226 | 229 | /*
|
227 | 230 | * Always add NUMERIC_PARTIAL_MISSING_LENGTH extra bytes because the length is not fixed.
|
228 | 231 | * This is only safe to do when the partial state is known to be short, otherwise an
|
229 | 232 | * exception is thrown if the serialized_partial is not fully consumed by deserialfn().
|
230 | 233 | */
|
| 234 | + TS_DEBUG_LOG("zero-filling serialized numeric type"); |
231 | 235 | return zero_fill_bytearray(serialized_partial, NUMERIC_PARTIAL_MISSING_LENGTH);
|
| 236 | + } |
232 | 237 |
|
233 | 238 | return serialized_partial;
|
234 | 239 | }
|
@@ -260,25 +265,56 @@ inner_agg_deserialize(FACombineFnMeta *combine_meta, bytea *volatile serialized_
|
260 | 265 | deser_fcinfo->isnull = false;
|
261 | 266 |
|
262 | 267 | /*
|
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. |
| 268 | + * When an exception is thrown and longjmp() is called, |
| 269 | + * CurrentMemoryContext is potentially different than what it was |
| 270 | + * inside the PG_TRY() block below. |
| 271 | + * |
| 272 | + * Restore it to the old value so that the code in the subsequent |
| 273 | + * PG_CATCH() block does not corrupt the memory. |
265 | 274 | *
|
266 |
| - * Restore it to the old value so that the code in the subsequent PG_CATCH() block does not |
267 |
| - * corrupt the memory. |
| 275 | + * No need for volatile variables since we don't modify any of this |
| 276 | + * function's stack frame inside the PG_TRY() block. |
268 | 277 | *
|
269 |
| - * No need for volatile variables since we don't modify any of this function's stack frame |
270 |
| - * inside the PG_TRY() block. |
| 278 | + * We create a subtransaction to run the functions below, in case they |
| 279 | + * abort. |
271 | 280 | */
|
272 | 281 | MemoryContext oldcontext = CurrentMemoryContext;
|
| 282 | + ResourceOwner oldowner = CurrentResourceOwner; |
| 283 | + BeginInternalSubTransaction(NULL); |
273 | 284 | PG_TRY();
|
274 | 285 | {
|
275 | 286 | deserialized = FunctionCallInvoke(deser_fcinfo);
|
| 287 | + ReleaseCurrentSubTransaction(); |
| 288 | + MemoryContextSwitchTo(oldcontext); |
| 289 | + CurrentResourceOwner = oldowner; |
276 | 290 | }
|
277 | 291 | PG_CATCH();
|
278 | 292 | {
|
279 |
| - CurrentMemoryContext = oldcontext; |
| 293 | + const int sqlerrcode = geterrcode(); |
| 294 | + |
| 295 | + /* |
| 296 | + * If we get a data exception category error or a protocol |
| 297 | + * violation or an internal error (which is generated by default |
| 298 | + * when using elog()), the format is wrong and we can attempt to |
| 299 | + * repair it by switching to a different function for |
| 300 | + * deserializing. |
| 301 | + * |
| 302 | + * If the error is an insufficient resources category we should |
| 303 | + * *not* continue executing. |
| 304 | + * |
| 305 | + * Errors in other categories are not expected, but we cannot do |
| 306 | + * anything with them anyway, so just re-throw them too. |
| 307 | + */ |
| 308 | + if (ERRCODE_TO_CATEGORY(sqlerrcode) != ERRCODE_DATA_EXCEPTION && |
| 309 | + sqlerrcode != ERRCODE_PROTOCOL_VIOLATION && sqlerrcode != ERRCODE_INTERNAL_ERROR) |
| 310 | + { |
| 311 | + PG_RE_THROW(); |
| 312 | + } |
280 | 313 | FlushErrorState();
|
281 |
| - /* attempt to repair the serialized partial */ |
| 314 | + RollbackAndReleaseCurrentSubTransaction(); |
| 315 | + MemoryContextSwitchTo(oldcontext); |
| 316 | + CurrentResourceOwner = oldowner; |
| 317 | + TS_DEBUG_LOG("attempting repair of serialized partial"); |
282 | 318 | serialized_partial =
|
283 | 319 | sanitize_serialized_partial(combine_meta->deserialfnoid, serialized_partial);
|
284 | 320 | FC_ARG(deser_fcinfo, 0) = PointerGetDatum(serialized_partial);
|
|
0 commit comments