-
Notifications
You must be signed in to change notification settings - Fork 3.8k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
106351: plpgsql: implement RAISE statements r=DrewKimball a=DrewKimball #### builtins: add builtin function to raise a notice synchronously to the client This patch adds a builtin function, `crdb_internal.plpgsql_raise`, which allows the caller to send a notice to the client with specified severity, message, detail, hint, and PG code. The notice is immediately flushed to the client instead of being buffered until the query result is closed. This functionality will be used to implement the PLpgSQL `RAISE` statement. The `crdb_internal.plpgsql_raise` builtin is undocumented and intended only for internal use. #### plpgsql: implement parsing for RAISE statements This patch adds parser support for PLpgSQL `RAISE` statements. This ncludes all syntax forms apart from the empty `RAISE`, which is only valid in combination with (currently unimplemented) `EXCEPTION` blocks. A future commit will add support in the optbuilder as well. #### plpgsql: implement RAISE statement This patch adds support for the PLpgSQL `RAISE` statement. The `RAISE` statement can send messages back to the client during execution, as well as raise a user-specified error. There are a few variations on the syntax, but in general `RAISE` statements have a log level (default `EXCEPTION`), a message (if not specified, the code string is used), and various options: `DETAIL`, `HINT`, `ERRCODE` etc. With log level `EXCEPTION` the error is returned just like any other error, but for other levels it is sent as a notice to the client and flushed synchronously before execution continues. This feature is often used to track progress, since the notices are sent before execution finishes. Fixes #105251 Release note (sql change): Added support for the PLpgSQL `RAISE` statement, which allows sending notices to the client and raising errors. Currently the notice is only sent to the client; support for logging notices is left for future work. Co-authored-by: Drew Kimball <[email protected]>
- Loading branch information
Showing
33 changed files
with
2,971 additions
and
91 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,166 @@ | ||
# Test different log levels. | ||
query T noticetrace | ||
SELECT crdb_internal.plpgsql_raise('DEBUG1', 'foo', '', '', ''); | ||
---- | ||
|
||
query T noticetrace | ||
SELECT crdb_internal.plpgsql_raise('LOG', 'foo', '', '', ''); | ||
---- | ||
|
||
query T noticetrace | ||
SELECT crdb_internal.plpgsql_raise('INFO', 'foo', '', '', ''); | ||
---- | ||
INFO: foo | ||
SQLSTATE: XXUUU | ||
|
||
query T noticetrace | ||
SELECT crdb_internal.plpgsql_raise('NOTICE', 'foo', '', '', ''); | ||
---- | ||
NOTICE: foo | ||
SQLSTATE: XXUUU | ||
|
||
query T noticetrace | ||
SELECT crdb_internal.plpgsql_raise('WARNING', 'foo', '', '', ''); | ||
---- | ||
WARNING: foo | ||
SQLSTATE: XXUUU | ||
|
||
statement ok | ||
SET client_min_messages = 'debug1'; | ||
|
||
query T noticetrace | ||
SELECT crdb_internal.plpgsql_raise('DEBUG1', 'foo', '', '', ''); | ||
---- | ||
DEBUG1: foo | ||
SQLSTATE: XXUUU | ||
|
||
query T noticetrace | ||
SELECT crdb_internal.plpgsql_raise('LOG', 'foo', '', '', ''); | ||
---- | ||
LOG: foo | ||
SQLSTATE: XXUUU | ||
|
||
query T noticetrace | ||
SELECT crdb_internal.plpgsql_raise('INFO', 'foo', '', '', ''); | ||
---- | ||
INFO: foo | ||
SQLSTATE: XXUUU | ||
|
||
query T noticetrace | ||
SELECT crdb_internal.plpgsql_raise('NOTICE', 'foo', '', '', ''); | ||
---- | ||
NOTICE: foo | ||
SQLSTATE: XXUUU | ||
|
||
query T noticetrace | ||
SELECT crdb_internal.plpgsql_raise('WARNING', 'foo', '', '', ''); | ||
---- | ||
WARNING: foo | ||
SQLSTATE: XXUUU | ||
|
||
statement ok | ||
SET client_min_messages = 'WARNING'; | ||
|
||
query T noticetrace | ||
SELECT crdb_internal.plpgsql_raise('DEBUG1', 'foo', '', '', ''); | ||
---- | ||
|
||
query T noticetrace | ||
SELECT crdb_internal.plpgsql_raise('LOG', 'foo', '', '', ''); | ||
---- | ||
|
||
# INFO-level notices are always sent to the client. | ||
query T noticetrace | ||
SELECT crdb_internal.plpgsql_raise('INFO', 'foo', '', '', ''); | ||
---- | ||
INFO: foo | ||
SQLSTATE: XXUUU | ||
|
||
query T noticetrace | ||
SELECT crdb_internal.plpgsql_raise('NOTICE', 'foo', '', '', ''); | ||
---- | ||
|
||
query T noticetrace | ||
SELECT crdb_internal.plpgsql_raise('WARNING', 'foo', '', '', ''); | ||
---- | ||
WARNING: foo | ||
SQLSTATE: XXUUU | ||
|
||
statement ok | ||
RESET client_min_messages; | ||
|
||
# Test RAISE options. | ||
query T noticetrace | ||
SELECT crdb_internal.plpgsql_raise('NOTICE', 'bar', 'this is a detail', '', ''); | ||
---- | ||
NOTICE: bar | ||
DETAIL: this is a detail | ||
SQLSTATE: XXUUU | ||
|
||
query T noticetrace | ||
SELECT crdb_internal.plpgsql_raise('NOTICE', 'baz', '', 'this is a hint', ''); | ||
---- | ||
NOTICE: baz | ||
HINT: this is a hint | ||
SQLSTATE: XXUUU | ||
|
||
query T noticetrace | ||
SELECT crdb_internal.plpgsql_raise('NOTICE', 'division by zero', '', '', '22012'); | ||
---- | ||
NOTICE: division by zero | ||
SQLSTATE: 22012 | ||
|
||
query T noticetrace | ||
SELECT crdb_internal.plpgsql_raise('WARNING', 'invalid password', '', '', '28P01'); | ||
---- | ||
WARNING: invalid password | ||
SQLSTATE: 28P01 | ||
|
||
query T noticetrace | ||
SELECT crdb_internal.plpgsql_raise('NOTICE', 'this is a message', 'this is a detail', 'this is a hint', 'P0001'); | ||
---- | ||
NOTICE: this is a message | ||
DETAIL: this is a detail | ||
HINT: this is a hint | ||
SQLSTATE: P0001 | ||
|
||
query T noticetrace | ||
SELECT crdb_internal.plpgsql_raise('NOTICE', 'division by zero msg', '', '', 'division_by_zero'); | ||
---- | ||
NOTICE: division by zero msg | ||
SQLSTATE: 22012 | ||
|
||
query T noticetrace | ||
SELECT crdb_internal.plpgsql_raise('NOTICE', '', 'message is empty', '', 'P0001'); | ||
---- | ||
NOTICE: | ||
DETAIL: message is empty | ||
SQLSTATE: P0001 | ||
|
||
query T noticetrace | ||
SELECT crdb_internal.plpgsql_raise('NOTICE', '', '', '', ''); | ||
---- | ||
NOTICE: | ||
SQLSTATE: XXUUU | ||
|
||
query error pgcode 42704 pq: unrecognized exception condition: \"this_is_not_valid\" | ||
SELECT crdb_internal.plpgsql_raise('NOTICE', '', '', '', 'this_is_not_valid'); | ||
|
||
query error pgcode 42704 pq: unrecognized exception condition: \"-50\" | ||
SELECT crdb_internal.plpgsql_raise('NOTICE', '', '', '', '-50'); | ||
|
||
query error pgcode 22023 pq: severity NOTE is invalid | ||
SELECT crdb_internal.plpgsql_raise('NOTE', '', '', '', '-50'); | ||
|
||
# Test severity ERROR. | ||
query error pgcode XXUUU pq: foo | ||
SELECT crdb_internal.plpgsql_raise('ERROR', 'foo', '', '', ''); | ||
|
||
query error pgcode 12345 pq: foo | ||
SELECT crdb_internal.plpgsql_raise('ERROR', 'foo', '', '', '12345'); | ||
|
||
query error pgcode 12345 pq: msg\nHINT: hint\nDETAIL: detail | ||
SELECT crdb_internal.plpgsql_raise('ERROR', 'msg', 'detail', 'hint', '12345'); | ||
|
||
query error pgcode XXUUU pq: | ||
SELECT crdb_internal.plpgsql_raise('ERROR', '', '', '', ''); |
Oops, something went wrong.