mirror of
https://git.postgresql.org/git/postgresql.git
synced 2025-01-24 18:55:04 +08:00
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:
parent
306a4287c3
commit
adb7764030
@ -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>
|
||||
|
||||
|
@ -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
|
||||
|
@ -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 */
|
||||
|
@ -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 \
|
||||
|
6
src/pl/plpython/expected/plpython_do.out
Normal file
6
src/pl/plpython/expected/plpython_do.out
Normal 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
|
@ -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
|
||||
*/
|
||||
|
@ -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;
|
||||
|
3
src/pl/plpython/sql/plpython_do.sql
Normal file
3
src/pl/plpython/sql/plpython_do.sql
Normal file
@ -0,0 +1,3 @@
|
||||
DO $$ plpy.notice("This is plpythonu.") $$ LANGUAGE plpythonu;
|
||||
|
||||
DO $$ nonsense $$ LANGUAGE plpythonu;
|
Loading…
Reference in New Issue
Block a user