Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit316186f

Browse files
committed
Handle SPIErrors raised directly in PL/Python code.
If a PL/Python function raises an SPIError (or one if its subclasses)directly with python's raise statement, treat it the same as an SPIErrorgenerated internally. In particular, if the user sets the sqlstateattribute, preserve that.Oskari Saarenmaa and Jan Urbański, reviewed by Karl O. Pinc.
1 parent96bb29d commit316186f

File tree

4 files changed

+119
-5
lines changed

4 files changed

+119
-5
lines changed

‎src/pl/plpython/expected/plpython_error.out

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -400,3 +400,29 @@ CONTEXT: Traceback (most recent call last):
400400
PL/Python function "manual_subxact_prepared", line 4, in <module>
401401
plpy.execute(save)
402402
PL/Python function "manual_subxact_prepared"
403+
/* raising plpy.spiexception.* from python code should preserve sqlstate
404+
*/
405+
CREATE FUNCTION plpy_raise_spiexception() RETURNS void AS $$
406+
raise plpy.spiexceptions.DivisionByZero()
407+
$$ LANGUAGE plpythonu;
408+
DO $$
409+
BEGIN
410+
SELECT plpy_raise_spiexception();
411+
EXCEPTION WHEN division_by_zero THEN
412+
-- NOOP
413+
END
414+
$$ LANGUAGE plpgsql;
415+
/* setting a custom sqlstate should be handled
416+
*/
417+
CREATE FUNCTION plpy_raise_spiexception_override() RETURNS void AS $$
418+
exc = plpy.spiexceptions.DivisionByZero()
419+
exc.sqlstate = 'SILLY'
420+
raise exc
421+
$$ LANGUAGE plpythonu;
422+
DO $$
423+
BEGIN
424+
SELECT plpy_raise_spiexception_override();
425+
EXCEPTION WHEN SQLSTATE 'SILLY' THEN
426+
-- NOOP
427+
END
428+
$$ LANGUAGE plpgsql;

‎src/pl/plpython/expected/plpython_error_0.out

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -400,3 +400,29 @@ CONTEXT: Traceback (most recent call last):
400400
PL/Python function "manual_subxact_prepared", line 4, in <module>
401401
plpy.execute(save)
402402
PL/Python function "manual_subxact_prepared"
403+
/* raising plpy.spiexception.* from python code should preserve sqlstate
404+
*/
405+
CREATE FUNCTION plpy_raise_spiexception() RETURNS void AS $$
406+
raise plpy.spiexceptions.DivisionByZero()
407+
$$ LANGUAGE plpythonu;
408+
DO $$
409+
BEGIN
410+
SELECT plpy_raise_spiexception();
411+
EXCEPTION WHEN division_by_zero THEN
412+
-- NOOP
413+
END
414+
$$ LANGUAGE plpgsql;
415+
/* setting a custom sqlstate should be handled
416+
*/
417+
CREATE FUNCTION plpy_raise_spiexception_override() RETURNS void AS $$
418+
exc = plpy.spiexceptions.DivisionByZero()
419+
exc.sqlstate = 'SILLY'
420+
raise exc
421+
$$ LANGUAGE plpythonu;
422+
DO $$
423+
BEGIN
424+
SELECT plpy_raise_spiexception_override();
425+
EXCEPTION WHEN SQLSTATE 'SILLY' THEN
426+
-- NOOP
427+
END
428+
$$ LANGUAGE plpgsql;

‎src/pl/plpython/plpy_elog.c

Lines changed: 37 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -336,6 +336,31 @@ PLy_traceback(char **xmsg, char **tbmsg, int *tb_depth)
336336
Py_DECREF(e);
337337
}
338338

339+
/*
340+
* Extract error code from SPIError's sqlstate attribute.
341+
*/
342+
staticvoid
343+
PLy_get_spi_sqlerrcode(PyObject*exc,int*sqlerrcode)
344+
{
345+
PyObject*sqlstate;
346+
char*buffer;
347+
348+
sqlstate=PyObject_GetAttrString(exc,"sqlstate");
349+
if (sqlstate==NULL)
350+
return;
351+
352+
buffer=PyString_AsString(sqlstate);
353+
if (strlen(buffer)==5&&
354+
strspn(buffer,"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ")==5)
355+
{
356+
*sqlerrcode=MAKE_SQLSTATE(buffer[0],buffer[1],buffer[2],
357+
buffer[3],buffer[4]);
358+
}
359+
360+
Py_DECREF(sqlstate);
361+
}
362+
363+
339364
/*
340365
* Extract the error data from a SPIError
341366
*/
@@ -345,13 +370,20 @@ PLy_get_spi_error_data(PyObject *exc, int *sqlerrcode, char **detail, char **hin
345370
PyObject*spidata=NULL;
346371

347372
spidata=PyObject_GetAttrString(exc,"spidata");
348-
if (!spidata)
349-
gotocleanup;
350373

351-
if (!PyArg_ParseTuple(spidata,"izzzi",sqlerrcode,detail,hint,query,position))
352-
gotocleanup;
374+
if (spidata!=NULL)
375+
{
376+
PyArg_ParseTuple(spidata,"izzzi",sqlerrcode,detail,hint,query,position);
377+
}
378+
else
379+
{
380+
/*
381+
* If there's no spidata, at least set the sqlerrcode. This can happen
382+
* if someone explicitly raises a SPI exception from Python code.
383+
*/
384+
PLy_get_spi_sqlerrcode(exc,sqlerrcode);
385+
}
353386

354-
cleanup:
355387
PyErr_Clear();
356388
/* no elog here, we simply won't report the errhint, errposition etc */
357389
Py_XDECREF(spidata);

‎src/pl/plpython/sql/plpython_error.sql

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -298,3 +298,33 @@ plpy.execute(rollback)
298298
$$ LANGUAGE plpythonu;
299299

300300
SELECT manual_subxact_prepared();
301+
302+
/* raising plpy.spiexception.* from python code should preserve sqlstate
303+
*/
304+
CREATEFUNCTIONplpy_raise_spiexception() RETURNS voidAS $$
305+
raiseplpy.spiexceptions.DivisionByZero()
306+
$$ LANGUAGE plpythonu;
307+
308+
DO $$
309+
BEGIN
310+
SELECT plpy_raise_spiexception();
311+
EXCEPTION WHEN division_by_zero THEN
312+
-- NOOP
313+
END
314+
$$ LANGUAGE plpgsql;
315+
316+
/* setting a custom sqlstate should be handled
317+
*/
318+
CREATEFUNCTIONplpy_raise_spiexception_override() RETURNS voidAS $$
319+
exc=plpy.spiexceptions.DivisionByZero()
320+
exc.sqlstate='SILLY'
321+
raise exc
322+
$$ LANGUAGE plpythonu;
323+
324+
DO $$
325+
BEGIN
326+
SELECT plpy_raise_spiexception_override();
327+
EXCEPTION WHEN SQLSTATE'SILLY' THEN
328+
-- NOOP
329+
END
330+
$$ LANGUAGE plpgsql;

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp