Merge branch 'release-v0.10.2' into release

This commit is contained in:
Steven Fackler 2015-12-02 21:58:29 -08:00
commit a402f7d3a6
23 changed files with 922 additions and 831 deletions

1
.gitattributes vendored
View File

@ -1 +0,0 @@
*.rs eol=lf

View File

@ -1,16 +0,0 @@
#!/bin/bash
set -o errexit -o nounset
git clone --branch gh-pages "https://$GH_TOKEN@github.com/${TRAVIS_REPO_SLUG}.git" deploy_docs
cd deploy_docs
git config user.name "Steven Fackler"
git config user.email "sfackler@gmail.com"
rm -rf doc/master
mv ../target/doc doc/master
git add -A .
git commit -m "rebuild pages at ${TRAVIS_COMMIT}"
git push

View File

@ -1,11 +1,11 @@
[package]
name = "postgres"
version = "0.10.1"
version = "0.10.2"
authors = ["Steven Fackler <sfackler@gmail.com>"]
license = "MIT"
description = "A native PostgreSQL driver"
repository = "https://github.com/sfackler/rust-postgres"
documentation = "https://sfackler.github.io/rust-postgres/doc/v0.10.1/postgres"
documentation = "https://sfackler.github.io/rust-postgres/doc/v0.10.2/postgres"
readme = "README.md"
keywords = ["database", "sql"]
build = "build.rs"
@ -31,7 +31,7 @@ phf = "0.7"
rustc-serialize = "0.3"
net2 = { version = "0.2", features = ["nightly"] }
chrono = { version = "0.2.14", optional = true }
openssl = { version = "0.6.4", optional = true }
openssl = { version = ">= 0.6.4, < 0.8", optional = true }
serde = { version = "0.3", optional = true } # Delete for 0.11
serde_json = { version = "0.6", optional = true }
time = { version = "0.1.14", optional = true }

View File

@ -1,7 +1,7 @@
# Rust-Postgres
A native PostgreSQL driver for Rust.
[Documentation](https://sfackler.github.io/rust-postgres/doc/v0.10.1/postgres)
[Documentation](https://sfackler.github.io/rust-postgres/doc/v0.10.2/postgres)
[![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)
@ -198,16 +198,16 @@ types. The driver currently supports the following conversions:
</tr>
<tr>
<td>
<a href="https://github.com/rust-lang/rustc-serialize">serialize::json::Json</a>
<a href="https://github.com/rust-lang-nursery/rustc-serialize">serialize::json::Json</a>
and
<a href="https://github.com/erickt/serde_json">serde_json::Value</a>
<a href="https://github.com/serde-rs/json">serde_json::Value</a>
(<a href="#optional-features">optional</a>)
</td>
<td>JSON, JSONB</td>
</tr>
<tr>
<td>
<a href="https://github.com/rust-lang/time">time::Timespec</a>
<a href="https://github.com/rust-lang-deprecated/time">time::Timespec</a>
and
<a href="https://github.com/lifthrasiir/rust-chrono">chrono::NaiveDateTime</a>
(<a href="#optional-features">optional</a>)
@ -216,7 +216,7 @@ types. The driver currently supports the following conversions:
</tr>
<tr>
<td>
<a href="https://github.com/rust-lang/time">time::Timespec</a>,
<a href="https://github.com/rust-lang-deprecated/time">time::Timespec</a>,
<a href="https://github.com/lifthrasiir/rust-chrono">chrono::DateTime&lt;UTC&gt;</a>,
<a href="https://github.com/lifthrasiir/rust-chrono">chrono::DateTime&lt;Local&gt;</a>,
and
@ -241,7 +241,7 @@ types. The driver currently supports the following conversions:
</tr>
<tr>
<td>
<a href="https://github.com/rust-lang/uuid">uuid::Uuid</a>
<a href="https://github.com/rust-lang-nursery/uuid">uuid::Uuid</a>
(<a href="#optional-features">optional</a>)
</td>
<td>UUID</td>
@ -284,8 +284,9 @@ implementations for `uuid`'s `Uuid` type.
[JSON and JSONB](http://www.postgresql.org/docs/9.4/static/datatype-json.html)
support is provided optionally by the `rustc-serialize` feature, which adds
`ToSql` and `FromSql` implementations for `rustc-serialize`'s `Json` type, and
the `serde` feature, which adds implementations for `serde_json`'s `Value`
type.
the `serde_json` feature, which adds implementations for `serde_json`'s `Value`
type. The `serde` feature provides implementations for the older
`serde::json::Value` type.
### TIMESTAMP/TIMESTAMPTZ/DATE/TIME types

View File

@ -48,10 +48,10 @@ impl DbErrorNew for DbError {
None => match map.remove(&b'p') {
Some(pos) => Some(ErrorPosition::Internal {
position: try!(pos.parse().map_err(|_| ())),
query: try!(map.remove(&b'q').ok_or(()))
query: try!(map.remove(&b'q').ok_or(())),
}),
None => None
}
None => None,
},
},
where_: map.remove(&b'W'),
schema: map.remove(&b's'),
@ -194,7 +194,7 @@ impl error::Error for DbError {
#[derive(Debug)]
pub enum ConnectError {
/// An error creating `ConnectParams`.
BadConnectParams(Box<error::Error+Sync+Send>),
BadConnectParams(Box<error::Error + Sync + Send>),
/// The `ConnectParams` was missing a user.
MissingUser,
/// An error from the Postgres server itself.
@ -207,7 +207,7 @@ pub enum ConnectError {
/// The Postgres server does not support SSL encryption.
NoSslSupport,
/// An error initializing the SSL session.
SslError(Box<error::Error+Sync+Send>),
SslError(Box<error::Error + Sync + Send>),
/// An error communicating with the server.
IoError(io::Error),
}
@ -220,7 +220,7 @@ impl fmt::Display for ConnectError {
ConnectError::DbError(ref err) => write!(fmt, ": {}", err),
ConnectError::SslError(ref err) => write!(fmt, ": {}", err),
ConnectError::IoError(ref err) => write!(fmt, ": {}", err),
_ => Ok(())
_ => Ok(()),
}
}
}
@ -231,7 +231,8 @@ impl error::Error for ConnectError {
ConnectError::BadConnectParams(_) => "Error creating `ConnectParams`",
ConnectError::MissingUser => "User missing in `ConnectParams`",
ConnectError::DbError(_) => "Error reported by Postgres",
ConnectError::MissingPassword => "The server requested a password but none was provided",
ConnectError::MissingPassword =>
"The server requested a password but none was provided",
ConnectError::UnsupportedAuthentication => {
"The server requested an unsupported authentication method"
}
@ -247,7 +248,7 @@ impl error::Error for ConnectError {
ConnectError::DbError(ref err) => Some(&**err),
ConnectError::SslError(ref err) => Some(&**err),
ConnectError::IoError(ref err) => Some(err),
_ => None
_ => None,
}
}
}
@ -280,8 +281,8 @@ pub enum ErrorPosition {
/// The byte position.
position: u32,
/// A query generated by the Postgres server.
query: String
}
query: String,
},
}
/// An error encountered when communicating with the Postgres server.
@ -297,7 +298,7 @@ pub enum Error {
/// An attempt was made to read from a column that does not exist.
InvalidColumn,
/// An error converting between Postgres and Rust types.
Conversion(Box<error::Error+Sync+Send>),
Conversion(Box<error::Error + Sync + Send>),
}
impl fmt::Display for Error {
@ -329,7 +330,7 @@ impl error::Error for Error {
Error::DbError(ref err) => Some(&**err),
Error::IoError(ref err) => Some(err),
Error::Conversion(ref err) => Some(&**err),
_ => None
_ => None,
}
}
}

View File

@ -26,6 +26,8 @@ pub trait NegotiateSsl {
///
/// The host portion of the connection parameters is provided for hostname
/// verification.
fn negotiate_ssl(&self, host: &str, stream: Stream)
-> Result<Box<StreamWrapper>, Box<Error+Sync+Send>>;
fn negotiate_ssl(&self,
host: &str,
stream: Stream)
-> Result<Box<StreamWrapper>, Box<Error + Sync + Send>>;
}

View File

@ -16,8 +16,10 @@ impl StreamWrapper for SslStream<Stream> {
}
impl NegotiateSsl for SslContext {
fn negotiate_ssl(&self, _: &str, stream: Stream)
-> Result<Box<StreamWrapper>, Box<Error+Send+Sync>> {
fn negotiate_ssl(&self,
_: &str,
stream: Stream)
-> Result<Box<StreamWrapper>, Box<Error + Send + Sync>> {
let stream = try!(SslStream::connect(self, stream));
Ok(Box::new(stream))
}

View File

@ -41,7 +41,7 @@
//! }
//! }
//! ```
#![doc(html_root_url="https://sfackler.github.io/rust-postgres/doc/v0.10.1")]
#![doc(html_root_url="https://sfackler.github.io/rust-postgres/doc/v0.10.2")]
#![warn(missing_docs)]
extern crate bufstream;
@ -114,7 +114,7 @@ pub enum ConnectTarget {
///
/// Only available on Unix platforms with the `unix_socket` feature.
#[cfg(feature = "unix_socket")]
Unix(PathBuf)
Unix(PathBuf),
}
/// Authentication information.
@ -148,17 +148,17 @@ pub struct ConnectParams {
/// A trait implemented by types that can be converted into a `ConnectParams`.
pub trait IntoConnectParams {
/// Converts the value of `self` into a `ConnectParams`.
fn into_connect_params(self) -> result::Result<ConnectParams, Box<StdError+StdSync+Send>>;
fn into_connect_params(self) -> result::Result<ConnectParams, Box<StdError + StdSync + Send>>;
}
impl IntoConnectParams for ConnectParams {
fn into_connect_params(self) -> result::Result<ConnectParams, Box<StdError+StdSync+Send>> {
fn into_connect_params(self) -> result::Result<ConnectParams, Box<StdError + StdSync + Send>> {
Ok(self)
}
}
impl<'a> IntoConnectParams for &'a str {
fn into_connect_params(self) -> result::Result<ConnectParams, Box<StdError+StdSync+Send>> {
fn into_connect_params(self) -> result::Result<ConnectParams, Box<StdError + StdSync + Send>> {
match Url::parse(self) {
Ok(url) => url.into_connect_params(),
Err(err) => return Err(err.into()),
@ -167,7 +167,7 @@ impl<'a> IntoConnectParams for &'a str {
}
impl IntoConnectParams for Url {
fn into_connect_params(self) -> result::Result<ConnectParams, Box<StdError+StdSync+Send>> {
fn into_connect_params(self) -> result::Result<ConnectParams, Box<StdError + StdSync + Send>> {
let Url {
host,
port,
@ -178,11 +178,11 @@ impl IntoConnectParams for Url {
#[cfg(feature = "unix_socket")]
fn make_unix(maybe_path: String)
-> result::Result<ConnectTarget, Box<StdError+StdSync+Send>> {
-> result::Result<ConnectTarget, Box<StdError + StdSync + Send>> {
Ok(ConnectTarget::Unix(PathBuf::from(maybe_path)))
}
#[cfg(not(feature = "unix_socket"))]
fn make_unix(_: String) -> result::Result<ConnectTarget, Box<StdError+StdSync+Send>> {
fn make_unix(_: String) -> result::Result<ConnectTarget, Box<StdError + StdSync + Send>> {
Err("unix socket support requires the `unix_socket` feature".into())
}
@ -194,7 +194,10 @@ impl IntoConnectParams for Url {
};
let user = user.map(|url::UserInfo { user, pass }| {
UserInfo { user: user, password: pass }
UserInfo {
user: user,
password: pass,
}
});
let database = if path.is_empty() {
@ -254,7 +257,7 @@ pub struct CancelData {
/// Only the host and port of the connection info are used. See
/// `Connection::connect` for details of the `params` argument.
///
/// ## Example
/// # Example
///
/// ```rust,no_run
/// # use postgres::{Connection, SslMode};
@ -265,19 +268,21 @@ pub struct CancelData {
/// thread::spawn(move || {
/// conn.execute("SOME EXPENSIVE QUERY", &[]).unwrap();
/// });
/// # let _ =
/// postgres::cancel_query(url, &SslMode::None, cancel_data);
/// postgres::cancel_query(url, &SslMode::None, cancel_data).unwrap();
/// ```
pub fn cancel_query<T>(params: T, ssl: &SslMode, data: CancelData)
-> result::Result<(), ConnectError>
where T: IntoConnectParams {
pub fn cancel_query<T>(params: T,
ssl: &SslMode,
data: CancelData)
-> result::Result<(), ConnectError>
where T: IntoConnectParams
{
let params = try!(params.into_connect_params().map_err(ConnectError::BadConnectParams));
let mut socket = try!(priv_io::initialize_stream(&params, ssl));
try!(socket.write_message(&CancelRequest {
code: message::CANCEL_CODE,
process_id: data.process_id,
secret_key: data.secret_key
secret_key: data.secret_key,
}));
try!(socket.flush());
@ -291,7 +296,8 @@ fn bad_response() -> std_io::Error {
fn desynchronized() -> std_io::Error {
std_io::Error::new(std_io::ErrorKind::Other,
"communication with the server has desynchronized due to an earlier IO error")
"communication with the server has desynchronized due to an earlier IO \
error")
}
/// An enumeration of transaction isolation levels.
@ -353,9 +359,9 @@ pub enum SslMode {
/// The connection will not use SSL.
None,
/// The connection will use SSL if the backend supports it.
Prefer(Box<NegotiateSsl+std::marker::Sync+Send>),
Prefer(Box<NegotiateSsl + std::marker::Sync + Send>),
/// The connection must use SSL.
Require(Box<NegotiateSsl+std::marker::Sync+Send>),
Require(Box<NegotiateSsl + std::marker::Sync + Send>),
}
impl fmt::Debug for SslMode {
@ -399,7 +405,8 @@ impl Drop for InnerConnection {
impl InnerConnection {
fn connect<T>(params: T, ssl: &SslMode) -> result::Result<InnerConnection, ConnectError>
where T: IntoConnectParams {
where T: IntoConnectParams
{
let params = try!(params.into_connect_params().map_err(ConnectError::BadConnectParams));
let stream = try!(priv_io::initialize_stream(&params, ssl));
@ -412,7 +419,10 @@ impl InnerConnection {
next_stmt_id: 0,
notice_handler: Box::new(LoggingNoticeHandler),
notifications: VecDeque::new(),
cancel_data: CancelData { process_id: 0, secret_key: 0 },
cancel_data: CancelData {
process_id: 0,
secret_key: 0,
},
unknown_types: HashMap::new(),
cached_statements: HashMap::new(),
parameters: HashMap::new(),
@ -432,9 +442,9 @@ impl InnerConnection {
}
try!(conn.write_messages(&[StartupMessage {
version: message::PROTOCOL_VERSION,
parameters: &options
}]));
version: message::PROTOCOL_VERSION,
parameters: &options,
}]));
try!(conn.handle_auth(user));
@ -455,21 +465,22 @@ impl InnerConnection {
Ok(conn)
}
#[cfg_attr(rustfmt, rustfmt_skip)]
fn setup_typeinfo_query(&mut self) -> result::Result<(), ConnectError> {
match self.raw_prepare(TYPEINFO_QUERY,
"SELECT t.typname, t.typelem, r.rngsubtype, n.nspname \
FROM pg_catalog.pg_type t \
LEFT OUTER JOIN pg_catalog.pg_range r \
ON r.rngtypid = t.oid \
INNER JOIN pg_catalog.pg_namespace n \
ON t.typnamespace = n.oid \
LEFT OUTER JOIN pg_catalog.pg_range r ON \
r.rngtypid = t.oid \
INNER JOIN pg_catalog.pg_namespace n ON \
t.typnamespace = n.oid \
WHERE t.oid = $1") {
Ok(..) => return Ok(()),
Err(Error::IoError(e)) => return Err(ConnectError::IoError(e)),
// Range types weren't added until Postgres 9.2, so pg_range may not exist
Err(Error::DbError(ref e)) if e.code() == &SqlState::UndefinedTable => {}
Err(Error::DbError(e)) => return Err(ConnectError::DbError(e)),
_ => unreachable!()
_ => unreachable!(),
}
match self.raw_prepare(TYPEINFO_QUERY,
@ -481,7 +492,7 @@ impl InnerConnection {
Ok(..) => Ok(()),
Err(Error::IoError(e)) => Err(ConnectError::IoError(e)),
Err(Error::DbError(e)) => Err(ConnectError::DbError(e)),
_ => unreachable!()
_ => unreachable!(),
}
}
@ -505,12 +516,13 @@ impl InnerConnection {
ParameterStatus { parameter, value } => {
self.parameters.insert(parameter, value);
}
val => return Ok(val)
val => return Ok(val),
}
}
}
fn read_message_with_notification_timeout(&mut self, timeout: Duration)
fn read_message_with_notification_timeout(&mut self,
timeout: Duration)
-> std::io::Result<Option<BackendMessage>> {
debug_assert!(!self.desynchronized);
loop {
@ -523,7 +535,7 @@ impl InnerConnection {
Some(ParameterStatus { parameter, value }) => {
self.parameters.insert(parameter, value);
}
val => return Ok(val)
val => return Ok(val),
}
}
}
@ -535,10 +547,10 @@ impl InnerConnection {
self.notifications.push_back(Notification {
pid: pid,
channel: channel,
payload: payload
payload: payload,
})
}
val => return Ok(val)
val => return Ok(val),
}
}
}
@ -548,9 +560,7 @@ impl InnerConnection {
AuthenticationOk => return Ok(()),
AuthenticationCleartextPassword => {
let pass = try!(user.password.ok_or(ConnectError::MissingPassword));
try!(self.write_messages(&[PasswordMessage {
password: &pass,
}]));
try!(self.write_messages(&[PasswordMessage { password: &pass }]));
}
AuthenticationMD5Password { salt } => {
let pass = try!(user.password.ok_or(ConnectError::MissingPassword));
@ -562,22 +572,20 @@ impl InnerConnection {
let _ = hasher.input(output.as_bytes());
let _ = hasher.input(&salt);
let output = format!("md5{}", hasher.result_str());
try!(self.write_messages(&[PasswordMessage {
password: &output
}]));
try!(self.write_messages(&[PasswordMessage { password: &output }]));
}
AuthenticationKerberosV5
| AuthenticationSCMCredential
| AuthenticationGSS
| AuthenticationSSPI => return Err(ConnectError::UnsupportedAuthentication),
AuthenticationKerberosV5 |
AuthenticationSCMCredential |
AuthenticationGSS |
AuthenticationSSPI => return Err(ConnectError::UnsupportedAuthentication),
ErrorResponse { fields } => return DbError::new_connect(fields),
_ => return Err(ConnectError::IoError(bad_response()))
_ => return Err(ConnectError::IoError(bad_response())),
}
match try!(self.read_message()) {
AuthenticationOk => Ok(()),
ErrorResponse { fields } => return DbError::new_connect(fields),
_ => return Err(ConnectError::IoError(bad_response()))
_ => return Err(ConnectError::IoError(bad_response())),
}
}
@ -588,17 +596,16 @@ impl InnerConnection {
fn raw_prepare(&mut self, stmt_name: &str, query: &str) -> Result<(Vec<Type>, Vec<Column>)> {
debug!("preparing query with name `{}`: {}", stmt_name, query);
try!(self.write_messages(&[
Parse {
name: stmt_name,
query: query,
param_types: &[]
},
Describe {
variant: b'S',
name: stmt_name,
},
Sync]));
try!(self.write_messages(&[Parse {
name: stmt_name,
query: query,
param_types: &[],
},
Describe {
variant: b'S',
name: stmt_name,
},
Sync]));
match try!(self.read_message()) {
ParseComplete => {}
@ -617,7 +624,7 @@ impl InnerConnection {
let raw_columns = match try!(self.read_message()) {
RowDescription { descriptions } => descriptions,
NoData => vec![],
_ => bad_response!(self)
_ => bad_response!(self),
};
try!(self.wait_for_ready());
@ -669,16 +676,15 @@ impl InnerConnection {
}
fn close_statement(&mut self, name: &str, type_: u8) -> Result<()> {
try!(self.write_messages(&[
Close {
variant: type_,
name: name,
},
Sync]));
try!(self.write_messages(&[Close {
variant: type_,
name: name,
},
Sync]));
let resp = match try!(self.read_message()) {
CloseComplete => Ok(()),
ErrorResponse { fields } => DbError::new(fields),
_ => bad_response!(self)
_ => bad_response!(self),
};
try!(self.wait_for_ready());
resp
@ -699,57 +705,56 @@ impl InnerConnection {
IsNull::Yes => None,
IsNull::No => Some(buf),
};
try!(self.write_messages(&[
Bind {
portal: "",
statement: TYPEINFO_QUERY,
formats: &[1],
values: &[value],
result_formats: &[1]
},
Execute {
portal: "",
max_rows: 0,
},
Sync]));
try!(self.write_messages(&[Bind {
portal: "",
statement: TYPEINFO_QUERY,
formats: &[1],
values: &[value],
result_formats: &[1],
},
Execute {
portal: "",
max_rows: 0,
},
Sync]));
match try!(self.read_message()) {
BindComplete => {}
ErrorResponse { fields } => {
try!(self.wait_for_ready());
return DbError::new(fields);
}
_ => bad_response!(self)
_ => bad_response!(self),
}
let (name, elem_oid, rngsubtype, schema): (String, Oid, Option<Oid>, String) =
match try!(self.read_message()) {
DataRow { row } => {
let ctx = SessionInfo::new(self);
(try!(FromSql::from_sql_nullable(&Type::Name,
row[0].as_ref().map(|r| &**r).as_mut(),
&ctx)),
try!(FromSql::from_sql_nullable(&Type::Oid,
row[1].as_ref().map(|r| &**r).as_mut(),
&ctx)),
try!(FromSql::from_sql_nullable(&Type::Oid,
row[2].as_ref().map(|r| &**r).as_mut(),
&ctx)),
try!(FromSql::from_sql_nullable(&Type::Name,
row[3].as_ref().map(|r| &**r).as_mut(),
&ctx)))
}
ErrorResponse { fields } => {
try!(self.wait_for_ready());
return DbError::new(fields);
}
_ => bad_response!(self)
};
match try!(self.read_message()) {
DataRow { row } => {
let ctx = SessionInfo::new(self);
(try!(FromSql::from_sql_nullable(&Type::Name,
row[0].as_ref().map(|r| &**r).as_mut(),
&ctx)),
try!(FromSql::from_sql_nullable(&Type::Oid,
row[1].as_ref().map(|r| &**r).as_mut(),
&ctx)),
try!(FromSql::from_sql_nullable(&Type::Oid,
row[2].as_ref().map(|r| &**r).as_mut(),
&ctx)),
try!(FromSql::from_sql_nullable(&Type::Name,
row[3].as_ref().map(|r| &**r).as_mut(),
&ctx)))
}
ErrorResponse { fields } => {
try!(self.wait_for_ready());
return DbError::new(fields);
}
_ => bad_response!(self),
};
match try!(self.read_message()) {
CommandComplete { .. } => {}
ErrorResponse { fields } => {
try!(self.wait_for_ready());
return DbError::new(fields);
}
_ => bad_response!(self)
_ => bad_response!(self),
}
try!(self.wait_for_ready());
@ -758,7 +763,7 @@ impl InnerConnection {
} else {
match rngsubtype {
Some(oid) => Kind::Range(try!(self.get_type(oid))),
None => Kind::Simple
None => Kind::Simple,
}
};
@ -774,7 +779,7 @@ impl InnerConnection {
fn wait_for_ready(&mut self) -> Result<()> {
match try!(self.read_message()) {
ReadyForQuery { .. } => Ok(()),
_ => bad_response!(self)
_ => bad_response!(self),
}
}
@ -788,16 +793,19 @@ impl InnerConnection {
match try!(self.read_message()) {
ReadyForQuery { .. } => break,
DataRow { row } => {
result.push(row.into_iter().map(|opt| {
opt.map(|b| String::from_utf8_lossy(&b).into_owned())
}).collect());
result.push(row.into_iter()
.map(|opt| {
opt.map(|b| String::from_utf8_lossy(&b).into_owned())
})
.collect());
}
CopyInResponse { .. } => {
try!(self.write_messages(&[
CopyFail {
message: "COPY queries cannot be directly executed",
},
Sync]));
CopyInResponse { .. } |
CopyOutResponse { .. } => {
try!(self.write_messages(&[CopyFail {
message: "COPY queries cannot be directly \
executed",
},
Sync]));
}
ErrorResponse { fields } => {
try!(self.wait_for_ready());
@ -817,25 +825,26 @@ impl InnerConnection {
}
fn _ensure_send() {
fn _is_send<T: Send>() {}
fn _is_send<T: Send>() {
}
_is_send::<Connection>();
}
/// A connection to a Postgres database.
pub struct Connection {
conn: RefCell<InnerConnection>
conn: RefCell<InnerConnection>,
}
impl fmt::Debug for Connection {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
let conn = self.conn.borrow();
fmt.debug_struct("Connection")
.field("cancel_data", &conn.cancel_data)
.field("notifications", &conn.notifications.len())
.field("transaction_depth", &conn.trans_depth)
.field("desynchronized", &conn.desynchronized)
.field("cached_statements", &conn.cached_statements.len())
.finish()
.field("cancel_data", &conn.cancel_data)
.field("notifications", &conn.notifications.len())
.field("transaction_depth", &conn.trans_depth)
.field("desynchronized", &conn.desynchronized)
.field("cached_statements", &conn.cached_statements.len())
.finish()
}
}
@ -860,28 +869,27 @@ impl Connection {
/// struct should be created manually and passed in. Note that Postgres
/// does not support SSL over Unix sockets.
///
/// ## Examples
/// # Examples
///
/// ```rust,no_run
/// # use postgres::{Connection, SslMode};
/// # fn f() -> Result<(), ::postgres::error::ConnectError> {
/// use postgres::{Connection, SslMode};
///
/// let url = "postgresql://postgres:hunter2@localhost:2994/foodb";
/// let conn = try!(Connection::connect(url, &SslMode::None));
/// # Ok(()) };
/// let conn = Connection::connect(url, &SslMode::None).unwrap();
/// ```
///
/// ```rust,no_run
/// # use postgres::{Connection, SslMode};
/// # fn f() -> Result<(), ::postgres::error::ConnectError> {
/// use postgres::{Connection, SslMode};
///
/// let url = "postgresql://postgres@%2Frun%2Fpostgres";
/// let conn = try!(Connection::connect(url, &SslMode::None));
/// # Ok(()) };
/// let conn = Connection::connect(url, &SslMode::None).unwrap();
/// ```
///
/// ```rust,no_run
/// # use postgres::{Connection, UserInfo, ConnectParams, SslMode, ConnectTarget};
/// use postgres::{Connection, UserInfo, ConnectParams, SslMode, ConnectTarget};
///
/// # #[cfg(feature = "unix_socket")]
/// # fn f() -> Result<(), ::postgres::error::ConnectError> {
/// # fn f() {
/// # let some_crazy_path = Path::new("");
/// let params = ConnectParams {
/// target: ConnectTarget::Unix(some_crazy_path),
@ -893,14 +901,13 @@ impl Connection {
/// database: None,
/// options: vec![],
/// };
/// let conn = try!(Connection::connect(params, &SslMode::None));
/// # Ok(()) };
/// let conn = Connection::connect(params, &SslMode::None).unwrap();
/// # }
/// ```
pub fn connect<T>(params: T, ssl: &SslMode) -> result::Result<Connection, ConnectError>
where T: IntoConnectParams {
InnerConnection::connect(params, ssl).map(|conn| {
Connection { conn: RefCell::new(conn) }
})
where T: IntoConnectParams
{
InnerConnection::connect(params, ssl).map(|conn| Connection { conn: RefCell::new(conn) })
}
/// Sets the notice handler for the connection, returning the old handler.
@ -924,16 +931,18 @@ impl Connection {
/// The statement is associated with the connection that created it and may
/// not outlive that connection.
///
/// ## Example
/// # Example
///
/// ```rust,no_run
/// # use postgres::{Connection, SslMode};
/// # let x = 10i32;
/// # let conn = Connection::connect("", &SslMode::None).unwrap();
/// let maybe_stmt = conn.prepare("SELECT foo FROM bar WHERE baz = $1");
/// let stmt = match maybe_stmt {
/// Ok(stmt) => stmt,
/// Err(err) => panic!("Error preparing statement: {:?}", err)
/// };
/// let stmt = conn.prepare("SELECT foo FROM bar WHERE baz = $1").unwrap();
/// for row in stmt.query(&[&x]).unwrap() {
/// let foo: String = row.get(0);
/// println!("foo: {}", foo);
/// }
/// ```
pub fn prepare<'a>(&'a self, query: &str) -> Result<Statement<'a>> {
self.conn.borrow_mut().prepare(query, self)
}
@ -945,18 +954,17 @@ impl Connection {
/// is going to be used frequently, caching it can improve performance by
/// reducing the number of round trips to the Postgres backend.
///
/// ## Example
/// # Example
///
/// ```rust,no_run
/// # use postgres::{Connection, SslMode};
/// # fn f() -> postgres::Result<()> {
/// # let x = 10i32;
/// # let conn = Connection::connect("", &SslMode::None).unwrap();
/// let stmt = try!(conn.prepare_cached("SELECT foo FROM bar WHERE baz = $1"));
/// for row in try!(stmt.query(&[&x])) {
/// println!("foo: {}", row.get::<_, String>(0));
/// let stmt = conn.prepare_cached("SELECT foo FROM bar WHERE baz = $1").unwrap();
/// for row in stmt.query(&[&x]).unwrap() {
/// let foo: String = row.get(0);
/// println!("foo: {}", foo);
/// }
/// # Ok(()) };
/// ```
pub fn prepare_cached<'a>(&'a self, query: &str) -> Result<Statement<'a>> {
self.conn.borrow_mut().prepare_cached(query, self)
@ -968,32 +976,30 @@ impl Connection {
/// the connection for the duration of the transaction. The transaction
/// is active until the `Transaction` object falls out of scope.
///
/// ## Note
/// # Note
/// A transaction will roll back by default. The `set_commit`,
/// `set_rollback`, and `commit` methods alter this behavior.
///
/// ## Panics
/// # Panics
///
/// Panics if a transaction is already active.
///
/// ## Example
/// # Example
///
/// ```rust,no_run
/// # use postgres::{Connection, SslMode};
/// # fn foo() -> Result<(), postgres::error::Error> {
/// # let conn = Connection::connect("", &SslMode::None).unwrap();
/// let trans = try!(conn.transaction());
/// try!(trans.execute("UPDATE foo SET bar = 10", &[]));
/// let trans = conn.transaction().unwrap();
/// trans.execute("UPDATE foo SET bar = 10", &[]).unwrap();
/// // ...
///
/// try!(trans.commit());
/// # Ok(())
/// # }
/// trans.commit().unwrap();
/// ```
pub fn transaction<'a>(&'a self) -> Result<Transaction<'a>> {
let mut conn = self.conn.borrow_mut();
check_desync!(conn);
assert!(conn.trans_depth == 0, "`transaction` must be called on the active transaction");
assert!(conn.trans_depth == 0,
"`transaction` must be called on the active transaction");
try!(conn.quick_query("BEGIN"));
conn.trans_depth += 1;
Ok(Transaction {
@ -1006,7 +1012,9 @@ impl Connection {
/// Sets the isolation level which will be used for future transactions.
///
/// ## Note
/// This is a simple wrapper around `SET TRANSACTION ISOLATION LEVEL ...`.
///
/// # Note
///
/// This will not change the behavior of an active transaction.
pub fn set_transaction_isolation(&self, level: IsolationLevel) -> Result<()> {
@ -1014,6 +1022,8 @@ impl Connection {
}
/// Returns the isolation level which will be used for future transactions.
///
/// This is a simple wrapper around `SHOW TRANSACTION ISOLATION LEVEL`.
pub fn transaction_isolation(&self) -> Result<IsolationLevel> {
let mut conn = self.conn.borrow_mut();
check_desync!(conn);
@ -1028,13 +1038,18 @@ impl Connection {
///
/// On success, returns the number of rows modified or 0 if not applicable.
///
/// ## Panics
/// # Panics
///
/// Panics if the number of parameters provided does not match the number
/// expected.
pub fn execute(&self, query: &str, params: &[&ToSql]) -> Result<u64> {
let (param_types, columns) = try!(self.conn.borrow_mut().raw_prepare("", query));
let stmt = Statement::new(self, "".to_owned(), param_types, columns, Cell::new(0), true);
let stmt = Statement::new(self,
"".to_owned(),
param_types,
columns,
Cell::new(0),
true);
stmt.execute(params)
}
@ -1045,33 +1060,32 @@ impl Connection {
/// execution of batches of non-dynamic statements - for example, creation
/// of a schema for a fresh database.
///
/// ## Warning
/// # Warning
///
/// Prepared statements should be used for any SQL statement which contains
/// user-specified data, as it provides functionality to safely embed that
/// data in the statement. Do not form statements via string concatenation
/// and feed them into this method.
///
/// ## Example
/// # Example
///
/// ```rust,no_run
/// # use postgres::{Connection, Result};
/// fn init_db(conn: &Connection) -> Result<()> {
/// conn.batch_execute("
/// CREATE TABLE person (
/// id SERIAL PRIMARY KEY,
/// name NOT NULL
/// );
/// # use postgres::{Connection, SslMode, Result};
/// # let conn = Connection::connect("", &SslMode::None).unwrap();
/// conn.batch_execute("
/// CREATE TABLE person (
/// id SERIAL PRIMARY KEY,
/// name NOT NULL
/// );
///
/// CREATE TABLE purchase (
/// id SERIAL PRIMARY KEY,
/// person INT NOT NULL REFERENCES person (id),
/// time TIMESTAMPTZ NOT NULL,
/// );
/// CREATE TABLE purchase (
/// id SERIAL PRIMARY KEY,
/// person INT NOT NULL REFERENCES person (id),
/// time TIMESTAMPTZ NOT NULL,
/// );
///
/// CREATE INDEX ON purchase (time);
/// ")
/// }
/// CREATE INDEX ON purchase (time);
/// ").unwrap();
/// ```
pub fn batch_execute(&self, query: &str) -> Result<()> {
self.conn.borrow_mut().quick_query(query).map(|_| ())
@ -1133,9 +1147,9 @@ pub struct Transaction<'conn> {
impl<'a> fmt::Debug for Transaction<'a> {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.debug_struct("Transaction")
.field("commit", &self.commit.get())
.field("depth", &self.depth)
.finish()
.field("commit", &self.commit.get())
.field("depth", &self.depth)
.finish()
}
}
@ -1186,7 +1200,7 @@ impl<'conn> Transaction<'conn> {
/// Like `Connection::transaction`.
///
/// ## Panics
/// # Panics
///
/// Panics if there is an active nested transaction.
pub fn transaction<'a>(&'a self) -> Result<Transaction<'a>> {
@ -1263,11 +1277,10 @@ fn read_rows(conn: &mut InnerConnection, buf: &mut VecDeque<Vec<Option<Vec<u8>>>
return DbError::new(fields);
}
CopyInResponse { .. } => {
try!(conn.write_messages(&[
CopyFail {
message: "COPY queries cannot be directly executed",
},
Sync]));
try!(conn.write_messages(&[CopyFail {
message: "COPY queries cannot be directly executed",
},
Sync]));
}
CopyOutResponse { .. } => {
loop {
@ -1276,9 +1289,9 @@ fn read_rows(conn: &mut InnerConnection, buf: &mut VecDeque<Vec<Option<Vec<u8>>>
_ => {}
}
}
return Err(Error::IoError(std_io::Error::new(
std_io::ErrorKind::InvalidInput,
"COPY queries cannot be directly executed")));
return Err(Error::IoError(std_io::Error::new(std_io::ErrorKind::InvalidInput,
"COPY queries cannot be directly \
executed")));
}
_ => {
conn.desynchronized = true;
@ -1384,7 +1397,8 @@ trait LazyRowsNew<'trans, 'stmt> {
row_limit: i32,
more_rows: bool,
finished: bool,
trans: &'trans Transaction<'trans>) -> LazyRows<'trans, 'stmt>;
trans: &'trans Transaction<'trans>)
-> LazyRows<'trans, 'stmt>;
}
trait SessionInfoNew<'a> {
@ -1397,7 +1411,8 @@ trait StatementInternals<'conn> {
param_types: Vec<Type>,
columns: Vec<Column>,
next_portal_id: Cell<u32>,
finished: bool) -> Statement<'conn>;
finished: bool)
-> Statement<'conn>;
fn conn(&self) -> &'conn Connection;
}

View File

@ -18,7 +18,7 @@ use std::iter::repeat;
struct StepUp<T> {
next: T,
end: T,
ammount: T
ammount: T,
}
impl <T> Iterator for StepUp<T> where
@ -47,7 +47,7 @@ impl <T> RangeExt<T> for Range<T> where
StepUp {
next: self.start,
end: self.end,
ammount: ammount
ammount: ammount,
}
}
}
@ -72,7 +72,7 @@ fn zero(dst: &mut [u8]) {
}
/// Read a vector of bytes into a vector of u32s. The values are read in little-endian format.
fn read_u32v_le(dst: &mut[u32], input: &[u8]) {
fn read_u32v_le(dst: &mut [u32], input: &[u8]) {
assert!(dst.len() * 4 == input.len());
unsafe {
let mut x: *mut u32 = dst.get_unchecked_mut(0);
@ -89,7 +89,7 @@ fn read_u32v_le(dst: &mut[u32], input: &[u8]) {
/// Write a u32 into a vector, which must be 4 bytes long. The value is written in little-endian
/// format.
fn write_u32_le(dst: &mut[u8], mut input: u32) {
fn write_u32_le(dst: &mut [u8], mut input: u32) {
assert!(dst.len() == 4);
input = input.to_le();
unsafe {
@ -147,7 +147,7 @@ trait FixedBuffer {
/// Get the current buffer. The buffer must already be full. This clears the buffer as well.
fn full_buffer<'s>(&'s mut self) -> &'s [u8];
/// Get the current buffer.
/// Get the current buffer.
fn current_buffer<'s>(&'s mut self) -> &'s [u8];
/// Get the current position of the buffer.
@ -247,14 +247,18 @@ struct FixedBuffer64 {
buffer_idx: usize,
}
impl Clone for FixedBuffer64 { fn clone(&self) -> FixedBuffer64 { *self } }
impl Clone for FixedBuffer64 {
fn clone(&self) -> FixedBuffer64 {
*self
}
}
impl FixedBuffer64 {
/// Create a new buffer
fn new() -> FixedBuffer64 {
FixedBuffer64 {
buffer: [0u8; 64],
buffer_idx: 0
buffer_idx: 0,
}
}
}
@ -266,7 +270,7 @@ struct Md5State {
s0: u32,
s1: u32,
s2: u32,
s3: u32
s3: u32,
}
impl Md5State {
@ -275,7 +279,7 @@ impl Md5State {
s0: 0x67452301,
s1: 0xefcdab89,
s2: 0x98badcfe,
s3: 0x10325476
s3: 0x10325476,
}
}
@ -341,8 +345,18 @@ impl Md5State {
for i in (0..16).step_up(4) {
a = op_g(a, b, c, d, data[t & 0x0f].wrapping_add(C2[i]), 5);
d = op_g(d, a, b, c, data[(t + 5) & 0x0f].wrapping_add(C2[i + 1]), 9);
c = op_g(c, d, a, b, data[(t + 10) & 0x0f].wrapping_add(C2[i + 2]), 14);
b = op_g(b, c, d, a, data[(t + 15) & 0x0f].wrapping_add(C2[i + 3]), 20);
c = op_g(c,
d,
a,
b,
data[(t + 10) & 0x0f].wrapping_add(C2[i + 2]),
14);
b = op_g(b,
c,
d,
a,
data[(t + 15) & 0x0f].wrapping_add(C2[i + 3]),
20);
t += 20;
}
@ -361,8 +375,18 @@ impl Md5State {
for i in (0..16).step_up(4) {
a = op_i(a, b, c, d, data[t & 0x0f].wrapping_add(C4[i]), 6);
d = op_i(d, a, b, c, data[(t + 7) & 0x0f].wrapping_add(C4[i + 1]), 10);
c = op_i(c, d, a, b, data[(t + 14) & 0x0f].wrapping_add(C4[i + 2]), 15);
b = op_i(b, c, d, a, data[(t + 21) & 0x0f].wrapping_add(C4[i + 3]), 21);
c = op_i(c,
d,
a,
b,
data[(t + 14) & 0x0f].wrapping_add(C4[i + 2]),
15);
b = op_i(b,
c,
d,
a,
data[(t + 21) & 0x0f].wrapping_add(C4[i + 3]),
21);
t += 28;
}
@ -374,28 +398,24 @@ impl Md5State {
}
// Round 1 constants
static C1: [u32; 16] = [
0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501,
0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821
];
static C1: [u32; 16] = [0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, 0xf57c0faf, 0x4787c62a,
0xa8304613, 0xfd469501, 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be,
0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821];
// Round 2 constants
static C2: [u32; 16] = [
0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8,
0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a
];
static C2: [u32; 16] = [0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, 0xd62f105d, 0x02441453,
0xd8a1e681, 0xe7d3fbc8, 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed,
0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a];
// Round 3 constants
static C3: [u32; 16] = [
0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70,
0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05, 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665
];
static C3: [u32; 16] = [0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, 0xa4beea44, 0x4bdecfa9,
0xf6bb4b60, 0xbebfbc70, 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05,
0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665];
// Round 4 constants
static C4: [u32; 16] = [
0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1,
0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391
];
static C4: [u32; 16] = [0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, 0x655b59c3, 0x8f0ccc92,
0xffeff47d, 0x85845dd1, 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1,
0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391];
/// The MD5 Digest algorithm
pub struct Md5 {
@ -412,7 +432,7 @@ impl Md5 {
length_bytes: 0,
buffer: FixedBuffer64::new(),
state: Md5State::new(),
finished: false
finished: false,
}
}
@ -422,8 +442,9 @@ impl Md5 {
// 2^64 - ie: integer overflow is OK.
self.length_bytes += input.len() as u64;
let self_state = &mut self.state;
self.buffer.input(input, |d: &[u8]| { self_state.process_block(d);}
);
self.buffer.input(input, |d: &[u8]| {
self_state.process_block(d);
});
}
pub fn reset(&mut self) {
@ -436,7 +457,9 @@ impl Md5 {
pub fn result(&mut self, out: &mut [u8]) {
if !self.finished {
let self_state = &mut self.state;
self.buffer.standard_padding(8, |d: &[u8]| { self_state.process_block(d); });
self.buffer.standard_padding(8, |d: &[u8]| {
self_state.process_block(d);
});
write_u32_le(self.buffer.next(4), (self.length_bytes << 3) as u32);
write_u32_le(self.buffer.next(4), (self.length_bytes >> 29) as u32);
self_state.process_block(self.buffer.full_buffer());
@ -449,12 +472,14 @@ impl Md5 {
write_u32_le(&mut out[12..16], self.state.s3);
}
fn output_bits(&self) -> usize { 128 }
fn output_bits(&self) -> usize {
128
}
pub fn result_str(&mut self) -> String {
use serialize::hex::ToHex;
let mut buf: Vec<u8> = repeat(0).take((self.output_bits()+7)/8).collect();
let mut buf: Vec<u8> = repeat(0).take((self.output_bits() + 7) / 8).collect();
self.result(&mut buf);
buf[..].to_hex()
}

View File

@ -20,14 +20,14 @@ pub enum BackendMessage {
AuthenticationGSS,
AuthenticationKerberosV5,
AuthenticationMD5Password {
salt: [u8; 4]
salt: [u8; 4],
},
AuthenticationOk,
AuthenticationSCMCredential,
AuthenticationSSPI,
BackendKeyData {
process_id: u32,
secret_key: u32
secret_key: u32,
},
BindComplete,
CloseComplete,
@ -48,15 +48,15 @@ pub enum BackendMessage {
column_formats: Vec<u16>,
},
DataRow {
row: Vec<Option<Vec<u8>>>
row: Vec<Option<Vec<u8>>>,
},
EmptyQueryResponse,
ErrorResponse {
fields: Vec<(u8, String)>
fields: Vec<(u8, String)>,
},
NoData,
NoticeResponse {
fields: Vec<(u8, String)>
fields: Vec<(u8, String)>,
},
NotificationResponse {
pid: u32,
@ -64,7 +64,7 @@ pub enum BackendMessage {
payload: String,
},
ParameterDescription {
types: Vec<Oid>
types: Vec<Oid>,
},
ParameterStatus {
parameter: String,
@ -73,11 +73,11 @@ pub enum BackendMessage {
ParseComplete,
PortalSuspended,
ReadyForQuery {
_state: u8
_state: u8,
},
RowDescription {
descriptions: Vec<RowDescriptionEntry>
}
descriptions: Vec<RowDescriptionEntry>,
},
}
pub struct RowDescriptionEntry {
@ -87,7 +87,7 @@ pub struct RowDescriptionEntry {
pub type_oid: Oid,
pub type_size: i16,
pub type_modifier: i32,
pub format: i16
pub format: i16,
}
pub enum FrontendMessage<'a> {
@ -96,7 +96,7 @@ pub enum FrontendMessage<'a> {
statement: &'a str,
formats: &'a [i16],
values: &'a [Option<Vec<u8>>],
result_formats: &'a [i16]
result_formats: &'a [i16],
},
CancelRequest {
code: u32,
@ -105,43 +105,43 @@ pub enum FrontendMessage<'a> {
},
Close {
variant: u8,
name: &'a str
name: &'a str,
},
CopyData {
data: &'a [u8],
},
CopyDone,
CopyFail {
message: &'a str
message: &'a str,
},
Describe {
variant: u8,
name: &'a str
name: &'a str,
},
Execute {
portal: &'a str,
max_rows: i32
max_rows: i32,
},
Parse {
name: &'a str,
query: &'a str,
param_types: &'a [Oid]
param_types: &'a [Oid],
},
PasswordMessage {
password: &'a str
password: &'a str,
},
Query {
query: &'a str
query: &'a str,
},
SslRequest {
code: u32
code: u32,
},
StartupMessage {
version: u32,
parameters: &'a [(String, String)]
parameters: &'a [(String, String)],
},
Sync,
Terminate
Terminate,
}
#[doc(hidden)]
@ -158,7 +158,7 @@ impl<W: Write> WriteCStr for W {
#[doc(hidden)]
pub trait WriteMessage {
fn write_message(&mut self, &FrontendMessage) -> io::Result<()> ;
fn write_message(&mut self, &FrontendMessage) -> io::Result<()>;
}
impl<W: Write> WriteMessage for W {
@ -285,8 +285,7 @@ impl<R: BufRead> ReadCStr for R {
pub trait ReadMessage {
fn read_message(&mut self) -> io::Result<BackendMessage>;
fn read_message_timeout(&mut self, timeout: Duration)
-> io::Result<Option<BackendMessage>>;
fn read_message_timeout(&mut self, timeout: Duration) -> io::Result<Option<BackendMessage>>;
fn finish_read_message(&mut self, ident: u8) -> io::Result<BackendMessage>;
}
@ -297,8 +296,7 @@ impl<R: BufRead + ReadTimeout> ReadMessage for R {
self.finish_read_message(ident)
}
fn read_message_timeout(&mut self, timeout: Duration)
-> io::Result<Option<BackendMessage>> {
fn read_message_timeout(&mut self, timeout: Duration) -> io::Result<Option<BackendMessage>> {
try!(self.set_read_timeout(Some(timeout)));
let ident = self.read_u8();
try!(self.set_read_timeout(None));
@ -328,16 +326,14 @@ impl<R: BufRead + ReadTimeout> ReadMessage for R {
b'A' => NotificationResponse {
pid: try!(rdr.read_u32::<BigEndian>()),
channel: try!(rdr.read_cstr()),
payload: try!(rdr.read_cstr())
payload: try!(rdr.read_cstr()),
},
b'c' => BCopyDone,
b'C' => CommandComplete { tag: try!(rdr.read_cstr()) },
b'd' => {
let mut data = vec![];
try!(rdr.read_to_end(&mut data));
BCopyData {
data: data,
}
BCopyData { data: data }
}
b'D' => try!(read_data_row(&mut rdr)),
b'E' => ErrorResponse { fields: try!(read_fields(&mut rdr)) },
@ -366,7 +362,7 @@ impl<R: BufRead + ReadTimeout> ReadMessage for R {
b'I' => EmptyQueryResponse,
b'K' => BackendKeyData {
process_id: try!(rdr.read_u32::<BigEndian>()),
secret_key: try!(rdr.read_u32::<BigEndian>())
secret_key: try!(rdr.read_u32::<BigEndian>()),
},
b'n' => NoData,
b'N' => NoticeResponse { fields: try!(read_fields(&mut rdr)) },
@ -374,7 +370,7 @@ impl<R: BufRead + ReadTimeout> ReadMessage for R {
b's' => PortalSuspended,
b'S' => ParameterStatus {
parameter: try!(rdr.read_cstr()),
value: try!(rdr.read_cstr())
value: try!(rdr.read_cstr()),
},
b't' => try!(read_parameter_description(&mut rdr)),
b'T' => try!(read_row_description(&mut rdr)),
@ -431,7 +427,7 @@ fn read_auth_message<R: Read>(buf: &mut R) -> io::Result<BackendMessage> {
let mut salt = [0; 4];
try!(util::read_all(buf, &mut salt));
AuthenticationMD5Password { salt: salt }
},
}
6 => AuthenticationSCMCredential,
7 => AuthenticationGSS,
9 => AuthenticationSSPI,

View File

@ -20,14 +20,14 @@ pub struct Notification {
/// An iterator over asynchronous notifications.
pub struct Notifications<'conn> {
conn: &'conn Connection
conn: &'conn Connection,
}
impl<'a> fmt::Debug for Notifications<'a> {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.debug_struct("Notifications")
.field("pending", &self.len())
.finish()
.field("pending", &self.len())
.finish()
}
}
@ -45,9 +45,7 @@ impl<'conn> Notifications<'conn> {
/// `None` if more notifications are received. However, those notifications
/// will not be registered until the connection is used in some way.
pub fn iter<'a>(&'a self) -> Iter<'a> {
Iter {
conn: self.conn,
}
Iter { conn: self.conn }
}
/// Returns an iterator over notifications that blocks until one is
@ -55,9 +53,7 @@ impl<'conn> Notifications<'conn> {
///
/// The iterator will never return `None`.
pub fn blocking_iter<'a>(&'a self) -> BlockingIter<'a> {
BlockingIter {
conn: self.conn,
}
BlockingIter { conn: self.conn }
}
/// Returns an iterator over notifications that blocks for a limited time
@ -86,9 +82,7 @@ impl<'a, 'conn> IntoIterator for &'a Notifications<'conn> {
impl<'conn> NotificationsNew<'conn> for Notifications<'conn> {
fn new(conn: &'conn Connection) -> Notifications<'conn> {
Notifications {
conn: conn,
}
Notifications { conn: conn }
}
}
@ -129,11 +123,11 @@ impl<'a> Iterator for BlockingIter<'a> {
Some(Ok(Notification {
pid: pid,
channel: channel,
payload: payload
payload: payload,
}))
}
Err(err) => Some(Err(Error::IoError(err))),
_ => unreachable!()
_ => unreachable!(),
}
}
}
@ -164,12 +158,12 @@ impl<'a> Iterator for TimeoutIter<'a> {
Some(Ok(Notification {
pid: pid,
channel: channel,
payload: payload
payload: payload,
}))
}
Ok(None) => None,
Err(err) => Some(Err(Error::IoError(err))),
_ => unreachable!()
_ => unreachable!(),
}
}
}

View File

@ -13,7 +13,7 @@ use std::os::unix::io::{AsRawFd, RawFd};
use std::os::windows::io::{AsRawSocket, RawSocket};
use {SslMode, ConnectParams, ConnectTarget};
use error::{ConnectError};
use error::ConnectError;
use io::{NegotiateSsl, StreamWrapper};
use message::{self, WriteMessage};
use message::FrontendMessage::SslRequest;
@ -28,7 +28,8 @@ pub trait ReadTimeout {
impl ReadTimeout for BufStream<Box<StreamWrapper>> {
fn set_read_timeout(&self, timeout: Option<Duration>) -> io::Result<()> {
match self.get_ref().get_ref().0 {
InternalStream::Tcp(ref s) => <TcpStream as TcpStreamExt>::set_read_timeout(s, timeout),
InternalStream::Tcp(ref s) =>
<TcpStream as TcpStreamExt>::set_read_timeout(s, timeout),
#[cfg(feature = "unix_socket")]
InternalStream::Unix(ref s) => s.set_read_timeout(timeout),
}
@ -136,8 +137,9 @@ fn open_socket(params: &ConnectParams) -> Result<InternalStream, ConnectError> {
}
}
pub fn initialize_stream(params: &ConnectParams, ssl: &SslMode)
-> Result<Box<StreamWrapper>, ConnectError> {
pub fn initialize_stream(params: &ConnectParams,
ssl: &SslMode)
-> Result<Box<StreamWrapper>, ConnectError> {
let mut socket = Stream(try!(open_socket(params)));
let (ssl_required, negotiator) = match *ssl {
@ -161,11 +163,11 @@ pub fn initialize_stream(params: &ConnectParams, ssl: &SslMode)
let host = match params.target {
ConnectTarget::Tcp(ref host) => host,
#[cfg(feature = "unix_socket")]
ConnectTarget::Unix(_) => return Err(ConnectError::IoError(::bad_response()))
ConnectTarget::Unix(_) => return Err(ConnectError::IoError(::bad_response())),
};
match negotiator.negotiate_ssl(host, socket) {
Ok(stream) => Ok(stream),
Err(err) => Err(ConnectError::SslError(err))
Err(err) => Err(ConnectError::SslError(err)),
}
}

View File

@ -7,13 +7,7 @@ use std::borrow::Cow;
use std::slice;
use std::vec;
use {Result,
Transaction,
read_rows,
DbErrorNew,
SessionInfoNew,
RowsNew,
LazyRowsNew,
use {Result, Transaction, read_rows, DbErrorNew, SessionInfoNew, RowsNew, LazyRowsNew,
StatementInternals};
use types::{FromSql, SessionInfo};
use stmt::{Statement, Column};
@ -38,9 +32,9 @@ impl<'a> RowsNew<'a> for Rows<'a> {
impl<'a> fmt::Debug for Rows<'a> {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.debug_struct("Rows")
.field("columns", &self.columns())
.field("rows", &self.data.len())
.finish()
.field("columns", &self.columns())
.field("rows", &self.data.len())
.finish()
}
}
@ -71,7 +65,7 @@ impl<'stmt> Rows<'stmt> {
pub fn iter<'a>(&'a self) -> Iter<'a> {
Iter {
stmt: self.stmt,
iter: self.data.iter()
iter: self.data.iter(),
}
}
}
@ -92,7 +86,7 @@ impl<'stmt> IntoIterator for Rows<'stmt> {
fn into_iter(self) -> IntoIter<'stmt> {
IntoIter {
stmt: self.stmt,
iter: self.data.into_iter()
iter: self.data.into_iter(),
}
}
}
@ -172,14 +166,14 @@ impl<'stmt> ExactSizeIterator for IntoIter<'stmt> {}
/// A single result row of a query.
pub struct Row<'a> {
stmt: &'a Statement<'a>,
data: Cow<'a, [Option<Vec<u8>>]>
data: Cow<'a, [Option<Vec<u8>>]>,
}
impl<'a> fmt::Debug for Row<'a> {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.debug_struct("Row")
.field("statement", self.stmt)
.finish()
.field("statement", self.stmt)
.finish()
}
}
@ -201,14 +195,18 @@ impl<'a> Row<'a> {
///
/// Returns an `Error` value if the index does not reference a column or
/// the return type is not compatible with the Postgres type.
pub fn get_opt<I, T>(&self, idx: I) -> Result<T> where I: RowIndex, T: FromSql {
pub fn get_opt<I, T>(&self, idx: I) -> Result<T>
where I: RowIndex,
T: FromSql
{
let idx = try!(idx.idx(self.stmt).ok_or(Error::InvalidColumn));
let ty = self.stmt.columns()[idx].type_();
if !<T as FromSql>::accepts(ty) {
return Err(Error::WrongType(ty.clone()));
}
let conn = self.stmt.conn().conn.borrow();
FromSql::from_sql_nullable(ty, self.data[idx].as_ref().map(|e| &**e).as_mut(),
FromSql::from_sql_nullable(ty,
self.data[idx].as_ref().map(|e| &**e).as_mut(),
&SessionInfo::new(&*conn))
}
@ -217,35 +215,41 @@ impl<'a> Row<'a> {
/// A field can be accessed by the name or index of its column, though
/// access by index is more efficient. Rows are 0-indexed.
///
/// ## Panics
/// # Panics
///
/// Panics if the index does not reference a column or the return type is
/// not compatible with the Postgres type.
///
/// ## Example
/// # Example
///
/// ```rust,no_run
/// # use postgres::{Connection, SslMode};
/// # let conn = Connection::connect("", &SslMode::None).unwrap();
/// # let stmt = conn.prepare("").unwrap();
/// # let mut result = stmt.query(&[]).unwrap();
/// # let row = result.iter().next().unwrap();
/// let foo: i32 = row.get(0);
/// let bar: String = row.get("bar");
/// let stmt = conn.prepare("SELECT foo, bar from BAZ").unwrap();
/// for row in stmt.query(&[]).unwrap() {
/// let foo: i32 = row.get(0);
/// let bar: String = row.get("bar");
/// println!("{}: {}", foo, bar);
/// }
/// ```
pub fn get<I, T>(&self, idx: I) -> T where I: RowIndex + fmt::Debug + Clone, T: FromSql {
pub fn get<I, T>(&self, idx: I) -> T
where I: RowIndex + fmt::Debug + Clone,
T: FromSql
{
match self.get_opt(idx.clone()) {
Ok(ok) => ok,
Err(err) => panic!("error retrieving column {:?}: {:?}", idx, err)
Err(err) => panic!("error retrieving column {:?}: {:?}", idx, err),
}
}
/// Retrieves the specified field as a raw buffer of Postgres data.
///
/// ## Panics
/// # Panics
///
/// Panics if the index does not reference a column.
pub fn get_bytes<I>(&self, idx: I) -> Option<&[u8]> where I: RowIndex + fmt::Debug {
pub fn get_bytes<I>(&self, idx: I) -> Option<&[u8]>
where I: RowIndex + fmt::Debug
{
match idx.idx(self.stmt) {
Some(idx) => self.data[idx].as_ref().map(|e| &**e),
None => panic!("invalid index {:?}", idx),
@ -303,7 +307,8 @@ impl<'trans, 'stmt> LazyRowsNew<'trans, 'stmt> for LazyRows<'trans, 'stmt> {
row_limit: i32,
more_rows: bool,
finished: bool,
trans: &'trans Transaction<'trans>) -> LazyRows<'trans, 'stmt> {
trans: &'trans Transaction<'trans>)
-> LazyRows<'trans, 'stmt> {
LazyRows {
stmt: stmt,
data: data,
@ -311,7 +316,7 @@ impl<'trans, 'stmt> LazyRowsNew<'trans, 'stmt> for LazyRows<'trans, 'stmt> {
row_limit: row_limit,
more_rows: more_rows,
finished: finished,
_trans: trans
_trans: trans,
}
}
}
@ -327,11 +332,11 @@ impl<'a, 'b> Drop for LazyRows<'a, 'b> {
impl<'a, 'b> fmt::Debug for LazyRows<'a, 'b> {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.debug_struct("LazyRows")
.field("name", &self.name)
.field("row_limit", &self.row_limit)
.field("remaining_rows", &self.data.len())
.field("more_rows", &self.more_rows)
.finish()
.field("name", &self.name)
.field("row_limit", &self.row_limit)
.field("remaining_rows", &self.data.len())
.field("more_rows", &self.more_rows)
.finish()
}
}
@ -345,12 +350,11 @@ impl<'trans, 'stmt> LazyRows<'trans, 'stmt> {
fn execute(&mut self) -> Result<()> {
let mut conn = self.stmt.conn().conn.borrow_mut();
try!(conn.write_messages(&[
Execute {
portal: &self.name,
max_rows: self.row_limit
},
Sync]));
try!(conn.write_messages(&[Execute {
portal: &self.name,
max_rows: self.row_limit,
},
Sync]));
read_rows(&mut conn, &mut self.data).map(|more_rows| self.more_rows = more_rows)
}

View File

@ -28,10 +28,10 @@ pub struct Statement<'conn> {
impl<'a> fmt::Debug for Statement<'a> {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.debug_struct("Statement")
.field("name", &self.name)
.field("parameter_types", &self.param_types)
.field("columns", &self.columns)
.finish()
.field("name", &self.name)
.field("parameter_types", &self.param_types)
.field("columns", &self.columns)
.finish()
}
}
@ -47,7 +47,8 @@ impl<'conn> StatementInternals<'conn> for Statement<'conn> {
param_types: Vec<Type>,
columns: Vec<Column>,
next_portal_id: Cell<u32>,
finished: bool) -> Statement<'conn> {
finished: bool)
-> Statement<'conn> {
Statement {
conn: conn,
name: name,
@ -81,7 +82,9 @@ impl<'conn> Statement<'conn> {
"expected {} parameters but got {}",
self.param_types.len(),
params.len());
debug!("executing statement {} with parameters: {:?}", self.name, params);
debug!("executing statement {} with parameters: {:?}",
self.name,
params);
let mut values = vec![];
for (param, ty) in params.iter().zip(self.param_types.iter()) {
let mut buf = vec![];
@ -89,21 +92,20 @@ impl<'conn> Statement<'conn> {
IsNull::Yes => values.push(None),
IsNull::No => values.push(Some(buf)),
}
};
}
try!(conn.write_messages(&[
Bind {
portal: portal_name,
statement: &self.name,
formats: &[1],
values: &values,
result_formats: &[1]
},
Execute {
portal: portal_name,
max_rows: row_limit
},
Sync]));
try!(conn.write_messages(&[Bind {
portal: portal_name,
statement: &self.name,
formats: &[1],
values: &values,
result_formats: &[1],
},
Execute {
portal: portal_name,
max_rows: row_limit,
},
Sync]));
match try!(conn.read_message()) {
BindComplete => Ok(()),
@ -118,7 +120,10 @@ impl<'conn> Statement<'conn> {
}
}
fn inner_query<'a>(&'a self, portal_name: &str, row_limit: i32, params: &[&ToSql])
fn inner_query<'a>(&'a self,
portal_name: &str,
row_limit: i32,
params: &[&ToSql])
-> Result<(VecDeque<Vec<Option<Vec<u8>>>>, bool)> {
try!(self.inner_execute(portal_name, row_limit, params));
@ -141,12 +146,12 @@ impl<'conn> Statement<'conn> {
///
/// If the statement does not modify any rows (e.g. SELECT), 0 is returned.
///
/// ## Panics
/// # Panics
///
/// Panics if the number of parameters provided does not match the number
/// expected.
///
/// ## Example
/// # Example
///
/// ```rust,no_run
/// # use postgres::{Connection, SslMode};
@ -154,10 +159,8 @@ impl<'conn> Statement<'conn> {
/// # let bar = 1i32;
/// # let baz = true;
/// let stmt = conn.prepare("UPDATE foo SET bar = $1 WHERE baz = $2").unwrap();
/// match stmt.execute(&[&bar, &baz]) {
/// Ok(count) => println!("{} row(s) updated", count),
/// Err(err) => println!("Error executing query: {:?}", err)
/// }
/// let rows_updated = stmt.execute(&[&bar, &baz]).unwrap();
/// println!("{} rows updated", rows_updated);
/// ```
pub fn execute(&self, params: &[&ToSql]) -> Result<u64> {
check_desync!(self.conn);
@ -181,11 +184,11 @@ impl<'conn> Statement<'conn> {
break;
}
CopyInResponse { .. } => {
try!(conn.write_messages(&[
CopyFail {
message: "COPY queries cannot be directly executed",
},
Sync]));
try!(conn.write_messages(&[CopyFail {
message: "COPY queries cannot be directly \
executed",
},
Sync]));
}
CopyOutResponse { .. } => {
loop {
@ -214,32 +217,26 @@ impl<'conn> Statement<'conn> {
/// Executes the prepared statement, returning the resulting rows.
///
/// ## Panics
/// # Panics
///
/// Panics if the number of parameters provided does not match the number
/// expected.
///
/// ## Example
/// # Example
///
/// ```rust,no_run
/// # use postgres::{Connection, SslMode};
/// # let conn = Connection::connect("", &SslMode::None).unwrap();
/// let stmt = conn.prepare("SELECT foo FROM bar WHERE baz = $1").unwrap();
/// # let baz = true;
/// let rows = match stmt.query(&[&baz]) {
/// Ok(rows) => rows,
/// Err(err) => panic!("Error running query: {:?}", err)
/// };
/// for row in &rows {
/// for row in stmt.query(&[&baz]).unwrap() {
/// let foo: i32 = row.get("foo");
/// println!("foo: {}", foo);
/// }
/// ```
pub fn query<'a>(&'a self, params: &[&ToSql]) -> Result<Rows<'a>> {
check_desync!(self.conn);
self.inner_query("", 0, params).map(|(buf, _)| {
Rows::new(self, buf.into_iter().collect())
})
self.inner_query("", 0, params).map(|(buf, _)| Rows::new(self, buf.into_iter().collect()))
}
/// Executes the prepared statement, returning a lazily loaded iterator
@ -254,7 +251,7 @@ impl<'conn> Statement<'conn> {
/// object representing the active transaction must be passed to
/// `lazy_query`.
///
/// ## Panics
/// # Panics
///
/// Panics if the provided `Transaction` is not associated with the same
/// `Connection` as this `Statement`, if the `Transaction` is not
@ -318,9 +315,10 @@ impl<'conn> Statement<'conn> {
loop {
match try!(conn.read_message()) {
ReadyForQuery { .. } => {
return Err(Error::IoError(io::Error::new(
io::ErrorKind::InvalidInput,
"called `copy_in` on a non-`COPY FROM STDIN` statement")));
return Err(Error::IoError(io::Error::new(io::ErrorKind::InvalidInput,
"called `copy_in` on a \
non-`COPY FROM STDIN` \
statement")));
}
_ => {}
}
@ -339,20 +337,15 @@ impl<'conn> Statement<'conn> {
match fill_copy_buf(&mut buf, r, &info) {
Ok(0) => break,
Ok(len) => {
try_desync!(info.conn, info.conn.stream.write_message(
&CopyData {
data: &buf[..len],
}));
try_desync!(info.conn,
info.conn.stream.write_message(&CopyData { data: &buf[..len] }));
}
Err(err) => {
try!(info.conn.write_messages(&[
CopyFail {
message: "",
},
CopyDone,
Sync]));
try!(info.conn.write_messages(&[CopyFail { message: "" }, CopyDone, Sync]));
match try!(info.conn.read_message()) {
ErrorResponse { .. } => { /* expected from the CopyFail */ }
ErrorResponse { .. } => {
// expected from the CopyFail
}
_ => {
info.conn.desynchronized = true;
return Err(Error::IoError(bad_response()));
@ -401,7 +394,7 @@ impl<'conn> Statement<'conn> {
/// INSERT INTO people (id, name) VALUES (1, 'john'), (2, 'jane');").unwrap();
/// let stmt = conn.prepare("COPY people TO STDOUT").unwrap();
/// let mut buf = vec![];
/// let mut r = stmt.copy_out(&[], &mut buf).unwrap();
/// stmt.copy_out(&[], &mut buf).unwrap();
/// assert_eq!(buf, b"1\tjohn\n2\tjane\n");
/// ```
pub fn copy_out<'a, W: WriteWithInfo>(&'a self, params: &[&ToSql], w: &mut W) -> Result<u64> {
@ -411,23 +404,20 @@ impl<'conn> Statement<'conn> {
let (format, column_formats) = match try!(conn.read_message()) {
CopyOutResponse { format, column_formats } => (format, column_formats),
CopyInResponse { .. } => {
try!(conn.write_messages(&[
CopyFail {
message: "",
},
CopyDone,
Sync]));
try!(conn.write_messages(&[CopyFail { message: "" }, CopyDone, Sync]));
match try!(conn.read_message()) {
ErrorResponse { .. } => { /* expected from the CopyFail */ }
ErrorResponse { .. } => {
// expected from the CopyFail
}
_ => {
conn.desynchronized = true;
return Err(Error::IoError(bad_response()));
}
}
try!(conn.wait_for_ready());
return Err(Error::IoError(io::Error::new(
io::ErrorKind::InvalidInput,
"called `copy_out` on a non-`COPY TO STDOUT` statement")));
return Err(Error::IoError(io::Error::new(io::ErrorKind::InvalidInput,
"called `copy_out` on a non-`COPY TO \
STDOUT` statement")));
}
ErrorResponse { fields } => {
try!(conn.wait_for_ready());
@ -437,9 +427,10 @@ impl<'conn> Statement<'conn> {
loop {
match try!(conn.read_message()) {
ReadyForQuery { .. } => {
return Err(Error::IoError(io::Error::new(
io::ErrorKind::InvalidInput,
"called `copy_out` on a non-`COPY TO STDOUT` statement")));
return Err(Error::IoError(io::Error::new(io::ErrorKind::InvalidInput,
"called `copy_out` on a \
non-`COPY TO STDOUT` \
statement")));
}
_ => {}
}
@ -472,7 +463,7 @@ impl<'conn> Statement<'conn> {
}
}
}
BCopyDone => {},
BCopyDone => {}
CommandComplete { tag } => {
count = util::parse_update_count(tag);
break;
@ -512,8 +503,7 @@ impl<'conn> Statement<'conn> {
}
}
fn fill_copy_buf<R: ReadWithInfo>(buf: &mut [u8], r: &mut R, info: &CopyInfo)
-> io::Result<usize> {
fn fill_copy_buf<R: ReadWithInfo>(buf: &mut [u8], r: &mut R, info: &CopyInfo) -> io::Result<usize> {
let mut nread = 0;
while nread < buf.len() {
match r.read_with_info(&mut buf[nread..], info) {
@ -530,7 +520,7 @@ fn fill_copy_buf<R: ReadWithInfo>(buf: &mut [u8], r: &mut R, info: &CopyInfo)
#[derive(PartialEq, Eq, Clone, Debug)]
pub struct Column {
name: String,
type_: Type
type_: Type,
}
impl ColumnNew for Column {

View File

@ -3,7 +3,8 @@ extern crate chrono;
use std::error;
use std::io::prelude::*;
use byteorder::{ReadBytesExt, WriteBytesExt, BigEndian};
use self::chrono::{Duration, NaiveDate, NaiveTime, NaiveDateTime, DateTime, UTC, Local, FixedOffset};
use self::chrono::{Duration, NaiveDate, NaiveTime, NaiveDateTime, DateTime, UTC, Local,
FixedOffset};
use Result;
use error::Error;
@ -23,11 +24,15 @@ impl FromSql for NaiveDateTime {
}
impl ToSql for NaiveDateTime {
fn to_sql<W: Write+?Sized>(&self, _: &Type, mut w: &mut W, _: &SessionInfo) -> Result<IsNull> {
fn to_sql<W: Write + ?Sized>(&self,
_: &Type,
mut w: &mut W,
_: &SessionInfo)
-> Result<IsNull> {
let time = match (*self - base()).num_microseconds() {
Some(time) => time,
None => {
let err: Box<error::Error+Sync+Send> = "value too large to transmit".into();
let err: Box<error::Error + Sync + Send> = "value too large to transmit".into();
return Err(Error::Conversion(err));
}
};
@ -49,8 +54,11 @@ impl FromSql for DateTime<UTC> {
}
impl ToSql for DateTime<UTC> {
fn to_sql<W: Write+?Sized>(&self, type_: &Type, mut w: &mut W, info: &SessionInfo)
-> Result<IsNull> {
fn to_sql<W: Write + ?Sized>(&self,
type_: &Type,
mut w: &mut W,
info: &SessionInfo)
-> Result<IsNull> {
self.naive_utc().to_sql(type_, w, info)
}
@ -68,8 +76,11 @@ impl FromSql for DateTime<Local> {
}
impl ToSql for DateTime<Local> {
fn to_sql<W: Write+?Sized>(&self, type_: &Type, mut w: &mut W, info: &SessionInfo)
-> Result<IsNull> {
fn to_sql<W: Write + ?Sized>(&self,
type_: &Type,
mut w: &mut W,
info: &SessionInfo)
-> Result<IsNull> {
self.with_timezone(&UTC).to_sql(type_, w, info)
}
@ -78,7 +89,9 @@ impl ToSql for DateTime<Local> {
}
impl FromSql for DateTime<FixedOffset> {
fn from_sql<R: Read>(type_: &Type, raw: &mut R, info: &SessionInfo)
fn from_sql<R: Read>(type_: &Type,
raw: &mut R,
info: &SessionInfo)
-> Result<DateTime<FixedOffset>> {
let utc = try!(DateTime::<UTC>::from_sql(type_, raw, info));
Ok(utc.with_timezone(&FixedOffset::east(0)))
@ -88,8 +101,11 @@ impl FromSql for DateTime<FixedOffset> {
}
impl ToSql for DateTime<FixedOffset> {
fn to_sql<W: Write+?Sized>(&self, type_: &Type, mut w: &mut W, info: &SessionInfo)
-> Result<IsNull> {
fn to_sql<W: Write + ?Sized>(&self,
type_: &Type,
mut w: &mut W,
info: &SessionInfo)
-> Result<IsNull> {
self.with_timezone(&UTC).to_sql(type_, w, info)
}
@ -107,10 +123,14 @@ impl FromSql for NaiveDate {
}
impl ToSql for NaiveDate {
fn to_sql<W: Write+?Sized>(&self, _: &Type, mut w: &mut W, _: &SessionInfo) -> Result<IsNull> {
fn to_sql<W: Write + ?Sized>(&self,
_: &Type,
mut w: &mut W,
_: &SessionInfo)
-> Result<IsNull> {
let jd = (*self - base().date()).num_days();
if jd > i32::max_value() as i64 || jd < i32::min_value() as i64 {
let err: Box<error::Error+Sync+Send> = "value too large to transmit".into();
let err: Box<error::Error + Sync + Send> = "value too large to transmit".into();
return Err(Error::Conversion(err));
}
@ -132,12 +152,16 @@ impl FromSql for NaiveTime {
}
impl ToSql for NaiveTime {
fn to_sql<W: Write+?Sized>(&self, _: &Type, mut w: &mut W, _: &SessionInfo) -> Result<IsNull> {
fn to_sql<W: Write + ?Sized>(&self,
_: &Type,
mut w: &mut W,
_: &SessionInfo)
-> Result<IsNull> {
let delta = *self - NaiveTime::from_hms(0, 0, 0);
let time = match delta.num_microseconds() {
Some(time) => time,
None => {
let err: Box<error::Error+Sync+Send> = "value too large to transmit".into();
let err: Box<error::Error + Sync + Send> = "value too large to transmit".into();
return Err(Error::Conversion(err));
}
};

View File

@ -37,7 +37,7 @@ macro_rules! to_sql_checked {
if !<Self as $crate::types::ToSql>::accepts(ty) {
return Err($crate::error::Error::WrongType(ty.clone()));
}
self.to_sql(ty, out, ctx)
$crate::types::ToSql::to_sql(self, ty, out, ctx)
}
}
}
@ -63,9 +63,7 @@ pub struct SessionInfo<'a> {
impl<'a> SessionInfoNew<'a> for SessionInfo<'a> {
fn new(conn: &'a InnerConnection) -> SessionInfo<'a> {
SessionInfo {
conn: conn
}
SessionInfo { conn: conn }
}
}
@ -176,317 +174,317 @@ macro_rules! make_postgres_type {
// Values from pg_type.h
make_postgres_type! {
#[doc="BOOL - boolean, 'true'/'false'"]
/// BOOL - boolean, 'true'/'false'
16: "bool" => Bool: Kind::Simple,
#[doc="BYTEA - variable-length string, binary values escaped"]
/// BYTEA - variable-length string, binary values escaped
17: "bytea" => Bytea: Kind::Simple,
#[doc="\"char\" - single character"]
/// "char" - single character
18: "char" => Char: Kind::Simple,
#[doc="NAME - 63-byte type for storing system identifiers"]
/// NAME - 63-byte type for storing system identifiers
19: "name" => Name: Kind::Simple,
#[doc="INT8/BIGINT - ~18 digit integer, 8-byte storage"]
/// INT8/BIGINT - ~18 digit integer, 8-byte storage
20: "int8" => Int8: Kind::Simple,
#[doc="INT2/SMALLINT - -32 thousand to 32 thousand, 2-byte storage"]
/// INT2/SMALLINT - -32 thousand to 32 thousand, 2-byte storage
21: "int2" => Int2: Kind::Simple,
#[doc="INT2VECTOR - array of int2, used in system tables"]
/// INT2VECTOR - array of int2, used in system tables
22: "int2vector" => Int2Vector: Kind::Array(Type::Int2),
#[doc="INT4/INT - -2 billion to 2 billion integer, 4-byte storage"]
/// INT4/INT - -2 billion to 2 billion integer, 4-byte storage
23: "int4" => Int4: Kind::Simple,
#[doc="REGPROC - registered procedure"]
/// REGPROC - registered procedure
24: "regproc" => Regproc: Kind::Simple,
#[doc="TEXT - variable-length string, no limit specified"]
/// TEXT - variable-length string, no limit specified
25: "text" => Text: Kind::Simple,
#[doc="OID - object identifier(oid), maximum 4 billion"]
/// OID - object identifier(oid), maximum 4 billion
26: "oid" => Oid: Kind::Simple,
#[doc="TID - (block, offset), physical location of tuple"]
/// TID - (block, offset), physical location of tuple
27: "tid" => Tid: Kind::Simple,
#[doc="XID - transaction id"]
/// XID - transaction id
28: "xid" => Xid: Kind::Simple,
#[doc="CID - command identifier type, sequence in transaction id"]
/// CID - command identifier type, sequence in transaction id
29: "cid" => Cid: Kind::Simple,
#[doc="OIDVECTOR - array of oids, used in system tables"]
/// OIDVECTOR - array of oids, used in system tables
30: "oidvector" => OidVector: Kind::Array(Type::Oid),
#[doc="PG_TYPE"]
/// PG_TYPE
71: "pg_type" => PgType: Kind::Simple,
#[doc="PG_ATTRIBUTE"]
/// PG_ATTRIBUTE
75: "pg_attribute" => PgAttribute: Kind::Simple,
#[doc="PG_PROC"]
/// PG_PROC
81: "pg_proc" => PgProc: Kind::Simple,
#[doc="PG_CLASS"]
/// PG_CLASS
83: "pg_class" => PgClass: Kind::Simple,
#[doc="JSON"]
/// JSON
114: "json" => Json: Kind::Simple,
#[doc="XML - XML content"]
/// XML - XML content
142: "xml" => Xml: Kind::Simple,
#[doc="XML[]"]
/// XML[]
143: "_xml" => XmlArray: Kind::Array(Type::Xml),
#[doc="PG_NODE_TREE - string representing an internal node tree"]
/// PG_NODE_TREE - string representing an internal node tree
194: "pg_node_tree" => PgNodeTree: Kind::Simple,
#[doc="JSON[]"]
/// JSON[]
199: "_json" => JsonArray: Kind::Array(Type::Json),
#[doc="SMGR - storage manager"]
/// SMGR - storage manager
210: "smgr" => Smgr: Kind::Simple,
#[doc="POINT - geometric point '(x, y)'"]
/// POINT - geometric point '(x, y)'
600: "point" => Point: Kind::Simple,
#[doc="LSEG - geometric line segment '(pt1,pt2)'"]
/// LSEG - geometric line segment '(pt1,pt2)'
601: "lseg" => Lseg: Kind::Simple,
#[doc="PATH - geometric path '(pt1,...)'"]
/// PATH - geometric path '(pt1,...)'
602: "path" => Path: Kind::Simple,
#[doc="BOX - geometric box '(lower left,upper right)'"]
/// BOX - geometric box '(lower left,upper right)'
603: "box" => Box: Kind::Simple,
#[doc="POLYGON - geometric polygon '(pt1,...)'"]
/// POLYGON - geometric polygon '(pt1,...)'
604: "polygon" => Polygon: Kind::Simple,
#[doc="LINE - geometric line"]
/// LINE - geometric line
628: "line" => Line: Kind::Simple,
#[doc="LINE[]"]
/// LINE[]
629: "_line" => LineArray: Kind::Array(Type::Line),
#[doc="CIDR - network IP address/netmask, network address"]
/// CIDR - network IP address/netmask, network address
650: "cidr" => Cidr: Kind::Simple,
#[doc="CIDR[]"]
/// CIDR[]
651: "_cidr" => CidrArray: Kind::Array(Type::Cidr),
#[doc="FLOAT4/REAL - single-precision floating point number, 4-byte storage"]
/// FLOAT4/REAL - single-precision floating point number, 4-byte storage
700: "float4" => Float4: Kind::Simple,
#[doc="FLOAT8/DOUBLE PRECISION - double-precision floating point number, 8-byte storage"]
/// FLOAT8/DOUBLE PRECISION - double-precision floating point number, 8-byte storage
701: "float8" => Float8: Kind::Simple,
#[doc="ABSTIME - absolute, limited-range date and time (Unix system time)"]
/// ABSTIME - absolute, limited-range date and time (Unix system time)
702: "abstime" => Abstime: Kind::Simple,
#[doc="RELTIME - relative, limited-range date and time (Unix delta time)"]
/// RELTIME - relative, limited-range date and time (Unix delta time)
703: "reltime" => Reltime: Kind::Simple,
#[doc="TINTERVAL - (abstime,abstime), time interval"]
/// TINTERVAL - (abstime,abstime), time interval
704: "tinterval" => Tinterval: Kind::Simple,
#[doc="UNKNOWN"]
/// UNKNOWN
705: "unknown" => Unknown: Kind::Simple,
#[doc="CIRCLE - geometric circle '(center,radius)'"]
/// CIRCLE - geometric circle '(center,radius)'
718: "circle" => Circle: Kind::Simple,
#[doc="CIRCLE[]"]
/// CIRCLE[]
719: "_circle" => CircleArray: Kind::Array(Type::Circle),
#[doc="MONEY - monetary amounts, $d,ddd.cc"]
/// MONEY - monetary amounts, $d,ddd.cc
790: "money" => Money: Kind::Simple,
#[doc="MONEY[]"]
/// MONEY[]
791: "_money" => MoneyArray: Kind::Array(Type::Money),
#[doc="MACADDR - XX:XX:XX:XX:XX:XX, MAC address"]
/// MACADDR - XX:XX:XX:XX:XX:XX, MAC address
829: "macaddr" => Macaddr: Kind::Simple,
#[doc="INET - IP address/netmask, host address, netmask optional"]
/// INET - IP address/netmask, host address, netmask optional
869: "inet" => Inet: Kind::Simple,
#[doc="BOOL[]"]
/// BOOL[]
1000: "_bool" => BoolArray: Kind::Array(Type::Bool),
#[doc="BYTEA[]"]
/// BYTEA[]
1001: "_bytea" => ByteaArray: Kind::Array(Type::Bytea),
#[doc="\"char\"[]"]
/// "char"[]
1002: "_char" => CharArray: Kind::Array(Type::Char),
#[doc="NAME[]"]
/// NAME[]
1003: "_name" => NameArray: Kind::Array(Type::Name),
#[doc="INT2[]"]
/// INT2[]
1005: "_int2" => Int2Array: Kind::Array(Type::Int2),
#[doc="INT2VECTOR[]"]
/// INT2VECTOR[]
1006: "_int2vector" => Int2VectorArray: Kind::Array(Type::Int2Vector),
#[doc="INT4[]"]
/// INT4[]
1007: "_int4" => Int4Array: Kind::Array(Type::Int4),
#[doc="REGPROC[]"]
/// REGPROC[]
1008: "_regproc" => RegprocArray: Kind::Array(Type::Regproc),
#[doc="TEXT[]"]
/// TEXT[]
1009: "_text" => TextArray: Kind::Array(Type::Text),
#[doc="TID[]"]
/// TID[]
1010: "_tid" => TidArray: Kind::Array(Type::Tid),
#[doc="XID[]"]
/// XID[]
1011: "_xid" => XidArray: Kind::Array(Type::Xid),
#[doc="CID[]"]
/// CID[]
1012: "_cid" => CidArray: Kind::Array(Type::Cid),
#[doc="OIDVECTOR[]"]
/// OIDVECTOR[]
1013: "_oidvector" => OidVectorArray: Kind::Array(Type::OidVector),
#[doc="BPCHAR[]"]
/// BPCHAR[]
1014: "_bpchar" => BpcharArray: Kind::Array(Type::Bpchar),
#[doc="VARCHAR[]"]
/// VARCHAR[]
1015: "_varchar" => VarcharArray: Kind::Array(Type::Varchar),
#[doc="INT8[]"]
/// INT8[]
1016: "_int8" => Int8Array: Kind::Array(Type::Int8),
#[doc="POINT[]"]
/// POINT[]
1017: "_point" => PointArray: Kind::Array(Type::Point),
#[doc="LSEG[]"]
/// LSEG[]
1018: "_lseg" => LsegArray: Kind::Array(Type::Lseg),
#[doc="PATH[]"]
/// PATH[]
1019: "_path" => PathArray: Kind::Array(Type::Path),
#[doc="BOX[]"]
/// BOX[]
1020: "_box" => BoxArray: Kind::Array(Type::Box),
#[doc="FLOAT4[]"]
/// FLOAT4[]
1021: "_float4" => Float4Array: Kind::Array(Type::Float4),
#[doc="FLOAT8[]"]
/// FLOAT8[]
1022: "_float8" => Float8Array: Kind::Array(Type::Float8),
#[doc="ABSTIME[]"]
/// ABSTIME[]
1023: "_abstime" => AbstimeArray: Kind::Array(Type::Abstime),
#[doc="RELTIME[]"]
/// RELTIME[]
1024: "_reltime" => ReltimeArray: Kind::Array(Type::Reltime),
#[doc="TINTERVAL[]"]
/// TINTERVAL[]
1025: "_tinterval" => TintervalArray: Kind::Array(Type::Tinterval),
#[doc="POLYGON[]"]
/// POLYGON[]
1027: "_polygon" => PolygonArray: Kind::Array(Type::Polygon),
#[doc="OID[]"]
/// OID[]
1028: "_oid" => OidArray: Kind::Array(Type::Oid),
#[doc="ACLITEM - access control list"]
/// ACLITEM - access control list
1033: "aclitem" => Aclitem: Kind::Simple,
#[doc="ACLITEM[]"]
/// ACLITEM[]
1034: "_aclitem" => AclitemArray: Kind::Array(Type::Aclitem),
#[doc="MACADDR[]"]
/// MACADDR[]
1040: "_macaddr" => MacaddrArray: Kind::Array(Type::Macaddr),
#[doc="INET[]"]
/// INET[]
1041: "_inet" => InetArray: Kind::Array(Type::Inet),
#[doc="BPCHAR - char(length), blank-padded string, fixed storage length"]
/// BPCHAR - char(length), blank-padded string, fixed storage length
1042: "bpchar" => Bpchar: Kind::Simple,
#[doc="VARCHAR - varchar(length), non-blank-padded string, variable storage length"]
/// VARCHAR - varchar(length), non-blank-padded string, variable storage length
1043: "varchar" => Varchar: Kind::Simple,
#[doc="DATE - date"]
/// DATE - date
1082: "date" => Date: Kind::Simple,
#[doc="TIME - time of day"]
/// TIME - time of day
1083: "time" => Time: Kind::Simple,
#[doc="TIMESTAMP - date and time"]
/// TIMESTAMP - date and time
1114: "timestamp" => Timestamp: Kind::Simple,
#[doc="TIMESTAMP[]"]
/// TIMESTAMP[]
1115: "_timestamp" => TimestampArray: Kind::Array(Type::Timestamp),
#[doc="DATE[]"]
/// DATE[]
1182: "_date" => DateArray: Kind::Array(Type::Date),
#[doc="TIME[]"]
/// TIME[]
1183: "_time" => TimeArray: Kind::Array(Type::Time),
#[doc="TIMESTAMPTZ - date and time with time zone"]
/// TIMESTAMPTZ - date and time with time zone
1184: "timestamptz" => TimestampTZ: Kind::Simple,
#[doc="TIMESTAMPTZ[]"]
/// TIMESTAMPTZ[]
1185: "_timestamptz" => TimestampTZArray: Kind::Array(Type::TimestampTZ),
#[doc="INTERVAL - @ &lt;number&gt; &lt;units&gt;, time interval"]
/// INTERVAL - @ &lt;number&gt; &lt;units&gt;, time interval
1186: "interval" => Interval: Kind::Simple,
#[doc="INTERVAL[]"]
/// INTERVAL[]
1187: "_interval" => IntervalArray: Kind::Array(Type::Interval),
#[doc="NUMERIC[]"]
/// NUMERIC[]
1231: "_numeric" => NumericArray: Kind::Array(Type::Numeric),
#[doc="CSTRING[]"]
/// CSTRING[]
1263: "_cstring" => CstringArray: Kind::Array(Type::Cstring),
#[doc="TIMETZ - time of day with time zone"]
/// TIMETZ - time of day with time zone
1266: "timetz" => Timetz: Kind::Simple,
#[doc="TIMETZ[]"]
/// TIMETZ[]
1270: "_timetz" => TimetzArray: Kind::Array(Type::Timetz),
#[doc="BIT - fixed-length bit string"]
/// BIT - fixed-length bit string
1560: "bit" => Bit: Kind::Simple,
#[doc="BIT[]"]
/// BIT[]
1561: "_bit" => BitArray: Kind::Array(Type::Bit),
#[doc="VARBIT - variable-length bit string"]
/// VARBIT - variable-length bit string
1562: "varbit" => Varbit: Kind::Simple,
#[doc="VARBIT[]"]
/// VARBIT[]
1563: "_varbit" => VarbitArray: Kind::Array(Type::Varbit),
#[doc="NUMERIC - numeric(precision, decimal), arbitrary precision number"]
/// NUMERIC - numeric(precision, decimal), arbitrary precision number
1700: "numeric" => Numeric: Kind::Simple,
#[doc="REFCURSOR - reference to cursor (portal name)"]
/// REFCURSOR - reference to cursor (portal name)
1790: "refcursor" => Refcursor: Kind::Simple,
#[doc="REFCURSOR[]"]
/// REFCURSOR[]
2201: "_refcursor" => RefcursorArray: Kind::Array(Type::Refcursor),
#[doc="REGPROCEDURE - registered procedure (with args)"]
/// REGPROCEDURE - registered procedure (with args)
2202: "regprocedure" => Regprocedure: Kind::Simple,
#[doc="REGOPER - registered operator"]
/// REGOPER - registered operator
2203: "regoper" => Regoper: Kind::Simple,
#[doc="REGOPERATOR - registered operator (with args)"]
/// REGOPERATOR - registered operator (with args)
2204: "regoperator" => Regoperator: Kind::Simple,
#[doc="REGCLASS - registered class"]
/// REGCLASS - registered class
2205: "regclass" => Regclass: Kind::Simple,
#[doc="REGTYPE - registered type"]
/// REGTYPE - registered type
2206: "regtype" => Regtype: Kind::Simple,
#[doc="REGPROCEDURE[]"]
/// REGPROCEDURE[]
2207: "_regprocedure" => RegprocedureArray: Kind::Array(Type::Regprocedure),
#[doc="REGOPER[]"]
/// REGOPER[]
2208: "_regoper" => RegoperArray: Kind::Array(Type::Regoper),
#[doc="REGOPERATOR[]"]
/// REGOPERATOR[]
2209: "_regoperator" => RegoperatorArray: Kind::Array(Type::Regoperator),
#[doc="REGCLASS[]"]
/// REGCLASS[]
2210: "_regclass" => RegclassArray: Kind::Array(Type::Regclass),
#[doc="REGTYPE[]"]
/// REGTYPE[]
2211: "_regtype" => RegtypeArray: Kind::Array(Type::Regtype),
#[doc="RECORD"]
/// RECORD
2249: "record" => Record: Kind::Simple,
#[doc="CSTRING"]
/// CSTRING
2275: "cstring" => Cstring: Kind::Simple,
#[doc="ANY"]
/// ANY
2276: "any" => Any: Kind::Simple,
#[doc="ANYARRAY"]
/// ANYARRAY
2277: "anyarray" => AnyArray: Kind::Array(Type::Any),
#[doc="VOID"]
/// VOID
2278: "void" => Void: Kind::Simple,
#[doc="TRIGGER"]
/// TRIGGER
2279: "trigger" => Trigger: Kind::Simple,
#[doc="LANGUAGE_HANDLER"]
/// LANGUAGE_HANDLER
2280: "language_handler" => LanguageHandler: Kind::Simple,
#[doc="INTERNAL"]
/// INTERNAL
2281: "internal" => Internal: Kind::Simple,
#[doc="OPAQUE"]
/// OPAQUE
2282: "opaque" => Opaque: Kind::Simple,
#[doc="ANYELEMENT"]
/// ANYELEMENT
2283: "anyelement" => Anyelement: Kind::Simple,
#[doc="RECORD[]"]
/// RECORD[]
2287: "_record" => RecordArray: Kind::Array(Type::Record),
#[doc="ANYNONARRAY"]
/// ANYNONARRAY
2776: "anynonarray" => Anynonarray: Kind::Simple,
#[doc="TXID_SNAPSHOT[]"]
/// TXID_SNAPSHOT[]
2949: "_txid_snapshot" => TxidSnapshotArray: Kind::Array(Type::TxidSnapshot),
#[doc="UUID - UUID datatype"]
/// UUID - UUID datatype
2950: "uuid" => Uuid: Kind::Simple,
#[doc="TXID_SNAPSHOT - txid snapshot"]
/// TXID_SNAPSHOT - txid snapshot
2970: "txid_snapshot" => TxidSnapshot: Kind::Simple,
#[doc="UUID[]"]
/// UUID[]
2951: "_uuid" => UuidArray: Kind::Array(Type::Uuid),
#[doc="FDW_HANDLER"]
/// FDW_HANDLER
3115: "fdw_handler" => FdwHandler: Kind::Simple,
#[doc="PG_LSN - PostgreSQL LSN datatype"]
/// PG_LSN - PostgreSQL LSN datatype
3220: "pg_lsn" => PgLsn: Kind::Simple,
#[doc="PG_LSN[]"]
/// PG_LSN[]
3221: "_pg_lsn" => PgLsnArray: Kind::Array(Type::PgLsn),
#[doc="ANYENUM"]
/// ANYENUM
3500: "anyenum" => Anyenum: Kind::Simple,
#[doc="TSVECTOR - text representation for text search"]
/// TSVECTOR - text representation for text search
3614: "tsvector" => Tsvector: Kind::Simple,
#[doc="TSQUERY - query representation for text search"]
/// TSQUERY - query representation for text search
3615: "tsquery" => Tsquery: Kind::Simple,
#[doc="GTSVECTOR - GiST index internal text representation for text search"]
/// GTSVECTOR - GiST index internal text representation for text search
3642: "gtsvector" => Gtsvector: Kind::Simple,
#[doc="TSVECTOR[]"]
/// TSVECTOR[]
3643: "_tsvector" => TsvectorArray: Kind::Array(Type::Tsvector),
#[doc="GTSVECTOR[]"]
/// GTSVECTOR[]
3644: "_gtsvector" => GtsvectorArray: Kind::Array(Type::Gtsvector),
#[doc="TSQUERY[]"]
/// TSQUERY[]
3645: "_tsquery" => TsqueryArray: Kind::Array(Type::Tsquery),
#[doc="REGCONFIG - registered text search configuration"]
/// REGCONFIG - registered text search configuration
3734: "regconfig" => Regconfig: Kind::Simple,
#[doc="REGCONFIG[]"]
/// REGCONFIG[]
3735: "_regconfig" => RegconfigArray: Kind::Array(Type::Regconfig),
#[doc="REGDICTIONARY - registered text search dictionary"]
/// REGDICTIONARY - registered text search dictionary
3769: "regdictionary" => Regdictionary: Kind::Simple,
#[doc="REGDICTIONARY[]"]
/// REGDICTIONARY[]
3770: "_regdictionary" => RegdictionaryArray: Kind::Array(Type::Regdictionary),
#[doc="JSONB"]
/// JSONB
3802: "jsonb" => Jsonb: Kind::Simple,
#[doc="ANYRANGE"]
/// ANYRANGE
3831: "anyrange" => Anyrange: Kind::Simple,
#[doc="JSONB[]"]
/// JSONB[]
3807: "_jsonb" => JsonbArray: Kind::Array(Type::Jsonb),
#[doc="INT4RANGE - range of integers"]
/// INT4RANGE - range of integers
3904: "int4range" => Int4Range: Kind::Range(Type::Int4),
#[doc="INT4RANGE[]"]
/// INT4RANGE[]
3905: "_int4range" => Int4RangeArray: Kind::Array(Type::Int4Range),
#[doc="NUMRANGE - range of numerics"]
/// NUMRANGE - range of numerics
3906: "numrange" => NumRange: Kind::Range(Type::Numeric),
#[doc="NUMRANGE[]"]
/// NUMRANGE[]
3907: "_numrange" => NumRangeArray: Kind::Array(Type::NumRange),
#[doc="TSRANGE - range of timestamps without time zone"]
/// TSRANGE - range of timestamps without time zone
3908: "tsrange" => TsRange: Kind::Range(Type::Timestamp),
#[doc="TSRANGE[]"]
/// TSRANGE[]
3909: "_tsrange" => TsRangeArray: Kind::Array(Type::TsRange),
#[doc="TSTZRANGE - range of timestamps with time zone"]
/// TSTZRANGE - range of timestamps with time zone
3910: "tstzrange" => TstzRange: Kind::Range(Type::TimestampTZ),
#[doc="TSTZRANGE[]"]
/// TSTZRANGE[]
3911: "_tstzrange" => TstzRangeArray: Kind::Array(Type::TstzRange),
#[doc="DATERANGE - range of dates"]
/// DATERANGE - range of dates
3912: "daterange" => DateRange: Kind::Range(Type::Date),
#[doc="DATERANGE[]"]
/// DATERANGE[]
3913: "_daterange" => DateRangeArray: Kind::Array(Type::DateRange),
#[doc="INT8RANGE - range of bigints"]
/// INT8RANGE - range of bigints
3926: "int8range" => Int8Range: Kind::Range(Type::Int8),
#[doc="INT8RANGE[]"]
/// INT8RANGE[]
3927: "_int8range" => Int8RangeArray: Kind::Array(Type::Int8Range),
#[doc="EVENT_TRIGGER"]
/// EVENT_TRIGGER
3838: "event_trigger" => EventTrigger: Kind::Simple
}
@ -596,7 +594,9 @@ impl error::Error for WasNull {
/// nullable Postgres value.
pub trait FromSql: Sized {
/// ### Deprecated
fn from_sql_nullable<R: Read>(ty: &Type, raw: Option<&mut R>, ctx: &SessionInfo)
fn from_sql_nullable<R: Read>(ty: &Type,
raw: Option<&mut R>,
ctx: &SessionInfo)
-> Result<Self> {
match raw {
Some(raw) => FromSql::from_sql(ty, raw, ctx),
@ -704,7 +704,9 @@ primitive_from!(f32, read_f32, Type::Float4);
primitive_from!(f64, read_f64, Type::Float8);
impl FromSql for HashMap<String, Option<String>> {
fn from_sql<R: Read>(_: &Type, raw: &mut R, _: &SessionInfo)
fn from_sql<R: Read>(_: &Type,
raw: &mut R,
_: &SessionInfo)
-> Result<HashMap<String, Option<String>>> {
let mut map = HashMap::new();
@ -740,7 +742,7 @@ impl FromSql for HashMap<String, Option<String>> {
fn accepts(ty: &Type) -> bool {
match *ty {
Type::Other(ref u) if u.name() == "hstore" => true,
_ => false
_ => false,
}
}
}
@ -811,7 +813,8 @@ pub trait ToSql: fmt::Debug {
/// `NULL`. If this is the case, implementations **must not** write
/// anything to `out`.
fn to_sql<W: ?Sized>(&self, ty: &Type, out: &mut W, ctx: &SessionInfo) -> Result<IsNull>
where Self: Sized, W: Write;
where Self: Sized,
W: Write;
/// Determines if a value of this type can be converted to the specified
/// Postgres `Type`.
@ -821,34 +824,33 @@ pub trait ToSql: fmt::Debug {
///
/// *All* implementations of this method should be generated by the
/// `to_sql_checked!()` macro.
fn to_sql_checked(&self, ty: &Type, out: &mut Write, ctx: &SessionInfo)
-> Result<IsNull>;
fn to_sql_checked(&self, ty: &Type, out: &mut Write, ctx: &SessionInfo) -> Result<IsNull>;
}
impl<'a, T> ToSql for &'a T where T: ToSql {
fn to_sql_checked(&self, ty: &Type, out: &mut Write, ctx: &SessionInfo)
-> Result<IsNull> {
if !<&'a T as ToSql>::accepts(ty) {
return Err(Error::WrongType(ty.clone()));
}
self.to_sql(ty, out, ctx)
}
to_sql_checked!();
fn to_sql<W: Write + ?Sized>(&self, ty: &Type, out: &mut W, ctx: &SessionInfo) -> Result<IsNull> {
fn to_sql<W: Write + ?Sized>(&self,
ty: &Type,
out: &mut W,
ctx: &SessionInfo)
-> Result<IsNull> {
(*self).to_sql(ty, out, ctx)
}
fn accepts(ty: &Type) -> bool { T::accepts(ty) }
fn accepts(ty: &Type) -> bool {
T::accepts(ty)
}
}
impl<T: ToSql> ToSql for Option<T> {
to_sql_checked!();
fn to_sql<W: Write+?Sized>(&self, ty: &Type, out: &mut W, ctx: &SessionInfo)
-> Result<IsNull> {
fn to_sql<W: Write + ?Sized>(&self,
ty: &Type,
out: &mut W,
ctx: &SessionInfo)
-> Result<IsNull> {
match *self {
Some(ref val) => val.to_sql(ty, out, ctx),
None => Ok(IsNull::Yes),
@ -863,8 +865,11 @@ impl<T: ToSql> ToSql for Option<T> {
impl ToSql for bool {
to_sql_checked!();
fn to_sql<W: Write+?Sized>(&self, _: &Type, mut w: &mut W, _: &SessionInfo)
-> Result<IsNull> {
fn to_sql<W: Write + ?Sized>(&self,
_: &Type,
mut w: &mut W,
_: &SessionInfo)
-> Result<IsNull> {
try!(w.write_u8(*self as u8));
Ok(IsNull::No)
}
@ -873,17 +878,9 @@ impl ToSql for bool {
}
impl<'a> ToSql for &'a [u8] {
// FIXME should use to_sql_checked!() but blocked on rust-lang/rust#24308
fn to_sql_checked(&self, ty: &Type, out: &mut Write, ctx: &SessionInfo)
-> Result<IsNull> {
if !<&'a [u8] as ToSql>::accepts(ty) {
return Err(Error::WrongType(ty.clone()));
}
self.to_sql(ty, out, ctx)
}
to_sql_checked!();
fn to_sql<W: Write+?Sized>(&self, _: &Type, w: &mut W, _: &SessionInfo)
-> Result<IsNull> {
fn to_sql<W: Write + ?Sized>(&self, _: &Type, w: &mut W, _: &SessionInfo) -> Result<IsNull> {
try!(w.write_all(*self));
Ok(IsNull::No)
}
@ -894,8 +891,7 @@ impl<'a> ToSql for &'a [u8] {
impl ToSql for Vec<u8> {
to_sql_checked!();
fn to_sql<W: Write+?Sized>(&self, ty: &Type, w: &mut W, ctx: &SessionInfo)
-> Result<IsNull> {
fn to_sql<W: Write + ?Sized>(&self, ty: &Type, w: &mut W, ctx: &SessionInfo) -> Result<IsNull> {
<&[u8] as ToSql>::to_sql(&&**self, ty, w, ctx)
}
@ -905,17 +901,9 @@ impl ToSql for Vec<u8> {
}
impl<'a> ToSql for &'a str {
// FIXME should use to_sql_checked!() but blocked on rust-lang/rust#24308
fn to_sql_checked(&self, ty: &Type, out: &mut Write, ctx: &SessionInfo)
-> Result<IsNull> {
if !<&'a str as ToSql>::accepts(ty) {
return Err(Error::WrongType(ty.clone()));
}
self.to_sql(ty, out, ctx)
}
to_sql_checked!();
fn to_sql<W: Write+?Sized>(&self, _: &Type, w: &mut W, _: &SessionInfo)
-> Result<IsNull> {
fn to_sql<W: Write + ?Sized>(&self, _: &Type, w: &mut W, _: &SessionInfo) -> Result<IsNull> {
try!(w.write_all(self.as_bytes()));
Ok(IsNull::No)
}
@ -932,8 +920,7 @@ impl<'a> ToSql for &'a str {
impl ToSql for String {
to_sql_checked!();
fn to_sql<W: Write+?Sized>(&self, ty: &Type, w: &mut W, ctx: &SessionInfo)
-> Result<IsNull> {
fn to_sql<W: Write + ?Sized>(&self, ty: &Type, w: &mut W, ctx: &SessionInfo) -> Result<IsNull> {
<&str as ToSql>::to_sql(&&**self, ty, w, ctx)
}
@ -945,8 +932,11 @@ impl ToSql for String {
impl ToSql for i8 {
to_sql_checked!();
fn to_sql<W: Write+?Sized>(&self, _: &Type, mut w: &mut W, _: &SessionInfo)
-> Result<IsNull> {
fn to_sql<W: Write + ?Sized>(&self,
_: &Type,
mut w: &mut W,
_: &SessionInfo)
-> Result<IsNull> {
try!(w.write_i8(*self));
Ok(IsNull::No)
}
@ -980,8 +970,11 @@ to_primitive!(f64, write_f64, Type::Float8);
impl ToSql for HashMap<String, Option<String>> {
to_sql_checked!();
fn to_sql<W: Write+?Sized>(&self, _: &Type, mut w: &mut W, _: &SessionInfo)
-> Result<IsNull> {
fn to_sql<W: Write + ?Sized>(&self,
_: &Type,
mut w: &mut W,
_: &SessionInfo)
-> Result<IsNull> {
try!(w.write_i32::<BigEndian>(try!(downcast(self.len()))));
for (key, val) in self {
@ -993,7 +986,7 @@ impl ToSql for HashMap<String, Option<String>> {
try!(w.write_i32::<BigEndian>(try!(downcast(val.len()))));
try!(w.write_all(val.as_bytes()));
}
None => try!(w.write_i32::<BigEndian>(-1))
None => try!(w.write_i32::<BigEndian>(-1)),
}
}
@ -1010,7 +1003,7 @@ impl ToSql for HashMap<String, Option<String>> {
fn downcast(len: usize) -> Result<i32> {
if len > i32::max_value() as usize {
let err: Box<error::Error+Sync+Send> = "value too large to transmit".into();
let err: Box<error::Error + Sync + Send> = "value too large to transmit".into();
Err(Error::Conversion(err))
} else {
Ok(len as i32)

View File

@ -12,7 +12,8 @@ impl FromSql for json::Json {
if let Type::Jsonb = *ty {
// We only support version 1 of the jsonb binary format
if try!(raw.read_u8()) != 1 {
let err: Box<error::Error+Sync+Send> = "unsupported JSONB encoding version".into();
let err: Box<error::Error + Sync + Send> = "unsupported JSONB encoding version"
.into();
return Err(Error::Conversion(err));
}
}
@ -23,8 +24,11 @@ impl FromSql for json::Json {
}
impl ToSql for json::Json {
fn to_sql<W: Write+?Sized>(&self, ty: &Type, mut out: &mut W, _: &SessionInfo)
-> Result<IsNull> {
fn to_sql<W: Write + ?Sized>(&self,
ty: &Type,
mut out: &mut W,
_: &SessionInfo)
-> Result<IsNull> {
if let Type::Jsonb = *ty {
try!(out.write_u8(1));
}

View File

@ -14,7 +14,8 @@ impl FromSql for Value {
if let Type::Jsonb = *ty {
// We only support version 1 of the jsonb binary format
if try!(raw.read_u8()) != 1 {
let err: Box<error::Error+Sync+Send> = "unsupported JSONB encoding version".into();
let err: Box<error::Error + Sync + Send> = "unsupported JSONB encoding version"
.into();
return Err(Error::Conversion(err));
}
}
@ -25,8 +26,11 @@ impl FromSql for Value {
}
impl ToSql for Value {
fn to_sql<W: Write+?Sized>(&self, ty: &Type, mut out: &mut W, _: &SessionInfo)
-> Result<IsNull> {
fn to_sql<W: Write + ?Sized>(&self,
ty: &Type,
mut out: &mut W,
_: &SessionInfo)
-> Result<IsNull> {
if let Type::Jsonb = *ty {
try!(out.write_u8(1));
}

View File

@ -14,7 +14,8 @@ impl FromSql for Value {
if let Type::Jsonb = *ty {
// We only support version 1 of the jsonb binary format
if try!(raw.read_u8()) != 1 {
let err: Box<error::Error+Sync+Send> = "unsupported JSONB encoding version".into();
let err: Box<error::Error + Sync + Send> = "unsupported JSONB encoding version"
.into();
return Err(Error::Conversion(err));
}
}
@ -25,8 +26,11 @@ impl FromSql for Value {
}
impl ToSql for Value {
fn to_sql<W: Write+?Sized>(&self, ty: &Type, mut out: &mut W, _: &SessionInfo)
-> Result<IsNull> {
fn to_sql<W: Write + ?Sized>(&self,
ty: &Type,
mut out: &mut W,
_: &SessionInfo)
-> Result<IsNull> {
if let Type::Jsonb = *ty {
try!(out.write_u8(1));
}

View File

@ -38,7 +38,11 @@ impl<'a, T: 'a + ToSql> ToSql for Slice<'a, T> {
self.to_sql(ty, out, ctx)
}
fn to_sql<W: Write+?Sized>(&self, ty: &Type, mut w: &mut W, ctx: &SessionInfo) -> Result<IsNull> {
fn to_sql<W: Write + ?Sized>(&self,
ty: &Type,
mut w: &mut W,
ctx: &SessionInfo)
-> Result<IsNull> {
let member_type = match ty.kind() {
&Kind::Array(ref member) => member,
_ => panic!("expected array type"),

View File

@ -31,7 +31,11 @@ impl FromSql for Timespec {
}
impl ToSql for Timespec {
fn to_sql<W: Write+?Sized>(&self, _: &Type, mut w: &mut W, _: &SessionInfo) -> Result<IsNull> {
fn to_sql<W: Write + ?Sized>(&self,
_: &Type,
mut w: &mut W,
_: &SessionInfo)
-> Result<IsNull> {
let t = (self.sec - TIME_SEC_CONVERSION) * USEC_PER_SEC + self.nsec as i64 / NSEC_PER_USEC;
try!(w.write_i64::<BigEndian>(t));
Ok(IsNull::No)

View File

@ -18,7 +18,7 @@ impl FromSql for Uuid {
}
impl ToSql for Uuid {
fn to_sql<W: Write+?Sized>(&self, _: &Type, w: &mut W, _: &SessionInfo) -> Result<IsNull> {
fn to_sql<W: Write + ?Sized>(&self, _: &Type, w: &mut W, _: &SessionInfo) -> Result<IsNull> {
try!(w.write_all(self.as_bytes()));
Ok(IsNull::No)
}

View File

@ -23,12 +23,12 @@ pub struct Url {
pub struct Path {
pub path: String,
pub query: Query,
pub fragment: Option<String>
pub fragment: Option<String>,
}
pub struct UserInfo {
pub user: String,
pub pass: Option<String>
pub pass: Option<String>,
}
pub type Query = Vec<(String, String)>;
@ -47,7 +47,7 @@ impl Url {
user: user,
host: host,
port: port,
path: Path::new(path, query, fragment)
path: Path::new(path, query, fragment),
}
}
@ -66,21 +66,18 @@ impl Url {
let (query, fragment) = try!(get_query_fragment(rest));
let url = Url::new(scheme.to_owned(),
userinfo,
host.to_owned(),
port,
path,
query,
fragment);
userinfo,
host.to_owned(),
port,
path,
query,
fragment);
Ok(url)
}
}
impl Path {
pub fn new(path: String,
query: Query,
fragment: Option<String>)
-> Path {
pub fn new(path: String, query: Query, fragment: Option<String>) -> Path {
Path {
path: path,
query: query,
@ -94,14 +91,21 @@ impl Path {
// query and fragment
let (query, fragment) = try!(get_query_fragment(&rest));
Ok(Path{ path: path, query: query, fragment: fragment })
Ok(Path {
path: path,
query: query,
fragment: fragment,
})
}
}
impl UserInfo {
#[inline]
pub fn new(user: String, pass: Option<String>) -> UserInfo {
UserInfo { user: user, pass: pass }
UserInfo {
user: user,
pass: pass,
}
}
}
@ -121,28 +125,40 @@ fn decode_inner(c: &str, full_url: bool) -> DecodeResult<String> {
'%' => {
let bytes = match (iter.next(), iter.next()) {
(Some(one), Some(two)) => [one, two],
_ => return Err(format!("Malformed input: found '%' \
without two trailing bytes")),
_ => return Err(format!("Malformed input: found '%' without two \
trailing bytes")),
};
// Only decode some characters if full_url:
match str::from_utf8(&bytes).unwrap().from_hex().unwrap()[0] as char {
// gen-delims:
':' | '/' | '?' | '#' | '[' | ']' | '@' |
// sub-delims:
'!' | '$' | '&' | '"' | '(' | ')' | '*' |
'+' | ',' | ';' | '='
if full_url => {
':' |
'/' |
'?' |
'#' |
'[' |
']' |
'@' |
'!' |
'$' |
'&' |
'"' |
'(' |
')' |
'*' |
'+' |
',' |
';' |
'=' if full_url => {
out.push('%');
out.push(bytes[0] as char);
out.push(bytes[1] as char);
}
ch => out.push(ch)
ch => out.push(ch),
}
}
ch => out.push(ch)
ch => out.push(ch),
},
None => return Ok(out),
}
@ -160,12 +176,11 @@ fn split_char_first(s: &str, c: char) -> (&str, &str) {
}
fn query_from_str(rawquery: &str) -> DecodeResult<Query> {
let mut query: Query = vec!();
let mut query: Query = vec![];
if !rawquery.is_empty() {
for p in rawquery.split('&') {
let (k, v) = split_char_first(p, '=');
query.push((try!(decode_component(k)),
try!(decode_component(v))));
query.push((try!(decode_component(k)), try!(decode_component(v))));
}
}
@ -173,12 +188,14 @@ fn query_from_str(rawquery: &str) -> DecodeResult<Query> {
}
pub fn get_scheme(rawurl: &str) -> DecodeResult<(&str, &str)> {
for (i,c) in rawurl.chars().enumerate() {
for (i, c) in rawurl.chars().enumerate() {
let result = match c {
'A' ... 'Z'
| 'a' ... 'z' => continue,
'0' ... '9' | '+' | '-' | '.' => {
if i != 0 { continue }
'A'...'Z' |
'a'...'z' => continue,
'0'...'9' | '+' | '-' | '.' => {
if i != 0 {
continue;
}
Err("url: Scheme must begin with a letter.".to_owned())
}
@ -186,7 +203,7 @@ pub fn get_scheme(rawurl: &str) -> DecodeResult<(&str, &str)> {
if i == 0 {
Err("url: Scheme cannot be empty.".to_owned())
} else {
Ok((&rawurl[0..i], &rawurl[i+1..rawurl.len()]))
Ok((&rawurl[0..i], &rawurl[i + 1..rawurl.len()]))
}
}
_ => Err("url: Invalid character in scheme.".to_owned()),
@ -199,22 +216,21 @@ pub fn get_scheme(rawurl: &str) -> DecodeResult<(&str, &str)> {
}
// returns userinfo, host, port, and unparsed part, or an error
fn get_authority(rawurl: &str) ->
DecodeResult<(Option<UserInfo>, &str, Option<u16>, &str)> {
fn get_authority(rawurl: &str) -> DecodeResult<(Option<UserInfo>, &str, Option<u16>, &str)> {
enum State {
Start, // starting state
PassHostPort, // could be in user or port
Ip6Port, // either in ipv6 host or port
Ip6Host, // are in an ipv6 host
InHost, // are in a host - may be ipv6, but don't know yet
InPort // are in port
InPort, // are in port
}
#[derive(Clone, PartialEq)]
enum Input {
Digit, // all digits
Hex, // digits and letters a-f
Unreserved // all other legal characters
Unreserved, // all other legal characters
}
if !rawurl.starts_with("//") {
@ -235,23 +251,35 @@ fn get_authority(rawurl: &str) ->
let mut begin = 2;
let mut end = len;
for (i,c) in rawurl.chars().enumerate()
// ignore the leading '//' handled by early return
.skip(2) {
for (i, c) in rawurl.chars()
.enumerate()
.skip(2) {
// deal with input class first
match c {
'0' ... '9' => (),
'A' ... 'F'
| 'a' ... 'f' => {
'0'...'9' => (),
'A'...'F' |
'a'...'f' => {
if input == Input::Digit {
input = Input::Hex;
}
}
'G' ... 'Z'
| 'g' ... 'z'
| '-' | '.' | '_' | '~' | '%'
| '&' |'\'' | '(' | ')' | '+'
| '!' | '*' | ',' | ';' | '=' => input = Input::Unreserved,
'G'...'Z' |
'g'...'z' |
'-' |
'.' |
'_' |
'~' |
'%' |
'&' |
'\'' |
'(' |
')' |
'+' |
'!' |
'*' |
',' |
';' |
'=' => input = Input::Unreserved,
':' | '@' | '?' | '#' | '/' => {
// separators, don't change anything
}
@ -260,97 +288,96 @@ fn get_authority(rawurl: &str) ->
// now process states
match c {
':' => {
colon_count += 1;
match st {
State::Start => {
pos = i;
st = State::PassHostPort;
}
State::PassHostPort => {
// multiple colons means ipv6 address.
if input == Input::Unreserved {
return Err(
"Illegal characters in IPv6 address.".to_owned());
':' => {
colon_count += 1;
match st {
State::Start => {
pos = i;
st = State::PassHostPort;
}
State::PassHostPort => {
// multiple colons means ipv6 address.
if input == Input::Unreserved {
return Err("Illegal characters in IPv6 address.".to_owned());
}
st = State::Ip6Host;
}
State::InHost => {
pos = i;
if input == Input::Unreserved {
// must be port
host = &rawurl[begin..i];
st = State::InPort;
} else {
// can't be sure whether this is an ipv6 address or a port
st = State::Ip6Port;
}
}
State::Ip6Port => {
if input == Input::Unreserved {
return Err("Illegal characters in authority.".to_owned());
}
st = State::Ip6Host;
}
State::Ip6Host => {
if colon_count > 7 {
host = &rawurl[begin..i];
pos = i;
st = State::InPort;
}
}
_ => return Err("Invalid ':' in authority.".to_owned()),
}
st = State::Ip6Host;
}
State::InHost => {
pos = i;
if input == Input::Unreserved {
// must be port
host = &rawurl[begin..i];
st = State::InPort;
} else {
// can't be sure whether this is an ipv6 address or a port
st = State::Ip6Port;
}
}
State::Ip6Port => {
if input == Input::Unreserved {
return Err("Illegal characters in authority.".to_owned());
}
st = State::Ip6Host;
}
State::Ip6Host => {
if colon_count > 7 {
host = &rawurl[begin..i];
pos = i;
st = State::InPort;
}
}
_ => return Err("Invalid ':' in authority.".to_owned()),
input = Input::Digit; // reset input class
}
input = Input::Digit; // reset input class
}
'@' => {
input = Input::Digit; // reset input class
colon_count = 0; // reset count
match st {
State::Start => {
let user = try!(decode_component(&rawurl[begin..i]));
userinfo = Some(UserInfo::new(user, None));
st = State::InHost;
}
State::PassHostPort => {
let user = try!(decode_component(&rawurl[begin..pos]));
let pass = try!(decode_component(&rawurl[pos+1..i]));
userinfo = Some(UserInfo::new(user, Some(pass)));
st = State::InHost;
}
_ => return Err("Invalid '@' in authority.".to_owned()),
'@' => {
input = Input::Digit; // reset input class
colon_count = 0; // reset count
match st {
State::Start => {
let user = try!(decode_component(&rawurl[begin..i]));
userinfo = Some(UserInfo::new(user, None));
st = State::InHost;
}
State::PassHostPort => {
let user = try!(decode_component(&rawurl[begin..pos]));
let pass = try!(decode_component(&rawurl[pos + 1..i]));
userinfo = Some(UserInfo::new(user, Some(pass)));
st = State::InHost;
}
_ => return Err("Invalid '@' in authority.".to_owned()),
}
begin = i + 1;
}
begin = i+1;
}
'?' | '#' | '/' => {
end = i;
break;
}
_ => ()
'?' | '#' | '/' => {
end = i;
break;
}
_ => (),
}
}
// finish up
match st {
State::Start => host = &rawurl[begin..end],
State::PassHostPort
| State::Ip6Port => {
if input != Input::Digit {
return Err("Non-digit characters in port.".to_owned());
State::Start => host = &rawurl[begin..end],
State::PassHostPort |
State::Ip6Port => {
if input != Input::Digit {
return Err("Non-digit characters in port.".to_owned());
}
host = &rawurl[begin..pos];
port = Some(&rawurl[pos + 1..end]);
}
host = &rawurl[begin..pos];
port = Some(&rawurl[pos+1..end]);
}
State::Ip6Host
| State::InHost => host = &rawurl[begin..end],
State::InPort => {
if input != Input::Digit {
return Err("Non-digit characters in port.".to_owned());
State::Ip6Host |
State::InHost => host = &rawurl[begin..end],
State::InPort => {
if input != Input::Digit {
return Err("Non-digit characters in port.".to_owned());
}
port = Some(&rawurl[pos + 1..end]);
}
port = Some(&rawurl[pos+1..end]);
}
}
let rest = &rawurl[end..len];
@ -359,8 +386,8 @@ fn get_authority(rawurl: &str) ->
None => None,
opt => match opt.and_then(|p| FromStr::from_str(p).ok()) {
None => return Err(format!("Failed to parse port: {:?}", port)),
opt => opt
}
opt => opt,
},
};
Ok((userinfo, host, port, rest))
@ -371,26 +398,39 @@ fn get_authority(rawurl: &str) ->
fn get_path(rawurl: &str, is_authority: bool) -> DecodeResult<(String, &str)> {
let len = rawurl.len();
let mut end = len;
for (i,c) in rawurl.chars().enumerate() {
for (i, c) in rawurl.chars().enumerate() {
match c {
'A' ... 'Z'
| 'a' ... 'z'
| '0' ... '9'
| '&' |'\'' | '(' | ')' | '.'
| '@' | ':' | '%' | '/' | '+'
| '!' | '*' | ',' | ';' | '='
| '_' | '-' | '~' => continue,
'?' | '#' => {
end = i;
break;
}
_ => return Err("Invalid character in path.".to_owned())
'A'...'Z' |
'a'...'z' |
'0'...'9' |
'&' |
'\'' |
'(' |
')' |
'.' |
'@' |
':' |
'%' |
'/' |
'+' |
'!' |
'*' |
',' |
';' |
'=' |
'_' |
'-' |
'~' => continue,
'?' | '#' => {
end = i;
break;
}
_ => return Err("Invalid character in path.".to_owned()),
}
}
if is_authority && end != 0 && !rawurl.starts_with("/") {
Err("Non-empty path must begin with \
'/' in presence of authority.".to_owned())
Err("Non-empty path must begin with '/' in presence of authority.".to_owned())
} else {
Ok((try!(decode_component(&rawurl[0..end])), &rawurl[end..len]))
}
@ -403,12 +443,12 @@ fn get_query_fragment(rawurl: &str) -> DecodeResult<(Query, Option<String>)> {
// Parse the fragment if available
let fragment = match raw_fragment {
"" => None,
raw => Some(try!(decode_component(raw)))
raw => Some(try!(decode_component(raw))),
};
match before_fragment.chars().next() {
Some('?') => Ok((try!(query_from_str(&before_fragment[1..])), fragment)),
None => Ok((vec!(), fragment)),
None => Ok((vec![], fragment)),
_ => Err(format!("Query didn't start with '?': '{}..'", before_fragment)),
}
}
@ -426,4 +466,3 @@ impl FromStr for Path {
Path::parse(s)
}
}