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

Commite748e90

Browse files
committed
Fix broken logic for reporting PL/Python function names in errcontext.
plpython_error_callback() reported the name of the function associatedwith the topmost PL/Python execution context. This was not merelywrong if there were nested PL/Python contexts, but it risked a coredump if the topmost one is an inline code block rather than a namedfunction. That will have proname = NULL, and so we were passing a NULLpointer to snprintf("%s"). It seems that none of the PL/Python-testingmachines in the buildfarm will dump core for that, but some platforms do,as reported by Marina Polyakova.Investigation finds that there actually is an existing regression testthat used to prove that the behavior was wrong, though apparently no onehad noticed that it was printing the wrong function name. It stoppedshowing the problem in 9.6 when we adjusted psql to not print CONTEXTby default for NOTICE messages. The problem is masked (if your platformavoids the core dump) in error cases, because PL/Python will throw awaythe originally generated error info in favor of a new traceback producedat the outer level.Repair by using ErrorContextCallback.arg to pass the correct context tothe error callback. Add a regression test illustrating correct behavior.Back-patch to all supported branches, since they're all broken this way.Discussion:https://postgr.es/m/156b989dbc6fe7c4d3223cf51da61195@postgrespro.ru
1 parentf926300 commite748e90

File tree

6 files changed

+112
-29
lines changed

6 files changed

+112
-29
lines changed

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

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -422,3 +422,26 @@ EXCEPTION WHEN SQLSTATE 'SILLY' THEN
422422
-- NOOP
423423
END
424424
$$ LANGUAGE plpgsql;
425+
/* test the context stack trace for nested execution levels
426+
*/
427+
CREATE FUNCTION notice_innerfunc() RETURNS int AS $$
428+
plpy.execute("DO LANGUAGE plpythonu $x$ plpy.notice('inside DO') $x$")
429+
return 1
430+
$$ LANGUAGE plpythonu;
431+
CREATE FUNCTION notice_outerfunc() RETURNS int AS $$
432+
plpy.execute("SELECT notice_innerfunc()")
433+
return 1
434+
$$ LANGUAGE plpythonu;
435+
\set SHOW_CONTEXT always
436+
SELECT notice_outerfunc();
437+
NOTICE: inside DO
438+
CONTEXT: PL/Python anonymous code block
439+
SQL statement "DO LANGUAGE plpythonu $x$ plpy.notice('inside DO') $x$"
440+
PL/Python function "notice_innerfunc"
441+
SQL statement "SELECT notice_innerfunc()"
442+
PL/Python function "notice_outerfunc"
443+
notice_outerfunc
444+
------------------
445+
1
446+
(1 row)
447+

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

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -422,3 +422,26 @@ EXCEPTION WHEN SQLSTATE 'SILLY' THEN
422422
-- NOOP
423423
END
424424
$$ LANGUAGE plpgsql;
425+
/* test the context stack trace for nested execution levels
426+
*/
427+
CREATE FUNCTION notice_innerfunc() RETURNS int AS $$
428+
plpy.execute("DO LANGUAGE plpythonu $x$ plpy.notice('inside DO') $x$")
429+
return 1
430+
$$ LANGUAGE plpythonu;
431+
CREATE FUNCTION notice_outerfunc() RETURNS int AS $$
432+
plpy.execute("SELECT notice_innerfunc()")
433+
return 1
434+
$$ LANGUAGE plpythonu;
435+
\set SHOW_CONTEXT always
436+
SELECT notice_outerfunc();
437+
NOTICE: inside DO
438+
CONTEXT: PL/Python anonymous code block
439+
SQL statement "DO LANGUAGE plpythonu $x$ plpy.notice('inside DO') $x$"
440+
PL/Python function "notice_innerfunc"
441+
SQL statement "SELECT notice_innerfunc()"
442+
PL/Python function "notice_outerfunc"
443+
notice_outerfunc
444+
------------------
445+
1
446+
(1 row)
447+

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

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -422,3 +422,26 @@ EXCEPTION WHEN SQLSTATE 'SILLY' THEN
422422
-- NOOP
423423
END
424424
$$ LANGUAGE plpgsql;
425+
/* test the context stack trace for nested execution levels
426+
*/
427+
CREATE FUNCTION notice_innerfunc() RETURNS int AS $$
428+
plpy.execute("DO LANGUAGE plpythonu $x$ plpy.notice('inside DO') $x$")
429+
return 1
430+
$$ LANGUAGE plpythonu;
431+
CREATE FUNCTION notice_outerfunc() RETURNS int AS $$
432+
plpy.execute("SELECT notice_innerfunc()")
433+
return 1
434+
$$ LANGUAGE plpythonu;
435+
\set SHOW_CONTEXT always
436+
SELECT notice_outerfunc();
437+
NOTICE: inside DO
438+
CONTEXT: PL/Python anonymous code block
439+
SQL statement "DO LANGUAGE plpythonu $x$ plpy.notice('inside DO') $x$"
440+
PL/Python function "notice_innerfunc"
441+
SQL statement "SELECT notice_innerfunc()"
442+
PL/Python function "notice_outerfunc"
443+
notice_outerfunc
444+
------------------
445+
1
446+
(1 row)
447+

‎src/pl/plpython/plpy_main.c

Lines changed: 26 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -237,23 +237,26 @@ plpython_call_handler(PG_FUNCTION_ARGS)
237237
/*
238238
* Push execution context onto stack. It is important that this get
239239
* popped again, so avoid putting anything that could throw error between
240-
* here and the PG_TRY. (plpython_error_callback expects the stack entry
241-
* to be there, so we have to make the context first.)
240+
* here and the PG_TRY.
242241
*/
243242
exec_ctx=PLy_push_execution_context(!nonatomic);
244243

245-
/*
246-
* Setup error traceback support for ereport()
247-
*/
248-
plerrcontext.callback=plpython_error_callback;
249-
plerrcontext.previous=error_context_stack;
250-
error_context_stack=&plerrcontext;
251-
252244
PG_TRY();
253245
{
254246
Oidfuncoid=fcinfo->flinfo->fn_oid;
255247
PLyProcedure*proc;
256248

249+
/*
250+
* Setup error traceback support for ereport(). Note that the PG_TRY
251+
* structure pops this for us again at exit, so we needn't do that
252+
* explicitly, nor do we risk the callback getting called after we've
253+
* destroyed the exec_ctx.
254+
*/
255+
plerrcontext.callback=plpython_error_callback;
256+
plerrcontext.arg=exec_ctx;
257+
plerrcontext.previous=error_context_stack;
258+
error_context_stack=&plerrcontext;
259+
257260
if (CALLED_AS_TRIGGER(fcinfo))
258261
{
259262
Relationtgrel= ((TriggerData*)fcinfo->context)->tg_relation;
@@ -279,9 +282,7 @@ plpython_call_handler(PG_FUNCTION_ARGS)
279282
}
280283
PG_END_TRY();
281284

282-
/* Pop the error context stack */
283-
error_context_stack=plerrcontext.previous;
284-
/* ... and then the execution context */
285+
/* Destroy the execution context */
285286
PLy_pop_execution_context();
286287

287288
returnretval;
@@ -333,21 +334,22 @@ plpython_inline_handler(PG_FUNCTION_ARGS)
333334
/*
334335
* Push execution context onto stack. It is important that this get
335336
* popped again, so avoid putting anything that could throw error between
336-
* here and the PG_TRY. (plpython_inline_error_callback doesn't currently
337-
* need the stack entry, but for consistency with plpython_call_handler we
338-
* do it in this order.)
337+
* here and the PG_TRY.
339338
*/
340339
exec_ctx=PLy_push_execution_context(codeblock->atomic);
341340

342-
/*
343-
* Setup error traceback support for ereport()
344-
*/
345-
plerrcontext.callback=plpython_inline_error_callback;
346-
plerrcontext.previous=error_context_stack;
347-
error_context_stack=&plerrcontext;
348-
349341
PG_TRY();
350342
{
343+
/*
344+
* Setup error traceback support for ereport().
345+
* plpython_inline_error_callback doesn't currently need exec_ctx, but
346+
* for consistency with plpython_call_handler we do it the same way.
347+
*/
348+
plerrcontext.callback=plpython_inline_error_callback;
349+
plerrcontext.arg=exec_ctx;
350+
plerrcontext.previous=error_context_stack;
351+
error_context_stack=&plerrcontext;
352+
351353
PLy_procedure_compile(&proc,codeblock->source_text);
352354
exec_ctx->curr_proc=&proc;
353355
PLy_exec_function(&fake_fcinfo,&proc);
@@ -361,9 +363,7 @@ plpython_inline_handler(PG_FUNCTION_ARGS)
361363
}
362364
PG_END_TRY();
363365

364-
/* Pop the error context stack */
365-
error_context_stack=plerrcontext.previous;
366-
/* ... and then the execution context */
366+
/* Destroy the execution context */
367367
PLy_pop_execution_context();
368368

369369
/* Now clean up the transient procedure we made */
@@ -391,7 +391,7 @@ PLy_procedure_is_trigger(Form_pg_proc procStruct)
391391
staticvoid
392392
plpython_error_callback(void*arg)
393393
{
394-
PLyExecutionContext*exec_ctx=PLy_current_execution_context();
394+
PLyExecutionContext*exec_ctx=(PLyExecutionContext*)arg;
395395

396396
if (exec_ctx->curr_proc)
397397
{

‎src/pl/plpython/plpy_procedure.c

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,9 +47,7 @@ init_procedure_caches(void)
4747
}
4848

4949
/*
50-
* Get the name of the last procedure called by the backend (the
51-
* innermost, if a plpython procedure call calls the backend and the
52-
* backend calls another plpython procedure).
50+
* PLy_procedure_name: get the name of the specified procedure.
5351
*
5452
* NB: this returns the SQL name, not the internal Python procedure name
5553
*/

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

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -328,3 +328,19 @@ EXCEPTION WHEN SQLSTATE 'SILLY' THEN
328328
-- NOOP
329329
END
330330
$$ LANGUAGE plpgsql;
331+
332+
/* test the context stack trace for nested execution levels
333+
*/
334+
CREATEFUNCTIONnotice_innerfunc() RETURNSintAS $$
335+
plpy.execute("DO LANGUAGE plpythonu $x$ plpy.notice('inside DO') $x$")
336+
return1
337+
$$ LANGUAGE plpythonu;
338+
339+
CREATEFUNCTIONnotice_outerfunc() RETURNSintAS $$
340+
plpy.execute("SELECT notice_innerfunc()")
341+
return1
342+
$$ LANGUAGE plpythonu;
343+
344+
\set SHOW_CONTEXT always
345+
346+
SELECT notice_outerfunc();

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp