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

Commit8d2a5fb

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 parent99e2076 commit8d2a5fb

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
@@ -81,6 +81,7 @@ typedef struct remoteConn
8181
* Internal declarations
8282
*/
8383
staticDatumdblink_record_internal(FunctionCallInfofcinfo,boolis_async);
84+
staticvoidprepTuplestoreResult(FunctionCallInfofcinfo);
8485
staticvoidmaterializeResult(FunctionCallInfofcinfo,PGresult*res);
8586
staticremoteConn*getConnectionByName(constchar*name);
8687
staticHTAB*createConnHash(void);
@@ -509,7 +510,6 @@ PG_FUNCTION_INFO_V1(dblink_fetch);
509510
Datum
510511
dblink_fetch(PG_FUNCTION_ARGS)
511512
{
512-
ReturnSetInfo*rsinfo= (ReturnSetInfo*)fcinfo->resultinfo;
513513
PGresult*res=NULL;
514514
char*conname=NULL;
515515
remoteConn*rconn=NULL;
@@ -519,6 +519,8 @@ dblink_fetch(PG_FUNCTION_ARGS)
519519
inthowmany=0;
520520
boolfail= true;/* default to backward compatible */
521521

522+
prepTuplestoreResult(fcinfo);
523+
522524
DBLINK_INIT;
523525

524526
if (PG_NARGS()==4)
@@ -565,11 +567,6 @@ dblink_fetch(PG_FUNCTION_ARGS)
565567
if (!conn)
566568
DBLINK_CONN_NOT_AVAIL;
567569

568-
/* let the caller know we're sending back a tuplestore */
569-
rsinfo->returnMode=SFRM_Materialize;
570-
rsinfo->setResult=NULL;
571-
rsinfo->setDesc=NULL;
572-
573570
initStringInfo(&buf);
574571
appendStringInfo(&buf,"FETCH %d FROM %s",howmany,curname);
575572

@@ -646,7 +643,6 @@ dblink_get_result(PG_FUNCTION_ARGS)
646643
staticDatum
647644
dblink_record_internal(FunctionCallInfofcinfo,boolis_async)
648645
{
649-
ReturnSetInfo*rsinfo= (ReturnSetInfo*)fcinfo->resultinfo;
650646
char*msg;
651647
PGresult*res=NULL;
652648
PGconn*conn=NULL;
@@ -657,16 +653,7 @@ dblink_record_internal(FunctionCallInfo fcinfo, bool is_async)
657653
boolfail= true;/* default to backward compatible */
658654
boolfreeconn= false;
659655

660-
/* check to see if caller supports us returning a tuplestore */
661-
if (rsinfo==NULL|| !IsA(rsinfo,ReturnSetInfo))
662-
ereport(ERROR,
663-
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
664-
errmsg("set-valued function called in context that cannot accept a set")));
665-
if (!(rsinfo->allowedModes&SFRM_Materialize))
666-
ereport(ERROR,
667-
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
668-
errmsg("materialize mode required, but it is not " \
669-
"allowed in this context")));
656+
prepTuplestoreResult(fcinfo);
670657

671658
DBLINK_INIT;
672659

@@ -726,11 +713,6 @@ dblink_record_internal(FunctionCallInfo fcinfo, bool is_async)
726713
if (!conn)
727714
DBLINK_CONN_NOT_AVAIL;
728715

729-
/* let the caller know we're sending back a tuplestore */
730-
rsinfo->returnMode=SFRM_Materialize;
731-
rsinfo->setResult=NULL;
732-
rsinfo->setDesc=NULL;
733-
734716
/* synchronous query, or async result retrieval */
735717
if (!is_async)
736718
res=PQexec(conn,sql);
@@ -759,14 +741,45 @@ dblink_record_internal(FunctionCallInfo fcinfo, bool is_async)
759741
}
760742

761743
/*
762-
* Materialize the PGresult to return them as the function result.
763-
* The res will be released in this function.
744+
* Verify function caller can handle a tuplestore result, and set up for that.
745+
*
746+
* Note: if the caller returns without actually creating a tuplestore, the
747+
* executor will treat the function result as an empty set.
748+
*/
749+
staticvoid
750+
prepTuplestoreResult(FunctionCallInfofcinfo)
751+
{
752+
ReturnSetInfo*rsinfo= (ReturnSetInfo*)fcinfo->resultinfo;
753+
754+
/* check to see if query supports us returning a tuplestore */
755+
if (rsinfo==NULL|| !IsA(rsinfo,ReturnSetInfo))
756+
ereport(ERROR,
757+
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
758+
errmsg("set-valued function called in context that cannot accept a set")));
759+
if (!(rsinfo->allowedModes&SFRM_Materialize))
760+
ereport(ERROR,
761+
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
762+
errmsg("materialize mode required, but it is not allowed in this context")));
763+
764+
/* let the executor know we're sending back a tuplestore */
765+
rsinfo->returnMode=SFRM_Materialize;
766+
767+
/* caller must fill these to return a non-empty result */
768+
rsinfo->setResult=NULL;
769+
rsinfo->setDesc=NULL;
770+
}
771+
772+
/*
773+
* Copy the contents of the PGresult into a tuplestore to be returned
774+
* as the result of the current function.
775+
* The PGresult will be released in this function.
764776
*/
765777
staticvoid
766778
materializeResult(FunctionCallInfofcinfo,PGresult*res)
767779
{
768780
ReturnSetInfo*rsinfo= (ReturnSetInfo*)fcinfo->resultinfo;
769781

782+
/* prepTuplestoreResult must have been called previously */
770783
Assert(rsinfo->returnMode==SFRM_Materialize);
771784

772785
PG_TRY();
@@ -1018,85 +1031,97 @@ PG_FUNCTION_INFO_V1(dblink_exec);
10181031
Datum
10191032
dblink_exec(PG_FUNCTION_ARGS)
10201033
{
1021-
char*msg;
1022-
PGresult*res=NULL;
1023-
text*sql_cmd_status=NULL;
1024-
PGconn*conn=NULL;
1025-
char*connstr=NULL;
1026-
char*sql=NULL;
1027-
char*conname=NULL;
1028-
remoteConn*rconn=NULL;
1029-
boolfreeconn= false;
1030-
boolfail= true;/* default to backward compatible behavior */
1034+
text*volatilesql_cmd_status=NULL;
1035+
PGconn*volatileconn=NULL;
1036+
volatileboolfreeconn= false;
10311037

10321038
DBLINK_INIT;
10331039

1034-
if (PG_NARGS()==3)
1035-
{
1036-
/* must be text,text,bool */
1037-
DBLINK_GET_CONN;
1038-
sql=text_to_cstring(PG_GETARG_TEXT_PP(1));
1039-
fail=PG_GETARG_BOOL(2);
1040-
}
1041-
elseif (PG_NARGS()==2)
1040+
PG_TRY();
10421041
{
1043-
/* might be text,text or text,bool */
1044-
if (get_fn_expr_argtype(fcinfo->flinfo,1)==BOOLOID)
1042+
char*msg;
1043+
PGresult*res=NULL;
1044+
char*connstr=NULL;
1045+
char*sql=NULL;
1046+
char*conname=NULL;
1047+
remoteConn*rconn=NULL;
1048+
boolfail= true;/* default to backward compatible behavior */
1049+
1050+
if (PG_NARGS()==3)
1051+
{
1052+
/* must be text,text,bool */
1053+
DBLINK_GET_CONN;
1054+
sql=text_to_cstring(PG_GETARG_TEXT_PP(1));
1055+
fail=PG_GETARG_BOOL(2);
1056+
}
1057+
elseif (PG_NARGS()==2)
1058+
{
1059+
/* might be text,text or text,bool */
1060+
if (get_fn_expr_argtype(fcinfo->flinfo,1)==BOOLOID)
1061+
{
1062+
conn=pconn->conn;
1063+
sql=text_to_cstring(PG_GETARG_TEXT_PP(0));
1064+
fail=PG_GETARG_BOOL(1);
1065+
}
1066+
else
1067+
{
1068+
DBLINK_GET_CONN;
1069+
sql=text_to_cstring(PG_GETARG_TEXT_PP(1));
1070+
}
1071+
}
1072+
elseif (PG_NARGS()==1)
10451073
{
1074+
/* must be single text argument */
10461075
conn=pconn->conn;
10471076
sql=text_to_cstring(PG_GETARG_TEXT_PP(0));
1048-
fail=PG_GETARG_BOOL(1);
10491077
}
10501078
else
1051-
{
1052-
DBLINK_GET_CONN;
1053-
sql=text_to_cstring(PG_GETARG_TEXT_PP(1));
1054-
}
1055-
}
1056-
elseif (PG_NARGS()==1)
1057-
{
1058-
/* must be single text argument */
1059-
conn=pconn->conn;
1060-
sql=text_to_cstring(PG_GETARG_TEXT_PP(0));
1061-
}
1062-
else
1063-
/* shouldn't happen */
1064-
elog(ERROR,"wrong number of arguments");
1079+
/* shouldn't happen */
1080+
elog(ERROR,"wrong number of arguments");
10651081

1066-
if (!conn)
1067-
DBLINK_CONN_NOT_AVAIL;
1082+
if (!conn)
1083+
DBLINK_CONN_NOT_AVAIL;
10681084

1069-
res=PQexec(conn,sql);
1070-
if (!res||
1071-
(PQresultStatus(res)!=PGRES_COMMAND_OK&&
1072-
PQresultStatus(res)!=PGRES_TUPLES_OK))
1073-
{
1074-
dblink_res_error(conname,res,"could not execute command",fail);
1085+
res=PQexec(conn,sql);
1086+
if (!res||
1087+
(PQresultStatus(res)!=PGRES_COMMAND_OK&&
1088+
PQresultStatus(res)!=PGRES_TUPLES_OK))
1089+
{
1090+
dblink_res_error(conname,res,"could not execute command",fail);
10751091

1076-
/*
1077-
* and save a copy of the command status string to return as our
1078-
* result tuple
1079-
*/
1080-
sql_cmd_status=cstring_to_text("ERROR");
1081-
}
1082-
elseif (PQresultStatus(res)==PGRES_COMMAND_OK)
1083-
{
1084-
/*
1085-
* and save a copy of the command status string to return as our
1086-
* result tuple
1087-
*/
1088-
sql_cmd_status=cstring_to_text(PQcmdStatus(res));
1089-
PQclear(res);
1092+
/*
1093+
* and save a copy of the command status string to return as our
1094+
* result tuple
1095+
*/
1096+
sql_cmd_status=cstring_to_text("ERROR");
1097+
}
1098+
elseif (PQresultStatus(res)==PGRES_COMMAND_OK)
1099+
{
1100+
/*
1101+
* and save a copy of the command status string to return as our
1102+
* result tuple
1103+
*/
1104+
sql_cmd_status=cstring_to_text(PQcmdStatus(res));
1105+
PQclear(res);
1106+
}
1107+
else
1108+
{
1109+
PQclear(res);
1110+
ereport(ERROR,
1111+
(errcode(ERRCODE_S_R_E_PROHIBITED_SQL_STATEMENT_ATTEMPTED),
1112+
errmsg("statement returning results not allowed")));
1113+
}
10901114
}
1091-
else
1115+
PG_CATCH();
10921116
{
1093-
PQclear(res);
1094-
ereport(ERROR,
1095-
(errcode(ERRCODE_S_R_E_PROHIBITED_SQL_STATEMENT_ATTEMPTED),
1096-
errmsg("statement returning results not allowed")));
1117+
/* if needed, close the connection to the database */
1118+
if (freeconn)
1119+
PQfinish(conn);
1120+
PG_RE_THROW();
10971121
}
1122+
PG_END_TRY();
10981123

1099-
/* if needed, close the connection to the databaseand cleanup*/
1124+
/* if needed, close the connection to the database */
11001125
if (freeconn)
11011126
PQfinish(conn);
11021127

@@ -1517,13 +1542,15 @@ dblink_get_notify(PG_FUNCTION_ARGS)
15171542
MemoryContextper_query_ctx;
15181543
MemoryContextoldcontext;
15191544

1545+
prepTuplestoreResult(fcinfo);
1546+
15201547
DBLINK_INIT;
15211548
if (PG_NARGS()==1)
15221549
DBLINK_GET_NAMED_CONN;
15231550
else
15241551
conn=pconn->conn;
15251552

1526-
/* create the tuplestore */
1553+
/* create the tuplestorein per-query memory*/
15271554
per_query_ctx=rsinfo->econtext->ecxt_per_query_memory;
15281555
oldcontext=MemoryContextSwitchTo(per_query_ctx);
15291556

@@ -1536,7 +1563,6 @@ dblink_get_notify(PG_FUNCTION_ARGS)
15361563
TEXTOID,-1,0);
15371564

15381565
tupstore=tuplestore_begin_heap(true, false,work_mem);
1539-
rsinfo->returnMode=SFRM_Materialize;
15401566
rsinfo->setResult=tupstore;
15411567
rsinfo->setDesc=tupdesc;
15421568

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp