Re: [HACKERS] pl/python custom exceptions for SPI

2011-03-01 Thread Jan Urbański
On 28/02/11 19:38, Tom Lane wrote:
> Peter Eisentraut  writes:
>> On mån, 2011-02-28 at 12:08 -0500, Tom Lane wrote:
>>> I'm seeing a core dump as well as multiple inconsistencies in error
>>> message spelling in the plpython regression tests on a Fedora 13 box
>>> (python 2.6.4).  Several buildfarm critters don't look too happy either.
> 
>> Fixed.  (Well, some of it.  We'll see ...)
> 
> Core dump is still there.  It appears to be a python assertion failure.
> I installed python's debuginfo and got this backtrace:
> 
> Program terminated with signal 6, Aborted.
> #0  0x0032a36328f5 in raise (sig=6) at 
> ../nptl/sysdeps/unix/sysv/linux/raise.c:64
> 64return INLINE_SYSCALL (tgkill, 3, pid, selftid, sig);
> Missing separate debuginfos, use: debuginfo-install 
> keyutils-libs-1.2-6.fc12.x86_64 krb5-libs-1.7.1-17.fc13.x86_64 
> libcom_err-1.41.10-7.fc13.x86_64 libselinux-2.0.94-2.fc13.x86_64 
> openssl-1.0.0c-1.fc13.x86_64 zlib-1.2.3-23.fc12.x86_64
> (gdb) bt
> #0  0x0032a36328f5 in raise (sig=6) at 
> ../nptl/sysdeps/unix/sysv/linux/raise.c:64
> #1  0x0032a36340d5 in abort () at abort.c:92
> #2  0x0032a362b8b5 in __assert_fail (assertion=0x32a5b46391 
> "gc->gc.gc_refs != 0", file=, line=277, function= optimized out>)
> at assert.c:81
> #3  0x0032a5b0853e in visit_decref (op=, 
> data=) at Modules/gcmodule.c:277
> #4  0x0032a5a7cbd9 in dict_traverse (op=
> {'info': , 'notice': , 
> 'Fatal': , 'log': , 
> 'prepare': , 'spiexceptions':  0x7f11c3666d38>, 'SPIError': , 'Error':  remote 0x1bba300>, 'execute': , '__package__': 
> None, 'quote_ident': , 'warning':  function warning>, 'subtransaction': , 
> 'quote_literal': , 'quote_nullable': 
> , 'error': , 
> 'debug': , '__name__': 'plpy', 'fatal':  function fatal>, '__doc__': None}, visit=0x32a5b084c0 , arg=0x0)
> at Objects/dictobject.c:2003
> [...]
> #24 0x0032a5af22c4 in PyImport_ImportModuleLevel (name=0x7f11c40c2084 
> "string", globals=
> 
> Don't know python enough to do anything useful with this, but the
> reference to "gc_refs" sure makes it look like something is dropping the
> ball on when to do INCREF/DECREF.

That's strange, the error occurs while trying to import the "string"
module. But the error itself seems to be caused by trying to unref the
spiexceptions module (showing up here as ). Apparently adding spiexceptions as an object to the
plpy module is not done exactly right.

I'll try to reproduce it in my environment.

Cheers,
Jan

-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] pl/python custom exceptions for SPI

2011-02-28 Thread Tom Lane
Peter Eisentraut  writes:
> On mån, 2011-02-28 at 12:08 -0500, Tom Lane wrote:
>> I'm seeing a core dump as well as multiple inconsistencies in error
>> message spelling in the plpython regression tests on a Fedora 13 box
>> (python 2.6.4).  Several buildfarm critters don't look too happy either.

> Fixed.  (Well, some of it.  We'll see ...)

Core dump is still there.  It appears to be a python assertion failure.
I installed python's debuginfo and got this backtrace:

Program terminated with signal 6, Aborted.
#0  0x0032a36328f5 in raise (sig=6) at 
../nptl/sysdeps/unix/sysv/linux/raise.c:64
64return INLINE_SYSCALL (tgkill, 3, pid, selftid, sig);
Missing separate debuginfos, use: debuginfo-install 
keyutils-libs-1.2-6.fc12.x86_64 krb5-libs-1.7.1-17.fc13.x86_64 
libcom_err-1.41.10-7.fc13.x86_64 libselinux-2.0.94-2.fc13.x86_64 
openssl-1.0.0c-1.fc13.x86_64 zlib-1.2.3-23.fc12.x86_64
(gdb) bt
#0  0x0032a36328f5 in raise (sig=6) at 
../nptl/sysdeps/unix/sysv/linux/raise.c:64
#1  0x0032a36340d5 in abort () at abort.c:92
#2  0x0032a362b8b5 in __assert_fail (assertion=0x32a5b46391 "gc->gc.gc_refs 
!= 0", file=, line=277, function=)
at assert.c:81
#3  0x0032a5b0853e in visit_decref (op=, 
data=) at Modules/gcmodule.c:277
#4  0x0032a5a7cbd9 in dict_traverse (op=
{'info': , 'notice': , 
'Fatal': , 'log': , 'prepare': 
, 'spiexceptions': , 'SPIError': , 'Error': , 'execute': , '__package__': None, 
'quote_ident': , 'warning': , 'subtransaction': , 
'quote_literal': , 'quote_nullable': , 'error': , 'debug': 
, '__name__': 'plpy', 'fatal': , '__doc__': None}, visit=0x32a5b084c0 , arg=0x0)
at Objects/dictobject.c:2003
#5  0x0032a5b08c9f in subtract_refs (generation=1) at Modules/gcmodule.c:296
#6  collect (generation=1) at Modules/gcmodule.c:817
#7  0x0032a5b096fa in collect_generations (basicsize=) 
at Modules/gcmodule.c:924
#8  _PyObject_GC_Malloc (basicsize=) at 
Modules/gcmodule.c:1363
#9  0x0032a5b0972e in _PyObject_GC_NewVar (tp=0x32a5d899a0, nitems=1) at 
Modules/gcmodule.c:1383
#10 0x0032a5a9703f in PyTuple_New (size=1) at Objects/tupleobject.c:69
#11 0x0032a5af3697 in r_object (p=0x7fffe1f5f330) at Python/marshal.c:788
#12 0x0032a5af389c in r_object (p=0x7fffe1f5f330) at Python/marshal.c:927
#13 0x0032a5af36dd in r_object (p=0x7fffe1f5f330) at Python/marshal.c:794
#14 0x0032a5af389c in r_object (p=0x7fffe1f5f330) at Python/marshal.c:927
#15 0x0032a5af36dd in r_object (p=0x7fffe1f5f330) at Python/marshal.c:794
#16 0x0032a5af389c in r_object (p=0x7fffe1f5f330) at Python/marshal.c:927
#17 0x0032a5af3fd8 in PyMarshal_ReadObjectFromString (str=, len=) at Python/marshal.c:1107
#18 0x0032a5af5952 in PyMarshal_ReadLastObjectFromFile (fp=0x1c66e50) at 
Python/marshal.c:1066
#19 0x0032a5aedb39 in read_compiled_module (cpathname=0x7fffe1f63540 
"/usr/lib64/python2.6/string.pyc", fp=) at 
Python/import.c:767
#20 0x0032a5aef69d in load_source_module (name=0x7fffe1f656a0 "string", 
pathname=0x7fffe1f645c0 "/usr/lib64/python2.6/string.py", fp=0x1c29b30)
at Python/import.c:991
#21 0x0032a5af0cb5 in import_submodule (mod=None, subname=0x7fffe1f656a0 
"string", fullname=0x7fffe1f656a0 "string") at Python/import.c:2589
#22 0x0032a5af0f34 in load_next (mod=None, altmod=None, p_name=, buf=0x7fffe1f656a0 "string", p_buflen=0x7fffe1f65698)
at Python/import.c:2409
#23 0x0032a5af1582 in import_module_level (name=0x0, globals=, locals=, fromlist=None, level=)
at Python/import.c:2131
#24 0x0032a5af22c4 in PyImport_ImportModuleLevel (name=0x7f11c40c2084 
"string", globals=
{'plpy': , 'GD': {}, 'args': [], 
'__builtins__': , '__name__': '__main__', 
'SD': {}, '__doc__': None, '__plpython_procedure_import_succeed_41194': 
, '__package__': None}, locals=None, 
fromlist=None, 
level=) at Python/import.c:2182
#25 0x0032a5ad762f in builtin___import__ (self=, 
args=, kwds=) at 
Python/bltinmodule.c:48
#26 0x0032a5a43db3 in PyObject_Call (func=, 
arg=, kw=) at Objects/abstract.c:2492
#27 0x0032a5ad7ba3 in PyEval_CallObjectWithKeywords (func=, arg=
('string', {'plpy': , 'GD': {}, 'args': 
[], '__builtins__': , '__name__': '__main__', 
'SD': {}, '__doc__': None, '__plpython_procedure_import_succeed_41194': 
, '__package__': None}, None, None), 
kw=)
at Python/ceval.c:3633
#28 0x0032a5ada844 in PyEval_EvalFrameEx (f=, 
throwflag=) at Python/ceval.c:2192
#29 0x0032a5ade312 in fast_function (f=, 
throwflag=) at Python/ceval.c:3850
#30 call_function (f=, throwflag=) at 
Python/ceval.c:3785
#31 PyEval_EvalFrameEx (f=, throwflag=) at Python/ceval.c:2445
#32 0x0032a5adf4e9 in PyEval_EvalCodeEx (co=0x7f11c36526c0, globals=, locals=, args=, 
argcount=0, kws=0x0, kwcount=0, defs=0x0, defcount=0, closure=0x0) at 
Python/ceval.c:3026
#33 0x0032a5adf5b2 in PyEval_EvalCode (co=, 
globals=, locals=) at 
Python/ceval.c:526
#34 0x7f11c418cab2 in PLy_procedure_call (proc=0x1c2c9d8, kargs=,

Re: [HACKERS] pl/python custom exceptions for SPI

2011-02-28 Thread Peter Eisentraut
On mån, 2011-02-28 at 12:08 -0500, Tom Lane wrote:
> Peter Eisentraut  writes:
> > On lör, 2011-02-12 at 11:58 +0100, Jan Urbański wrote:
> >> Here's an updated patch with documentation. It's an incremental patch on
> >> top of the latest explicit-subxacts version.
> 
> > Committed.
> 
> I'm seeing a core dump as well as multiple inconsistencies in error
> message spelling in the plpython regression tests on a Fedora 13 box
> (python 2.6.4).  Several buildfarm critters don't look too happy either.

Fixed.  (Well, some of it.  We'll see ...)


-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] pl/python custom exceptions for SPI

2011-02-28 Thread Tom Lane
Peter Eisentraut  writes:
> On lör, 2011-02-12 at 11:58 +0100, Jan Urbański wrote:
>> Here's an updated patch with documentation. It's an incremental patch on
>> top of the latest explicit-subxacts version.

> Committed.

I'm seeing a core dump as well as multiple inconsistencies in error
message spelling in the plpython regression tests on a Fedora 13 box
(python 2.6.4).  Several buildfarm critters don't look too happy either.

regards, tom lane

-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] pl/python custom exceptions for SPI

2011-02-28 Thread Peter Eisentraut
On lör, 2011-02-12 at 11:58 +0100, Jan Urbański wrote:
> On 11/02/11 10:53, Jan Urbański wrote:
> > On 10/02/11 22:26, Steve Singer wrote:
> 
> Here's an updated patch with documentation. It's an incremental patch on
> top of the latest explicit-subxacts version.

Committed.


-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] pl/python custom exceptions for SPI

2011-02-13 Thread Steve Singer

On 11-02-12 05:58 AM, Jan Urbański wrote:

On 11/02/11 10:53, Jan Urbański wrote:

On 10/02/11 22:26, Steve Singer wrote:

Here's an updated patch with documentation. It's an incremental patch on
top of the latest explicit-subxacts version.



This looks fine.  I've attached a one word documentation change to go o 
top of the patch.


I'll let Peter decide if he likes those assert's or not.  I don't have a 
good enough sense of if we often use asserts in that fashion elsewhere.





Cheers,
Jan





diff --git a/doc/src/sgml/plpython.sgml b/doc/src/sgml/plpython.sgml
index aee54bf..4a90430 100644
*** a/doc/src/sgml/plpython.sgml
--- b/doc/src/sgml/plpython.sgml
*** $$ LANGUAGE plpythonu;
*** 966,972 
  
 
 
! The actual class of the exception being raised corresponds to exact
  condition that caused the error (refer to 
  for a list of possible conditions).  The
  plpy.spiexceptions module defines an exception class for
--- 966,972 
  
 
 
! The actual class of the exception being raised corresponds to the exact
  condition that caused the error (refer to 
  for a list of possible conditions).  The
  plpy.spiexceptions module defines an exception class for

-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] pl/python custom exceptions for SPI

2011-02-12 Thread Jan Urbański
On 11/02/11 10:53, Jan Urbański wrote:
> On 10/02/11 22:26, Steve Singer wrote:

Here's an updated patch with documentation. It's an incremental patch on
top of the latest explicit-subxacts version.

Cheers,
Jan
diff --git a/doc/src/sgml/plpython.sgml b/doc/src/sgml/plpython.sgml
index 87be8c2..aee54bf 100644
*** a/doc/src/sgml/plpython.sgml
--- b/doc/src/sgml/plpython.sgml
*** $$ LANGUAGE plpythonu;
*** 950,960 
  Functions accessing the database might encounter errors, which
  will cause them to abort and raise an exception.  Both
  plpy.execute and
! plpy.prepare can raise an instance of
! plpy.SPIError, which by default will terminate
! the function.  This error can be handled just like any other
! Python exception, by using the try/except
! construct.  For example:
  
  CREATE FUNCTION try_adding_joe() RETURNS text AS $$
  try:
--- 950,959 
  Functions accessing the database might encounter errors, which
  will cause them to abort and raise an exception.  Both
  plpy.execute and
! plpy.prepare can raise an instance of a subclass of
! plpy.SPIError, which by default will terminate the
! function.  This error can be handled just like any other Python exception,
! by using the try/except construct.  For example:
  
  CREATE FUNCTION try_adding_joe() RETURNS text AS $$
  try:
*** CREATE FUNCTION try_adding_joe() RETURNS
*** 966,971 
--- 965,1007 
  $$ LANGUAGE plpythonu;
  
 
+
+ The actual class of the exception being raised corresponds to exact
+ condition that caused the error (refer to 
+ for a list of possible conditions).  The
+ plpy.spiexceptions module defines an exception class for
+ each PostgreSQL condition, deriving their names
+ from the condition name.  For instance, division_by_zero
+ becomes DivisionByZero, unique_violation
+ becomes UniqueViolation, fdw_error
+ becomes FdwError and so on.  Each of these exception
+ classes inherits from SPIError.  This separation makes
+ it easier to handle specific errors, for instance:
+ 
+ CREATE FUNCTION insert_fraction(numerator int, denominator int) RETURNS text AS $$
+ from plpy import spiexceptions
+ try:
+ plpy.execute("INSERT INTO fractions(frac) VALUES (%d / %d)" %
+ (numerator, denominator))
+ except spiexceptions.DivisionByZero:
+ return "denominator cannot equal zero"
+ except spiexceptions.UniqueViolation:
+ return "already have that fraction"
+ except plpy.SPIError, e:
+ return "other error, SQLSTATE %s" % e.sqlstate
+ else:
+ return "fraction inserted"
+ $$ LANGUAGE plpythonu;
+ 
+
+
+ Note that because all exceptions from
+ the plpy.spiexceptions module inherit
+ from SPIError, an except clause
+ handling it will catch any database access error. You can differentiate
+ inside the except block by looking at
+ the sqlstate string attribute.
+

   
  
diff --git a/src/pl/plpython/Makefile b/src/pl/plpython/Makefile
index 33dddc6..b3f0d0e 100644
*** a/src/pl/plpython/Makefile
--- b/src/pl/plpython/Makefile
*** PSQLDIR = $(bindir)
*** 86,94 
--- 86,102 
  
  include $(top_srcdir)/src/Makefile.shlib
  
+ # Force this dependency to be known (see src/pl/plpgsql/src/Makefile)
+ plpython.o: spiexceptions.h
+ 
+ # Generate spiexceptions.h from utils/errcodes.h
+ spiexceptions.h: $(top_srcdir)/src/backend/utils/errcodes.txt generate-spiexceptions.pl
+ 	$(PERL) $(srcdir)/generate-spiexceptions.pl $< > $@
  
  all: all-lib
  
+ distprep: spiexceptions.h
+ 
  install: all installdirs install-lib
  ifeq ($(python_majorversion),2)
  	cd '$(DESTDIR)$(pkglibdir)' && rm -f plpython$(DLSUFFIX) && $(LN_S) $(shlib) plpython$(DLSUFFIX)
*** endif
*** 134,143 
  submake:
  	$(MAKE) -C $(top_builddir)/src/test/regress pg_regress$(X)
  
! clean distclean maintainer-clean: clean-lib
  	rm -f $(OBJS)
  	rm -rf results
  	rm -f regression.diffs regression.out
  ifeq ($(PORTNAME), win32)
  	rm -f python${pytverstr}.def
  endif
--- 142,156 
  submake:
  	$(MAKE) -C $(top_builddir)/src/test/regress pg_regress$(X)
  
! clean distclean: clean-lib
  	rm -f $(OBJS)
  	rm -rf results
  	rm -f regression.diffs regression.out
+ 
+ # since we distribute spiexceptions.h, only remove it in maintainer-clean
+ maintainer-clean: clean distclean
+ 	rm -f spiexceptions.h
+ 
  ifeq ($(PORTNAME), win32)
  	rm -f python${pytverstr}.def
  endif
diff --git a/src/pl/plpython/expected/plpython_error.out b/src/pl/plpython/expected/plpython_error.out
index 7597ca7..afbc6db 100644
*** a/src/pl/plpython/expected/plpython_error.out
--- b/src/pl/plpython/expected/plpython_error.out
*** CREATE FUNCTION sql_syntax_error() RETUR
*** 32,38 
  'plpy.execute("syntax error")'
  LANGUAGE plpythonu;
  SELECT sql_syntax_error();
! ERROR:  plpy.SPIError: syntax error 

Re: [HACKERS] pl/python custom exceptions for SPI

2011-02-11 Thread Jan Urbański
On 10/02/11 22:26, Steve Singer wrote:
> On 11-02-10 03:13 PM, Jan Urbański wrote:
>> On 10/02/11 20:24, Peter Eisentraut wrote:
> 
> Here is the rest of my review.

Thanks!

> Ideally char * members of ExceptionMap would be const, but since many
> versions of python take a non-const value to PyErr_NewException that
> won't work :(

Yeah, I got "discards qualifier" warnings when I tried to declare it as
const :(

> After you search the for an exception in the hash you have:
> 
> /* We really should find it, but just in case have a fallback */
> Assert(entry != NULL);
> exc = entry ? entry->exc : PLy_exc_spi_error;
> 
> I'm not sure the assert is needed here.  Just falling back to the
> exception type seems reasonable and more desirable than an assert if
> showhow a new exception gets missed from the list. I don't feel that
> strongly on this.

Maybe the comment doesn't explain this enough. My intention was that in
regular builds you have a fallback and if you're missing an entry in the
exceptions hash, you just get SPIError. But in assert-enabled builds you
get an error, so you can detect it and fix the exceptions hash.

> line 3575: PLy_elog(ERROR, "Failed to add the spiexceptions module");
> "Failed" should be "failed"

Gah, I'll never learn. Will fix.

> Other than that the patch looks fine to me.

Thanks, I'll have the docs ready by today (and I should've have them by
yesterday :/).

Jan

-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] pl/python custom exceptions for SPI

2011-02-10 Thread Steve Singer

On 11-02-10 03:13 PM, Jan Urbański wrote:

On 10/02/11 20:24, Peter Eisentraut wrote:


Here is the rest of my review.


Submission Review
---
Patch applies cleanly.
Documentation is still outstanding but Jan has promised it soon.

Usability Review
---
We don't have this for plpython,  that we have a similar idea with 
plpgsql.  I think this feature is useful and worth having.


The CamelCase naming of the exceptions is consistent with how the 
built-in python exceptions are named (camel case).




Feature Test
---
I did basic testing of the feature (catching a few exception types 
thrown from both direct SQL and prepared statements) and the feature 
worked as expected.


Performance Impact

The impact of mapping error codes to exception types shouldn't come into 
play unless an SPI error is returned and with the hash it should still 
be minimal.




Code Review
-

Ideally char * members of ExceptionMap would be const, but since many 
versions of python take a non-const value to PyErr_NewException that 
won't work :(


After you search the for an exception in the hash you have:

/* We really should find it, but just in case have a fallback */
Assert(entry != NULL);
exc = entry ? entry->exc : PLy_exc_spi_error;

I'm not sure the assert is needed here.  Just falling back to the 
exception type seems reasonable and more desirable than an assert if 
showhow a new exception gets missed from the list. I don't feel that 
strongly on this.



line 3575:  PLy_elog(ERROR, "Failed to add the spiexceptions module");
"Failed" should be "failed"

Other than that the patch looks fine to me.





Updated again.


Why do the error messages print spiexceptions.SyntaxError instead of
plpy.spiexceptions.SyntaxError?  Is this intentional or just the way it
comes out of Python?


That's how traceback.format_exception() works IIRC, which is what the
Python interpreter uses and what PL/Python mimicks in PLy_traceback.


Please add some documentation.  Not a list of all exceptions, but at
least a paragraph that various kinds of specific exceptions may be
generated, what package and module they are in, and how they relate.


Sure, Steve already asked for docs in another thread, and I'm writing them.

Jan




--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] pl/python custom exceptions for SPI

2011-02-10 Thread Jan Urbański
On 10/02/11 20:24, Peter Eisentraut wrote:
> On sön, 2011-02-06 at 20:44 +0100, Jan Urbański wrote:
>> On 27/01/11 23:24, Jan Urbański wrote:
>>> On 11/01/11 12:20, Jan Urbański wrote:
 On 11/01/11 01:27, Tom Lane wrote:
> Hannu Krosing  writes:
>> On 10.1.2011 17:20, Jan Urbański wrote:
>>> I changed that patch to use Perl instead of sed to generate the
>>> exceptions, which should be a more portable.
>>>
>>> Updated as an incremental patch on to of the recently sent version of
>>> explicit-subxacts.
>>
>> Updated again.
> 
> Why do the error messages print spiexceptions.SyntaxError instead of
> plpy.spiexceptions.SyntaxError?  Is this intentional or just the way it
> comes out of Python?

That's how traceback.format_exception() works IIRC, which is what the
Python interpreter uses and what PL/Python mimicks in PLy_traceback.

> Please add some documentation.  Not a list of all exceptions, but at
> least a paragraph that various kinds of specific exceptions may be
> generated, what package and module they are in, and how they relate.

Sure, Steve already asked for docs in another thread, and I'm writing them.

Jan

-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] pl/python custom exceptions for SPI

2011-02-10 Thread Peter Eisentraut
On sön, 2011-02-06 at 20:44 +0100, Jan Urbański wrote:
> On 27/01/11 23:24, Jan Urbański wrote:
> > On 11/01/11 12:20, Jan Urbański wrote:
> >> On 11/01/11 01:27, Tom Lane wrote:
> >>> Hannu Krosing  writes:
>  On 10.1.2011 17:20, Jan Urbański wrote:
> > I changed that patch to use Perl instead of sed to generate the
> > exceptions, which should be a more portable.
> > 
> > Updated as an incremental patch on to of the recently sent version of
> > explicit-subxacts.
> 
> Updated again.

Why do the error messages print spiexceptions.SyntaxError instead of
plpy.spiexceptions.SyntaxError?  Is this intentional or just the way it
comes out of Python?

Please add some documentation.  Not a list of all exceptions, but at
least a paragraph that various kinds of specific exceptions may be
generated, what package and module they are in, and how they relate.


-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] pl/python custom exceptions for SPI

2011-02-06 Thread Jan Urbański
On 27/01/11 23:24, Jan Urbański wrote:
> On 11/01/11 12:20, Jan Urbański wrote:
>> On 11/01/11 01:27, Tom Lane wrote:
>>> Hannu Krosing  writes:
 On 10.1.2011 17:20, Jan Urbański wrote:
> I changed that patch to use Perl instead of sed to generate the
> exceptions, which should be a more portable.
> 
> Updated as an incremental patch on to of the recently sent version of
> explicit-subxacts.

Updated again.
diff --git a/src/pl/plpython/Makefile b/src/pl/plpython/Makefile
index 33dddc6..b3f0d0e 100644
*** a/src/pl/plpython/Makefile
--- b/src/pl/plpython/Makefile
*** PSQLDIR = $(bindir)
*** 86,94 
--- 86,102 
  
  include $(top_srcdir)/src/Makefile.shlib
  
+ # Force this dependency to be known (see src/pl/plpgsql/src/Makefile)
+ plpython.o: spiexceptions.h
+ 
+ # Generate spiexceptions.h from utils/errcodes.h
+ spiexceptions.h: $(top_srcdir)/src/backend/utils/errcodes.txt generate-spiexceptions.pl
+ 	$(PERL) $(srcdir)/generate-spiexceptions.pl $< > $@
  
  all: all-lib
  
+ distprep: spiexceptions.h
+ 
  install: all installdirs install-lib
  ifeq ($(python_majorversion),2)
  	cd '$(DESTDIR)$(pkglibdir)' && rm -f plpython$(DLSUFFIX) && $(LN_S) $(shlib) plpython$(DLSUFFIX)
*** endif
*** 134,143 
  submake:
  	$(MAKE) -C $(top_builddir)/src/test/regress pg_regress$(X)
  
! clean distclean maintainer-clean: clean-lib
  	rm -f $(OBJS)
  	rm -rf results
  	rm -f regression.diffs regression.out
  ifeq ($(PORTNAME), win32)
  	rm -f python${pytverstr}.def
  endif
--- 142,156 
  submake:
  	$(MAKE) -C $(top_builddir)/src/test/regress pg_regress$(X)
  
! clean distclean: clean-lib
  	rm -f $(OBJS)
  	rm -rf results
  	rm -f regression.diffs regression.out
+ 
+ # since we distribute spiexceptions.h, only remove it in maintainer-clean
+ maintainer-clean: clean distclean
+ 	rm -f spiexceptions.h
+ 
  ifeq ($(PORTNAME), win32)
  	rm -f python${pytverstr}.def
  endif
diff --git a/src/pl/plpython/expected/plpython_error.out b/src/pl/plpython/expected/plpython_error.out
index 7597ca7..afbc6db 100644
*** a/src/pl/plpython/expected/plpython_error.out
--- b/src/pl/plpython/expected/plpython_error.out
*** CREATE FUNCTION sql_syntax_error() RETUR
*** 32,38 
  'plpy.execute("syntax error")'
  LANGUAGE plpythonu;
  SELECT sql_syntax_error();
! ERROR:  plpy.SPIError: syntax error at or near "syntax"
  LINE 1: syntax error
  ^
  QUERY:  syntax error
--- 32,38 
  'plpy.execute("syntax error")'
  LANGUAGE plpythonu;
  SELECT sql_syntax_error();
! ERROR:  spiexceptions.SyntaxError: syntax error at or near "syntax"
  LINE 1: syntax error
  ^
  QUERY:  syntax error
*** CREATE FUNCTION exception_index_invalid_
*** 54,60 
  return rv[0]'
  	LANGUAGE plpythonu;
  SELECT exception_index_invalid_nested();
! ERROR:  plpy.SPIError: function test5(unknown) does not exist
  LINE 1: SELECT test5('foo')
 ^
  HINT:  No function matches the given name and argument types. You might need to add explicit type casts.
--- 54,60 
  return rv[0]'
  	LANGUAGE plpythonu;
  SELECT exception_index_invalid_nested();
! ERROR:  spiexceptions.UndefinedFunction: function test5(unknown) does not exist
  LINE 1: SELECT test5('foo')
 ^
  HINT:  No function matches the given name and argument types. You might need to add explicit type casts.
*** return None
*** 74,80 
  '
  	LANGUAGE plpythonu;
  SELECT invalid_type_uncaught('rick');
! ERROR:  plpy.SPIError: type "test" does not exist
  CONTEXT:  PL/Python function "invalid_type_uncaught"
  /* for what it's worth catch the exception generated by
   * the typo, and return None
--- 74,80 
  '
  	LANGUAGE plpythonu;
  SELECT invalid_type_uncaught('rick');
! ERROR:  spiexceptions.UndefinedObject: type "test" does not exist
  CONTEXT:  PL/Python function "invalid_type_uncaught"
  /* for what it's worth catch the exception generated by
   * the typo, and return None
*** SELECT valid_type('rick');
*** 140,145 
--- 140,183 
   
  (1 row)
  
+ /* Check catching specific types of exceptions
+  */
+ CREATE TABLE specific (
+ i integer PRIMARY KEY
+ );
+ NOTICE:  CREATE TABLE / PRIMARY KEY will create implicit index "specific_pkey" for table "specific"
+ CREATE FUNCTION specific_exception(i integer) RETURNS void AS
+ $$
+ from plpy import spiexceptions
+ try:
+ plpy.execute("insert into specific values (%s)" % (i or "NULL"));
+ except spiexceptions.NotNullViolation, e:
+ plpy.notice("Violated the NOT NULL constraint, sqlstate %s" % e.sqlstate)
+ except spiexceptions.UniqueViolation, e:
+ plpy.notice("Violated the UNIQUE constraint, sqlstate %s" % e.sqlstate)
+ $$ LANGUAGE plpythonu;
+ SELECT specific_exception(2);
+  specific_exception 
+ 
+  
+ (1 row)
+ 
+ SELECT specific_exception(NULL);
+ NOTICE:  Violated the NOT NULL constraint, sqlstate 23502
+ CONTEXT:  PL/Python function "specific_exception"
+  

Re: [HACKERS] pl/python custom exceptions for SPI

2011-01-27 Thread Jan Urbański
On 11/01/11 12:20, Jan Urbański wrote:
> On 11/01/11 01:27, Tom Lane wrote:
>> Hannu Krosing  writes:
>>> On 10.1.2011 17:20, Jan Urbański wrote:
 I changed that patch to use Perl instead of sed to generate the
 exceptions, which should be a more portable.

Updated as an incremental patch on to of the recently sent version of
explicit-subxacts.
diff --git a/src/pl/plpython/Makefile b/src/pl/plpython/Makefile
index 33dddc6..1fe386b 100644
*** a/src/pl/plpython/Makefile
--- b/src/pl/plpython/Makefile
*** rpathdir = $(python_libdir)
*** 38,44 
  
  NAME = plpython$(python_majorversion)
  OBJS = plpython.o
! 
  
  # Python on win32 ships with import libraries only for Microsoft Visual C++,
  # which are not compatible with mingw gcc. Therefore we need to build a
--- 38,44 
  
  NAME = plpython$(python_majorversion)
  OBJS = plpython.o
! SPIEXCEPTIONS = spiexceptions.h
  
  # Python on win32 ships with import libraries only for Microsoft Visual C++,
  # which are not compatible with mingw gcc. Therefore we need to build a
*** PSQLDIR = $(bindir)
*** 86,93 
  
  include $(top_srcdir)/src/Makefile.shlib
  
  
! all: all-lib
  
  install: all installdirs install-lib
  ifeq ($(python_majorversion),2)
--- 86,102 
  
  include $(top_srcdir)/src/Makefile.shlib
  
+ .PHONY: gen-spiexceptions
  
! # Generate spiexceptions.h from utils/errcodes.h
! spiexceptions.h: $(top_srcdir)/src/include/utils/errcodes.h
! 	$(PERL) $(srcdir)/generate-spiexceptions.pl $^ > $(SPIEXCEPTIONS)
! 
! gen-spiexceptions: $(SPIEXCEPTIONS)
! 
! all: gen-spiexceptions all-lib
! 
! distprep: gen-spiexceptions
  
  install: all installdirs install-lib
  ifeq ($(python_majorversion),2)
*** endif
*** 134,143 
  submake:
  	$(MAKE) -C $(top_builddir)/src/test/regress pg_regress$(X)
  
! clean distclean maintainer-clean: clean-lib
  	rm -f $(OBJS)
  	rm -rf results
  	rm -f regression.diffs regression.out
  ifeq ($(PORTNAME), win32)
  	rm -f python${pytverstr}.def
  endif
--- 143,157 
  submake:
  	$(MAKE) -C $(top_builddir)/src/test/regress pg_regress$(X)
  
! clean distclean: clean-lib
  	rm -f $(OBJS)
  	rm -rf results
  	rm -f regression.diffs regression.out
+ 
+ # since we distribute spiexceptions.h, only remove it in maintainer-clean
+ maintainer-clean: clean distclean
+ 	rm -f $(SPIEXCEPTIONS)
+ 
  ifeq ($(PORTNAME), win32)
  	rm -f python${pytverstr}.def
  endif
diff --git a/src/pl/plpython/expected/plpython_error.out b/src/pl/plpython/expected/plpython_error.out
index 4eeda6f..45ce136 100644
*** a/src/pl/plpython/expected/plpython_error.out
--- b/src/pl/plpython/expected/plpython_error.out
*** CREATE FUNCTION sql_syntax_error() RETUR
*** 8,14 
  'plpy.execute("syntax error")'
  LANGUAGE plpythonu;
  SELECT sql_syntax_error();
! ERROR:  plpy.SPIError: syntax error at or near "syntax"
  LINE 1: syntax error
  ^
  QUERY:  syntax error
--- 8,14 
  'plpy.execute("syntax error")'
  LANGUAGE plpythonu;
  SELECT sql_syntax_error();
! ERROR:  spiexceptions.SyntaxError: syntax error at or near "syntax"
  LINE 1: syntax error
  ^
  QUERY:  syntax error
*** CREATE FUNCTION exception_index_invalid_
*** 30,36 
  return rv[0]'
  	LANGUAGE plpythonu;
  SELECT exception_index_invalid_nested();
! ERROR:  plpy.SPIError: function test5(unknown) does not exist
  LINE 1: SELECT test5('foo')
 ^
  HINT:  No function matches the given name and argument types. You might need to add explicit type casts.
--- 30,36 
  return rv[0]'
  	LANGUAGE plpythonu;
  SELECT exception_index_invalid_nested();
! ERROR:  spiexceptions.UndefinedFunction: function test5(unknown) does not exist
  LINE 1: SELECT test5('foo')
 ^
  HINT:  No function matches the given name and argument types. You might need to add explicit type casts.
*** return None
*** 50,56 
  '
  	LANGUAGE plpythonu;
  SELECT invalid_type_uncaught('rick');
! ERROR:  plpy.SPIError: type "test" does not exist
  CONTEXT:  PL/Python function "invalid_type_uncaught"
  /* for what it's worth catch the exception generated by
   * the typo, and return None
--- 50,56 
  '
  	LANGUAGE plpythonu;
  SELECT invalid_type_uncaught('rick');
! ERROR:  spiexceptions.UndefinedObject: type "test" does not exist
  CONTEXT:  PL/Python function "invalid_type_uncaught"
  /* for what it's worth catch the exception generated by
   * the typo, and return None
*** SELECT valid_type('rick');
*** 116,121 
--- 116,159 
   
  (1 row)
  
+ /* Check catching specific types of exceptions
+  */
+ CREATE TABLE specific (
+ i integer PRIMARY KEY
+ );
+ NOTICE:  CREATE TABLE / PRIMARY KEY will create implicit index "specific_pkey" for table "specific"
+ CREATE FUNCTION specific_exception(i integer) RETURNS void AS
+ $$
+ from plpy import spiexceptions
+ try:
+ plpy.execute("insert into specific values (%s)" % (i or "NULL"));
+ except spiexcepti

Re: [HACKERS] pl/python custom exceptions for SPI

2011-01-11 Thread Jan Urbański
On 11/01/11 01:27, Tom Lane wrote:
> Hannu Krosing  writes:
>> On 10.1.2011 17:20, Jan Urbański wrote:
>>> I changed that patch to use Perl instead of sed to generate the
>>> exceptions, which should be a more portable.
> 
>> Why not python ?
> 
> Because we're not adding even more different tool requirements to the
> build process.  Perl is what we've chosen to depend on, and there is no
> reason to use a different tool here.

Yep, exactly.

While looking at it again I fixed a problem with spiexceptions.h not
being distributed (and IIRC we don't require Perl for tarball builds)
and added generating it to the MSVC build system.

Updated patch attached.

Cheers,
Jan
diff --git a/src/pl/plpython/Makefile b/src/pl/plpython/Makefile
index 33dddc6..1fe386b 100644
*** a/src/pl/plpython/Makefile
--- b/src/pl/plpython/Makefile
*** rpathdir = $(python_libdir)
*** 38,44 
  
  NAME = plpython$(python_majorversion)
  OBJS = plpython.o
! 
  
  # Python on win32 ships with import libraries only for Microsoft Visual C++,
  # which are not compatible with mingw gcc. Therefore we need to build a
--- 38,44 
  
  NAME = plpython$(python_majorversion)
  OBJS = plpython.o
! SPIEXCEPTIONS = spiexceptions.h
  
  # Python on win32 ships with import libraries only for Microsoft Visual C++,
  # which are not compatible with mingw gcc. Therefore we need to build a
*** PSQLDIR = $(bindir)
*** 86,93 
  
  include $(top_srcdir)/src/Makefile.shlib
  
  
! all: all-lib
  
  install: all installdirs install-lib
  ifeq ($(python_majorversion),2)
--- 86,102 
  
  include $(top_srcdir)/src/Makefile.shlib
  
+ .PHONY: gen-spiexceptions
  
! # Generate spiexceptions.h from utils/errcodes.h
! spiexceptions.h: $(top_srcdir)/src/include/utils/errcodes.h
! 	$(PERL) $(srcdir)/generate-spiexceptions.pl $^ > $(SPIEXCEPTIONS)
! 
! gen-spiexceptions: $(SPIEXCEPTIONS)
! 
! all: gen-spiexceptions all-lib
! 
! distprep: gen-spiexceptions
  
  install: all installdirs install-lib
  ifeq ($(python_majorversion),2)
*** endif
*** 134,143 
  submake:
  	$(MAKE) -C $(top_builddir)/src/test/regress pg_regress$(X)
  
! clean distclean maintainer-clean: clean-lib
  	rm -f $(OBJS)
  	rm -rf results
  	rm -f regression.diffs regression.out
  ifeq ($(PORTNAME), win32)
  	rm -f python${pytverstr}.def
  endif
--- 143,157 
  submake:
  	$(MAKE) -C $(top_builddir)/src/test/regress pg_regress$(X)
  
! clean distclean: clean-lib
  	rm -f $(OBJS)
  	rm -rf results
  	rm -f regression.diffs regression.out
+ 
+ # since we distribute spiexceptions.h, only remove it in maintainer-clean
+ maintainer-clean: clean distclean
+ 	rm -f $(SPIEXCEPTIONS)
+ 
  ifeq ($(PORTNAME), win32)
  	rm -f python${pytverstr}.def
  endif
diff --git a/src/pl/plpython/expected/plpython_error.out b/src/pl/plpython/expected/plpython_error.out
index 7fc8337..718ebce 100644
*** a/src/pl/plpython/expected/plpython_error.out
--- b/src/pl/plpython/expected/plpython_error.out
*** CREATE FUNCTION sql_syntax_error() RETUR
*** 8,14 
  'plpy.execute("syntax error")'
  LANGUAGE plpythonu;
  SELECT sql_syntax_error();
! ERROR:  plpy.SPIError: syntax error at or near "syntax"
  CONTEXT:  PL/Python function "sql_syntax_error"
  /* check the handling of uncaught python exceptions
   */
--- 8,14 
  'plpy.execute("syntax error")'
  LANGUAGE plpythonu;
  SELECT sql_syntax_error();
! ERROR:  spiexceptions.SyntaxError: syntax error at or near "syntax"
  CONTEXT:  PL/Python function "sql_syntax_error"
  /* check the handling of uncaught python exceptions
   */
*** CREATE FUNCTION exception_index_invalid_
*** 27,33 
  return rv[0]'
  	LANGUAGE plpythonu;
  SELECT exception_index_invalid_nested();
! ERROR:  plpy.SPIError: function test5(unknown) does not exist
  CONTEXT:  PL/Python function "exception_index_invalid_nested"
  /* a typo
   */
--- 27,33 
  return rv[0]'
  	LANGUAGE plpythonu;
  SELECT exception_index_invalid_nested();
! ERROR:  spiexceptions.UndefinedFunction: function test5(unknown) does not exist
  CONTEXT:  PL/Python function "exception_index_invalid_nested"
  /* a typo
   */
*** return None
*** 43,49 
  '
  	LANGUAGE plpythonu;
  SELECT invalid_type_uncaught('rick');
! ERROR:  plpy.SPIError: type "test" does not exist
  CONTEXT:  PL/Python function "invalid_type_uncaught"
  /* for what it's worth catch the exception generated by
   * the typo, and return None
--- 43,49 
  '
  	LANGUAGE plpythonu;
  SELECT invalid_type_uncaught('rick');
! ERROR:  spiexceptions.UndefinedObject: type "test" does not exist
  CONTEXT:  PL/Python function "invalid_type_uncaught"
  /* for what it's worth catch the exception generated by
   * the typo, and return None
*** SELECT valid_type('rick');
*** 109,111 
--- 109,149 
   
  (1 row)
  
+ /* Check catching specific types of exceptions
+  */
+ CREATE TABLE specific (
+ i integer PRIMARY KEY
+ );
+ NOTICE:  CREATE TABLE / P

Re: [HACKERS] pl/python custom exceptions for SPI

2011-01-10 Thread Tom Lane
Hannu Krosing  writes:
> On 10.1.2011 17:20, Jan Urbański wrote:
>> I changed that patch to use Perl instead of sed to generate the
>> exceptions, which should be a more portable.

> Why not python ?

Because we're not adding even more different tool requirements to the
build process.  Perl is what we've chosen to depend on, and there is no
reason to use a different tool here.

regards, tom lane

-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] pl/python custom exceptions for SPI

2011-01-10 Thread Hannu Krosing

On 10.1.2011 17:20, Jan Urbański wrote:

On 23/12/10 15:40, Jan Urbański wrote:

Here's a patch implementing custom Python exceptions for SPI errors
mentioned in
http://archives.postgresql.org/pgsql-hackers/2010-12/msg01991.php. It's
an incremental patch on top of the explicit-subxacts patch sent eariler.

I changed that patch to use Perl instead of sed to generate the
exceptions, which should be a more portable.

Why not python ?

  It's still not nice, and I
think the way forward is to have a common format for SQLSTATE
conditions, as proposed in
http://archives.postgresql.org/message-id/4d19c93c.5000...@wulczer.org.

I failed to follow on with that patch because I couldn't figure out how
to persuade the buildsystem to generate errcodes.h early enough for the
rest of the system to compile, not to mention doing it for the MSVC
build system.

Cheers,
Jan






--

Hannu Krosing
Senior Consultant,
Infinite Scalability&  Performance
http://www.2ndQuadrant.com/books/



Re: [HACKERS] pl/python custom exceptions for SPI

2011-01-10 Thread Jan Urbański
On 23/12/10 15:40, Jan Urbański wrote:
> Here's a patch implementing custom Python exceptions for SPI errors
> mentioned in
> http://archives.postgresql.org/pgsql-hackers/2010-12/msg01991.php. It's
> an incremental patch on top of the explicit-subxacts patch sent eariler.

I changed that patch to use Perl instead of sed to generate the
exceptions, which should be a more portable. It's still not nice, and I
think the way forward is to have a common format for SQLSTATE
conditions, as proposed in
http://archives.postgresql.org/message-id/4d19c93c.5000...@wulczer.org.

I failed to follow on with that patch because I couldn't figure out how
to persuade the buildsystem to generate errcodes.h early enough for the
rest of the system to compile, not to mention doing it for the MSVC
build system.

Cheers,
Jan
diff --git a/src/pl/plpython/Makefile b/src/pl/plpython/Makefile
index 33dddc6..0d7ddee 100644
*** a/src/pl/plpython/Makefile
--- b/src/pl/plpython/Makefile
*** rpathdir = $(python_libdir)
*** 38,44 
  
  NAME = plpython$(python_majorversion)
  OBJS = plpython.o
! 
  
  # Python on win32 ships with import libraries only for Microsoft Visual C++,
  # which are not compatible with mingw gcc. Therefore we need to build a
--- 38,44 
  
  NAME = plpython$(python_majorversion)
  OBJS = plpython.o
! SPIEXCEPTIONS = spiexceptions.h
  
  # Python on win32 ships with import libraries only for Microsoft Visual C++,
  # which are not compatible with mingw gcc. Therefore we need to build a
*** PSQLDIR = $(bindir)
*** 86,93 
  
  include $(top_srcdir)/src/Makefile.shlib
  
  
! all: all-lib
  
  install: all installdirs install-lib
  ifeq ($(python_majorversion),2)
--- 86,102 
  
  include $(top_srcdir)/src/Makefile.shlib
  
+ .PHONY: gen-spiexceptions
  
! # Generate spiexceptions.h from utils/errcodes.h
! spiexceptions.h: $(top_srcdir)/src/include/utils/errcodes.h
! 	$(PERL) $(srcdir)/generate-spiexceptions.pl $^ > $(SPIEXCEPTIONS)
! 
! gen-spiexceptions: $(SPIEXCEPTIONS)
! 
! all: gen-spiexceptions all-lib
! 
! distprep: gen-spiexceptions
  
  install: all installdirs install-lib
  ifeq ($(python_majorversion),2)
*** clean distclean maintainer-clean: clean-
*** 138,143 
--- 147,153 
  	rm -f $(OBJS)
  	rm -rf results
  	rm -f regression.diffs regression.out
+ 	rm -f $(SPIEXCEPTIONS)
  ifeq ($(PORTNAME), win32)
  	rm -f python${pytverstr}.def
  endif
diff --git a/src/pl/plpython/expected/plpython_error.out b/src/pl/plpython/expected/plpython_error.out
index 7fc8337..718ebce 100644
*** a/src/pl/plpython/expected/plpython_error.out
--- b/src/pl/plpython/expected/plpython_error.out
*** CREATE FUNCTION sql_syntax_error() RETUR
*** 8,14 
  'plpy.execute("syntax error")'
  LANGUAGE plpythonu;
  SELECT sql_syntax_error();
! ERROR:  plpy.SPIError: syntax error at or near "syntax"
  CONTEXT:  PL/Python function "sql_syntax_error"
  /* check the handling of uncaught python exceptions
   */
--- 8,14 
  'plpy.execute("syntax error")'
  LANGUAGE plpythonu;
  SELECT sql_syntax_error();
! ERROR:  spiexceptions.SyntaxError: syntax error at or near "syntax"
  CONTEXT:  PL/Python function "sql_syntax_error"
  /* check the handling of uncaught python exceptions
   */
*** CREATE FUNCTION exception_index_invalid_
*** 27,33 
  return rv[0]'
  	LANGUAGE plpythonu;
  SELECT exception_index_invalid_nested();
! ERROR:  plpy.SPIError: function test5(unknown) does not exist
  CONTEXT:  PL/Python function "exception_index_invalid_nested"
  /* a typo
   */
--- 27,33 
  return rv[0]'
  	LANGUAGE plpythonu;
  SELECT exception_index_invalid_nested();
! ERROR:  spiexceptions.UndefinedFunction: function test5(unknown) does not exist
  CONTEXT:  PL/Python function "exception_index_invalid_nested"
  /* a typo
   */
*** return None
*** 43,49 
  '
  	LANGUAGE plpythonu;
  SELECT invalid_type_uncaught('rick');
! ERROR:  plpy.SPIError: type "test" does not exist
  CONTEXT:  PL/Python function "invalid_type_uncaught"
  /* for what it's worth catch the exception generated by
   * the typo, and return None
--- 43,49 
  '
  	LANGUAGE plpythonu;
  SELECT invalid_type_uncaught('rick');
! ERROR:  spiexceptions.UndefinedObject: type "test" does not exist
  CONTEXT:  PL/Python function "invalid_type_uncaught"
  /* for what it's worth catch the exception generated by
   * the typo, and return None
*** SELECT valid_type('rick');
*** 109,111 
--- 109,149 
   
  (1 row)
  
+ /* Check catching specific types of exceptions
+  */
+ CREATE TABLE specific (
+ i integer PRIMARY KEY
+ );
+ NOTICE:  CREATE TABLE / PRIMARY KEY will create implicit index "specific_pkey" for table "specific"
+ CREATE FUNCTION specific_exception(i integer) RETURNS void AS
+ $$
+ from plpy import spiexceptions
+ try:
+ plpy.execute("insert into specific values (%s)" % (i or "NULL"));
+ except spiexceptions.NotNullViolation, e:
+ plpy.notice

[HACKERS] pl/python custom exceptions for SPI

2010-12-23 Thread Jan Urbański
Here's a patch implementing custom Python exceptions for SPI errors
mentioned in
http://archives.postgresql.org/pgsql-hackers/2010-12/msg01991.php. It's
an incremental patch on top of the explicit-subxacts patch sent eariler.

Git branch for this patch:
https://github.com/wulczer/postgres/tree/custom-spi-exceptions.

What the patch does is provide a Python exception per each error defined
in utils/errcodes.h, and then raise the corresponding exception when a
SPI call fails. The parsing of errcodes.h in the Makefile is a little
grotty and would probably have to be ported to the Windows build system,
which I have no idea about.

With this patch you can do:

from plpy import spiexceptions

try:
plpy.execute("insert into t values (4)")
catch spiexceptions.UniqueViolation:
plpy.notice("unique constraint violation")
catch spiexceptions.NotNullViolation:
plpy.notice("not null constraint violation")

All exceptions inherint from plpy.SPIError, so code thta just catches a
blanket SPIErorr will continue to work.

The patch lacks user-facing docs, if it gets accepted I'll write some.
Not sure if we should provide a table similar to
http://www.postgresql.org/docs/current/static/errcodes-appendix.html, or
just refer to that table and state that the rule is changing underscores
to camel case...

Also, I just realised that this patch does not really depend on the
explicit-subxacts change, but rather only on the spi-in-subxacts, so if
need be I can generate it as an incremental changeset ofer the latter
and not the former.

Cheers,
Jan
diff --git a/src/pl/plpython/Makefile b/src/pl/plpython/Makefile
index 33dddc6..dd5b445 100644
*** a/src/pl/plpython/Makefile
--- b/src/pl/plpython/Makefile
*** rpathdir = $(python_libdir)
*** 38,44 
  
  NAME = plpython$(python_majorversion)
  OBJS = plpython.o
! 
  
  # Python on win32 ships with import libraries only for Microsoft Visual C++,
  # which are not compatible with mingw gcc. Therefore we need to build a
--- 38,44 
  
  NAME = plpython$(python_majorversion)
  OBJS = plpython.o
! SPIEXCEPTIONS = spiexceptions.h
  
  # Python on win32 ships with import libraries only for Microsoft Visual C++,
  # which are not compatible with mingw gcc. Therefore we need to build a
*** PSQLDIR = $(bindir)
*** 86,93 
  
  include $(top_srcdir)/src/Makefile.shlib
  
  
! all: all-lib
  
  install: all installdirs install-lib
  ifeq ($(python_majorversion),2)
--- 86,113 
  
  include $(top_srcdir)/src/Makefile.shlib
  
+ # A quite horrendous sed, but does the job. The steps are, in order:
+ # 1. Remove everything up to the line with Class 03. We only generate
+ #exceptions for errors, not for warnings or notices
+ # 2. Remove lines that don't define an error code
+ # 3. Change ERRCODE_XXX into { "spiexceptions.ERRCODE_XY_Z, "XY_Z", ERRCODE_XY_Z },
+ # 4. Leave an uppercase letter after a dot or a quote, change the rest
+ #into lowercase thus giving us
+ #{ "spiexceptions.Errcode_xy_z, "Xy_z", ERRCODE_XY_Z },
+ # 5. change lowercase letters after an underscore into uppercase, giving us
+ #{ "spiexceptions.ErrcodeXyZ, "XyZ", ERRCODE_XY_Z },
+ gen-spiexceptions:
+ 	echo "/* autogenerated from utils/errcodes.h, do not edit */" > $(SPIEXCEPTIONS)
+ 	sed -e '1,/Class 03/ d' \
+ -e '/^#define ERRCODE_.*MAKE_SQLSTATE/! d' \
+ -e 's|#define ERRCODE_\([^\t ]*\).*|{ "spiexceptions.\1", "\1", ERRCODE_\1 },|' \
+ -e 's|\(["\.]\)\([A-Z]\)\([^"]*\)|\1\2\L\3|g' \
+ -e 's|_\([a-z]\)|\u\1|g' \
+ 	$(top_srcdir)/src/include/utils/errcodes.h >> $(SPIEXCEPTIONS)
  
! .PHONY: gen-spiexceptions
! 
! all: gen-spiexceptions all-lib
  
  install: all installdirs install-lib
  ifeq ($(python_majorversion),2)
*** clean distclean maintainer-clean: clean-
*** 138,143 
--- 158,164 
  	rm -f $(OBJS)
  	rm -rf results
  	rm -f regression.diffs regression.out
+ 	rm -f $(SPIEXCEPTIONS)
  ifeq ($(PORTNAME), win32)
  	rm -f python${pytverstr}.def
  endif
diff --git a/src/pl/plpython/expected/plpython_error.out b/src/pl/plpython/expected/plpython_error.out
index 7fc8337..718ebce 100644
*** a/src/pl/plpython/expected/plpython_error.out
--- b/src/pl/plpython/expected/plpython_error.out
*** CREATE FUNCTION sql_syntax_error() RETUR
*** 8,14 
  'plpy.execute("syntax error")'
  LANGUAGE plpythonu;
  SELECT sql_syntax_error();
! ERROR:  plpy.SPIError: syntax error at or near "syntax"
  CONTEXT:  PL/Python function "sql_syntax_error"
  /* check the handling of uncaught python exceptions
   */
--- 8,14 
  'plpy.execute("syntax error")'
  LANGUAGE plpythonu;
  SELECT sql_syntax_error();
! ERROR:  spiexceptions.SyntaxError: syntax error at or near "syntax"
  CONTEXT:  PL/Python function "sql_syntax_error"
  /* check the handling of uncaught python exceptions
   */
*** CREATE FUNCTION exception_index_invalid_
*** 27,33 
  return rv[0]'
  	LANGUAGE plpythonu;
  SEL