Commit f0688d6e authored by Peter Eisentraut's avatar Peter Eisentraut

PL/Python: Clean up extended error reporting docs and tests

Format the example and test code more to Python style standards.
Improve whitespace.  Improve documentation formatting.
parent fab9d1da
......@@ -1341,13 +1341,15 @@ $$ LANGUAGE plpythonu;
<title>Utility Functions</title>
<para>
The <literal>plpy</literal> module also provides the functions
<literal>plpy.debug(<replaceable>msg, **kwargs</>)</literal>,
<literal>plpy.log(<replaceable>msg, **kwargs</>)</literal>,
<literal>plpy.info(<replaceable>msg, **kwargs</>)</literal>,
<literal>plpy.notice(<replaceable>msg, **kwargs</>)</literal>,
<literal>plpy.warning(<replaceable>msg, **kwargs</>)</literal>,
<literal>plpy.error(<replaceable>msg, **kwargs</>)</literal>, and
<literal>plpy.fatal(<replaceable>msg, **kwargs</>)</literal>.
<simplelist>
<member><literal>plpy.debug(<replaceable>msg, **kwargs</>)</literal></member>
<member><literal>plpy.log(<replaceable>msg, **kwargs</>)</literal></member>
<member><literal>plpy.info(<replaceable>msg, **kwargs</>)</literal></member>
<member><literal>plpy.notice(<replaceable>msg, **kwargs</>)</literal></member>
<member><literal>plpy.warning(<replaceable>msg, **kwargs</>)</literal></member>
<member><literal>plpy.error(<replaceable>msg, **kwargs</>)</literal></member>
<member><literal>plpy.fatal(<replaceable>msg, **kwargs</>)</literal></member>
</simplelist>
<indexterm><primary>elog</><secondary>in PL/Python</></indexterm>
<function>plpy.error</function> and <function>plpy.fatal</function>
actually raise a Python exception which, if uncaught, propagates out to
......@@ -1366,35 +1368,42 @@ $$ LANGUAGE plpythonu;
</para>
<para>
The <replaceable>msg</> argument is given as a positional argument. For
backward compatibility, more than one positional argument can be given. In
that case, the string representation of the tuple of positional arguments
becomes the message reported to the client.
</para>
<para>
The following keyword-only arguments are accepted:
<literal>
<replaceable>detail</replaceable>, <replaceable>hint</replaceable>,
<replaceable>sqlstate</replaceable>, <replaceable>schema_name</replaceable>,
<replaceable>table_name</replaceable>, <replaceable>column_name</replaceable>,
<replaceable>datatype_name</replaceable> , <replaceable>constraint_name</replaceable>
</literal>.
<simplelist>
<member><literal>detail</literal></member>
<member><literal>hint</literal></member>
<member><literal>sqlstate</literal></member>
<member><literal>schema_name</literal></member>
<member><literal>table_name</literal></member>
<member><literal>column_name</literal></member>
<member><literal>datatype_name</literal></member>
<member><literal>constraint_name</literal></member>
</simplelist>
The string representation of the objects passed as keyword-only arguments
is used to enrich the messages reported to the client. For example:
<programlisting>
CREATE FUNCTION raise_custom_exception() RETURNS void AS $$
plpy.error("custom exception message", detail = "some info about exception", hint = "hint for users")
plpy.error("custom exception message",
detail="some info about exception",
hint="hint for users")
$$ LANGUAGE plpythonu;
postgres=# select raise_custom_exception();
ERROR: XX000: plpy.Error: custom exception message
=# SELECT raise_custom_exception();
ERROR: plpy.Error: custom exception message
DETAIL: some info about exception
HINT: hint for users
CONTEXT: Traceback (most recent call last):
PL/Python function "raise_custom_exception", line 2, in &lt;module&gt;
plpy.error("custom exception message", detail = "some info about exception", hint = "hint for users")
PL/Python function "raise_custom_exception", line 4, in &lt;module&gt;
hint="hint for users")
PL/Python function "raise_custom_exception"
LOCATION: PLy_elog, plpy_elog.c:132
</programlisting>
</para>
......
CREATE FUNCTION elog_test() RETURNS void
AS $$
plpy.debug('debug', detail = 'some detail')
plpy.log('log', detail = 'some detail')
plpy.info('info', detail = 'some detail')
plpy.debug('debug', detail='some detail')
plpy.log('log', detail='some detail')
plpy.info('info', detail='some detail')
plpy.info()
plpy.info('the question', detail = 42);
plpy.info('the question', detail=42);
plpy.info('This is message text.',
detail = 'This is detail text',
hint = 'This is hint text.',
sqlstate = 'XX000',
schema_name = 'any info about schema',
table_name = 'any info about table',
column_name = 'any info about column',
datatype_name = 'any info about datatype',
constraint_name = 'any info about constraint')
plpy.notice('notice', detail = 'some detail')
plpy.warning('warning', detail = 'some detail')
plpy.error('stop on error', detail = 'some detail', hint = 'some hint')
detail='This is detail text',
hint='This is hint text.',
sqlstate='XX000',
schema_name='any info about schema',
table_name='any info about table',
column_name='any info about column',
datatype_name='any info about datatype',
constraint_name='any info about constraint')
plpy.notice('notice', detail='some detail')
plpy.warning('warning', detail='some detail')
plpy.error('stop on error', detail='some detail', hint='some hint')
$$ LANGUAGE plpythonu;
SELECT elog_test();
INFO: info
......@@ -36,46 +36,52 @@ DETAIL: some detail
HINT: some hint
CONTEXT: Traceback (most recent call last):
PL/Python function "elog_test", line 18, in <module>
plpy.error('stop on error', detail = 'some detail', hint = 'some hint')
plpy.error('stop on error', detail='some detail', hint='some hint')
PL/Python function "elog_test"
do $$ plpy.info('other types', detail = (10,20)) $$ LANGUAGE plpythonu;
DO $$ plpy.info('other types', detail=(10, 20)) $$ LANGUAGE plpythonu;
INFO: other types
DETAIL: (10, 20)
do $$
DO $$
import time;
from datetime import date
plpy.info('other types', detail = date(2016,2,26))
plpy.info('other types', detail=date(2016, 2, 26))
$$ LANGUAGE plpythonu;
INFO: other types
DETAIL: 2016-02-26
do $$
DO $$
basket = ['apple', 'orange', 'apple', 'pear', 'orange', 'banana']
plpy.info('other types', detail = basket)
plpy.info('other types', detail=basket)
$$ LANGUAGE plpythonu;
INFO: other types
DETAIL: ['apple', 'orange', 'apple', 'pear', 'orange', 'banana']
-- should fail
do $$ plpy.info('wrong sqlstate', sqlstate='54444A') $$ LANGUAGE plpythonu;
DO $$ plpy.info('wrong sqlstate', sqlstate='54444A') $$ LANGUAGE plpythonu;
ERROR: invalid SQLSTATE code
CONTEXT: PL/Python anonymous code block
do $$ plpy.info('unsupported argument', blabla='fooboo') $$ LANGUAGE plpythonu;
DO $$ plpy.info('unsupported argument', blabla='fooboo') $$ LANGUAGE plpythonu;
ERROR: 'blabla' is an invalid keyword argument for this function
CONTEXT: PL/Python anonymous code block
do $$ plpy.info('first message', message='second message') $$ LANGUAGE plpythonu;
DO $$ plpy.info('first message', message='second message') $$ LANGUAGE plpythonu;
ERROR: the message is already specified
CONTEXT: PL/Python anonymous code block
do $$ plpy.info('first message', 'second message', message='third message') $$ LANGUAGE plpythonu;
DO $$ plpy.info('first message', 'second message', message='third message') $$ LANGUAGE plpythonu;
ERROR: the message is already specified
CONTEXT: PL/Python anonymous code block
-- raise exception in python, handle exception in plgsql
CREATE OR REPLACE FUNCTION raise_exception(_message text, _detail text DEFAULT NULL, _hint text DEFAULT NULL,
_sqlstate text DEFAULT NULL,
_schema_name text DEFAULT NULL, _table_name text DEFAULT NULL, _column_name text DEFAULT NULL,
_datatype_name text DEFAULT NULL, _constraint_name text DEFAULT NULL)
_schema_name text DEFAULT NULL,
_table_name text DEFAULT NULL,
_column_name text DEFAULT NULL,
_datatype_name text DEFAULT NULL,
_constraint_name text DEFAULT NULL)
RETURNS void AS $$
kwargs = { "message":_message, "detail":_detail, "hint":_hint,
"sqlstate":_sqlstate, "schema_name":_schema_name, "table_name":_table_name,
"column_name":_column_name, "datatype_name":_datatype_name, "constraint_name":_constraint_name }
kwargs = {
"message": _message, "detail": _detail, "hint": _hint,
"sqlstate": _sqlstate, "schema_name": _schema_name, "table_name": _table_name,
"column_name": _column_name, "datatype_name": _datatype_name,
"constraint_name": _constraint_name
}
# ignore None values - should work on Python2.3
dict = {}
for k in kwargs:
......@@ -87,14 +93,14 @@ SELECT raise_exception('hello', 'world');
ERROR: plpy.Error: hello
DETAIL: world
CONTEXT: Traceback (most recent call last):
PL/Python function "raise_exception", line 10, in <module>
PL/Python function "raise_exception", line 13, in <module>
plpy.error(**dict)
PL/Python function "raise_exception"
SELECT raise_exception('message text', 'detail text', _sqlstate => 'YY333');
ERROR: plpy.Error: message text
DETAIL: detail text
CONTEXT: Traceback (most recent call last):
PL/Python function "raise_exception", line 10, in <module>
PL/Python function "raise_exception", line 13, in <module>
plpy.error(**dict)
PL/Python function "raise_exception"
SELECT raise_exception(_message => 'message text',
......@@ -110,7 +116,7 @@ ERROR: plpy.Error: message text
DETAIL: detail text
HINT: hint text
CONTEXT: Traceback (most recent call last):
PL/Python function "raise_exception", line 10, in <module>
PL/Python function "raise_exception", line 13, in <module>
plpy.error(**dict)
PL/Python function "raise_exception"
SELECT raise_exception(_message => 'message text',
......@@ -121,7 +127,7 @@ SELECT raise_exception(_message => 'message text',
ERROR: plpy.Error: message text
HINT: hint text
CONTEXT: Traceback (most recent call last):
PL/Python function "raise_exception", line 10, in <module>
PL/Python function "raise_exception", line 13, in <module>
plpy.error(**dict)
PL/Python function "raise_exception"
DO $$
......@@ -166,10 +172,10 @@ END;
$$;
NOTICE: handled exception
DETAIL: message:(plpy.Error: message text), detail:(detail text), hint: (hint text), sqlstate: (XX555), schema_name:(schema text), table_name:(table text), column_name:(column text), datatype_name:(datatype text), constraint_name:(constraint text)
-- the displayed context is different between Python2 and Python3,
-- but that's not important for this test
-- The displayed context is different between Python2 and Python3,
-- but that's not important for this test.
\set SHOW_CONTEXT never
do $$
DO $$
try:
plpy.execute("select raise_exception(_message => 'my message', _sqlstate => 'XX987', _hint => 'some hint', _table_name => 'users_tab', _datatype_name => 'user_type')")
except Exception, e:
......@@ -179,7 +185,7 @@ $$ LANGUAGE plpythonu;
INFO: (119577128, None, 'some hint', None, 0, None, 'users_tab', None, 'user_type', None)
ERROR: plpy.SPIError: plpy.Error: my message
HINT: some hint
do $$
DO $$
try:
plpy.error(message = 'my message', sqlstate = 'XX987', hint = 'some hint', table_name = 'users_tab', datatype_name = 'user_type')
except Exception, e:
......
CREATE FUNCTION elog_test() RETURNS void
AS $$
plpy.debug('debug', detail = 'some detail')
plpy.log('log', detail = 'some detail')
plpy.info('info', detail = 'some detail')
plpy.debug('debug', detail='some detail')
plpy.log('log', detail='some detail')
plpy.info('info', detail='some detail')
plpy.info()
plpy.info('the question', detail = 42);
plpy.info('the question', detail=42);
plpy.info('This is message text.',
detail = 'This is detail text',
hint = 'This is hint text.',
sqlstate = 'XX000',
schema_name = 'any info about schema',
table_name = 'any info about table',
column_name = 'any info about column',
datatype_name = 'any info about datatype',
constraint_name = 'any info about constraint')
plpy.notice('notice', detail = 'some detail')
plpy.warning('warning', detail = 'some detail')
plpy.error('stop on error', detail = 'some detail', hint = 'some hint')
detail='This is detail text',
hint='This is hint text.',
sqlstate='XX000',
schema_name='any info about schema',
table_name='any info about table',
column_name='any info about column',
datatype_name='any info about datatype',
constraint_name='any info about constraint')
plpy.notice('notice', detail='some detail')
plpy.warning('warning', detail='some detail')
plpy.error('stop on error', detail='some detail', hint='some hint')
$$ LANGUAGE plpythonu;
SELECT elog_test();
do $$ plpy.info('other types', detail = (10,20)) $$ LANGUAGE plpythonu;
DO $$ plpy.info('other types', detail=(10, 20)) $$ LANGUAGE plpythonu;
do $$
DO $$
import time;
from datetime import date
plpy.info('other types', detail = date(2016,2,26))
plpy.info('other types', detail=date(2016, 2, 26))
$$ LANGUAGE plpythonu;
do $$
DO $$
basket = ['apple', 'orange', 'apple', 'pear', 'orange', 'banana']
plpy.info('other types', detail = basket)
plpy.info('other types', detail=basket)
$$ LANGUAGE plpythonu;
-- should fail
do $$ plpy.info('wrong sqlstate', sqlstate='54444A') $$ LANGUAGE plpythonu;
do $$ plpy.info('unsupported argument', blabla='fooboo') $$ LANGUAGE plpythonu;
do $$ plpy.info('first message', message='second message') $$ LANGUAGE plpythonu;
do $$ plpy.info('first message', 'second message', message='third message') $$ LANGUAGE plpythonu;
DO $$ plpy.info('wrong sqlstate', sqlstate='54444A') $$ LANGUAGE plpythonu;
DO $$ plpy.info('unsupported argument', blabla='fooboo') $$ LANGUAGE plpythonu;
DO $$ plpy.info('first message', message='second message') $$ LANGUAGE plpythonu;
DO $$ plpy.info('first message', 'second message', message='third message') $$ LANGUAGE plpythonu;
-- raise exception in python, handle exception in plgsql
CREATE OR REPLACE FUNCTION raise_exception(_message text, _detail text DEFAULT NULL, _hint text DEFAULT NULL,
_sqlstate text DEFAULT NULL,
_schema_name text DEFAULT NULL, _table_name text DEFAULT NULL, _column_name text DEFAULT NULL,
_datatype_name text DEFAULT NULL, _constraint_name text DEFAULT NULL)
_schema_name text DEFAULT NULL,
_table_name text DEFAULT NULL,
_column_name text DEFAULT NULL,
_datatype_name text DEFAULT NULL,
_constraint_name text DEFAULT NULL)
RETURNS void AS $$
kwargs = { "message":_message, "detail":_detail, "hint":_hint,
"sqlstate":_sqlstate, "schema_name":_schema_name, "table_name":_table_name,
"column_name":_column_name, "datatype_name":_datatype_name, "constraint_name":_constraint_name }
kwargs = {
"message": _message, "detail": _detail, "hint": _hint,
"sqlstate": _sqlstate, "schema_name": _schema_name, "table_name": _table_name,
"column_name": _column_name, "datatype_name": _datatype_name,
"constraint_name": _constraint_name
}
# ignore None values - should work on Python2.3
dict = {}
for k in kwargs:
......@@ -116,11 +122,11 @@ BEGIN
END;
$$;
-- the displayed context is different between Python2 and Python3,
-- but that's not important for this test
-- The displayed context is different between Python2 and Python3,
-- but that's not important for this test.
\set SHOW_CONTEXT never
do $$
DO $$
try:
plpy.execute("select raise_exception(_message => 'my message', _sqlstate => 'XX987', _hint => 'some hint', _table_name => 'users_tab', _datatype_name => 'user_type')")
except Exception, e:
......@@ -128,7 +134,7 @@ except Exception, e:
raise e
$$ LANGUAGE plpythonu;
do $$
DO $$
try:
plpy.error(message = 'my message', sqlstate = 'XX987', hint = 'some hint', table_name = 'users_tab', datatype_name = 'user_type')
except Exception, e:
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment