PL/Python DO handler

Also cleaned up some redundancies between the primary error messages and the
error context in PL/Python.

Hannu Valtonen
This commit is contained in:
Peter Eisentraut 2010-01-22 15:45:15 +00:00
parent 306a4287c3
commit adb7764030
8 changed files with 102 additions and 16 deletions

View File

@ -1,4 +1,4 @@
<!-- $PostgreSQL: pgsql/doc/src/sgml/plpython.sgml,v 1.43 2009/12/19 22:23:21 petere Exp $ -->
<!-- $PostgreSQL: pgsql/doc/src/sgml/plpython.sgml,v 1.44 2010/01/22 15:45:15 petere Exp $ -->
<chapter id="plpython">
<title>PL/Python - Python Procedural Language</title>
@ -551,6 +551,24 @@ $$ LANGUAGE plpythonu;
</para>
</sect1>
<sect1 id="plpython-do">
<title>Anonymous Code Blocks</title>
<para>
PL/Python also supports anonymous code blocks called with the
<xref linkend="sql-do"> statement:
<programlisting>
DO $$
# PL/Python code
$$ LANGUAGE plpythonu;
</programlisting>
An anonymous code block receives no arguments, and whatever value it
might return is discarded. Otherwise it behaves just like a function.
</para>
</sect1>
<sect1 id="plpython-trigger">
<title>Trigger Functions</title>

View File

@ -37,7 +37,7 @@
* Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.576 2010/01/19 14:11:32 mha Exp $
* $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.577 2010/01/22 15:45:15 petere Exp $
*
*-------------------------------------------------------------------------
*/
@ -53,6 +53,6 @@
*/
/* yyyymmddN */
#define CATALOG_VERSION_NO 201001191
#define CATALOG_VERSION_NO 201001221
#endif

View File

@ -8,7 +8,7 @@
* Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/catalog/pg_pltemplate.h,v 1.12 2010/01/05 01:06:56 tgl Exp $
* $PostgreSQL: pgsql/src/include/catalog/pg_pltemplate.h,v 1.13 2010/01/22 15:45:15 petere Exp $
*
* NOTES
* the genbki.pl script reads this file and generates .bki
@ -72,8 +72,8 @@ DATA(insert ( "pltcl" t t "pltcl_call_handler" _null_ _null_ "$libdir/pltcl" _n
DATA(insert ( "pltclu" f f "pltclu_call_handler" _null_ _null_ "$libdir/pltcl" _null_ ));
DATA(insert ( "plperl" t t "plperl_call_handler" "plperl_inline_handler" "plperl_validator" "$libdir/plperl" _null_ ));
DATA(insert ( "plperlu" f f "plperl_call_handler" "plperl_inline_handler" "plperl_validator" "$libdir/plperl" _null_ ));
DATA(insert ( "plpythonu" f f "plpython_call_handler" _null_ _null_ "$libdir/plpython" _null_ ));
DATA(insert ( "plpython2u" f f "plpython_call_handler" _null_ _null_ "$libdir/plpython2" _null_ ));
DATA(insert ( "plpython3u" f f "plpython_call_handler" _null_ _null_ "$libdir/plpython3" _null_ ));
DATA(insert ( "plpythonu" f f "plpython_call_handler" "plpython_inline_handler" _null_ "$libdir/plpython" _null_ ));
DATA(insert ( "plpython2u" f f "plpython_call_handler" "plpython_inline_handler" _null_ "$libdir/plpython2" _null_ ));
DATA(insert ( "plpython3u" f f "plpython_call_handler" "plpython_inline_handler" _null_ "$libdir/plpython3" _null_ ));
#endif /* PG_PLTEMPLATE_H */

View File

@ -1,4 +1,4 @@
# $PostgreSQL: pgsql/src/pl/plpython/Makefile,v 1.35 2009/12/15 22:59:54 petere Exp $
# $PostgreSQL: pgsql/src/pl/plpython/Makefile,v 1.36 2010/01/22 15:45:15 petere Exp $
subdir = src/pl/plpython
top_builddir = ../../..
@ -66,6 +66,7 @@ REGRESS = \
plpython_schema \
plpython_populate \
plpython_test \
plpython_do \
plpython_global \
plpython_import \
plpython_spi \

View File

@ -0,0 +1,6 @@
DO $$ plpy.notice("This is plpythonu.") $$ LANGUAGE plpythonu;
NOTICE: This is plpythonu.
CONTEXT: PL/Python anonymous code block
DO $$ nonsense $$ LANGUAGE plpythonu;
ERROR: PL/Python: NameError: global name 'nonsense' is not defined
CONTEXT: PL/Python anonymous code block

View File

@ -22,8 +22,7 @@ CREATE FUNCTION exception_index_invalid(text) RETURNS text
'return args[1]'
LANGUAGE plpythonu;
SELECT exception_index_invalid('test');
ERROR: PL/Python: PL/Python function "exception_index_invalid" failed
DETAIL: IndexError: list index out of range
ERROR: PL/Python: IndexError: list index out of range
CONTEXT: PL/Python function "exception_index_invalid"
/* check handling of nested exceptions
*/

View File

@ -1,7 +1,7 @@
/**********************************************************************
* plpython.c - python as a procedural language for PostgreSQL
*
* $PostgreSQL: pgsql/src/pl/plpython/plpython.c,v 1.135 2010/01/16 11:03:51 petere Exp $
* $PostgreSQL: pgsql/src/pl/plpython/plpython.c,v 1.136 2010/01/22 15:45:15 petere Exp $
*
*********************************************************************
*/
@ -243,14 +243,13 @@ typedef struct PLyResultObject
/* function declarations */
/* Two exported functions: first is the magic telling Postgresql
* what function call interface it implements. Second is for
* initialization of the interpreter during library load.
*/
/* exported functions */
Datum plpython_call_handler(PG_FUNCTION_ARGS);
Datum plpython_inline_handler(PG_FUNCTION_ARGS);
void _PG_init(void);
PG_FUNCTION_INFO_V1(plpython_call_handler);
PG_FUNCTION_INFO_V1(plpython_inline_handler);
/* most of the remaining of the declarations, all static */
@ -418,6 +417,12 @@ plpython_error_callback(void *arg)
errcontext("PL/Python function \"%s\"", PLy_procedure_name(PLy_curr_procedure));
}
static void
plpython_inline_error_callback(void *arg)
{
errcontext("PL/Python anonymous code block");
}
static void
plpython_trigger_error_callback(void *arg)
{
@ -495,6 +500,60 @@ plpython_call_handler(PG_FUNCTION_ARGS)
return retval;
}
Datum
plpython_inline_handler(PG_FUNCTION_ARGS)
{
InlineCodeBlock *codeblock = (InlineCodeBlock *) DatumGetPointer(PG_GETARG_DATUM(0));
FunctionCallInfoData fake_fcinfo;
FmgrInfo flinfo;
PLyProcedure *save_curr_proc;
PLyProcedure *volatile proc = NULL;
ErrorContextCallback plerrcontext;
if (SPI_connect() != SPI_OK_CONNECT)
elog(ERROR, "SPI_connect failed");
save_curr_proc = PLy_curr_procedure;
/*
* Setup error traceback support for ereport()
*/
plerrcontext.callback = plpython_inline_error_callback;
plerrcontext.previous = error_context_stack;
error_context_stack = &plerrcontext;
MemSet(&fake_fcinfo, 0, sizeof(fake_fcinfo));
MemSet(&flinfo, 0, sizeof(flinfo));
fake_fcinfo.flinfo = &flinfo;
flinfo.fn_oid = InvalidOid;
flinfo.fn_mcxt = CurrentMemoryContext;
proc = PLy_malloc0(sizeof(PLyProcedure));
proc->pyname = PLy_strdup("__plpython_inline_block");
proc->result.out.d.typoid = VOIDOID;
PG_TRY();
{
PLy_procedure_compile(proc, codeblock->source_text);
PLy_curr_procedure = proc;
PLy_function_handler(&fake_fcinfo, proc);
}
PG_CATCH();
{
PLy_curr_procedure = save_curr_proc;
PyErr_Clear();
PG_RE_THROW();
}
PG_END_TRY();
/* Pop the error context stack */
error_context_stack = plerrcontext.previous;
PLy_curr_procedure = save_curr_proc;
PG_RETURN_VOID();
}
/* trigger and function sub handlers
*
* the python function is expected to return Py_None if the tuple is
@ -1107,7 +1166,7 @@ PLy_procedure_call(PLyProcedure *proc, char *kargs, PyObject *vargs)
if (rv == NULL || PyErr_Occurred())
{
Py_XDECREF(rv);
PLy_elog(ERROR, "PL/Python function \"%s\" failed", proc->proname);
PLy_elog(ERROR, NULL);
}
return rv;

View File

@ -0,0 +1,3 @@
DO $$ plpy.notice("This is plpythonu.") $$ LANGUAGE plpythonu;
DO $$ nonsense $$ LANGUAGE plpythonu;