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

Commitd2192a1

Browse files
committed
Preserve SQLSTATE when an SPI error is propagated through PL/python
exception handler. This was a regression in 9.1, when the capabilityto catch specific SPI errors was added, so backpatch to 9.1.Mika Eloranta, with some editing by Jan Urbański.
1 parent94bdb19 commitd2192a1

File tree

4 files changed

+72
-6
lines changed

4 files changed

+72
-6
lines changed

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

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -351,6 +351,28 @@ CONTEXT: PL/Python function "specific_exception"
351351

352352
(1 row)
353353

354+
/* SPI errors in PL/Python functions should preserve the SQLSTATE value
355+
*/
356+
CREATE FUNCTION python_unique_violation() RETURNS void AS $$
357+
plpy.execute("insert into specific values (1)")
358+
plpy.execute("insert into specific values (1)")
359+
$$ LANGUAGE plpythonu;
360+
CREATE FUNCTION catch_python_unique_violation() RETURNS text AS $$
361+
begin
362+
begin
363+
perform python_unique_violation();
364+
exception when unique_violation then
365+
return 'ok';
366+
end;
367+
return 'not reached';
368+
end;
369+
$$ language plpgsql;
370+
SELECT catch_python_unique_violation();
371+
catch_python_unique_violation
372+
-------------------------------
373+
ok
374+
(1 row)
375+
354376
/* manually starting subtransactions - a bad idea
355377
*/
356378
CREATE FUNCTION manual_subxact() RETURNS void AS $$

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

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -351,6 +351,28 @@ CONTEXT: PL/Python function "specific_exception"
351351

352352
(1 row)
353353

354+
/* SPI errors in PL/Python functions should preserve the SQLSTATE value
355+
*/
356+
CREATE FUNCTION python_unique_violation() RETURNS void AS $$
357+
plpy.execute("insert into specific values (1)")
358+
plpy.execute("insert into specific values (1)")
359+
$$ LANGUAGE plpythonu;
360+
CREATE FUNCTION catch_python_unique_violation() RETURNS text AS $$
361+
begin
362+
begin
363+
perform python_unique_violation();
364+
exception when unique_violation then
365+
return 'ok';
366+
end;
367+
return 'not reached';
368+
end;
369+
$$ language plpgsql;
370+
SELECT catch_python_unique_violation();
371+
catch_python_unique_violation
372+
-------------------------------
373+
ok
374+
(1 row)
375+
354376
/* manually starting subtransactions - a bad idea
355377
*/
356378
CREATE FUNCTION manual_subxact() RETURNS void AS $$

‎src/pl/plpython/plpython.c

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -343,7 +343,7 @@ static char *PLy_procedure_name(PLyProcedure *);
343343
staticvoid
344344
PLy_elog(int,constchar*,...)
345345
__attribute__((format(PG_PRINTF_ATTRIBUTE,2,3)));
346-
staticvoidPLy_get_spi_error_data(PyObject*exc,char**detail,char**hint,char**query,int*position);
346+
staticvoidPLy_get_spi_error_data(PyObject*exc,int*sqlerrcode,char**detail,char**hint,char**query,int*position);
347347
staticvoidPLy_traceback(char**,char**,int*);
348348

349349
staticvoid*PLy_malloc(size_t);
@@ -4404,7 +4404,7 @@ PLy_spi_exception_set(PyObject *excclass, ErrorData *edata)
44044404
if (!spierror)
44054405
gotofailure;
44064406

4407-
spidata=Py_BuildValue("(zzzi)",edata->detail,edata->hint,
4407+
spidata=Py_BuildValue("(izzzi)",edata->sqlerrcode,edata->detail,edata->hint,
44084408
edata->internalquery,edata->internalpos);
44094409
if (!spidata)
44104410
gotofailure;
@@ -4444,6 +4444,7 @@ PLy_elog(int elevel, const char *fmt,...)
44444444
*val,
44454445
*tb;
44464446
constchar*primary=NULL;
4447+
intsqlerrcode=0;
44474448
char*detail=NULL;
44484449
char*hint=NULL;
44494450
char*query=NULL;
@@ -4453,7 +4454,7 @@ PLy_elog(int elevel, const char *fmt,...)
44534454
if (exc!=NULL)
44544455
{
44554456
if (PyErr_GivenExceptionMatches(val,PLy_exc_spi_error))
4456-
PLy_get_spi_error_data(val,&detail,&hint,&query,&position);
4457+
PLy_get_spi_error_data(val,&sqlerrcode,&detail,&hint,&query,&position);
44574458
elseif (PyErr_GivenExceptionMatches(val,PLy_exc_fatal))
44584459
elevel=FATAL;
44594460
}
@@ -4494,7 +4495,8 @@ PLy_elog(int elevel, const char *fmt,...)
44944495
PG_TRY();
44954496
{
44964497
ereport(elevel,
4497-
(errmsg_internal("%s",primary ?primary :"no exception data"),
4498+
(errcode(sqlerrcode ?sqlerrcode :ERRCODE_INTERNAL_ERROR),
4499+
errmsg_internal("%s",primary ?primary :"no exception data"),
44984500
(detail) ?errdetail_internal("%s",detail) :0,
44994501
(tb_depth>0&&tbmsg) ?errcontext("%s",tbmsg) :0,
45004502
(hint) ?errhint("%s",hint) :0,
@@ -4525,15 +4527,15 @@ PLy_elog(int elevel, const char *fmt,...)
45254527
* Extract the error data from a SPIError
45264528
*/
45274529
staticvoid
4528-
PLy_get_spi_error_data(PyObject*exc,char**detail,char**hint,char**query,int*position)
4530+
PLy_get_spi_error_data(PyObject*exc,int*sqlerrcode,char**detail,char**hint,char**query,int*position)
45294531
{
45304532
PyObject*spidata=NULL;
45314533

45324534
spidata=PyObject_GetAttrString(exc,"spidata");
45334535
if (!spidata)
45344536
gotocleanup;
45354537

4536-
if (!PyArg_ParseTuple(spidata,"zzzi",detail,hint,query,position))
4538+
if (!PyArg_ParseTuple(spidata,"izzzi",sqlerrcode,detail,hint,query,position))
45374539
gotocleanup;
45384540

45394541
cleanup:

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

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,26 @@ SELECT specific_exception(2);
257257
SELECT specific_exception(NULL);
258258
SELECT specific_exception(2);
259259

260+
/* SPI errors in PL/Python functions should preserve the SQLSTATE value
261+
*/
262+
CREATEFUNCTIONpython_unique_violation() RETURNS voidAS $$
263+
plpy.execute("insert into specific values (1)")
264+
plpy.execute("insert into specific values (1)")
265+
$$ LANGUAGE plpythonu;
266+
267+
CREATEFUNCTIONcatch_python_unique_violation() RETURNStextAS $$
268+
begin
269+
begin
270+
perform python_unique_violation();
271+
exception when unique_violation then
272+
return'ok';
273+
end;
274+
return'not reached';
275+
end;
276+
$$ language plpgsql;
277+
278+
SELECT catch_python_unique_violation();
279+
260280
/* manually starting subtransactions - a bad idea
261281
*/
262282
CREATEFUNCTIONmanual_subxact() RETURNS voidAS $$

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp