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

Commit49281db

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 parente1a6679 commit49281db

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);
@@ -510,7 +511,6 @@ PG_FUNCTION_INFO_V1(dblink_fetch);
510511
Datum
511512
dblink_fetch(PG_FUNCTION_ARGS)
512513
{
513-
ReturnSetInfo*rsinfo= (ReturnSetInfo*)fcinfo->resultinfo;
514514
PGresult*res=NULL;
515515
char*conname=NULL;
516516
remoteConn*rconn=NULL;
@@ -520,6 +520,8 @@ dblink_fetch(PG_FUNCTION_ARGS)
520520
inthowmany=0;
521521
boolfail= true;/* default to backward compatible */
522522

523+
prepTuplestoreResult(fcinfo);
524+
523525
DBLINK_INIT;
524526

525527
if (PG_NARGS()==4)
@@ -566,11 +568,6 @@ dblink_fetch(PG_FUNCTION_ARGS)
566568
if (!conn)
567569
DBLINK_CONN_NOT_AVAIL;
568570

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

@@ -650,7 +647,6 @@ dblink_get_result(PG_FUNCTION_ARGS)
650647
staticDatum
651648
dblink_record_internal(FunctionCallInfofcinfo,boolis_async)
652649
{
653-
ReturnSetInfo*rsinfo= (ReturnSetInfo*)fcinfo->resultinfo;
654650
char*msg;
655651
PGresult*res=NULL;
656652
PGconn*conn=NULL;
@@ -661,16 +657,7 @@ dblink_record_internal(FunctionCallInfo fcinfo, bool is_async)
661657
boolfail= true;/* default to backward compatible */
662658
boolfreeconn= false;
663659

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

675662
DBLINK_INIT;
676663

@@ -730,11 +717,6 @@ dblink_record_internal(FunctionCallInfo fcinfo, bool is_async)
730717
if (!conn)
731718
DBLINK_CONN_NOT_AVAIL;
732719

733-
/* let the caller know we're sending back a tuplestore */
734-
rsinfo->returnMode=SFRM_Materialize;
735-
rsinfo->setResult=NULL;
736-
rsinfo->setDesc=NULL;
737-
738720
/* synchronous query, or async result retrieval */
739721
if (!is_async)
740722
res=PQexec(conn,sql);
@@ -763,14 +745,45 @@ dblink_record_internal(FunctionCallInfo fcinfo, bool is_async)
763745
}
764746

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

786+
/* prepTuplestoreResult must have been called previously */
774787
Assert(rsinfo->returnMode==SFRM_Materialize);
775788

776789
PG_TRY();
@@ -1022,85 +1035,97 @@ PG_FUNCTION_INFO_V1(dblink_exec);
10221035
Datum
10231036
dblink_exec(PG_FUNCTION_ARGS)
10241037
{
1025-
char*msg;
1026-
PGresult*res=NULL;
1027-
text*sql_cmd_status=NULL;
1028-
PGconn*conn=NULL;
1029-
char*connstr=NULL;
1030-
char*sql=NULL;
1031-
char*conname=NULL;
1032-
remoteConn*rconn=NULL;
1033-
boolfreeconn= false;
1034-
boolfail= true;/* default to backward compatible behavior */
1038+
text*volatilesql_cmd_status=NULL;
1039+
PGconn*volatileconn=NULL;
1040+
volatileboolfreeconn= false;
10351041

10361042
DBLINK_INIT;
10371043

1038-
if (PG_NARGS()==3)
1039-
{
1040-
/* must be text,text,bool */
1041-
DBLINK_GET_CONN;
1042-
sql=text_to_cstring(PG_GETARG_TEXT_PP(1));
1043-
fail=PG_GETARG_BOOL(2);
1044-
}
1045-
elseif (PG_NARGS()==2)
1044+
PG_TRY();
10461045
{
1047-
/* might be text,text or text,bool */
1048-
if (get_fn_expr_argtype(fcinfo->flinfo,1)==BOOLOID)
1046+
char*msg;
1047+
PGresult*res=NULL;
1048+
char*connstr=NULL;
1049+
char*sql=NULL;
1050+
char*conname=NULL;
1051+
remoteConn*rconn=NULL;
1052+
boolfail= true;/* default to backward compatible behavior */
1053+
1054+
if (PG_NARGS()==3)
10491055
{
1056+
/* must be text,text,bool */
1057+
DBLINK_GET_CONN;
1058+
sql=text_to_cstring(PG_GETARG_TEXT_PP(1));
1059+
fail=PG_GETARG_BOOL(2);
1060+
}
1061+
elseif (PG_NARGS()==2)
1062+
{
1063+
/* might be text,text or text,bool */
1064+
if (get_fn_expr_argtype(fcinfo->flinfo,1)==BOOLOID)
1065+
{
1066+
conn=pconn->conn;
1067+
sql=text_to_cstring(PG_GETARG_TEXT_PP(0));
1068+
fail=PG_GETARG_BOOL(1);
1069+
}
1070+
else
1071+
{
1072+
DBLINK_GET_CONN;
1073+
sql=text_to_cstring(PG_GETARG_TEXT_PP(1));
1074+
}
1075+
}
1076+
elseif (PG_NARGS()==1)
1077+
{
1078+
/* must be single text argument */
10501079
conn=pconn->conn;
10511080
sql=text_to_cstring(PG_GETARG_TEXT_PP(0));
1052-
fail=PG_GETARG_BOOL(1);
10531081
}
10541082
else
1055-
{
1056-
DBLINK_GET_CONN;
1057-
sql=text_to_cstring(PG_GETARG_TEXT_PP(1));
1058-
}
1059-
}
1060-
elseif (PG_NARGS()==1)
1061-
{
1062-
/* must be single text argument */
1063-
conn=pconn->conn;
1064-
sql=text_to_cstring(PG_GETARG_TEXT_PP(0));
1065-
}
1066-
else
1067-
/* shouldn't happen */
1068-
elog(ERROR,"wrong number of arguments");
1083+
/* shouldn't happen */
1084+
elog(ERROR,"wrong number of arguments");
10691085

1070-
if (!conn)
1071-
DBLINK_CONN_NOT_AVAIL;
1086+
if (!conn)
1087+
DBLINK_CONN_NOT_AVAIL;
10721088

1073-
res=PQexec(conn,sql);
1074-
if (!res||
1075-
(PQresultStatus(res)!=PGRES_COMMAND_OK&&
1076-
PQresultStatus(res)!=PGRES_TUPLES_OK))
1077-
{
1078-
dblink_res_error(conname,res,"could not execute command",fail);
1089+
res=PQexec(conn,sql);
1090+
if (!res||
1091+
(PQresultStatus(res)!=PGRES_COMMAND_OK&&
1092+
PQresultStatus(res)!=PGRES_TUPLES_OK))
1093+
{
1094+
dblink_res_error(conname,res,"could not execute command",fail);
10791095

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

1103-
/* if needed, close the connection to the databaseand cleanup*/
1128+
/* if needed, close the connection to the database */
11041129
if (freeconn)
11051130
PQfinish(conn);
11061131

@@ -1521,13 +1546,15 @@ dblink_get_notify(PG_FUNCTION_ARGS)
15211546
MemoryContextper_query_ctx;
15221547
MemoryContextoldcontext;
15231548

1549+
prepTuplestoreResult(fcinfo);
1550+
15241551
DBLINK_INIT;
15251552
if (PG_NARGS()==1)
15261553
DBLINK_GET_NAMED_CONN;
15271554
else
15281555
conn=pconn->conn;
15291556

1530-
/* create the tuplestore */
1557+
/* create the tuplestorein per-query memory*/
15311558
per_query_ctx=rsinfo->econtext->ecxt_per_query_memory;
15321559
oldcontext=MemoryContextSwitchTo(per_query_ctx);
15331560

@@ -1540,7 +1567,6 @@ dblink_get_notify(PG_FUNCTION_ARGS)
15401567
TEXTOID,-1,0);
15411568

15421569
tupstore=tuplestore_begin_heap(true, false,work_mem);
1543-
rsinfo->returnMode=SFRM_Materialize;
15441570
rsinfo->setResult=tupstore;
15451571
rsinfo->setDesc=tupdesc;
15461572

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp