Skip to content

Commit 04884f1

Browse files
authored
close unnamed portal after each executed extended query (launchbadge#2081)
This allows to free server resources earlier and run the same logic as simple Query does: "The simple Query message is approximately equivalent to the series Parse, Bind, portal Describe, Execute, Close, Sync,"
1 parent 20877d8 commit 04884f1

File tree

2 files changed

+27
-6
lines changed

2 files changed

+27
-6
lines changed

sqlx-core/src/postgres/connection/executor.rs

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,6 @@ impl PgConnection {
134134
message if message.format == MessageFormat::PortalSuspended => {
135135
// there was an open portal
136136
// this can happen if the last time a statement was used it was not fully executed
137-
// such as in [fetch_one]
138137
}
139138

140139
message if message.format == MessageFormat::CloseComplete => {
@@ -219,8 +218,7 @@ impl PgConnection {
219218
// patch holes created during encoding
220219
arguments.apply_patches(self, &metadata.parameters).await?;
221220

222-
// apply patches use fetch_optional thaht may produce `PortalSuspended` message,
223-
// consume messages til `ReadyForQuery` before bind and execute
221+
// consume messages till `ReadyForQuery` before bind and execute
224222
self.wait_until_ready().await?;
225223

226224
// bind to attach the arguments to the statement and create a portal
@@ -239,6 +237,16 @@ impl PgConnection {
239237
portal: None,
240238
limit: limit.into(),
241239
});
240+
// From https://www.postgresql.org/docs/current/protocol-flow.html:
241+
//
242+
// "An unnamed portal is destroyed at the end of the transaction, or as
243+
// soon as the next Bind statement specifying the unnamed portal as
244+
// destination is issued. (Note that a simple Query message also
245+
// destroys the unnamed portal."
246+
247+
// we ask the database server to close the unnamed portal and free the associated resources
248+
// earlier - after the execution of the current query.
249+
self.stream.write(message::Close::Portal(None));
242250

243251
// finally, [Sync] asks postgres to process the messages that we sent and respond with
244252
// a [ReadyForQuery] message when it's completely done. Theoretically, we could send
@@ -271,10 +279,17 @@ impl PgConnection {
271279
MessageFormat::BindComplete
272280
| MessageFormat::ParseComplete
273281
| MessageFormat::ParameterDescription
274-
| MessageFormat::NoData => {
282+
| MessageFormat::NoData
283+
// unnamed portal has been closed
284+
| MessageFormat::CloseComplete
285+
=> {
275286
// harmless messages to ignore
276287
}
277288

289+
// "Execute phase is always terminated by the appearance of
290+
// exactly one of these messages: CommandComplete,
291+
// EmptyQueryResponse (if the portal was created from an
292+
// empty query string), ErrorResponse, or PortalSuspended"
278293
MessageFormat::CommandComplete => {
279294
// a SQL command completed normally
280295
let cc: CommandComplete = message.decode()?;
@@ -290,6 +305,11 @@ impl PgConnection {
290305
// empty query string passed to an unprepared execute
291306
}
292307

308+
// Message::ErrorResponse is handled in self.stream.recv()
309+
310+
// incomplete query execution has finished
311+
MessageFormat::PortalSuspended => {}
312+
293313
MessageFormat::RowDescription => {
294314
// indicates that a *new* set of rows are about to be returned
295315
let (columns, column_names) = self

sqlx-core/src/postgres/message/close.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@ const CLOSE_STATEMENT: u8 = b'S';
99
#[allow(dead_code)]
1010
pub enum Close {
1111
Statement(Oid),
12-
Portal(Oid),
12+
// None selects the unnamed portal
13+
Portal(Option<Oid>),
1314
}
1415

1516
impl Encode<'_> for Close {
@@ -26,7 +27,7 @@ impl Encode<'_> for Close {
2627

2728
Close::Portal(id) => {
2829
buf.push(CLOSE_PORTAL);
29-
buf.put_portal_name(Some(*id));
30+
buf.put_portal_name(*id);
3031
}
3132
})
3233
}

0 commit comments

Comments
 (0)