Skip to content

Commit 321cc4d

Browse files
committed
Merge branch 'release-v0.10.1' into release
2 parents ef3de8a + bb35807 commit 321cc4d

File tree

15 files changed

+529
-273
lines changed

15 files changed

+529
-273
lines changed

.travis.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,11 @@ sudo: required
33
rust:
44
- nightly
55
- beta
6-
- stable
6+
- 1.3.0
77
addons:
88
postgresql: 9.4
99
before_script:
1010
- "./.travis/setup.sh"
1111
script:
1212
- cargo test
13-
- cargo test --features "uuid rustc-serialize time unix_socket serde chrono openssl"
13+
- cargo test --features "uuid rustc-serialize time unix_socket serde_json chrono openssl"

Cargo.toml

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
[package]
22
name = "postgres"
3-
version = "0.10.0"
3+
version = "0.10.1"
44
authors = ["Steven Fackler <[email protected]>"]
55
license = "MIT"
66
description = "A native PostgreSQL driver"
77
repository = "https://github.com/sfackler/rust-postgres"
8-
documentation = "https://sfackler.github.io/rust-postgres/doc/v0.10.0/postgres"
8+
documentation = "https://sfackler.github.io/rust-postgres/doc/v0.10.1/postgres"
99
readme = "README.md"
1010
keywords = ["database", "sql"]
1111
build = "build.rs"
@@ -25,15 +25,17 @@ phf_codegen = "0.7"
2525

2626
[dependencies]
2727
bufstream = "0.1"
28-
byteorder = "0.3"
28+
byteorder = ">= 0.3, < 0.5"
2929
log = "0.3"
3030
phf = "0.7"
3131
rustc-serialize = "0.3"
32+
net2 = { version = "0.2", features = ["nightly"] }
3233
chrono = { version = "0.2.14", optional = true }
3334
openssl = { version = "0.6.4", optional = true }
34-
serde = { version = "0.3", optional = true }
35+
serde = { version = "0.3", optional = true } # Delete for 0.11
36+
serde_json = { version = "0.6", optional = true }
3537
time = { version = "0.1.14", optional = true }
36-
unix_socket = { version = ">= 0.3, < 0.5", optional = true }
38+
unix_socket = { version = ">= 0.3, < 0.5", optional = true, features = ["socket_timeout"] }
3739
uuid = { version = "0.1", optional = true }
3840

3941
[dev-dependencies]

README.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# Rust-Postgres
22
A native PostgreSQL driver for Rust.
33

4-
[Documentation](https://sfackler.github.io/rust-postgres/doc/v0.10.0/postgres)
4+
[Documentation](https://sfackler.github.io/rust-postgres/doc/v0.10.1/postgres)
55

66
[![Build Status](https://travis-ci.org/sfackler/rust-postgres.png?branch=master)](https://travis-ci.org/sfackler/rust-postgres) [![Latest Version](https://img.shields.io/crates/v/postgres.svg)](https://crates.io/crates/postgres)
77

@@ -57,7 +57,7 @@ fn main() {
5757
```
5858

5959
## Requirements
60-
* **Rust** - Rust-Postgres is developed against the 1.2 release of Rust
60+
* **Rust** - Rust-Postgres is developed against the 1.3 release of Rust
6161
available on http://www.rust-lang.org. It should also compile against more
6262
recent releases.
6363

@@ -200,7 +200,7 @@ types. The driver currently supports the following conversions:
200200
<td>
201201
<a href="https://github.com/rust-lang/rustc-serialize">serialize::json::Json</a>
202202
and
203-
<a href="https://github.com/erickt/serde">serde::json::Value</a>
203+
<a href="https://github.com/erickt/serde_json">serde_json::Value</a>
204204
(<a href="#optional-features">optional</a>)
205205
</td>
206206
<td>JSON, JSONB</td>
@@ -284,7 +284,7 @@ implementations for `uuid`'s `Uuid` type.
284284
[JSON and JSONB](http://www.postgresql.org/docs/9.4/static/datatype-json.html)
285285
support is provided optionally by the `rustc-serialize` feature, which adds
286286
`ToSql` and `FromSql` implementations for `rustc-serialize`'s `Json` type, and
287-
the `serde` feature, which adds implementations for `serde`'s `json::Value`
287+
the `serde` feature, which adds implementations for `serde_json`'s `Value`
288288
type.
289289

290290
### TIMESTAMP/TIMESTAMPTZ/DATE/TIME types

src/lib.rs

Lines changed: 39 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
//! )", &[]).unwrap();
2525
//! let me = Person {
2626
//! id: 0,
27-
//! name: "Steven".to_string(),
27+
//! name: "Steven".to_owned(),
2828
//! data: None
2929
//! };
3030
//! conn.execute("INSERT INTO person (name, data) VALUES ($1, $2)",
@@ -41,7 +41,7 @@
4141
//! }
4242
//! }
4343
//! ```
44-
#![doc(html_root_url="https://sfackler.github.io/rust-postgres/doc/v0.10.0")]
44+
#![doc(html_root_url="https://sfackler.github.io/rust-postgres/doc/v0.10.1")]
4545
#![warn(missing_docs)]
4646

4747
extern crate bufstream;
@@ -52,6 +52,7 @@ extern crate phf;
5252
extern crate rustc_serialize as serialize;
5353
#[cfg(feature = "unix_socket")]
5454
extern crate unix_socket;
55+
extern crate net2;
5556

5657
use bufstream::BufStream;
5758
use md5::Md5;
@@ -67,6 +68,7 @@ use std::io::prelude::*;
6768
use std::marker::Sync as StdSync;
6869
use std::mem;
6970
use std::result;
71+
use std::time::Duration;
7072
#[cfg(feature = "unix_socket")]
7173
use std::path::PathBuf;
7274

@@ -455,10 +457,12 @@ impl InnerConnection {
455457

456458
fn setup_typeinfo_query(&mut self) -> result::Result<(), ConnectError> {
457459
match self.raw_prepare(TYPEINFO_QUERY,
458-
"SELECT t.typname, t.typelem, r.rngsubtype \
460+
"SELECT t.typname, t.typelem, r.rngsubtype, n.nspname \
459461
FROM pg_catalog.pg_type t \
460462
LEFT OUTER JOIN pg_catalog.pg_range r \
461463
ON r.rngtypid = t.oid \
464+
INNER JOIN pg_catalog.pg_namespace n \
465+
ON t.typnamespace = n.oid \
462466
WHERE t.oid = $1") {
463467
Ok(..) => return Ok(()),
464468
Err(Error::IoError(e)) => return Err(ConnectError::IoError(e)),
@@ -469,9 +473,11 @@ impl InnerConnection {
469473
}
470474

471475
match self.raw_prepare(TYPEINFO_QUERY,
472-
"SELECT typname, typelem, NULL::OID \
473-
FROM pg_catalog.pg_type \
474-
WHERE oid = $1") {
476+
"SELECT t.typname, t.typelem, NULL::OID, n.nspname \
477+
FROM pg_catalog.pg_type t \
478+
INNER JOIN pg_catalog.pg_namespace n \
479+
ON t.typnamespace = n.oid \
480+
WHERE t.oid = $1") {
475481
Ok(..) => Ok(()),
476482
Err(Error::IoError(e)) => Err(ConnectError::IoError(e)),
477483
Err(Error::DbError(e)) => Err(ConnectError::DbError(e)),
@@ -504,6 +510,24 @@ impl InnerConnection {
504510
}
505511
}
506512

513+
fn read_message_with_notification_timeout(&mut self, timeout: Duration)
514+
-> std::io::Result<Option<BackendMessage>> {
515+
debug_assert!(!self.desynchronized);
516+
loop {
517+
match try_desync!(self, self.stream.read_message_timeout(timeout)) {
518+
Some(NoticeResponse { fields }) => {
519+
if let Ok(err) = DbError::new_raw(fields) {
520+
self.notice_handler.handle_notice(err);
521+
}
522+
}
523+
Some(ParameterStatus { parameter, value }) => {
524+
self.parameters.insert(parameter, value);
525+
}
526+
val => return Ok(val)
527+
}
528+
}
529+
}
530+
507531
fn read_message(&mut self) -> std_io::Result<BackendMessage> {
508532
loop {
509533
match try!(self.read_message_with_notification()) {
@@ -661,7 +685,7 @@ impl InnerConnection {
661685
}
662686

663687
fn get_type(&mut self, oid: Oid) -> Result<Type> {
664-
if let Some(ty) = Type::new(oid) {
688+
if let Some(ty) = Type::from_oid(oid) {
665689
return Ok(ty);
666690
}
667691

@@ -696,7 +720,7 @@ impl InnerConnection {
696720
}
697721
_ => bad_response!(self)
698722
}
699-
let (name, elem_oid, rngsubtype): (String, Oid, Option<Oid>) =
723+
let (name, elem_oid, rngsubtype, schema): (String, Oid, Option<Oid>, String) =
700724
match try!(self.read_message()) {
701725
DataRow { row } => {
702726
let ctx = SessionInfo::new(self);
@@ -708,6 +732,9 @@ impl InnerConnection {
708732
&ctx)),
709733
try!(FromSql::from_sql_nullable(&Type::Oid,
710734
row[2].as_ref().map(|r| &**r).as_mut(),
735+
&ctx)),
736+
try!(FromSql::from_sql_nullable(&Type::Name,
737+
row[3].as_ref().map(|r| &**r).as_mut(),
711738
&ctx)))
712739
}
713740
ErrorResponse { fields } => {
@@ -735,7 +762,7 @@ impl InnerConnection {
735762
}
736763
};
737764

738-
let type_ = Type::Other(Box::new(Other::new(name, oid, kind)));
765+
let type_ = Type::Other(Box::new(Other::new(name, oid, kind, schema)));
739766
self.unknown_types.insert(oid, type_.clone());
740767
Ok(type_)
741768
}
@@ -860,7 +887,7 @@ impl Connection {
860887
/// target: ConnectTarget::Unix(some_crazy_path),
861888
/// port: None,
862889
/// user: Some(UserInfo {
863-
/// user: "postgres".to_string(),
890+
/// user: "postgres".to_owned(),
864891
/// password: None
865892
/// }),
866893
/// database: None,
@@ -911,7 +938,7 @@ impl Connection {
911938
self.conn.borrow_mut().prepare(query, self)
912939
}
913940

914-
/// Creates cached prepared statement.
941+
/// Creates a cached prepared statement.
915942
///
916943
/// Like `prepare`, except that the statement is only prepared once over
917944
/// the lifetime of the connection and then cached. If the same statement
@@ -1337,7 +1364,7 @@ impl<'a> GenericConnection for Transaction<'a> {
13371364
}
13381365

13391366
trait OtherNew {
1340-
fn new(name: String, oid: Oid, kind: Kind) -> Other;
1367+
fn new(name: String, oid: Oid, kind: Kind, schema: String) -> Other;
13411368
}
13421369

13431370
trait DbErrorNew {
@@ -1346,10 +1373,6 @@ trait DbErrorNew {
13461373
fn new<T>(fields: Vec<(u8, String)>) -> Result<T>;
13471374
}
13481375

1349-
trait TypeNew {
1350-
fn new(oid: Oid) -> Option<Type>;
1351-
}
1352-
13531376
trait RowsNew<'a> {
13541377
fn new(stmt: &'a Statement<'a>, data: Vec<Vec<Option<Vec<u8>>>>) -> Rows<'a>;
13551378
}

src/message.rs

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
use std::io;
22
use std::io::prelude::*;
33
use std::mem;
4+
use std::time::Duration;
45
use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
56

67
use types::Oid;
78
use util;
9+
use priv_io::ReadTimeout;
810

911
use self::BackendMessage::*;
1012
use self::FrontendMessage::*;
@@ -282,12 +284,39 @@ impl<R: BufRead> ReadCStr for R {
282284
#[doc(hidden)]
283285
pub trait ReadMessage {
284286
fn read_message(&mut self) -> io::Result<BackendMessage>;
287+
288+
fn read_message_timeout(&mut self, timeout: Duration)
289+
-> io::Result<Option<BackendMessage>>;
290+
291+
fn finish_read_message(&mut self, ident: u8) -> io::Result<BackendMessage>;
285292
}
286293

287-
impl<R: BufRead> ReadMessage for R {
294+
impl<R: BufRead + ReadTimeout> ReadMessage for R {
288295
fn read_message(&mut self) -> io::Result<BackendMessage> {
289296
let ident = try!(self.read_u8());
297+
self.finish_read_message(ident)
298+
}
299+
300+
fn read_message_timeout(&mut self, timeout: Duration)
301+
-> io::Result<Option<BackendMessage>> {
302+
try!(self.set_read_timeout(Some(timeout)));
303+
let ident = self.read_u8();
304+
try!(self.set_read_timeout(None));
305+
306+
match ident {
307+
Ok(ident) => self.finish_read_message(ident).map(Some),
308+
Err(e) => {
309+
let e: io::Error = e.into();
310+
if e.kind() == io::ErrorKind::WouldBlock || e.kind() == io::ErrorKind::TimedOut {
311+
Ok(None)
312+
} else {
313+
Err(e)
314+
}
315+
}
316+
}
317+
}
290318

319+
fn finish_read_message(&mut self, ident: u8) -> io::Result<BackendMessage> {
291320
// subtract size of length value
292321
let len = try!(self.read_u32::<BigEndian>()) - mem::size_of::<u32>() as u32;
293322
let mut rdr = self.by_ref().take(len as u64);

src/notification.rs

Lines changed: 55 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
//! Asynchronous notifications.
22
33
use std::fmt;
4+
use std::time::Duration;
45

56
use {desynchronized, Result, Connection, NotificationsNew};
67
use message::BackendMessage::NotificationResponse;
@@ -41,22 +42,37 @@ impl<'conn> Notifications<'conn> {
4142
/// # Note
4243
///
4344
/// This iterator may start returning `Some` after previously returning
44-
/// `None` if more notifications are received.
45+
/// `None` if more notifications are received. However, those notifications
46+
/// will not be registered until the connection is used in some way.
4547
pub fn iter<'a>(&'a self) -> Iter<'a> {
4648
Iter {
4749
conn: self.conn,
4850
}
4951
}
5052

51-
/// Returns an iterator over notifications, blocking until one is received
52-
/// if none are pending.
53+
/// Returns an iterator over notifications that blocks until one is
54+
/// received if none are pending.
5355
///
5456
/// The iterator will never return `None`.
5557
pub fn blocking_iter<'a>(&'a self) -> BlockingIter<'a> {
5658
BlockingIter {
5759
conn: self.conn,
5860
}
5961
}
62+
63+
/// Returns an iterator over notifications that blocks for a limited time
64+
/// waiting to receive one if none are pending.
65+
///
66+
/// # Note
67+
///
68+
/// This iterator may start returning `Some` after previously returning
69+
/// `None` if more notifications are received.
70+
pub fn timeout_iter<'a>(&'a self, timeout: Duration) -> TimeoutIter<'a> {
71+
TimeoutIter {
72+
conn: self.conn,
73+
timeout: timeout,
74+
}
75+
}
6076
}
6177

6278
impl<'a, 'conn> IntoIterator for &'a Notifications<'conn> {
@@ -121,3 +137,39 @@ impl<'a> Iterator for BlockingIter<'a> {
121137
}
122138
}
123139
}
140+
141+
/// An iterator over notifications which will block for a period of time if
142+
/// none are pending.
143+
pub struct TimeoutIter<'a> {
144+
conn: &'a Connection,
145+
timeout: Duration,
146+
}
147+
148+
impl<'a> Iterator for TimeoutIter<'a> {
149+
type Item = Result<Notification>;
150+
151+
fn next(&mut self) -> Option<Result<Notification>> {
152+
let mut conn = self.conn.conn.borrow_mut();
153+
154+
if let Some(notification) = conn.notifications.pop_front() {
155+
return Some(Ok(notification));
156+
}
157+
158+
if conn.is_desynchronized() {
159+
return Some(Err(Error::IoError(desynchronized())));
160+
}
161+
162+
match conn.read_message_with_notification_timeout(self.timeout) {
163+
Ok(Some(NotificationResponse { pid, channel, payload })) => {
164+
Some(Ok(Notification {
165+
pid: pid,
166+
channel: channel,
167+
payload: payload
168+
}))
169+
}
170+
Ok(None) => None,
171+
Err(err) => Some(Err(Error::IoError(err))),
172+
_ => unreachable!()
173+
}
174+
}
175+
}

0 commit comments

Comments
 (0)