proposal: PL/Pythonu - function ereport

Started by Pavel Stehuleover 10 years ago107 messageshackers
Jump to latest
#1Pavel Stehule
pavel.stehule@gmail.com

Hi

We cannot to raise PostgreSQL exception with setting all possible fields. I
propose new function

plpy.ereport(level, [ message [, detail [, hint [, sqlstate, ... ]]]])

The implementation will be based on keyword parameters, so only required
parameters should be used.

Examples:

plpy.ereport(plpy.NOTICE, 'some message', 'some detai')
plpy.ereport(plpy.ERROR, 'some message', sqlstate = 'zx243');

Comments, notices, objections?

Regards

Pavel

#2Pavel Stehule
pavel.stehule@gmail.com
In reply to: Pavel Stehule (#1)
Re: proposal: PL/Pythonu - function ereport

2015-10-08 12:11 GMT+02:00 Pavel Stehule <pavel.stehule@gmail.com>:

Hi

We cannot to raise PostgreSQL exception with setting all possible fields.
I propose new function

plpy.ereport(level, [ message [, detail [, hint [, sqlstate, ... ]]]])

The implementation will be based on keyword parameters, so only required
parameters should be used.

Examples:

plpy.ereport(plpy.NOTICE, 'some message', 'some detai')
plpy.ereport(plpy.ERROR, 'some message', sqlstate = 'zx243');

patch attached

regards

Pavel

Show quoted text

Comments, notices, objections?

Regards

Pavel

Attachments:

plpython-ereport.patchtext/x-patch; charset=US-ASCII; name=plpython-ereport.patchDownload+260-14
#3Peter Eisentraut
peter_e@gmx.net
In reply to: Pavel Stehule (#1)
Re: proposal: PL/Pythonu - function ereport

On 10/8/15 6:11 AM, Pavel Stehule wrote:

We cannot to raise PostgreSQL exception with setting all possible
fields.

Such as? If there are fields missing, let's add them.

I propose new function

plpy.ereport(level, [ message [, detail [, hint [, sqlstate, ... ]]]])

That's not how Python works. If you want to cause an error, you should
raise an exception.

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

#4Pavel Stehule
pavel.stehule@gmail.com
In reply to: Peter Eisentraut (#3)
Re: proposal: PL/Pythonu - function ereport

2015-10-09 15:22 GMT+02:00 Peter Eisentraut <peter_e@gmx.net>:

On 10/8/15 6:11 AM, Pavel Stehule wrote:

We cannot to raise PostgreSQL exception with setting all possible
fields.

Such as? If there are fields missing, let's add them.

I propose new function

plpy.ereport(level, [ message [, detail [, hint [, sqlstate, ... ]]]])

That's not how Python works. If you want to cause an error, you should
raise an exception.

ok,

the patch had two parts - enhancing spi exception and ereport function.
I'll drop implementation of ereport.

Regards

Pavel

#5Pavel Stehule
pavel.stehule@gmail.com
In reply to: Peter Eisentraut (#3)
Re: proposal: PL/Pythonu - function ereport

Hi

2015-10-09 15:22 GMT+02:00 Peter Eisentraut <peter_e@gmx.net>:

On 10/8/15 6:11 AM, Pavel Stehule wrote:

We cannot to raise PostgreSQL exception with setting all possible
fields.

Such as? If there are fields missing, let's add them.

I propose new function

plpy.ereport(level, [ message [, detail [, hint [, sqlstate, ... ]]]])

That's not how Python works. If you want to cause an error, you should
raise an exception.

I wrote a example, how to do it

postgres=# do $$
x = plpy.SPIError('Nazdarek');
x.spidata = (100, "Some detail", "some hint", None, None);
raise x;
$$ language plpythonu;

ERROR: T1000: plpy.SPIError: Nazdarek
DETAIL: Some detail
HINT: some hint
CONTEXT: Traceback (most recent call last):
PL/Python anonymous code block, line 4, in <module>
raise x;
PL/Python anonymous code block
LOCATION: PLy_elog, plpy_elog.c:106
Time: 1.170 ms

Is it some better way?

I see a few disadvantages

1. sqlcode is entered via integer
2. it doesn't allow keyword parameters - so we can second constructor of
SPIError

some like

postgres=# do $$
def SPIError(message, detail = None, hint = None):
x = plpy.SPIError(message)
x.spidata = (0, detail, hint, None, None)
return x

raise SPIError('Nazdar Svete', hint = 'Hello world');
$$ language plpythonu;

The main problem is a name for this function.

Regards

Pavel

#6Craig Ringer
craig@2ndquadrant.com
In reply to: Pavel Stehule (#5)
Re: proposal: PL/Pythonu - function ereport

On 16 October 2015 at 02:47, Pavel Stehule <pavel.stehule@gmail.com> wrote:

postgres=# do $$
x = plpy.SPIError('Nazdarek');
x.spidata = (100, "Some detail", "some hint", None, None);
raise x;
$$ language plpythonu;

Shouldn't that look more like

raise plpy.SPIError(msg="Message", sqlstate="0P001", hint="Turn it on
and off again") ?

Keyword args are very much the norm for this sort of thing. I recall
them being pretty reasonable to deal with in the CPython API too, but
otherwise a trivial Python wrapper in the module can easily adapt the
interface.

--
Craig Ringer http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services

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

#7Pavel Stehule
pavel.stehule@gmail.com
In reply to: Craig Ringer (#6)
Re: proposal: PL/Pythonu - function ereport

2015-10-16 8:12 GMT+02:00 Craig Ringer <craig@2ndquadrant.com>:

On 16 October 2015 at 02:47, Pavel Stehule <pavel.stehule@gmail.com>
wrote:

postgres=# do $$
x = plpy.SPIError('Nazdarek');
x.spidata = (100, "Some detail", "some hint", None, None);
raise x;
$$ language plpythonu;

Shouldn't that look more like

raise plpy.SPIError(msg="Message", sqlstate="0P001", hint="Turn it on
and off again") ?

postgres=# do $$
raise plpy.SPIError(msg="Message", sqlstate="0P001", hint="Turn it on and
off again");
$$ language plpythonu;
ERROR: TypeError: SPIError does not take keyword arguments
CONTEXT: Traceback (most recent call last):
PL/Python anonymous code block, line 2, in <module>
raise plpy.SPIError(msg="Message", sqlstate="0P001", hint="Turn it on
and off again");
PL/Python anonymous code block
Time: 1.193 ms

Keyword args are very much the norm for this sort of thing. I recall
them being pretty reasonable to deal with in the CPython API too, but
otherwise a trivial Python wrapper in the module can easily adapt the
interface.

postgres=# do $$
class cSPIError(plpy.SPIError):
def __init__( self, message, detail = None, hint = None):
self.spidata = (0, detail, hint, None, None,)
self.args = ( message, )

x = cSPIError('Nazdarek', hint = 'some hint')
raise x
$$ language plpythonu;
ERROR: cSPIError: Nazdarek
HINT: some hint
CONTEXT: Traceback (most recent call last):
PL/Python anonymous code block, line 8, in <module>
raise x
PL/Python anonymous code block

This code is working, so it needs explicit constructor for class SPIError

Regards

Pavel

Show quoted text

--
Craig Ringer http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services

#8Pavel Stehule
pavel.stehule@gmail.com
In reply to: Craig Ringer (#6)
Re: proposal: PL/Pythonu - function ereport

2015-10-16 8:12 GMT+02:00 Craig Ringer <craig@2ndquadrant.com>:

On 16 October 2015 at 02:47, Pavel Stehule <pavel.stehule@gmail.com>
wrote:

postgres=# do $$
x = plpy.SPIError('Nazdarek');
x.spidata = (100, "Some detail", "some hint", None, None);
raise x;
$$ language plpythonu;

Shouldn't that look more like

raise plpy.SPIError(msg="Message", sqlstate="0P001", hint="Turn it on
and off again") ?

Keyword args are very much the norm for this sort of thing. I recall
them being pretty reasonable to deal with in the CPython API too, but
otherwise a trivial Python wrapper in the module can easily adapt the
interface.

I wrote a constructor for SPIError with keyword parameters support - see
attached patch

The code is working

postgres=# do $$
raise plpy.SPIError("pokus",hint = "some info");
$$ language plpythonu;
ERROR: plpy.SPIError: pokus
HINT: some info
CONTEXT: Traceback (most recent call last):
PL/Python anonymous code block, line 2, in <module>
raise plpy.SPIError("pokus",hint = "some info");
PL/Python anonymous code block

but the implementation is pretty ugly :( - I didn't write C extensions for
Python before, and the extending exception class with some methods isn't
well supported and well documented.

Any help is welcome

Regards

Pavel

Show quoted text

--
Craig Ringer http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services

Attachments:

plpythonu-spierror-keyword-params.patchtext/x-patch; charset=US-ASCII; name=plpythonu-spierror-keyword-params.patchDownload+266-68
#9Pavel Stehule
pavel.stehule@gmail.com
In reply to: Pavel Stehule (#8)
Re: proposal: PL/Pythonu - function ereport

but the implementation is pretty ugly :( - I didn't write C extensions for

Python before, and the extending exception class with some methods isn't
well supported and well documented.

here is new patch

cleaned, all unwanted artefacts removed. I am not sure if used way for
method registration is 100% valid, but I didn't find any related
documentation.

Regards

Pavel

Show quoted text

Any help is welcome

Regards

Pavel

--
Craig Ringer http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services

Attachments:

plpythonu-spierror-keyword-params-02.patchtext/x-patch; charset=US-ASCII; name=plpythonu-spierror-keyword-params-02.patchDownload+291-36
#10Catalin Iacob
iacobcatalin@gmail.com
In reply to: Pavel Stehule (#9)
Re: proposal: PL/Pythonu - function ereport

On Sat, Oct 17, 2015 at 8:18 PM, Pavel Stehule <pavel.stehule@gmail.com> wrote:

here is new patch

cleaned, all unwanted artefacts removed. I am not sure if used way for
method registration is 100% valid, but I didn't find any related
documentation.

Pavel, some notes about the patch, not a full review (yet?).

In PLy_add_exceptions PyDict_New is not checked for failure.

In PLy_spi_error__init__, kw will be NULL if SPIError is called with
no arguments. With the current code NULL will get passed to
PyDict_Size which will generate something like SystemError Bad
internal function call. This also means a test using just SPIError()
is needed.
It seems args should never be NULL by the way, if there are no
arguments it's an empty tuple so the other side of the check is ok.

The current code doesn't build on Python3 because the 3rd argument of
PyMethod_New, the troubled one you need set to NULL has been removed.
This has to do with the distinction between bound and unbound methods
which is gone in Python3.

There is http://bugs.python.org/issue1587 which discusses how to
replace the "third argument" functionality for PyMethod_New in
Python3. One of the messages there links to
http://bugs.python.org/issue1505 and
https://hg.python.org/cpython/rev/429cadbc5b10/ which has an example
very similar to what you're trying to do, rewritten to work in
Python3. But this is still confusing: note that the replaced code
*didn't really use PyMethod_New at all* as the removed line meth =
PyMethod_New(func, NULL, ComError); was commented out and the replaced
code used to simply assign the function to the class dictionary
without even creating a method.
Still, the above link shows a (more verbose but maybe better)
alternative: don't use PyErr_NewException and instead define an
SPIError type with each slot spelled out explicitly. This will remove
the "is it safe to set the third argument to NULL" question.

I tried to answer the "is it safe to use NULL for the third argument
of PyMethod_New in Python2?" question and don't have a definite answer
yet. If you look at the CPython code it's used to set im_class
(Objects/classobject.c) of PyMethodObject which is accessible from
Python.
But this code:
init = plpy.SPIError.__init__
plpy.notice("repr {} str {} im_class {}".format(repr(init), str(init),
init.im_class))
produces:
NOTICE: repr <unbound method SPIError.__init__> str <unbound method
SPIError.__init__> im_class <class 'plpy.SPIError'>
so the SPIError class name is set in im_class from somewhere. But this
is all moot if you use the explicit SPIError type definition.

Any help is welcome

I can work with you on this. I don't have a lot of experience with the
C API but not zero either.

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

#11Pavel Stehule
pavel.stehule@gmail.com
In reply to: Catalin Iacob (#10)
Re: proposal: PL/Pythonu - function ereport

Hi

2015-10-23 7:34 GMT+02:00 Catalin Iacob <iacobcatalin@gmail.com>:

On Sat, Oct 17, 2015 at 8:18 PM, Pavel Stehule <pavel.stehule@gmail.com>
wrote:

here is new patch

cleaned, all unwanted artefacts removed. I am not sure if used way for
method registration is 100% valid, but I didn't find any related
documentation.

Pavel, some notes about the patch, not a full review (yet?).

In PLy_add_exceptions PyDict_New is not checked for failure.

In PLy_spi_error__init__, kw will be NULL if SPIError is called with
no arguments. With the current code NULL will get passed to
PyDict_Size which will generate something like SystemError Bad
internal function call. This also means a test using just SPIError()
is needed.
It seems args should never be NULL by the way, if there are no
arguments it's an empty tuple so the other side of the check is ok.

The current code doesn't build on Python3 because the 3rd argument of
PyMethod_New, the troubled one you need set to NULL has been removed.
This has to do with the distinction between bound and unbound methods
which is gone in Python3.

this part of is well isolated, and we can do switch for Python2 and Python3
without significant problems.

There is http://bugs.python.org/issue1587 which discusses how to
replace the "third argument" functionality for PyMethod_New in
Python3. One of the messages there links to
http://bugs.python.org/issue1505 and
https://hg.python.org/cpython/rev/429cadbc5b10/ which has an example
very similar to what you're trying to do, rewritten to work in
Python3. But this is still confusing: note that the replaced code
*didn't really use PyMethod_New at all* as the removed line meth =
PyMethod_New(func, NULL, ComError); was commented out and the replaced
code used to simply assign the function to the class dictionary
without even creating a method.
Still, the above link shows a (more verbose but maybe better)
alternative: don't use PyErr_NewException and instead define an
SPIError type with each slot spelled out explicitly. This will remove
the "is it safe to set the third argument to NULL" question.

I tried to answer the "is it safe to use NULL for the third argument
of PyMethod_New in Python2?" question and don't have a definite answer
yet. If you look at the CPython code it's used to set im_class
(Objects/classobject.c) of PyMethodObject which is accessible from
Python.
But this code:
init = plpy.SPIError.__init__
plpy.notice("repr {} str {} im_class {}".format(repr(init), str(init),
init.im_class))
produces:
NOTICE: repr <unbound method SPIError.__init__> str <unbound method
SPIError.__init__> im_class <class 'plpy.SPIError'>
so the SPIError class name is set in im_class from somewhere. But this
is all moot if you use the explicit SPIError type definition.

Should be there some problems, if we lost dependency on basic exception
class? Some compatibility issues? Or is possible to create full type with
inheritance support?

Any help is welcome

I can work with you on this. I don't have a lot of experience with the
C API but not zero either.

It is very helpful for me - C API doesn't look difficult, but when I have
to do some really low level work I am lost :(

Regards

Pavel

#12Catalin Iacob
iacobcatalin@gmail.com
In reply to: Pavel Stehule (#11)
Re: proposal: PL/Pythonu - function ereport

On Tue, Oct 27, 2015 at 9:34 AM, Pavel Stehule <pavel.stehule@gmail.com> wrote:

Hi

2015-10-23 7:34 GMT+02:00 Catalin Iacob <iacobcatalin@gmail.com>:

The current code doesn't build on Python3 because the 3rd argument of
PyMethod_New, the troubled one you need set to NULL has been removed.
This has to do with the distinction between bound and unbound methods
which is gone in Python3.

this part of is well isolated, and we can do switch for Python2 and Python3
without significant problems.

I had a quick look at this and at least 2 things are needed for Python3:

* using PyInstanceMethod_New instead of PyMethod_New; as
http://bugs.python.org/issue1587 and
https://docs.python.org/3/c-api/method.html explain that's the new way
of binding a PyCFunction to a class, PyMethod_New(func, NULL) fails

* in the PLy_spi_error_methods definition, __init__ has to take
METH_VARARGS | METH_KEYWORDS not just METH_KEYWORDS; in Python2
METH_KEYWORDS implied METH_VARARGS so it's not needed (it also doesn't
hurt) but if I don't add it, in Python3 I get:
ERROR: SystemError: Bad call flags in PyCFunction_Call. METH_OLDARGS
is no longer supported!

Still, the above link shows a (more verbose but maybe better)
alternative: don't use PyErr_NewException and instead define an
SPIError type with each slot spelled out explicitly. This will remove
the "is it safe to set the third argument to NULL" question.

Should be there some problems, if we lost dependency on basic exception
class? Some compatibility issues? Or is possible to create full type with
inheritance support?

It's possible to give it a base type, see at
https://hg.python.org/cpython/rev/429cadbc5b10/ this line before
calling PyType_Ready:
PyComError_Type.tp_base = (PyTypeObject*)PyExc_Exception;

PyErr_NewException is a shortcut for defining simple Exception
deriving types, usually one defines a type with the full PyTypeObject
definition.

In the meantime, I had a deeper look at the 2.7.10 code and I trust
that PyMethod_New with the last argument set to NULL is ok. Setting
that to NULL will lead to the PyMethod representing __init__ im_class
being NULL. But that PyMethod object is not held onto by C code, it's
added to the SPIError class' dict. From there, it is always retrieved
from Python via an instance or via the class (so SPIError().__init__
or SPIError.__init__) which will lead to instancemethod_descr_get
being called because it's the tp_descr_get slot of PyMethod_Type and
that code knows the class you're retrieving the attribute from
(SPIError in this case), checks if the PyMethod already has a not NULL
im_class (which SPIError.__init__ doesn't) and, if not, calls
PyMethod_New again and passes the class (SPIError) as the 3rd
argument.

Given this, I think it's ok to keep using PyErr_NewException rather
than spelling out the type explicitly.

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

#13Pavel Stehule
pavel.stehule@gmail.com
In reply to: Catalin Iacob (#12)
Re: proposal: PL/Pythonu - function ereport

2015-10-28 7:25 GMT+01:00 Catalin Iacob <iacobcatalin@gmail.com>:

On Tue, Oct 27, 2015 at 9:34 AM, Pavel Stehule <pavel.stehule@gmail.com>
wrote:

Hi

2015-10-23 7:34 GMT+02:00 Catalin Iacob <iacobcatalin@gmail.com>:

The current code doesn't build on Python3 because the 3rd argument of
PyMethod_New, the troubled one you need set to NULL has been removed.
This has to do with the distinction between bound and unbound methods
which is gone in Python3.

this part of is well isolated, and we can do switch for Python2 and

Python3

without significant problems.

I had a quick look at this and at least 2 things are needed for Python3:

* using PyInstanceMethod_New instead of PyMethod_New; as
http://bugs.python.org/issue1587 and
https://docs.python.org/3/c-api/method.html explain that's the new way
of binding a PyCFunction to a class, PyMethod_New(func, NULL) fails

* in the PLy_spi_error_methods definition, __init__ has to take
METH_VARARGS | METH_KEYWORDS not just METH_KEYWORDS; in Python2
METH_KEYWORDS implied METH_VARARGS so it's not needed (it also doesn't
hurt) but if I don't add it, in Python3 I get:
ERROR: SystemError: Bad call flags in PyCFunction_Call. METH_OLDARGS
is no longer supported!

Still, the above link shows a (more verbose but maybe better)
alternative: don't use PyErr_NewException and instead define an
SPIError type with each slot spelled out explicitly. This will remove
the "is it safe to set the third argument to NULL" question.

Should be there some problems, if we lost dependency on basic exception
class? Some compatibility issues? Or is possible to create full type with
inheritance support?

It's possible to give it a base type, see at
https://hg.python.org/cpython/rev/429cadbc5b10/ this line before
calling PyType_Ready:
PyComError_Type.tp_base = (PyTypeObject*)PyExc_Exception;

PyErr_NewException is a shortcut for defining simple Exception
deriving types, usually one defines a type with the full PyTypeObject
definition.

In the meantime, I had a deeper look at the 2.7.10 code and I trust
that PyMethod_New with the last argument set to NULL is ok. Setting
that to NULL will lead to the PyMethod representing __init__ im_class
being NULL. But that PyMethod object is not held onto by C code, it's
added to the SPIError class' dict. From there, it is always retrieved
from Python via an instance or via the class (so SPIError().__init__
or SPIError.__init__) which will lead to instancemethod_descr_get
being called because it's the tp_descr_get slot of PyMethod_Type and
that code knows the class you're retrieving the attribute from
(SPIError in this case), checks if the PyMethod already has a not NULL
im_class (which SPIError.__init__ doesn't) and, if not, calls
PyMethod_New again and passes the class (SPIError) as the 3rd
argument.

Given this, I think it's ok to keep using PyErr_NewException rather
than spelling out the type explicitly.

Thank you very much for your analyse. I am sending new version of proposed
patch with Python3 support. Fixed missing check of dictionary
initialization.

Regards

Pavel

Attachments:

plpythonu-spierror-keyword-params-03.patchtext/x-patch; charset=US-ASCII; name=plpythonu-spierror-keyword-params-03.patchDownload+295-36
#14Catalin Iacob
iacobcatalin@gmail.com
In reply to: Pavel Stehule (#13)
Re: proposal: PL/Pythonu - function ereport

Hello,

Here's a detailed review:

1. in PLy_spi_error__init__ you need to check kw for NULL before doing
PyDict_Size(kw) otherwise for plpy.SPIError() you get Bad internal
call because PyDict_Size expects a real dictionary not NULL

2. a test with just plpy.SPIError() is still missing, this would have caught 1.

3. the tests have "possibility to set all accessable fields in custom
exception" above a test that doesn't set all fields, it's confusing
(and accessible is spelled wrong)

4. in the docs, "The constructor of SPIError exception (class)
supports keyword parameters." sounds better as "An SPIError instance
can be constructed using keyword parameters."

5. there is conceptual code duplication between PLy_spi_exception_set
in plpy_spi.c, since that code also constructs an SPIError but from C
and with more info available (edata->internalquery and
edata->internalpos). But making a tuple and assigning it to spidata is
in both. Not sure how this can be improved.

6. __init__ can use METH_VARARGS | METH_KEYWORDS in both Python2 and
3, no need for the #if

7. "could not create dictionary for SPI exception" would be more
precise as "could not create dictionary for SPIError" right?

8. in PLy_add_methods_to_dictionary I would avoid import since it
makes one think of importing modules; maybe "could not create function
wrapper for \"%s\"", "could not create method wrapper for \"%s\""

9. also in PLy_add_methods_to_dictionary "could public method \"%s\"
in dictionary" is not proper English and is missing not, maybe "could
not add method \"%s\" to class dictionary"?

10. in PLy_add_methods_to_dictionary if PyCFunction_New succeeds but
PyMethod_New fails, func will leak

11. it would be nice to have a test for the invalid SQLSTATE code part

12. similar to 10, in PLy_spi_error__init__ taking the "invalid
SQLSTATE" branch leaks exc_args, in general early returns via PLy_elog
will leave the intermediate Python objects leaking

Will mark the patch as Waiting for author.

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

#15Pavel Stehule
pavel.stehule@gmail.com
In reply to: Catalin Iacob (#14)
Re: proposal: PL/Pythonu - function ereport

2015-11-02 17:01 GMT+01:00 Catalin Iacob <iacobcatalin@gmail.com>:

Hello,

Here's a detailed review:

1. in PLy_spi_error__init__ you need to check kw for NULL before doing
PyDict_Size(kw) otherwise for plpy.SPIError() you get Bad internal
call because PyDict_Size expects a real dictionary not NULL

PyDict_Size returns -1 when the dictionary is NULL

http://grokbase.com/t/python/python-dev/042ft6qaqq/pydict-size-error-return

done

2. a test with just plpy.SPIError() is still missing, this would have
caught 1.

please, can you write some example - I am not able raise described error

3. the tests have "possibility to set all accessable fields in custom
exception" above a test that doesn't set all fields, it's confusing
(and accessible is spelled wrong)

done

4. in the docs, "The constructor of SPIError exception (class)
supports keyword parameters." sounds better as "An SPIError instance
can be constructed using keyword parameters."

done

5. there is conceptual code duplication between PLy_spi_exception_set
in plpy_spi.c, since that code also constructs an SPIError but from C
and with more info available (edata->internalquery and
edata->internalpos). But making a tuple and assigning it to spidata is
in both. Not sure how this can be improved.

I see it, but I don't think, so current code should be changed.
PLy_spi_exception_set is controlled directly by fully filled ErrorData
structure, __init__ is based only on keyword parameters with possibility
use inherited data. If I'll build ErrorData in __init__ function and call
PLy_spi_exception_set, then the code will be longer and more complex.

6. __init__ can use METH_VARARGS | METH_KEYWORDS in both Python2 and
3, no need for the #if

done

7. "could not create dictionary for SPI exception" would be more
precise as "could not create dictionary for SPIError" right?

done

8. in PLy_add_methods_to_dictionary I would avoid import since it
makes one think of importing modules; maybe "could not create
functionwrapper for \"%s\"", "could not create method wrapper for \"%s\""

done

9. also in PLy_add_methods_to_dictionary "could public method \"%s\"
in dictionary" is not proper English and is missing not, maybe "could
not add method \"%s\" to class dictionary"?

done

10. in PLy_add_methods_to_dictionary if PyCFunction_New succeeds but
PyMethod_New fails, func will leak

done

11. it would be nice to have a test for the invalid SQLSTATE code part

done

12. similar to 10, in PLy_spi_error__init__ taking the "invalid
SQLSTATE" branch leaks exc_args, in general early returns via PLy_elog
will leave the intermediate Python objects leaking

dome

Will mark the patch as Waiting for author.

attached new update

Regards

Pavel

Attachments:

plpythonu-spierror-keyword-params-04.patchtext/x-patch; charset=US-ASCII; name=plpythonu-spierror-keyword-params-04.patchDownload+328-36
#16Catalin Iacob
iacobcatalin@gmail.com
In reply to: Pavel Stehule (#15)
Re: proposal: PL/Pythonu - function ereport

On Tue, Nov 3, 2015 at 12:49 PM, Pavel Stehule <pavel.stehule@gmail.com> wrote:

1. in PLy_spi_error__init__ you need to check kw for NULL before doing
PyDict_Size(kw) otherwise for plpy.SPIError() you get Bad internal
call because PyDict_Size expects a real dictionary not NULL

PyDict_Size returns -1 when the dictionary is NULL

http://grokbase.com/t/python/python-dev/042ft6qaqq/pydict-size-error-return

Yes, but it also sets the error indicator to BadInternalCall. In 2.7
the code is:
Py_ssize_t
PyDict_Size(PyObject *mp)
{
if (mp == NULL || !PyDict_Check(mp)) {
PyErr_BadInternalCall();
return -1;
}
return ((PyDictObject *)mp)->ma_used;
}

I had a PLy_elog right after the PyDict_Size call for debugging and
that one was raising BadInternalCall since it checked the error
indicator. So the NULL check is needed.

2. a test with just plpy.SPIError() is still missing, this would have
caught 1.

please, can you write some example - I am not able raise described error

The example was plpy.SPIError() but I now realize that, in order to
see a failure, you need the extra PLy_elog which I had in there.
But this basic form of the constructor is still an important thing to
test so please add this as well to the regression test.

5. there is conceptual code duplication between PLy_spi_exception_set
in plpy_spi.c, since that code also constructs an SPIError but from C
and with more info available (edata->internalquery and
edata->internalpos). But making a tuple and assigning it to spidata is
in both. Not sure how this can be improved.

I see it, but I don't think, so current code should be changed.
PLy_spi_exception_set is controlled directly by fully filled ErrorData
structure, __init__ is based only on keyword parameters with possibility use
inherited data. If I'll build ErrorData in __init__ function and call
PLy_spi_exception_set, then the code will be longer and more complex.

Indeed, I don't really see how to improve this but it does bug me a bit.

One more thing,
+    The <literal>plpy</literal> module provides several possibilities to
+    to raise a exception:

This has "to" 2 times and is weird since it says it offers several
possibilities but then shows only one (the SPIError constructor).
And SPIError should be <literal>plpy.SPIError</literal> everywhere to
be consistent.

Maybe something like (needs markup):
A plpy.SPIError can be raised from PL/Python, the constructor accepts
keyword parameters:
plpy.SPIError([ message [, detail [, hint [, sqlstate [, schema [,
table [, column [, datatype [, constraint ]]]]]]]]])
then the example

If you fix the doc and add the plpy.SPIError() test I'm happy. I'll
give it one more test on Python2.7 and 3.5 and mark it Ready for
Committer.

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

#17Pavel Stehule
pavel.stehule@gmail.com
In reply to: Catalin Iacob (#16)
Re: proposal: PL/Pythonu - function ereport

2015-11-03 17:13 GMT+01:00 Catalin Iacob <iacobcatalin@gmail.com>:

On Tue, Nov 3, 2015 at 12:49 PM, Pavel Stehule <pavel.stehule@gmail.com>
wrote:

1. in PLy_spi_error__init__ you need to check kw for NULL before doing
PyDict_Size(kw) otherwise for plpy.SPIError() you get Bad internal
call because PyDict_Size expects a real dictionary not NULL

PyDict_Size returns -1 when the dictionary is NULL

http://grokbase.com/t/python/python-dev/042ft6qaqq/pydict-size-error-return

Yes, but it also sets the error indicator to BadInternalCall. In 2.7
the code is:
Py_ssize_t
PyDict_Size(PyObject *mp)
{
if (mp == NULL || !PyDict_Check(mp)) {
PyErr_BadInternalCall();
return -1;
}
return ((PyDictObject *)mp)->ma_used;
}

I had a PLy_elog right after the PyDict_Size call for debugging and
that one was raising BadInternalCall since it checked the error
indicator. So the NULL check is needed.

I did it in last patch - PyDict_Size is not called when kw is NULL

2. a test with just plpy.SPIError() is still missing, this would have
caught 1.

one test contains "x = plpy.SPIError()". Is it, what you want?

please, can you write some example - I am not able raise described error

The example was plpy.SPIError() but I now realize that, in order to
see a failure, you need the extra PLy_elog which I had in there.
But this basic form of the constructor is still an important thing to
test so please add this as well to the regression test.

5. there is conceptual code duplication between PLy_spi_exception_set
in plpy_spi.c, since that code also constructs an SPIError but from C
and with more info available (edata->internalquery and
edata->internalpos). But making a tuple and assigning it to spidata is
in both. Not sure how this can be improved.

I see it, but I don't think, so current code should be changed.
PLy_spi_exception_set is controlled directly by fully filled ErrorData
structure, __init__ is based only on keyword parameters with possibility

use

inherited data. If I'll build ErrorData in __init__ function and call
PLy_spi_exception_set, then the code will be longer and more complex.

Indeed, I don't really see how to improve this but it does bug me a bit.

One more thing,
+    The <literal>plpy</literal> module provides several possibilities to
+    to raise a exception:

This has "to" 2 times and is weird since it says it offers several
possibilities but then shows only one (the SPIError constructor).
And SPIError should be <literal>plpy.SPIError</literal> everywhere to
be consistent.

I'll do it tomorrow

Maybe something like (needs markup):
A plpy.SPIError can be raised from PL/Python, the constructor accepts
keyword parameters:
plpy.SPIError([ message [, detail [, hint [, sqlstate [, schema [,
table [, column [, datatype [, constraint ]]]]]]]]])
then the example

If you fix the doc and add the plpy.SPIError() test I'm happy. I'll
give it one more test on Python2.7 and 3.5 and mark it Ready for
Committer.

Regards

Pavel

#18Catalin Iacob
iacobcatalin@gmail.com
In reply to: Pavel Stehule (#17)
Re: proposal: PL/Pythonu - function ereport

Sorry, you're right, I didn't notice the x = plpy.SPIError() test.

I did notice that you included the kw != NULL, I was explaining why it
really is needed even though it *seems* the code also works without
it.

There's just the doc part left then.

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

#19Pavel Stehule
pavel.stehule@gmail.com
In reply to: Catalin Iacob (#18)
Re: proposal: PL/Pythonu - function ereport

Hi

2015-11-04 7:06 GMT+01:00 Catalin Iacob <iacobcatalin@gmail.com>:

Sorry, you're right, I didn't notice the x = plpy.SPIError() test.

I did notice that you included the kw != NULL, I was explaining why it
really is needed even though it *seems* the code also works without

it.

It helped me lot of, thank you

There's just the doc part left then.

done

Regards

Pavel

Attachments:

plpythonu-spierror-keyword-params-05.patchtext/x-patch; charset=US-ASCII; name=plpythonu-spierror-keyword-params-05.patchDownload+321-36
#20Catalin Iacob
iacobcatalin@gmail.com
In reply to: Pavel Stehule (#19)
Re: proposal: PL/Pythonu - function ereport

On Wed, Nov 4, 2015 at 10:12 AM, Pavel Stehule <pavel.stehule@gmail.com> wrote:

It helped me lot of, thank you

Welcome, I learned quite some from the process as well.

There's just the doc part left then.

done

We're almost there but not quite.

There's still a typo in the docs: excation.

A plpy.SPIError can be raised should be A
<literal>plpy.SPIError</literal> can be raised right?

And most importantly, for Python 3.5 there is a plpython_error_5.out
which is needed because of an alternative exception message in that
version. You didn't update this file, this makes the tests fail on
Python3.5.

Since you might not have Python 3.5 easily available I've attached a
patch to plpython_error_5.out which makes the tests pass, you can fold
this into your patch.

Attachments:

adjust_py35_expected.patchbinary/octet-stream; name=adjust_py35_expected.patchDownload+62-0
#21Pavel Stehule
pavel.stehule@gmail.com
In reply to: Catalin Iacob (#20)
#22Pavel Stehule
pavel.stehule@gmail.com
In reply to: Catalin Iacob (#20)
#23Catalin Iacob
iacobcatalin@gmail.com
In reply to: Pavel Stehule (#22)
#24Pavel Stehule
pavel.stehule@gmail.com
In reply to: Catalin Iacob (#23)
#25Catalin Iacob
iacobcatalin@gmail.com
In reply to: Pavel Stehule (#24)
#26Pavel Stehule
pavel.stehule@gmail.com
In reply to: Catalin Iacob (#25)
#27Peter Eisentraut
peter_e@gmx.net
In reply to: Pavel Stehule (#24)
#28Pavel Stehule
pavel.stehule@gmail.com
In reply to: Peter Eisentraut (#27)
#29Peter Eisentraut
peter_e@gmx.net
In reply to: Pavel Stehule (#28)
#30Teodor Sigaev
teodor@sigaev.ru
In reply to: Peter Eisentraut (#29)
#31Pavel Stehule
pavel.stehule@gmail.com
In reply to: Teodor Sigaev (#30)
#32Michael Paquier
michael@paquier.xyz
In reply to: Pavel Stehule (#31)
#33Pavel Stehule
pavel.stehule@gmail.com
In reply to: Michael Paquier (#32)
#34Pavel Stehule
pavel.stehule@gmail.com
In reply to: Peter Eisentraut (#29)
#35Michael Paquier
michael@paquier.xyz
In reply to: Pavel Stehule (#33)
#36Pavel Stehule
pavel.stehule@gmail.com
In reply to: Michael Paquier (#35)
#37Pavel Stehule
pavel.stehule@gmail.com
In reply to: Pavel Stehule (#34)
#38Catalin Iacob
iacobcatalin@gmail.com
In reply to: Pavel Stehule (#37)
#39Pavel Stehule
pavel.stehule@gmail.com
In reply to: Catalin Iacob (#38)
#40Catalin Iacob
iacobcatalin@gmail.com
In reply to: Pavel Stehule (#39)
#41Pavel Stehule
pavel.stehule@gmail.com
In reply to: Catalin Iacob (#40)
#42Catalin Iacob
iacobcatalin@gmail.com
In reply to: Pavel Stehule (#41)
#43Pavel Stehule
pavel.stehule@gmail.com
In reply to: Catalin Iacob (#42)
#44Pavel Stehule
pavel.stehule@gmail.com
In reply to: Catalin Iacob (#42)
#45Pavel Stehule
pavel.stehule@gmail.com
In reply to: Catalin Iacob (#42)
#46Catalin Iacob
iacobcatalin@gmail.com
In reply to: Pavel Stehule (#45)
#47Pavel Stehule
pavel.stehule@gmail.com
In reply to: Catalin Iacob (#46)
#48Catalin Iacob
iacobcatalin@gmail.com
In reply to: Pavel Stehule (#47)
#49Pavel Stehule
pavel.stehule@gmail.com
In reply to: Catalin Iacob (#48)
#50Jim Nasby
Jim.Nasby@BlueTreble.com
In reply to: Pavel Stehule (#49)
#51Pavel Stehule
pavel.stehule@gmail.com
In reply to: Jim Nasby (#50)
#52Jim Nasby
Jim.Nasby@BlueTreble.com
In reply to: Pavel Stehule (#51)
#53Pavel Stehule
pavel.stehule@gmail.com
In reply to: Jim Nasby (#52)
#54Catalin Iacob
iacobcatalin@gmail.com
In reply to: Pavel Stehule (#53)
#55Pavel Stehule
pavel.stehule@gmail.com
In reply to: Catalin Iacob (#54)
#56Catalin Iacob
iacobcatalin@gmail.com
In reply to: Pavel Stehule (#49)
#57Jim Nasby
Jim.Nasby@BlueTreble.com
In reply to: Catalin Iacob (#56)
#58Catalin Iacob
iacobcatalin@gmail.com
In reply to: Jim Nasby (#57)
#59Pavel Stehule
pavel.stehule@gmail.com
In reply to: Catalin Iacob (#58)
#60Jim Nasby
Jim.Nasby@BlueTreble.com
In reply to: Pavel Stehule (#59)
#61Catalin Iacob
iacobcatalin@gmail.com
In reply to: Pavel Stehule (#59)
#62Pavel Stehule
pavel.stehule@gmail.com
In reply to: Catalin Iacob (#61)
#63Pavel Stehule
pavel.stehule@gmail.com
In reply to: Pavel Stehule (#62)
#64Pavel Stehule
pavel.stehule@gmail.com
In reply to: Pavel Stehule (#63)
#65Chapman Flack
chap@anastigmatix.net
In reply to: Pavel Stehule (#62)
#66Pavel Stehule
pavel.stehule@gmail.com
In reply to: Chapman Flack (#65)
#67Catalin Iacob
iacobcatalin@gmail.com
In reply to: Pavel Stehule (#64)
#68Pavel Stehule
pavel.stehule@gmail.com
In reply to: Catalin Iacob (#67)
#69Catalin Iacob
iacobcatalin@gmail.com
In reply to: Pavel Stehule (#68)
#70Pavel Stehule
pavel.stehule@gmail.com
In reply to: Catalin Iacob (#69)
#71Catalin Iacob
iacobcatalin@gmail.com
In reply to: Pavel Stehule (#70)
#72Robert Haas
robertmhaas@gmail.com
In reply to: Catalin Iacob (#71)
#73Alvaro Herrera
alvherre@2ndquadrant.com
In reply to: Robert Haas (#72)
#74Jim Nasby
Jim.Nasby@BlueTreble.com
In reply to: Alvaro Herrera (#73)
#75Catalin Iacob
iacobcatalin@gmail.com
In reply to: Alvaro Herrera (#73)
#76Jim Nasby
Jim.Nasby@BlueTreble.com
In reply to: Catalin Iacob (#75)
#77Alvaro Herrera
alvherre@2ndquadrant.com
In reply to: Catalin Iacob (#75)
#78Pavel Stehule
pavel.stehule@gmail.com
In reply to: Jim Nasby (#74)
#79Jim Nasby
Jim.Nasby@BlueTreble.com
In reply to: Pavel Stehule (#78)
#80Pavel Stehule
pavel.stehule@gmail.com
In reply to: Catalin Iacob (#75)
#81Catalin Iacob
iacobcatalin@gmail.com
In reply to: Pavel Stehule (#80)
#82Catalin Iacob
iacobcatalin@gmail.com
In reply to: Catalin Iacob (#81)
#83Pavel Stehule
pavel.stehule@gmail.com
In reply to: Catalin Iacob (#82)
#84Pavel Stehule
pavel.stehule@gmail.com
In reply to: Catalin Iacob (#81)
#85Pavel Stehule
pavel.stehule@gmail.com
In reply to: Catalin Iacob (#82)
#86Catalin Iacob
iacobcatalin@gmail.com
In reply to: Pavel Stehule (#84)
#87Pavel Stehule
pavel.stehule@gmail.com
In reply to: Catalin Iacob (#86)
#88Catalin Iacob
iacobcatalin@gmail.com
In reply to: Pavel Stehule (#87)
#89Pavel Stehule
pavel.stehule@gmail.com
In reply to: Catalin Iacob (#88)
#90Catalin Iacob
iacobcatalin@gmail.com
In reply to: Pavel Stehule (#89)
#91Pavel Stehule
pavel.stehule@gmail.com
In reply to: Catalin Iacob (#90)
#92Catalin Iacob
iacobcatalin@gmail.com
In reply to: Pavel Stehule (#91)
#93Pavel Stehule
pavel.stehule@gmail.com
In reply to: Catalin Iacob (#92)
#94Catalin Iacob
iacobcatalin@gmail.com
In reply to: Pavel Stehule (#93)
#95Pavel Stehule
pavel.stehule@gmail.com
In reply to: Catalin Iacob (#94)
#96Pavel Stehule
pavel.stehule@gmail.com
In reply to: Pavel Stehule (#95)
#97Catalin Iacob
iacobcatalin@gmail.com
In reply to: Pavel Stehule (#96)
#98Pavel Stehule
pavel.stehule@gmail.com
In reply to: Catalin Iacob (#97)
#99Robert Haas
robertmhaas@gmail.com
In reply to: Pavel Stehule (#98)
#100Teodor Sigaev
teodor@sigaev.ru
In reply to: Pavel Stehule (#98)
#101Pavel Stehule
pavel.stehule@gmail.com
In reply to: Teodor Sigaev (#100)
#102Tom Lane
tgl@sss.pgh.pa.us
In reply to: Pavel Stehule (#101)
#103Pavel Stehule
pavel.stehule@gmail.com
In reply to: Tom Lane (#102)
#104Pavel Stehule
pavel.stehule@gmail.com
In reply to: Pavel Stehule (#103)
#105Tom Lane
tgl@sss.pgh.pa.us
In reply to: Pavel Stehule (#104)
#106Peter Eisentraut
peter_e@gmx.net
In reply to: Pavel Stehule (#101)
#107Pavel Stehule
pavel.stehule@gmail.com
In reply to: Peter Eisentraut (#106)