Skip to content

Commit adb7764

Browse files
committed
PL/Python DO handler
Also cleaned up some redundancies between the primary error messages and the error context in PL/Python. Hannu Valtonen
1 parent 306a428 commit adb7764

File tree

8 files changed

+102
-16
lines changed

8 files changed

+102
-16
lines changed

doc/src/sgml/plpython.sgml

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<!-- $PostgreSQL: pgsql/doc/src/sgml/plpython.sgml,v 1.43 2009/12/19 22:23:21 petere Exp $ -->
1+
<!-- $PostgreSQL: pgsql/doc/src/sgml/plpython.sgml,v 1.44 2010/01/22 15:45:15 petere Exp $ -->
22

33
<chapter id="plpython">
44
<title>PL/Python - Python Procedural Language</title>
@@ -551,6 +551,24 @@ $$ LANGUAGE plpythonu;
551551
</para>
552552
</sect1>
553553

554+
<sect1 id="plpython-do">
555+
<title>Anonymous Code Blocks</title>
556+
557+
<para>
558+
PL/Python also supports anonymous code blocks called with the
559+
<xref linkend="sql-do"> statement:
560+
561+
<programlisting>
562+
DO $$
563+
# PL/Python code
564+
$$ LANGUAGE plpythonu;
565+
</programlisting>
566+
567+
An anonymous code block receives no arguments, and whatever value it
568+
might return is discarded. Otherwise it behaves just like a function.
569+
</para>
570+
</sect1>
571+
554572
<sect1 id="plpython-trigger">
555573
<title>Trigger Functions</title>
556574

src/include/catalog/catversion.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737
* Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
3838
* Portions Copyright (c) 1994, Regents of the University of California
3939
*
40-
* $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.576 2010/01/19 14:11:32 mha Exp $
40+
* $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.577 2010/01/22 15:45:15 petere Exp $
4141
*
4242
*-------------------------------------------------------------------------
4343
*/
@@ -53,6 +53,6 @@
5353
*/
5454

5555
/* yyyymmddN */
56-
#define CATALOG_VERSION_NO 201001191
56+
#define CATALOG_VERSION_NO 201001221
5757

5858
#endif

src/include/catalog/pg_pltemplate.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
* Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
99
* Portions Copyright (c) 1994, Regents of the University of California
1010
*
11-
* $PostgreSQL: pgsql/src/include/catalog/pg_pltemplate.h,v 1.12 2010/01/05 01:06:56 tgl Exp $
11+
* $PostgreSQL: pgsql/src/include/catalog/pg_pltemplate.h,v 1.13 2010/01/22 15:45:15 petere Exp $
1212
*
1313
* NOTES
1414
* 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
7272
DATA(insert ( "pltclu" f f "pltclu_call_handler" _null_ _null_ "$libdir/pltcl" _null_ ));
7373
DATA(insert ( "plperl" t t "plperl_call_handler" "plperl_inline_handler" "plperl_validator" "$libdir/plperl" _null_ ));
7474
DATA(insert ( "plperlu" f f "plperl_call_handler" "plperl_inline_handler" "plperl_validator" "$libdir/plperl" _null_ ));
75-
DATA(insert ( "plpythonu" f f "plpython_call_handler" _null_ _null_ "$libdir/plpython" _null_ ));
76-
DATA(insert ( "plpython2u" f f "plpython_call_handler" _null_ _null_ "$libdir/plpython2" _null_ ));
77-
DATA(insert ( "plpython3u" f f "plpython_call_handler" _null_ _null_ "$libdir/plpython3" _null_ ));
75+
DATA(insert ( "plpythonu" f f "plpython_call_handler" "plpython_inline_handler" _null_ "$libdir/plpython" _null_ ));
76+
DATA(insert ( "plpython2u" f f "plpython_call_handler" "plpython_inline_handler" _null_ "$libdir/plpython2" _null_ ));
77+
DATA(insert ( "plpython3u" f f "plpython_call_handler" "plpython_inline_handler" _null_ "$libdir/plpython3" _null_ ));
7878

7979
#endif /* PG_PLTEMPLATE_H */

src/pl/plpython/Makefile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# $PostgreSQL: pgsql/src/pl/plpython/Makefile,v 1.35 2009/12/15 22:59:54 petere Exp $
1+
# $PostgreSQL: pgsql/src/pl/plpython/Makefile,v 1.36 2010/01/22 15:45:15 petere Exp $
22

33
subdir = src/pl/plpython
44
top_builddir = ../../..
@@ -66,6 +66,7 @@ REGRESS = \
6666
plpython_schema \
6767
plpython_populate \
6868
plpython_test \
69+
plpython_do \
6970
plpython_global \
7071
plpython_import \
7172
plpython_spi \
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
DO $$ plpy.notice("This is plpythonu.") $$ LANGUAGE plpythonu;
2+
NOTICE: This is plpythonu.
3+
CONTEXT: PL/Python anonymous code block
4+
DO $$ nonsense $$ LANGUAGE plpythonu;
5+
ERROR: PL/Python: NameError: global name 'nonsense' is not defined
6+
CONTEXT: PL/Python anonymous code block

src/pl/plpython/expected/plpython_error.out

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,7 @@ CREATE FUNCTION exception_index_invalid(text) RETURNS text
2222
'return args[1]'
2323
LANGUAGE plpythonu;
2424
SELECT exception_index_invalid('test');
25-
ERROR: PL/Python: PL/Python function "exception_index_invalid" failed
26-
DETAIL: IndexError: list index out of range
25+
ERROR: PL/Python: IndexError: list index out of range
2726
CONTEXT: PL/Python function "exception_index_invalid"
2827
/* check handling of nested exceptions
2928
*/

src/pl/plpython/plpython.c

Lines changed: 65 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/**********************************************************************
22
* plpython.c - python as a procedural language for PostgreSQL
33
*
4-
* $PostgreSQL: pgsql/src/pl/plpython/plpython.c,v 1.135 2010/01/16 11:03:51 petere Exp $
4+
* $PostgreSQL: pgsql/src/pl/plpython/plpython.c,v 1.136 2010/01/22 15:45:15 petere Exp $
55
*
66
*********************************************************************
77
*/
@@ -243,14 +243,13 @@ typedef struct PLyResultObject
243243

244244
/* function declarations */
245245

246-
/* Two exported functions: first is the magic telling Postgresql
247-
* what function call interface it implements. Second is for
248-
* initialization of the interpreter during library load.
249-
*/
246+
/* exported functions */
250247
Datum plpython_call_handler(PG_FUNCTION_ARGS);
248+
Datum plpython_inline_handler(PG_FUNCTION_ARGS);
251249
void _PG_init(void);
252250

253251
PG_FUNCTION_INFO_V1(plpython_call_handler);
252+
PG_FUNCTION_INFO_V1(plpython_inline_handler);
254253

255254
/* most of the remaining of the declarations, all static */
256255

@@ -418,6 +417,12 @@ plpython_error_callback(void *arg)
418417
errcontext("PL/Python function \"%s\"", PLy_procedure_name(PLy_curr_procedure));
419418
}
420419

420+
static void
421+
plpython_inline_error_callback(void *arg)
422+
{
423+
errcontext("PL/Python anonymous code block");
424+
}
425+
421426
static void
422427
plpython_trigger_error_callback(void *arg)
423428
{
@@ -495,6 +500,60 @@ plpython_call_handler(PG_FUNCTION_ARGS)
495500
return retval;
496501
}
497502

503+
Datum
504+
plpython_inline_handler(PG_FUNCTION_ARGS)
505+
{
506+
InlineCodeBlock *codeblock = (InlineCodeBlock *) DatumGetPointer(PG_GETARG_DATUM(0));
507+
FunctionCallInfoData fake_fcinfo;
508+
FmgrInfo flinfo;
509+
PLyProcedure *save_curr_proc;
510+
PLyProcedure *volatile proc = NULL;
511+
ErrorContextCallback plerrcontext;
512+
513+
if (SPI_connect() != SPI_OK_CONNECT)
514+
elog(ERROR, "SPI_connect failed");
515+
516+
save_curr_proc = PLy_curr_procedure;
517+
518+
/*
519+
* Setup error traceback support for ereport()
520+
*/
521+
plerrcontext.callback = plpython_inline_error_callback;
522+
plerrcontext.previous = error_context_stack;
523+
error_context_stack = &plerrcontext;
524+
525+
MemSet(&fake_fcinfo, 0, sizeof(fake_fcinfo));
526+
MemSet(&flinfo, 0, sizeof(flinfo));
527+
fake_fcinfo.flinfo = &flinfo;
528+
flinfo.fn_oid = InvalidOid;
529+
flinfo.fn_mcxt = CurrentMemoryContext;
530+
531+
proc = PLy_malloc0(sizeof(PLyProcedure));
532+
proc->pyname = PLy_strdup("__plpython_inline_block");
533+
proc->result.out.d.typoid = VOIDOID;
534+
535+
PG_TRY();
536+
{
537+
PLy_procedure_compile(proc, codeblock->source_text);
538+
PLy_curr_procedure = proc;
539+
PLy_function_handler(&fake_fcinfo, proc);
540+
}
541+
PG_CATCH();
542+
{
543+
PLy_curr_procedure = save_curr_proc;
544+
PyErr_Clear();
545+
PG_RE_THROW();
546+
}
547+
PG_END_TRY();
548+
549+
/* Pop the error context stack */
550+
error_context_stack = plerrcontext.previous;
551+
552+
PLy_curr_procedure = save_curr_proc;
553+
554+
PG_RETURN_VOID();
555+
}
556+
498557
/* trigger and function sub handlers
499558
*
500559
* 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)
11071166
if (rv == NULL || PyErr_Occurred())
11081167
{
11091168
Py_XDECREF(rv);
1110-
PLy_elog(ERROR, "PL/Python function \"%s\" failed", proc->proname);
1169+
PLy_elog(ERROR, NULL);
11111170
}
11121171

11131172
return rv;

src/pl/plpython/sql/plpython_do.sql

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
DO $$ plpy.notice("This is plpythonu.") $$ LANGUAGE plpythonu;
2+
3+
DO $$ nonsense $$ LANGUAGE plpythonu;

0 commit comments

Comments
 (0)