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

Commitd843ed2

Browse files
committed
Fix a couple of contrib/dblink bugs.
dblink_exec leaked temporary database connections if any error occurredafter connection setup, for exampleSELECT dblink_exec('...connect string...', 'select 1/0');Add a PG_TRY block to ensure PQfinish gets done when it is needed.(dblink_record_internal is on the hairy edge of needing similar treatment,but seems not to be actively broken at the moment.)Also, in 9.0 and up, only one of the three functions using tuplestorereturn mode was properly checking that the query context would allowa tuplestore result.Noted while reviewing dblink patch. Back-patch to all supported branches.
1 parent5e86c61 commitd843ed2

File tree

1 file changed

+115
-89
lines changed

1 file changed

+115
-89
lines changed

‎contrib/dblink/dblink.c

Lines changed: 115 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ typedef struct remoteConn
6767
* Internal declarations
6868
*/
6969
staticDatumdblink_record_internal(FunctionCallInfofcinfo,boolis_async);
70+
staticvoidprepTuplestoreResult(FunctionCallInfofcinfo);
7071
staticvoidmaterializeResult(FunctionCallInfofcinfo,PGresult*res);
7172
staticremoteConn*getConnectionByName(constchar*name);
7273
staticHTAB*createConnHash(void);
@@ -495,7 +496,6 @@ PG_FUNCTION_INFO_V1(dblink_fetch);
495496
Datum
496497
dblink_fetch(PG_FUNCTION_ARGS)
497498
{
498-
ReturnSetInfo*rsinfo= (ReturnSetInfo*)fcinfo->resultinfo;
499499
PGresult*res=NULL;
500500
char*conname=NULL;
501501
remoteConn*rconn=NULL;
@@ -505,6 +505,8 @@ dblink_fetch(PG_FUNCTION_ARGS)
505505
inthowmany=0;
506506
boolfail= true;/* default to backward compatible */
507507

508+
prepTuplestoreResult(fcinfo);
509+
508510
DBLINK_INIT;
509511

510512
if (PG_NARGS()==4)
@@ -551,11 +553,6 @@ dblink_fetch(PG_FUNCTION_ARGS)
551553
if (!conn)
552554
DBLINK_CONN_NOT_AVAIL;
553555

554-
/* let the caller know we're sending back a tuplestore */
555-
rsinfo->returnMode=SFRM_Materialize;
556-
rsinfo->setResult=NULL;
557-
rsinfo->setDesc=NULL;
558-
559556
initStringInfo(&buf);
560557
appendStringInfo(&buf,"FETCH %d FROM %s",howmany,curname);
561558

@@ -632,7 +629,6 @@ dblink_get_result(PG_FUNCTION_ARGS)
632629
staticDatum
633630
dblink_record_internal(FunctionCallInfofcinfo,boolis_async)
634631
{
635-
ReturnSetInfo*rsinfo= (ReturnSetInfo*)fcinfo->resultinfo;
636632
char*msg;
637633
PGresult*res=NULL;
638634
PGconn*conn=NULL;
@@ -643,16 +639,7 @@ dblink_record_internal(FunctionCallInfo fcinfo, bool is_async)
643639
boolfail= true;/* default to backward compatible */
644640
boolfreeconn= false;
645641

646-
/* check to see if caller supports us returning a tuplestore */
647-
if (rsinfo==NULL|| !IsA(rsinfo,ReturnSetInfo))
648-
ereport(ERROR,
649-
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
650-
errmsg("set-valued function called in context that cannot accept a set")));
651-
if (!(rsinfo->allowedModes&SFRM_Materialize))
652-
ereport(ERROR,
653-
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
654-
errmsg("materialize mode required, but it is not " \
655-
"allowed in this context")));
642+
prepTuplestoreResult(fcinfo);
656643

657644
DBLINK_INIT;
658645

@@ -712,11 +699,6 @@ dblink_record_internal(FunctionCallInfo fcinfo, bool is_async)
712699
if (!conn)
713700
DBLINK_CONN_NOT_AVAIL;
714701

715-
/* let the caller know we're sending back a tuplestore */
716-
rsinfo->returnMode=SFRM_Materialize;
717-
rsinfo->setResult=NULL;
718-
rsinfo->setDesc=NULL;
719-
720702
/* synchronous query, or async result retrieval */
721703
if (!is_async)
722704
res=PQexec(conn,sql);
@@ -745,14 +727,45 @@ dblink_record_internal(FunctionCallInfo fcinfo, bool is_async)
745727
}
746728

747729
/*
748-
* Materialize the PGresult to return them as the function result.
749-
* The res will be released in this function.
730+
* Verify function caller can handle a tuplestore result, and set up for that.
731+
*
732+
* Note: if the caller returns without actually creating a tuplestore, the
733+
* executor will treat the function result as an empty set.
734+
*/
735+
staticvoid
736+
prepTuplestoreResult(FunctionCallInfofcinfo)
737+
{
738+
ReturnSetInfo*rsinfo= (ReturnSetInfo*)fcinfo->resultinfo;
739+
740+
/* check to see if query supports us returning a tuplestore */
741+
if (rsinfo==NULL|| !IsA(rsinfo,ReturnSetInfo))
742+
ereport(ERROR,
743+
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
744+
errmsg("set-valued function called in context that cannot accept a set")));
745+
if (!(rsinfo->allowedModes&SFRM_Materialize))
746+
ereport(ERROR,
747+
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
748+
errmsg("materialize mode required, but it is not allowed in this context")));
749+
750+
/* let the executor know we're sending back a tuplestore */
751+
rsinfo->returnMode=SFRM_Materialize;
752+
753+
/* caller must fill these to return a non-empty result */
754+
rsinfo->setResult=NULL;
755+
rsinfo->setDesc=NULL;
756+
}
757+
758+
/*
759+
* Copy the contents of the PGresult into a tuplestore to be returned
760+
* as the result of the current function.
761+
* The PGresult will be released in this function.
750762
*/
751763
staticvoid
752764
materializeResult(FunctionCallInfofcinfo,PGresult*res)
753765
{
754766
ReturnSetInfo*rsinfo= (ReturnSetInfo*)fcinfo->resultinfo;
755767

768+
/* prepTuplestoreResult must have been called previously */
756769
Assert(rsinfo->returnMode==SFRM_Materialize);
757770

758771
PG_TRY();
@@ -1004,85 +1017,97 @@ PG_FUNCTION_INFO_V1(dblink_exec);
10041017
Datum
10051018
dblink_exec(PG_FUNCTION_ARGS)
10061019
{
1007-
char*msg;
1008-
PGresult*res=NULL;
1009-
text*sql_cmd_status=NULL;
1010-
PGconn*conn=NULL;
1011-
char*connstr=NULL;
1012-
char*sql=NULL;
1013-
char*conname=NULL;
1014-
remoteConn*rconn=NULL;
1015-
boolfreeconn= false;
1016-
boolfail= true;/* default to backward compatible behavior */
1020+
text*volatilesql_cmd_status=NULL;
1021+
PGconn*volatileconn=NULL;
1022+
volatileboolfreeconn= false;
10171023

10181024
DBLINK_INIT;
10191025

1020-
if (PG_NARGS()==3)
1021-
{
1022-
/* must be text,text,bool */
1023-
DBLINK_GET_CONN;
1024-
sql=text_to_cstring(PG_GETARG_TEXT_PP(1));
1025-
fail=PG_GETARG_BOOL(2);
1026-
}
1027-
elseif (PG_NARGS()==2)
1026+
PG_TRY();
10281027
{
1029-
/* might be text,text or text,bool */
1030-
if (get_fn_expr_argtype(fcinfo->flinfo,1)==BOOLOID)
1028+
char*msg;
1029+
PGresult*res=NULL;
1030+
char*connstr=NULL;
1031+
char*sql=NULL;
1032+
char*conname=NULL;
1033+
remoteConn*rconn=NULL;
1034+
boolfail= true;/* default to backward compatible behavior */
1035+
1036+
if (PG_NARGS()==3)
1037+
{
1038+
/* must be text,text,bool */
1039+
DBLINK_GET_CONN;
1040+
sql=text_to_cstring(PG_GETARG_TEXT_PP(1));
1041+
fail=PG_GETARG_BOOL(2);
1042+
}
1043+
elseif (PG_NARGS()==2)
1044+
{
1045+
/* might be text,text or text,bool */
1046+
if (get_fn_expr_argtype(fcinfo->flinfo,1)==BOOLOID)
1047+
{
1048+
conn=pconn->conn;
1049+
sql=text_to_cstring(PG_GETARG_TEXT_PP(0));
1050+
fail=PG_GETARG_BOOL(1);
1051+
}
1052+
else
1053+
{
1054+
DBLINK_GET_CONN;
1055+
sql=text_to_cstring(PG_GETARG_TEXT_PP(1));
1056+
}
1057+
}
1058+
elseif (PG_NARGS()==1)
10311059
{
1060+
/* must be single text argument */
10321061
conn=pconn->conn;
10331062
sql=text_to_cstring(PG_GETARG_TEXT_PP(0));
1034-
fail=PG_GETARG_BOOL(1);
10351063
}
10361064
else
1037-
{
1038-
DBLINK_GET_CONN;
1039-
sql=text_to_cstring(PG_GETARG_TEXT_PP(1));
1040-
}
1041-
}
1042-
elseif (PG_NARGS()==1)
1043-
{
1044-
/* must be single text argument */
1045-
conn=pconn->conn;
1046-
sql=text_to_cstring(PG_GETARG_TEXT_PP(0));
1047-
}
1048-
else
1049-
/* shouldn't happen */
1050-
elog(ERROR,"wrong number of arguments");
1065+
/* shouldn't happen */
1066+
elog(ERROR,"wrong number of arguments");
10511067

1052-
if (!conn)
1053-
DBLINK_CONN_NOT_AVAIL;
1068+
if (!conn)
1069+
DBLINK_CONN_NOT_AVAIL;
10541070

1055-
res=PQexec(conn,sql);
1056-
if (!res||
1057-
(PQresultStatus(res)!=PGRES_COMMAND_OK&&
1058-
PQresultStatus(res)!=PGRES_TUPLES_OK))
1059-
{
1060-
dblink_res_error(conname,res,"could not execute command",fail);
1071+
res=PQexec(conn,sql);
1072+
if (!res||
1073+
(PQresultStatus(res)!=PGRES_COMMAND_OK&&
1074+
PQresultStatus(res)!=PGRES_TUPLES_OK))
1075+
{
1076+
dblink_res_error(conname,res,"could not execute command",fail);
10611077

1062-
/*
1063-
* and save a copy of the command status string to return as our
1064-
* result tuple
1065-
*/
1066-
sql_cmd_status=cstring_to_text("ERROR");
1067-
}
1068-
elseif (PQresultStatus(res)==PGRES_COMMAND_OK)
1069-
{
1070-
/*
1071-
* and save a copy of the command status string to return as our
1072-
* result tuple
1073-
*/
1074-
sql_cmd_status=cstring_to_text(PQcmdStatus(res));
1075-
PQclear(res);
1078+
/*
1079+
* and save a copy of the command status string to return as our
1080+
* result tuple
1081+
*/
1082+
sql_cmd_status=cstring_to_text("ERROR");
1083+
}
1084+
elseif (PQresultStatus(res)==PGRES_COMMAND_OK)
1085+
{
1086+
/*
1087+
* and save a copy of the command status string to return as our
1088+
* result tuple
1089+
*/
1090+
sql_cmd_status=cstring_to_text(PQcmdStatus(res));
1091+
PQclear(res);
1092+
}
1093+
else
1094+
{
1095+
PQclear(res);
1096+
ereport(ERROR,
1097+
(errcode(ERRCODE_S_R_E_PROHIBITED_SQL_STATEMENT_ATTEMPTED),
1098+
errmsg("statement returning results not allowed")));
1099+
}
10761100
}
1077-
else
1101+
PG_CATCH();
10781102
{
1079-
PQclear(res);
1080-
ereport(ERROR,
1081-
(errcode(ERRCODE_S_R_E_PROHIBITED_SQL_STATEMENT_ATTEMPTED),
1082-
errmsg("statement returning results not allowed")));
1103+
/* if needed, close the connection to the database */
1104+
if (freeconn)
1105+
PQfinish(conn);
1106+
PG_RE_THROW();
10831107
}
1108+
PG_END_TRY();
10841109

1085-
/* if needed, close the connection to the databaseand cleanup*/
1110+
/* if needed, close the connection to the database */
10861111
if (freeconn)
10871112
PQfinish(conn);
10881113

@@ -1503,13 +1528,15 @@ dblink_get_notify(PG_FUNCTION_ARGS)
15031528
MemoryContextper_query_ctx;
15041529
MemoryContextoldcontext;
15051530

1531+
prepTuplestoreResult(fcinfo);
1532+
15061533
DBLINK_INIT;
15071534
if (PG_NARGS()==1)
15081535
DBLINK_GET_NAMED_CONN;
15091536
else
15101537
conn=pconn->conn;
15111538

1512-
/* create the tuplestore */
1539+
/* create the tuplestorein per-query memory*/
15131540
per_query_ctx=rsinfo->econtext->ecxt_per_query_memory;
15141541
oldcontext=MemoryContextSwitchTo(per_query_ctx);
15151542

@@ -1522,7 +1549,6 @@ dblink_get_notify(PG_FUNCTION_ARGS)
15221549
TEXTOID,-1,0);
15231550

15241551
tupstore=tuplestore_begin_heap(true, false,work_mem);
1525-
rsinfo->returnMode=SFRM_Materialize;
15261552
rsinfo->setResult=tupstore;
15271553
rsinfo->setDesc=tupdesc;
15281554

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp