Skip to content

Commit d011bb2

Browse files
jwilmsfackler
authored andcommitted
Make Rows a fully owned type (sfackler#264)
* Make Rows a fully owned type This allows Rows to outlive a statement and be sent to 'static threads. Resolves sfackler#263. * fixup! Make Rows a fully owned type * Remove unneeded Debug impl * Oops, we do actually need this :(
1 parent 06a6273 commit d011bb2

File tree

5 files changed

+54
-55
lines changed

5 files changed

+54
-55
lines changed

postgres/src/lib.rs

+10-8
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,7 @@ pub enum TlsMode<'a> {
218218
Require(&'a TlsHandshake),
219219
}
220220

221+
#[derive(Debug)]
221222
struct StatementInfo {
222223
name: String,
223224
param_types: Vec<Type>,
@@ -1082,7 +1083,7 @@ impl Connection {
10821083
/// println!("foo: {}", foo);
10831084
/// }
10841085
/// ```
1085-
pub fn query<'a>(&'a self, query: &str, params: &[&ToSql]) -> Result<Rows<'a>> {
1086+
pub fn query(&self, query: &str, params: &[&ToSql]) -> Result<Rows<'static>> {
10861087
let (param_types, columns) = self.0.borrow_mut().raw_prepare("", query)?;
10871088
let info = Arc::new(StatementInfo {
10881089
name: String::new(),
@@ -1300,7 +1301,7 @@ pub trait GenericConnection {
13001301
fn execute(&self, query: &str, params: &[&ToSql]) -> Result<u64>;
13011302

13021303
/// Like `Connection::query`.
1303-
fn query<'a>(&'a self, query: &str, params: &[&ToSql]) -> Result<Rows<'a>>;
1304+
fn query<'a>(&'a self, query: &str, params: &[&ToSql]) -> Result<Rows<'static>>;
13041305

13051306
/// Like `Connection::prepare`.
13061307
fn prepare<'a>(&'a self, query: &str) -> Result<Statement<'a>>;
@@ -1323,7 +1324,7 @@ impl GenericConnection for Connection {
13231324
self.execute(query, params)
13241325
}
13251326

1326-
fn query<'a>(&'a self, query: &str, params: &[&ToSql]) -> Result<Rows<'a>> {
1327+
fn query<'a>(&'a self, query: &str, params: &[&ToSql]) -> Result<Rows<'static>> {
13271328
self.query(query, params)
13281329
}
13291330

@@ -1353,7 +1354,7 @@ impl<'a> GenericConnection for Transaction<'a> {
13531354
self.execute(query, params)
13541355
}
13551356

1356-
fn query<'b>(&'b self, query: &str, params: &[&ToSql]) -> Result<Rows<'b>> {
1357+
fn query<'b>(&'b self, query: &str, params: &[&ToSql]) -> Result<Rows<'static>> {
13571358
self.query(query, params)
13581359
}
13591360

@@ -1396,9 +1397,8 @@ trait OtherNew {
13961397
fn new(name: String, oid: Oid, kind: Kind, schema: String) -> Other;
13971398
}
13981399

1399-
trait RowsNew<'a> {
1400-
fn new(stmt: &'a Statement<'a>, data: Vec<RowData>) -> Rows<'a>;
1401-
fn new_owned(stmt: Statement<'a>, data: Vec<RowData>) -> Rows<'a>;
1400+
trait RowsNew {
1401+
fn new(stmt: &Statement, data: Vec<RowData>) -> Rows<'static>;
14021402
}
14031403

14041404
trait LazyRowsNew<'trans, 'stmt> {
@@ -1421,7 +1421,9 @@ trait StatementInternals<'conn> {
14211421

14221422
fn conn(&self) -> &'conn Connection;
14231423

1424-
fn into_query(self, params: &[&ToSql]) -> Result<Rows<'conn>>;
1424+
fn info(&self) -> &Arc<StatementInfo>;
1425+
1426+
fn into_query(self, params: &[&ToSql]) -> Result<Rows<'static>>;
14251427
}
14261428

14271429
trait ColumnNew {

postgres/src/rows.rs

+30-33
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,10 @@ use std::fmt;
99
use std::io;
1010
use std::ops::Deref;
1111
use std::slice;
12+
use std::sync::Arc;
13+
use std::marker::PhantomData;
1214

13-
use {Result, RowsNew, LazyRowsNew, StatementInternals};
15+
use {Result, RowsNew, LazyRowsNew, StatementInternals, StatementInfo};
1416
use transaction::Transaction;
1517
use types::{FromSql, WrongType};
1618
use stmt::{Statement, Column};
@@ -33,23 +35,18 @@ impl<'a, T> Deref for MaybeOwned<'a, T> {
3335
}
3436

3537
/// The resulting rows of a query.
36-
pub struct Rows<'stmt> {
37-
stmt: MaybeOwned<'stmt, Statement<'stmt>>,
38+
pub struct Rows<'compat> {
39+
stmt_info: Arc<StatementInfo>,
3840
data: Vec<RowData>,
41+
_marker: PhantomData<&'compat u8>
3942
}
4043

41-
impl<'a> RowsNew<'a> for Rows<'a> {
42-
fn new(stmt: &'a Statement<'a>, data: Vec<RowData>) -> Rows<'a> {
44+
impl RowsNew for Rows<'static> {
45+
fn new(stmt: &Statement, data: Vec<RowData>) -> Rows<'static> {
4346
Rows {
44-
stmt: MaybeOwned::Borrowed(stmt),
45-
data: data,
46-
}
47-
}
48-
49-
fn new_owned(stmt: Statement<'a>, data: Vec<RowData>) -> Rows<'a> {
50-
Rows {
51-
stmt: MaybeOwned::Owned(stmt),
47+
stmt_info: stmt.info().clone(),
5248
data: data,
49+
_marker: PhantomData,
5350
}
5451
}
5552
}
@@ -63,10 +60,10 @@ impl<'a> fmt::Debug for Rows<'a> {
6360
}
6461
}
6562

66-
impl<'stmt> Rows<'stmt> {
63+
impl<'rows> Rows<'rows> {
6764
/// Returns a slice describing the columns of the `Rows`.
6865
pub fn columns(&self) -> &[Column] {
69-
self.stmt.columns()
66+
&self.stmt_info.columns[..]
7067
}
7168

7269
/// Returns the number of rows present.
@@ -86,15 +83,15 @@ impl<'stmt> Rows<'stmt> {
8683
/// Panics if `idx` is out of bounds.
8784
pub fn get<'a>(&'a self, idx: usize) -> Row<'a> {
8885
Row {
89-
stmt: &*self.stmt,
86+
stmt_info: &self.stmt_info,
9087
data: MaybeOwned::Borrowed(&self.data[idx]),
9188
}
9289
}
9390

9491
/// Returns an iterator over the `Row`s.
9592
pub fn iter<'a>(&'a self) -> Iter<'a> {
9693
Iter {
97-
stmt: &*self.stmt,
94+
stmt_info: &self.stmt_info,
9895
iter: self.data.iter(),
9996
}
10097
}
@@ -111,7 +108,7 @@ impl<'a> IntoIterator for &'a Rows<'a> {
111108

112109
/// An iterator over `Row`s.
113110
pub struct Iter<'a> {
114-
stmt: &'a Statement<'a>,
111+
stmt_info: &'a StatementInfo,
115112
iter: slice::Iter<'a, RowData>,
116113
}
117114

@@ -121,7 +118,7 @@ impl<'a> Iterator for Iter<'a> {
121118
fn next(&mut self) -> Option<Row<'a>> {
122119
self.iter.next().map(|row| {
123120
Row {
124-
stmt: &*self.stmt,
121+
stmt_info: self.stmt_info,
125122
data: MaybeOwned::Borrowed(row),
126123
}
127124
})
@@ -136,7 +133,7 @@ impl<'a> DoubleEndedIterator for Iter<'a> {
136133
fn next_back(&mut self) -> Option<Row<'a>> {
137134
self.iter.next_back().map(|row| {
138135
Row {
139-
stmt: &*self.stmt,
136+
stmt_info: self.stmt_info,
140137
data: MaybeOwned::Borrowed(row),
141138
}
142139
})
@@ -147,14 +144,14 @@ impl<'a> ExactSizeIterator for Iter<'a> {}
147144

148145
/// A single result row of a query.
149146
pub struct Row<'a> {
150-
stmt: &'a Statement<'a>,
147+
stmt_info: &'a StatementInfo,
151148
data: MaybeOwned<'a, RowData>,
152149
}
153150

154151
impl<'a> fmt::Debug for Row<'a> {
155152
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
156153
fmt.debug_struct("Row")
157-
.field("statement", self.stmt)
154+
.field("statement", self.stmt_info)
158155
.finish()
159156
}
160157
}
@@ -172,7 +169,7 @@ impl<'a> Row<'a> {
172169

173170
/// Returns a slice describing the columns of the `Row`.
174171
pub fn columns(&self) -> &[Column] {
175-
self.stmt.columns()
172+
&self.stmt_info.columns[..]
176173
}
177174

178175
/// Retrieves the contents of a field of the row.
@@ -227,12 +224,12 @@ impl<'a> Row<'a> {
227224
where I: RowIndex,
228225
T: FromSql
229226
{
230-
let idx = match idx.idx(self.stmt) {
227+
let idx = match idx.idx(&self.stmt_info.columns) {
231228
Some(idx) => idx,
232229
None => return None,
233230
};
234231

235-
let ty = self.stmt.columns()[idx].type_();
232+
let ty = self.stmt_info.columns[idx].type_();
236233
if !<T as FromSql>::accepts(ty) {
237234
return Some(Err(Error::Conversion(Box::new(WrongType::new(ty.clone())))));
238235
}
@@ -248,7 +245,7 @@ impl<'a> Row<'a> {
248245
pub fn get_bytes<I>(&self, idx: I) -> Option<&[u8]>
249246
where I: RowIndex + fmt::Debug
250247
{
251-
match idx.idx(self.stmt) {
248+
match idx.idx(&self.stmt_info.columns) {
252249
Some(idx) => self.data.get(idx),
253250
None => panic!("invalid index {:?}", idx),
254251
}
@@ -259,13 +256,13 @@ impl<'a> Row<'a> {
259256
pub trait RowIndex {
260257
/// Returns the index of the appropriate column, or `None` if no such
261258
/// column exists.
262-
fn idx(&self, stmt: &Statement) -> Option<usize>;
259+
fn idx(&self, _: &[Column]) -> Option<usize>;
263260
}
264261

265262
impl RowIndex for usize {
266263
#[inline]
267-
fn idx(&self, stmt: &Statement) -> Option<usize> {
268-
if *self >= stmt.columns().len() {
264+
fn idx(&self, columns: &[Column]) -> Option<usize> {
265+
if *self >= columns.len() {
269266
None
270267
} else {
271268
Some(*self)
@@ -275,15 +272,15 @@ impl RowIndex for usize {
275272

276273
impl<'a> RowIndex for &'a str {
277274
#[inline]
278-
fn idx(&self, stmt: &Statement) -> Option<usize> {
279-
if let Some(idx) = stmt.columns().iter().position(|d| d.name() == *self) {
275+
fn idx(&self, columns: &[Column]) -> Option<usize> {
276+
if let Some(idx) = columns.iter().position(|d| d.name() == *self) {
280277
return Some(idx);
281278
};
282279

283280
// FIXME ASCII-only case insensitivity isn't really the right thing to
284281
// do. Postgres itself uses a dubious wrapper around tolower and JDBC
285282
// uses the US locale.
286-
stmt.columns().iter().position(|d| d.name().eq_ignore_ascii_case(*self))
283+
columns.iter().position(|d| d.name().eq_ignore_ascii_case(*self))
287284
}
288285
}
289286

@@ -381,7 +378,7 @@ impl<'trans, 'stmt> FallibleIterator for LazyRows<'trans, 'stmt> {
381378
.pop_front()
382379
.map(|r| {
383380
Row {
384-
stmt: self.stmt,
381+
stmt_info: &**self.stmt.info(),
385382
data: MaybeOwned::Owned(r),
386383
}
387384
});

postgres/src/stmt.rs

+8-8
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,7 @@ pub struct Statement<'conn> {
2626

2727
impl<'a> fmt::Debug for Statement<'a> {
2828
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
29-
fmt.debug_struct("Statement")
30-
.field("name", &self.info.name)
31-
.field("parameter_types", &self.info.param_types)
32-
.field("columns", &self.info.columns)
33-
.finish()
29+
fmt::Debug::fmt(&*self.info, fmt)
3430
}
3531
}
3632

@@ -54,15 +50,19 @@ impl<'conn> StatementInternals<'conn> for Statement<'conn> {
5450
}
5551
}
5652

53+
fn info(&self) -> &Arc<StatementInfo> {
54+
&self.info
55+
}
56+
5757
fn conn(&self) -> &'conn Connection {
5858
self.conn
5959
}
6060

61-
fn into_query(self, params: &[&ToSql]) -> Result<Rows<'conn>> {
61+
fn into_query(self, params: &[&ToSql]) -> Result<Rows<'static>> {
6262
check_desync!(self.conn);
6363
let mut rows = vec![];
6464
self.inner_query("", 0, params, |row| rows.push(row))?;
65-
Ok(Rows::new_owned(self, rows))
65+
Ok(Rows::new(&self, rows))
6666
}
6767
}
6868

@@ -201,7 +201,7 @@ impl<'conn> Statement<'conn> {
201201
/// println!("foo: {}", foo);
202202
/// }
203203
/// ```
204-
pub fn query<'a>(&'a self, params: &[&ToSql]) -> Result<Rows<'a>> {
204+
pub fn query(&self, params: &[&ToSql]) -> Result<Rows<'static>> {
205205
check_desync!(self.conn);
206206
let mut rows = vec![];
207207
self.inner_query("", 0, params, |row| rows.push(row))?;

postgres/src/transaction.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -228,7 +228,7 @@ impl<'conn> Transaction<'conn> {
228228
}
229229

230230
/// Like `Connection::query`.
231-
pub fn query<'a>(&'a self, query: &str, params: &[&ToSql]) -> Result<Rows<'a>> {
231+
pub fn query<'a>(&'a self, query: &str, params: &[&ToSql]) -> Result<Rows<'static>> {
232232
self.conn.query(query, params)
233233
}
234234

postgres/tests/test.rs

+5-5
Original file line numberDiff line numberDiff line change
@@ -1088,11 +1088,11 @@ fn test_row_case_insensitive() {
10881088
conn.batch_execute("CREATE TEMPORARY TABLE foo (foo INT, \"bAr\" INT, \"Bar\" INT);")
10891089
.unwrap();
10901090
let stmt = conn.prepare("SELECT * FROM foo").unwrap();
1091-
assert_eq!(Some(0), "foo".idx(&stmt));
1092-
assert_eq!(Some(0), "FOO".idx(&stmt));
1093-
assert_eq!(Some(1), "bar".idx(&stmt));
1094-
assert_eq!(Some(1), "bAr".idx(&stmt));
1095-
assert_eq!(Some(2), "Bar".idx(&stmt));
1091+
assert_eq!(Some(0), "foo".idx(&stmt.columns()));
1092+
assert_eq!(Some(0), "FOO".idx(&stmt.columns()));
1093+
assert_eq!(Some(1), "bar".idx(&stmt.columns()));
1094+
assert_eq!(Some(1), "bAr".idx(&stmt.columns()));
1095+
assert_eq!(Some(2), "Bar".idx(&stmt.columns()));
10961096
}
10971097

10981098
#[test]

0 commit comments

Comments
 (0)