|
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(structNode*context,constchar*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 | +returnerrstart(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(structNode*context,constchar*filename,intlineno, |
| 687 | +constchar*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 | *
|
|