|
71 | 71 | #include "libpq/libpq.h"
|
72 | 72 | #include "libpq/pqformat.h"
|
73 | 73 | #include "mb/pg_wchar.h"
|
| 74 | +#include "nodes/miscnodes.h" |
74 | 75 | #include "miscadmin.h"
|
75 | 76 | #include "pgstat.h"
|
76 | 77 | #include "postmaster/bgworker.h"
|
@@ -611,6 +612,128 @@ errfinish(const char *filename, int lineno, const char *funcname)
|
611 | 612 | CHECK_FOR_INTERRUPTS();
|
612 | 613 | }
|
613 | 614 |
|
| 615 | + |
| 616 | +/* |
| 617 | + * errsave_start --- begin a "soft" error-reporting cycle |
| 618 | + * |
| 619 | + * If "context" isn't an ErrorSaveContext node, this behaves as |
| 620 | + * errstart(ERROR, domain), and the errsave() macro ends up acting |
| 621 | + * exactly like ereport(ERROR, ...). |
| 622 | + * |
| 623 | + * If "context" is an ErrorSaveContext node, but the node creator only wants |
| 624 | + * notification of the fact of a soft error without any details, we just set |
| 625 | + * the error_occurred flag in the ErrorSaveContext node and return false, |
| 626 | + * which will cause us to skip the remaining error processing steps. |
| 627 | + * |
| 628 | + * Otherwise, create and initialize error stack entry and return true. |
| 629 | + * Subsequently, errmsg() and perhaps other routines will be called to further |
| 630 | + * populate the stack entry. Finally, errsave_finish() will be called to |
| 631 | + * tidy up. |
| 632 | + */ |
| 633 | +bool |
| 634 | +errsave_start(struct Node *context, const char *domain) |
| 635 | +{ |
| 636 | + ErrorSaveContext *escontext; |
| 637 | + ErrorData *edata; |
| 638 | + |
| 639 | + /* |
| 640 | + * Do we have a context for soft error reporting? If not, just punt to |
| 641 | + * errstart(). |
| 642 | + */ |
| 643 | + if (context == NULL || !IsA(context, ErrorSaveContext)) |
| 644 | + return errstart(ERROR, domain); |
| 645 | + |
| 646 | + /* Report that a soft error was detected */ |
| 647 | + escontext = (ErrorSaveContext *) context; |
| 648 | + escontext->error_occurred = true; |
| 649 | + |
| 650 | + /* Nothing else to do if caller wants no further details */ |
| 651 | + if (!escontext->details_wanted) |
| 652 | + return false; |
| 653 | + |
| 654 | + /* |
| 655 | + * Okay, crank up a stack entry to store the info in. |
| 656 | + */ |
| 657 | + |
| 658 | + recursion_depth++; |
| 659 | + |
| 660 | + /* Initialize data for this error frame */ |
| 661 | + edata = get_error_stack_entry(); |
| 662 | + edata->elevel = LOG; /* signal all is well to errsave_finish */ |
| 663 | + set_stack_entry_domain(edata, domain); |
| 664 | + /* Select default errcode based on the assumed elevel of ERROR */ |
| 665 | + edata->sqlerrcode = ERRCODE_INTERNAL_ERROR; |
| 666 | + |
| 667 | + /* |
| 668 | + * Any allocations for this error state level should go into the caller's |
| 669 | + * context. We don't need to pollute ErrorContext, or even require it to |
| 670 | + * exist, in this code path. |
| 671 | + */ |
| 672 | + edata->assoc_context = CurrentMemoryContext; |
| 673 | + |
| 674 | + recursion_depth--; |
| 675 | + return true; |
| 676 | +} |
| 677 | + |
| 678 | +/* |
| 679 | + * errsave_finish --- end a "soft" error-reporting cycle |
| 680 | + * |
| 681 | + * If errsave_start() decided this was a regular error, behave as |
| 682 | + * errfinish(). Otherwise, package up the error details and save |
| 683 | + * them in the ErrorSaveContext node. |
| 684 | + */ |
| 685 | +void |
| 686 | +errsave_finish(struct Node *context, const char *filename, int lineno, |
| 687 | + const char *funcname) |
| 688 | +{ |
| 689 | + ErrorSaveContext *escontext = (ErrorSaveContext *) context; |
| 690 | + ErrorData *edata = &errordata[errordata_stack_depth]; |
| 691 | + |
| 692 | + /* verify stack depth before accessing *edata */ |
| 693 | + CHECK_STACK_DEPTH(); |
| 694 | + |
| 695 | + /* |
| 696 | + * If errsave_start punted to errstart, then elevel will be ERROR or |
| 697 | + * perhaps even PANIC. Punt likewise to errfinish. |
| 698 | + */ |
| 699 | + if (edata->elevel >= ERROR) |
| 700 | + { |
| 701 | + errfinish(filename, lineno, funcname); |
| 702 | + pg_unreachable(); |
| 703 | + } |
| 704 | + |
| 705 | + /* |
| 706 | + * Else, we should package up the stack entry contents and deliver them to |
| 707 | + * the caller. |
| 708 | + */ |
| 709 | + recursion_depth++; |
| 710 | + |
| 711 | + /* Save the last few bits of error state into the stack entry */ |
| 712 | + set_stack_entry_location(edata, filename, lineno, funcname); |
| 713 | + |
| 714 | + /* Replace the LOG value that errsave_start inserted */ |
| 715 | + edata->elevel = ERROR; |
| 716 | + |
| 717 | + /* |
| 718 | + * We skip calling backtrace and context functions, which are more likely |
| 719 | + * to cause trouble than provide useful context; they might act on the |
| 720 | + * assumption that a transaction abort is about to occur. |
| 721 | + */ |
| 722 | + |
| 723 | + /* |
| 724 | + * Make a copy of the error info for the caller. All the subsidiary |
| 725 | + * strings are already in the caller's context, so it's sufficient to |
| 726 | + * flat-copy the stack entry. |
| 727 | + */ |
| 728 | + escontext->error_data = palloc_object(ErrorData); |
| 729 | + memcpy(escontext->error_data, edata, sizeof(ErrorData)); |
| 730 | + |
| 731 | + /* Exit error-handling context */ |
| 732 | + errordata_stack_depth--; |
| 733 | + recursion_depth--; |
| 734 | +} |
| 735 | + |
| 736 | + |
614 | 737 | /*
|
615 | 738 | * get_error_stack_entry --- allocate and initialize a new stack entry
|
616 | 739 | *
|
|
0 commit comments