Skip to content

Commit bf06336

Browse files
committed
Fix pipelined preparation
We can end up double-preparing the typeinfo queries if we're pipelining preparation, so pick a unique name for them.
1 parent 53657b8 commit bf06336

File tree

5 files changed

+20
-38
lines changed

5 files changed

+20
-38
lines changed

tokio-postgres/src/lib.rs

+5-2
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,10 @@ pub mod tls;
4444

4545
static NEXT_STATEMENT_ID: AtomicUsize = AtomicUsize::new(0);
4646

47+
fn next_statement() -> String {
48+
format!("s{}", NEXT_STATEMENT_ID.fetch_add(1, Ordering::SeqCst))
49+
}
50+
4751
fn bad_response() -> Error {
4852
Error::from(io::Error::new(
4953
io::ErrorKind::InvalidInput,
@@ -80,8 +84,7 @@ impl Client {
8084
}
8185

8286
pub fn prepare_typed(&mut self, query: &str, param_types: &[Type]) -> Prepare {
83-
let name = format!("s{}", NEXT_STATEMENT_ID.fetch_add(1, Ordering::SeqCst));
84-
Prepare(self.0.prepare(name, query, param_types))
87+
Prepare(self.0.prepare(next_statement(), query, param_types))
8588
}
8689

8790
pub fn execute(&mut self, statement: &Statement, params: &[&ToSql]) -> Execute {

tokio-postgres/src/proto/typeinfo.rs

+3-9
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,14 @@ use futures::stream::{self, Stream};
22
use futures::{Async, Future, Poll};
33
use state_machine_future::RentToOwn;
44

5-
use bad_response;
65
use error::{Error, SqlState};
76
use proto::client::Client;
87
use proto::prepare::PrepareFuture;
98
use proto::query::QueryStream;
109
use proto::typeinfo_composite::TypeinfoCompositeFuture;
1110
use proto::typeinfo_enum::TypeinfoEnumFuture;
1211
use types::{Kind, Oid, Type};
13-
14-
const TYPEINFO_NAME: &'static str = "_rust_typeinfo";
12+
use {bad_response, next_statement};
1513

1614
const TYPEINFO_QUERY: &'static str = "
1715
SELECT t.typname, t.typtype, t.typelem, r.rngsubtype, t.typbasetype, n.nspname, t.typrelid
@@ -125,11 +123,7 @@ impl PollTypeinfo for Typeinfo {
125123
client: state.client,
126124
}),
127125
None => transition!(PreparingTypeinfo {
128-
future: Box::new(state.client.prepare(
129-
TYPEINFO_NAME.to_string(),
130-
TYPEINFO_QUERY,
131-
&[]
132-
)),
126+
future: Box::new(state.client.prepare(next_statement(), TYPEINFO_QUERY, &[])),
133127
oid: state.oid,
134128
client: state.client,
135129
}),
@@ -147,7 +141,7 @@ impl PollTypeinfo for Typeinfo {
147141

148142
transition!(PreparingTypeinfoFallback {
149143
future: Box::new(state.client.prepare(
150-
TYPEINFO_NAME.to_string(),
144+
next_statement(),
151145
TYPEINFO_FALLBACK_QUERY,
152146
&[]
153147
)),

tokio-postgres/src/proto/typeinfo_composite.rs

+2-4
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,13 @@ use state_machine_future::RentToOwn;
44
use std::mem;
55
use std::vec;
66

7-
use bad_response;
87
use error::Error;
98
use proto::client::Client;
109
use proto::prepare::PrepareFuture;
1110
use proto::query::QueryStream;
1211
use proto::typeinfo::TypeinfoFuture;
1312
use types::{Field, Oid};
14-
15-
const TYPEINFO_COMPOSITE_NAME: &'static str = "_rust_typeinfo_composite";
13+
use {bad_response, next_statement};
1614

1715
const TYPEINFO_COMPOSITE_QUERY: &'static str = "
1816
SELECT attname, atttypid
@@ -65,7 +63,7 @@ impl PollTypeinfoComposite for TypeinfoComposite {
6563
}),
6664
None => transition!(PreparingTypeinfoComposite {
6765
future: Box::new(state.client.prepare(
68-
TYPEINFO_COMPOSITE_NAME.to_string(),
66+
next_statement(),
6967
TYPEINFO_COMPOSITE_QUERY,
7068
&[]
7169
)),

tokio-postgres/src/proto/typeinfo_enum.rs

+7-9
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,12 @@ use futures::stream::{self, Stream};
22
use futures::{Async, Future, Poll};
33
use state_machine_future::RentToOwn;
44

5-
use bad_response;
65
use error::{Error, SqlState};
76
use proto::client::Client;
87
use proto::prepare::PrepareFuture;
98
use proto::query::QueryStream;
109
use types::Oid;
11-
12-
const TYPEINFO_ENUM_NAME: &'static str = "_rust_typeinfo_enum";
10+
use {bad_response, next_statement};
1311

1412
const TYPEINFO_ENUM_QUERY: &'static str = "
1513
SELECT enumlabel
@@ -66,11 +64,11 @@ impl PollTypeinfoEnum for TypeinfoEnum {
6664
client: state.client,
6765
}),
6866
None => transition!(PreparingTypeinfoEnum {
69-
future: Box::new(state.client.prepare(
70-
TYPEINFO_ENUM_NAME.to_string(),
71-
TYPEINFO_ENUM_QUERY,
72-
&[]
73-
)),
67+
future: Box::new(
68+
state
69+
.client
70+
.prepare(next_statement(), TYPEINFO_ENUM_QUERY, &[])
71+
),
7472
oid: state.oid,
7573
client: state.client,
7674
}),
@@ -88,7 +86,7 @@ impl PollTypeinfoEnum for TypeinfoEnum {
8886

8987
transition!(PreparingTypeinfoEnumFallback {
9088
future: Box::new(state.client.prepare(
91-
TYPEINFO_ENUM_NAME.to_string(),
89+
next_statement(),
9290
TYPEINFO_ENUM_FALLBACK_QUERY,
9391
&[]
9492
)),

tokio-postgres/tests/test.rs

+3-14
Original file line numberDiff line numberDiff line change
@@ -163,22 +163,11 @@ fn pipelined_prepare() {
163163
let connection = connection.map_err(|e| panic!("{}", e));
164164
runtime.handle().spawn(connection).unwrap();
165165

166-
let prepare1 = client.prepare("SELECT 1::BIGINT WHERE $1::BOOL");
167-
let prepare2 = client.prepare("SELECT ''::TEXT, 1::FLOAT4 WHERE $1::VARCHAR IS NOT NULL");
166+
let prepare1 = client.prepare("SELECT $1::HSTORE[]");
167+
let prepare2 = client.prepare("SELECT $1::HSTORE[]");
168168
let prepare = prepare1.join(prepare2);
169-
let (statement1, statement2) = runtime.block_on(prepare).unwrap();
169+
runtime.block_on(prepare).unwrap();
170170

171-
assert_eq!(statement1.params(), &[Type::BOOL]);
172-
assert_eq!(statement1.columns().len(), 1);
173-
assert_eq!(statement1.columns()[0].type_(), &Type::INT8);
174-
175-
assert_eq!(statement2.params(), &[Type::VARCHAR]);
176-
assert_eq!(statement2.columns().len(), 2);
177-
assert_eq!(statement2.columns()[0].type_(), &Type::TEXT);
178-
assert_eq!(statement2.columns()[1].type_(), &Type::FLOAT4);
179-
180-
drop(statement1);
181-
drop(statement2);
182171
drop(client);
183172
runtime.run().unwrap();
184173
}

0 commit comments

Comments
 (0)