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

Commitce1e7a2

Browse files
committed
Don't let libpq "event" procs break the state of PGresult objects.
As currently implemented, failure of a PGEVT_RESULTCREATE callbackcauses the PGresult to be converted to an error result. This isintellectually inconsistent (shouldn't a failing callback likewiseprevent creation of the error result? what about side-effects on thebehavior seen by other event procs? why does PQfireResultCreateEventsact differently from PQgetResult?), but more importantly it destroysany promises we might wish to make about the behavior of libpq innontrivial operating modes, such as pipeline mode. For example,it's not possible to promise that PGRES_PIPELINE_SYNC results willbe returned if an event callback fails on those. With thisdefinition, expecting applications to behave sanely in the face ofpossibly-failing callbacks seems like a very big lift.Hence, redefine the result of a callback failure as being simplythat that event procedure won't be called any more for this PGresult(which was true already). Event procedures can still signal failureback to the application through out-of-band mechanisms, for examplevia their passthrough arguments.Similarly, don't let failure of a PGEVT_RESULTCOPY callback preventPQcopyResult from succeeding. That definition allowed a misbehavingevent proc to break single-row mode (our sole internal use ofPQcopyResult), and it probably had equally deleterious effects foroutside uses.Discussion:https://postgr.es/m/3185105.1644960083@sss.pgh.pa.us
1 parentde447bb commitce1e7a2

File tree

3 files changed

+31
-51
lines changed

3 files changed

+31
-51
lines changed

‎doc/src/sgml/libpq.sgml

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -6831,6 +6831,7 @@ PGresult *PQcopyResult(const PGresult *src, int flags);
68316831
<literal>PG_COPYRES_EVENTS</literal> specifies copying the source
68326832
result's events. (But any instance data associated with the source
68336833
is not copied.)
6834+
The event procedures receive <literal>PGEVT_RESULTCOPY</literal> events.
68346835
</para>
68356836
</listitem>
68366837
</varlistentry>
@@ -7126,7 +7127,7 @@ defaultNoticeProcessor(void *arg, const char *message)
71267127
<xref linkend="libpq-PQinstanceData"/>,
71277128
<xref linkend="libpq-PQsetInstanceData"/>,
71287129
<xref linkend="libpq-PQresultInstanceData"/> and
7129-
<function>PQsetResultInstanceData</function> functions. Note that
7130+
<xref linkend="libpq-PQresultSetInstanceData"/> functions. Note that
71307131
unlike the pass-through pointer, instance data of a <structname>PGconn</structname>
71317132
is not automatically inherited by <structname>PGresult</structname>s created from
71327133
it. <application>libpq</application> does not know what pass-through
@@ -7154,7 +7155,7 @@ defaultNoticeProcessor(void *arg, const char *message)
71547155
is called. It is the ideal time to initialize any
71557156
<literal>instanceData</literal> an event procedure may need. Only one
71567157
register event will be fired per event handler per connection. If the
7157-
event procedure fails, the registration isaborted.
7158+
event procedure fails (returns zero), the registration iscancelled.
71587159

71597160
<synopsis>
71607161
typedef struct
@@ -7261,11 +7262,11 @@ typedef struct
72617262
<parameter>conn</parameter> is the connection used to generate the
72627263
result. This is the ideal place to initialize any
72637264
<literal>instanceData</literal> that needs to be associated with the
7264-
result. Ifthe event procedure fails, the result will be cleared and
7265-
the failurewill bepropagated. The event procedure must not try to
7266-
<xref linkend="libpq-PQclear"/> the result object for itself. When returning a
7267-
failure code, all cleanup must be performed as no
7268-
<literal>PGEVT_RESULTDESTROY</literal> event will be sent.
7265+
result. Ifan event procedure fails (returns zero), that event
7266+
procedurewill beignored for the remaining lifetime of the result;
7267+
that is, it will not receive <literal>PGEVT_RESULTCOPY</literal>
7268+
or <literal>PGEVT_RESULTDESTROY</literal> events for this result or
7269+
results copied from it.
72697270
</para>
72707271
</listitem>
72717272
</varlistentry>
@@ -7295,12 +7296,12 @@ typedef struct
72957296
<parameter>src</parameter> result is what was copied while the
72967297
<parameter>dest</parameter> result is the copy destination. This event
72977298
can be used to provide a deep copy of <literal>instanceData</literal>,
7298-
since <literal>PQcopyResult</literal> cannot do that. Ifthe event
7299-
procedure fails, the entire copy operationwillfail and the
7300-
<parameter>dest</parameter> result will be cleared. When returning a
7301-
failure code, all cleanup must be performed as no
7302-
<literal>PGEVT_RESULTDESTROY</literal>event will be sent for the
7303-
destination result.
7299+
since <literal>PQcopyResult</literal> cannot do that. Ifan event
7300+
procedure fails (returns zero), that event procedurewillbe
7301+
ignored for the remaining lifetime of the new result; that is, it
7302+
will not receive <literal>PGEVT_RESULTCOPY</literal>
7303+
or<literal>PGEVT_RESULTDESTROY</literal>events for that result or
7304+
results copied from it.
73047305
</para>
73057306
</listitem>
73067307
</varlistentry>
@@ -7618,7 +7619,7 @@ myEventProc(PGEventId evtId, void *evtInfo, void *passThrough)
76187619
mydata *res_data = dup_mydata(conn_data);
76197620

76207621
/* associate app specific data with result (copy it from conn) */
7621-
PQsetResultInstanceData(e->result, myEventProc, res_data);
7622+
PQresultSetInstanceData(e->result, myEventProc, res_data);
76227623
break;
76237624
}
76247625

@@ -7629,7 +7630,7 @@ myEventProc(PGEventId evtId, void *evtInfo, void *passThrough)
76297630
mydata *dest_data = dup_mydata(src_data);
76307631

76317632
/* associate app specific data with result (copy it from a result) */
7632-
PQsetResultInstanceData(e->dest, myEventProc, dest_data);
7633+
PQresultSetInstanceData(e->dest, myEventProc, dest_data);
76337634
break;
76347635
}
76357636

‎src/interfaces/libpq/fe-exec.c

Lines changed: 7 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -363,19 +363,16 @@ PQcopyResult(const PGresult *src, int flags)
363363
/* Okay, trigger PGEVT_RESULTCOPY event */
364364
for (i=0;i<dest->nEvents;i++)
365365
{
366+
/* We don't fire events that had some previous failure */
366367
if (src->events[i].resultInitialized)
367368
{
368369
PGEventResultCopyevt;
369370

370371
evt.src=src;
371372
evt.dest=dest;
372-
if (!dest->events[i].proc(PGEVT_RESULTCOPY,&evt,
373-
dest->events[i].passThrough))
374-
{
375-
PQclear(dest);
376-
returnNULL;
377-
}
378-
dest->events[i].resultInitialized= true;
373+
if (dest->events[i].proc(PGEVT_RESULTCOPY,&evt,
374+
dest->events[i].passThrough))
375+
dest->events[i].resultInitialized= true;
379376
}
380377
}
381378

@@ -2124,29 +2121,9 @@ PQgetResult(PGconn *conn)
21242121
break;
21252122
}
21262123

2127-
if (res)
2128-
{
2129-
inti;
2130-
2131-
for (i=0;i<res->nEvents;i++)
2132-
{
2133-
PGEventResultCreateevt;
2134-
2135-
evt.conn=conn;
2136-
evt.result=res;
2137-
if (!res->events[i].proc(PGEVT_RESULTCREATE,&evt,
2138-
res->events[i].passThrough))
2139-
{
2140-
appendPQExpBuffer(&conn->errorMessage,
2141-
libpq_gettext("PGEventProc \"%s\" failed during PGEVT_RESULTCREATE event\n"),
2142-
res->events[i].name);
2143-
pqSetResultError(res,&conn->errorMessage);
2144-
res->resultStatus=PGRES_FATAL_ERROR;
2145-
break;
2146-
}
2147-
res->events[i].resultInitialized= true;
2148-
}
2149-
}
2124+
/* Time to fire PGEVT_RESULTCREATE events, if there are any */
2125+
if (res&&res->nEvents>0)
2126+
(void)PQfireResultCreateEvents(conn,res);
21502127

21512128
returnres;
21522129
}

‎src/interfaces/libpq/libpq-events.c

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -184,26 +184,28 @@ PQresultInstanceData(const PGresult *result, PGEventProc proc)
184184
int
185185
PQfireResultCreateEvents(PGconn*conn,PGresult*res)
186186
{
187+
intresult= true;
187188
inti;
188189

189190
if (!res)
190191
return false;
191192

192193
for (i=0;i<res->nEvents;i++)
193194
{
195+
/* It's possible event was already fired, if so don't repeat it */
194196
if (!res->events[i].resultInitialized)
195197
{
196198
PGEventResultCreateevt;
197199

198200
evt.conn=conn;
199201
evt.result=res;
200-
if (!res->events[i].proc(PGEVT_RESULTCREATE,&evt,
201-
res->events[i].passThrough))
202-
return false;
203-
204-
res->events[i].resultInitialized=true;
202+
if (res->events[i].proc(PGEVT_RESULTCREATE,&evt,
203+
res->events[i].passThrough))
204+
res->events[i].resultInitialized= true;
205+
else
206+
result=false;
205207
}
206208
}
207209

208-
returntrue;
210+
returnresult;
209211
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp