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

Commitf21fc7f

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 parent5df1403 commitf21fc7f

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
@@ -383,7 +383,7 @@ static char *PLy_procedure_name(PLyProcedure *);
383383
staticvoid
384384
PLy_elog(int,constchar*,...)
385385
__attribute__((format(PG_PRINTF_ATTRIBUTE,2,3)));
386-
staticvoidPLy_get_spi_error_data(PyObject*exc,char**detail,char**hint,char**query,int*position);
386+
staticvoidPLy_get_spi_error_data(PyObject*exc,int*sqlerrcode,char**detail,char**hint,char**query,int*position);
387387
staticvoidPLy_traceback(char**,char**,int*);
388388

389389
staticvoid*PLy_malloc(size_t);
@@ -4441,7 +4441,7 @@ PLy_spi_exception_set(PyObject *excclass, ErrorData *edata)
44414441
if (!spierror)
44424442
gotofailure;
44434443

4444-
spidata=Py_BuildValue("(zzzi)",edata->detail,edata->hint,
4444+
spidata=Py_BuildValue("(izzzi)",edata->sqlerrcode,edata->detail,edata->hint,
44454445
edata->internalquery,edata->internalpos);
44464446
if (!spidata)
44474447
gotofailure;
@@ -4481,6 +4481,7 @@ PLy_elog(int elevel, const char *fmt,...)
44814481
*val,
44824482
*tb;
44834483
constchar*primary=NULL;
4484+
intsqlerrcode=0;
44844485
char*detail=NULL;
44854486
char*hint=NULL;
44864487
char*query=NULL;
@@ -4490,7 +4491,7 @@ PLy_elog(int elevel, const char *fmt,...)
44904491
if (exc!=NULL)
44914492
{
44924493
if (PyErr_GivenExceptionMatches(val,PLy_exc_spi_error))
4493-
PLy_get_spi_error_data(val,&detail,&hint,&query,&position);
4494+
PLy_get_spi_error_data(val,&sqlerrcode,&detail,&hint,&query,&position);
44944495
elseif (PyErr_GivenExceptionMatches(val,PLy_exc_fatal))
44954496
elevel=FATAL;
44964497
}
@@ -4531,7 +4532,8 @@ PLy_elog(int elevel, const char *fmt,...)
45314532
PG_TRY();
45324533
{
45334534
ereport(elevel,
4534-
(errmsg_internal("%s",primary ?primary :"no exception data"),
4535+
(errcode(sqlerrcode ?sqlerrcode :ERRCODE_INTERNAL_ERROR),
4536+
errmsg_internal("%s",primary ?primary :"no exception data"),
45354537
(detail) ?errdetail_internal("%s",detail) :0,
45364538
(tb_depth>0&&tbmsg) ?errcontext("%s",tbmsg) :0,
45374539
(hint) ?errhint("%s",hint) :0,
@@ -4562,15 +4564,15 @@ PLy_elog(int elevel, const char *fmt,...)
45624564
* Extract the error data from a SPIError
45634565
*/
45644566
staticvoid
4565-
PLy_get_spi_error_data(PyObject*exc,char**detail,char**hint,char**query,int*position)
4567+
PLy_get_spi_error_data(PyObject*exc,int*sqlerrcode,char**detail,char**hint,char**query,int*position)
45664568
{
45674569
PyObject*spidata=NULL;
45684570

45694571
spidata=PyObject_GetAttrString(exc,"spidata");
45704572
if (!spidata)
45714573
gotocleanup;
45724574

4573-
if (!PyArg_ParseTuple(spidata,"zzzi",detail,hint,query,position))
4575+
if (!PyArg_ParseTuple(spidata,"izzzi",sqlerrcode,detail,hint,query,position))
45744576
gotocleanup;
45754577

45764578
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