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

Commit8c57229

Browse files
committed
Fix error handling in pltcl_returnnext.
We can't throw elog(ERROR) out of a Tcl command procedure; we haveto catch the error and return TCL_ERROR to the Tcl interpreter.pltcl_returnnext failed to meet this requirement, so that errorsdetected by pltcl_build_tuple_result or other functions called hereled to longjmp'ing out of the Tcl interpreter and thereby leaving itin a bad state. Use the existing subtransaction support to preventthat. Oversight in commit26abb50, found more or less accidentallyby the buildfarm thanks to the tests added in961bed0.Report:https://postgr.es/m/30647.1483989734@sss.pgh.pa.us
1 parent3957b58 commit8c57229

File tree

1 file changed

+59
-40
lines changed

1 file changed

+59
-40
lines changed

‎src/pl/tcl/pltcl.c

Lines changed: 59 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -299,6 +299,14 @@ static int pltcl_SPI_execute_plan(ClientData cdata, Tcl_Interp *interp,
299299
staticintpltcl_SPI_lastoid(ClientDatacdata,Tcl_Interp*interp,
300300
intobjc,Tcl_Obj*constobjv[]);
301301

302+
staticvoidpltcl_subtrans_begin(MemoryContextoldcontext,
303+
ResourceOwneroldowner);
304+
staticvoidpltcl_subtrans_commit(MemoryContextoldcontext,
305+
ResourceOwneroldowner);
306+
staticvoidpltcl_subtrans_abort(Tcl_Interp*interp,
307+
MemoryContextoldcontext,
308+
ResourceOwneroldowner);
309+
302310
staticvoidpltcl_set_tuple_values(Tcl_Interp*interp,constchar*arrayname,
303311
uint64tupno,HeapTupletuple,TupleDesctupdesc);
304312
staticTcl_Obj*pltcl_build_tuple_argument(HeapTupletuple,TupleDesctupdesc);
@@ -2073,9 +2081,9 @@ pltcl_returnnext(ClientData cdata, Tcl_Interp *interp,
20732081
pltcl_call_state*call_state=pltcl_current_call_state;
20742082
FunctionCallInfofcinfo=call_state->fcinfo;
20752083
pltcl_proc_desc*prodesc=call_state->prodesc;
2076-
intresult=TCL_OK;
2077-
MemoryContexttmpcxt;
2078-
MemoryContextoldcxt;
2084+
MemoryContextoldcontext=CurrentMemoryContext;
2085+
ResourceOwneroldowner=CurrentResourceOwner;
2086+
volatileintresult=TCL_OK;
20792087

20802088
/*
20812089
* Check that we're called as a set-returning function
@@ -2103,52 +2111,63 @@ pltcl_returnnext(ClientData cdata, Tcl_Interp *interp,
21032111
returnTCL_ERROR;
21042112
}
21052113

2106-
/* Set up tuple store if first output row */
2107-
if (call_state->tuple_store==NULL)
2108-
pltcl_init_tuple_store(call_state);
2114+
/*
2115+
* The rest might throw elog(ERROR), so must run in a subtransaction.
2116+
*
2117+
* A small advantage of using a subtransaction is that it provides a
2118+
* short-lived memory context for free, so we needn't worry about leaking
2119+
* memory here. To use that context, call BeginInternalSubTransaction
2120+
* directly instead of going through pltcl_subtrans_begin.
2121+
*/
2122+
BeginInternalSubTransaction(NULL);
2123+
PG_TRY();
2124+
{
2125+
/* Set up tuple store if first output row */
2126+
if (call_state->tuple_store==NULL)
2127+
pltcl_init_tuple_store(call_state);
21092128

2110-
/* Make short-lived context to run input functions in */
2111-
tmpcxt=AllocSetContextCreate(CurrentMemoryContext,
2112-
"pltcl_returnnext",
2113-
ALLOCSET_SMALL_SIZES);
2114-
oldcxt=MemoryContextSwitchTo(tmpcxt);
2129+
if (prodesc->fn_retistuple)
2130+
{
2131+
Tcl_Obj**rowObjv;
2132+
introwObjc;
21152133

2116-
if (prodesc->fn_retistuple)
2117-
{
2118-
Tcl_Obj**rowObjv;
2119-
introwObjc;
2134+
/* result should be a list, so break it down */
2135+
if (Tcl_ListObjGetElements(interp,objv[1],&rowObjc,&rowObjv)==TCL_ERROR)
2136+
result=TCL_ERROR;
2137+
else
2138+
{
2139+
HeapTupletuple;
21202140

2121-
/* result should be a list, so break it down */
2122-
if (Tcl_ListObjGetElements(interp,objv[1],&rowObjc,&rowObjv)==TCL_ERROR)
2123-
result=TCL_ERROR;
2141+
tuple=pltcl_build_tuple_result(interp,rowObjv,rowObjc,
2142+
call_state);
2143+
tuplestore_puttuple(call_state->tuple_store,tuple);
2144+
}
2145+
}
21242146
else
21252147
{
2126-
HeapTupletuple;
2127-
2128-
tuple=pltcl_build_tuple_result(interp,rowObjv,rowObjc,
2129-
call_state);
2130-
tuplestore_puttuple(call_state->tuple_store,tuple);
2148+
Datumretval;
2149+
boolisNull= false;
2150+
2151+
/* for paranoia's sake, check that tupdesc has exactly one column */
2152+
if (call_state->ret_tupdesc->natts!=1)
2153+
elog(ERROR,"wrong result type supplied in return_next");
2154+
2155+
retval=InputFunctionCall(&prodesc->result_in_func,
2156+
utf_u2e((char*)Tcl_GetString(objv[1])),
2157+
prodesc->result_typioparam,
2158+
-1);
2159+
tuplestore_putvalues(call_state->tuple_store,call_state->ret_tupdesc,
2160+
&retval,&isNull);
21312161
}
2162+
2163+
pltcl_subtrans_commit(oldcontext,oldowner);
21322164
}
2133-
else
2165+
PG_CATCH();
21342166
{
2135-
Datumretval;
2136-
boolisNull= false;
2137-
2138-
/* for paranoia's sake, check that tupdesc has exactly one column */
2139-
if (call_state->ret_tupdesc->natts!=1)
2140-
elog(ERROR,"wrong result type supplied in return_next");
2141-
2142-
retval=InputFunctionCall(&prodesc->result_in_func,
2143-
utf_u2e((char*)Tcl_GetString(objv[1])),
2144-
prodesc->result_typioparam,
2145-
-1);
2146-
tuplestore_putvalues(call_state->tuple_store,call_state->ret_tupdesc,
2147-
&retval,&isNull);
2167+
pltcl_subtrans_abort(interp,oldcontext,oldowner);
2168+
returnTCL_ERROR;
21482169
}
2149-
2150-
MemoryContextSwitchTo(oldcxt);
2151-
MemoryContextDelete(tmpcxt);
2170+
PG_END_TRY();
21522171

21532172
returnresult;
21542173
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp