From adb77640304a375883eaaec9eb9b21036c2be0bd Mon Sep 17 00:00:00 2001 From: Peter Eisentraut Date: Fri, 22 Jan 2010 15:45:15 +0000 Subject: [PATCH] PL/Python DO handler Also cleaned up some redundancies between the primary error messages and the error context in PL/Python. Hannu Valtonen --- doc/src/sgml/plpython.sgml | 20 +++++- src/include/catalog/catversion.h | 4 +- src/include/catalog/pg_pltemplate.h | 8 +-- src/pl/plpython/Makefile | 3 +- src/pl/plpython/expected/plpython_do.out | 6 ++ src/pl/plpython/expected/plpython_error.out | 3 +- src/pl/plpython/plpython.c | 71 +++++++++++++++++++-- src/pl/plpython/sql/plpython_do.sql | 3 + 8 files changed, 102 insertions(+), 16 deletions(-) create mode 100644 src/pl/plpython/expected/plpython_do.out create mode 100644 src/pl/plpython/sql/plpython_do.sql diff --git a/doc/src/sgml/plpython.sgml b/doc/src/sgml/plpython.sgml index a623f3509b..384b7aecc4 100644 --- a/doc/src/sgml/plpython.sgml +++ b/doc/src/sgml/plpython.sgml @@ -1,4 +1,4 @@ - + PL/Python - Python Procedural Language @@ -551,6 +551,24 @@ $$ LANGUAGE plpythonu; + + Anonymous Code Blocks + + + PL/Python also supports anonymous code blocks called with the + statement: + + +DO $$ + # PL/Python code +$$ LANGUAGE plpythonu; + + + An anonymous code block receives no arguments, and whatever value it + might return is discarded. Otherwise it behaves just like a function. + + + Trigger Functions diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h index f37b9077a9..29e04bea01 100644 --- a/src/include/catalog/catversion.h +++ b/src/include/catalog/catversion.h @@ -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 diff --git a/src/include/catalog/pg_pltemplate.h b/src/include/catalog/pg_pltemplate.h index f7b77081cb..59c890100b 100644 --- a/src/include/catalog/pg_pltemplate.h +++ b/src/include/catalog/pg_pltemplate.h @@ -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 */ diff --git a/src/pl/plpython/Makefile b/src/pl/plpython/Makefile index 5db880b08e..4b18076a0f 100644 --- a/src/pl/plpython/Makefile +++ b/src/pl/plpython/Makefile @@ -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 \ diff --git a/src/pl/plpython/expected/plpython_do.out b/src/pl/plpython/expected/plpython_do.out new file mode 100644 index 0000000000..9de261ae45 --- /dev/null +++ b/src/pl/plpython/expected/plpython_do.out @@ -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 diff --git a/src/pl/plpython/expected/plpython_error.out b/src/pl/plpython/expected/plpython_error.out index 36ffa8b5bd..1f24c13892 100644 --- a/src/pl/plpython/expected/plpython_error.out +++ b/src/pl/plpython/expected/plpython_error.out @@ -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 */ diff --git a/src/pl/plpython/plpython.c b/src/pl/plpython/plpython.c index 8ddb08c202..c6accdac9a 100644 --- a/src/pl/plpython/plpython.c +++ b/src/pl/plpython/plpython.c @@ -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; diff --git a/src/pl/plpython/sql/plpython_do.sql b/src/pl/plpython/sql/plpython_do.sql new file mode 100644 index 0000000000..8596c39d37 --- /dev/null +++ b/src/pl/plpython/sql/plpython_do.sql @@ -0,0 +1,3 @@ +DO $$ plpy.notice("This is plpythonu.") $$ LANGUAGE plpythonu; + +DO $$ nonsense $$ LANGUAGE plpythonu; -- 2.40.0