Merge branch 'release-v0.10.2' into release
This commit is contained in:
commit
a402f7d3a6
1
.gitattributes
vendored
1
.gitattributes
vendored
@ -1 +0,0 @@
|
|||||||
*.rs eol=lf
|
|
@ -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
|
|
@ -1,11 +1,11 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "postgres"
|
name = "postgres"
|
||||||
version = "0.10.1"
|
version = "0.10.2"
|
||||||
authors = ["Steven Fackler <sfackler@gmail.com>"]
|
authors = ["Steven Fackler <sfackler@gmail.com>"]
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
description = "A native PostgreSQL driver"
|
description = "A native PostgreSQL driver"
|
||||||
repository = "https://github.com/sfackler/rust-postgres"
|
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"
|
readme = "README.md"
|
||||||
keywords = ["database", "sql"]
|
keywords = ["database", "sql"]
|
||||||
build = "build.rs"
|
build = "build.rs"
|
||||||
@ -31,7 +31,7 @@ phf = "0.7"
|
|||||||
rustc-serialize = "0.3"
|
rustc-serialize = "0.3"
|
||||||
net2 = { version = "0.2", features = ["nightly"] }
|
net2 = { version = "0.2", features = ["nightly"] }
|
||||||
chrono = { version = "0.2.14", optional = true }
|
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 = { version = "0.3", optional = true } # Delete for 0.11
|
||||||
serde_json = { version = "0.6", optional = true }
|
serde_json = { version = "0.6", optional = true }
|
||||||
time = { version = "0.1.14", optional = true }
|
time = { version = "0.1.14", optional = true }
|
||||||
|
17
README.md
17
README.md
@ -1,7 +1,7 @@
|
|||||||
# Rust-Postgres
|
# Rust-Postgres
|
||||||
A native PostgreSQL driver for Rust.
|
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)
|
[![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>
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<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
|
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>)
|
(<a href="#optional-features">optional</a>)
|
||||||
</td>
|
</td>
|
||||||
<td>JSON, JSONB</td>
|
<td>JSON, JSONB</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<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
|
and
|
||||||
<a href="https://github.com/lifthrasiir/rust-chrono">chrono::NaiveDateTime</a>
|
<a href="https://github.com/lifthrasiir/rust-chrono">chrono::NaiveDateTime</a>
|
||||||
(<a href="#optional-features">optional</a>)
|
(<a href="#optional-features">optional</a>)
|
||||||
@ -216,7 +216,7 @@ types. The driver currently supports the following conversions:
|
|||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<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<UTC></a>,
|
<a href="https://github.com/lifthrasiir/rust-chrono">chrono::DateTime<UTC></a>,
|
||||||
<a href="https://github.com/lifthrasiir/rust-chrono">chrono::DateTime<Local></a>,
|
<a href="https://github.com/lifthrasiir/rust-chrono">chrono::DateTime<Local></a>,
|
||||||
and
|
and
|
||||||
@ -241,7 +241,7 @@ types. The driver currently supports the following conversions:
|
|||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<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>)
|
(<a href="#optional-features">optional</a>)
|
||||||
</td>
|
</td>
|
||||||
<td>UUID</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)
|
[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
|
support is provided optionally by the `rustc-serialize` feature, which adds
|
||||||
`ToSql` and `FromSql` implementations for `rustc-serialize`'s `Json` type, and
|
`ToSql` and `FromSql` implementations for `rustc-serialize`'s `Json` type, and
|
||||||
the `serde` feature, which adds implementations for `serde_json`'s `Value`
|
the `serde_json` feature, which adds implementations for `serde_json`'s `Value`
|
||||||
type.
|
type. The `serde` feature provides implementations for the older
|
||||||
|
`serde::json::Value` type.
|
||||||
|
|
||||||
### TIMESTAMP/TIMESTAMPTZ/DATE/TIME types
|
### TIMESTAMP/TIMESTAMPTZ/DATE/TIME types
|
||||||
|
|
||||||
|
25
src/error.rs
25
src/error.rs
@ -48,10 +48,10 @@ impl DbErrorNew for DbError {
|
|||||||
None => match map.remove(&b'p') {
|
None => match map.remove(&b'p') {
|
||||||
Some(pos) => Some(ErrorPosition::Internal {
|
Some(pos) => Some(ErrorPosition::Internal {
|
||||||
position: try!(pos.parse().map_err(|_| ())),
|
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'),
|
where_: map.remove(&b'W'),
|
||||||
schema: map.remove(&b's'),
|
schema: map.remove(&b's'),
|
||||||
@ -194,7 +194,7 @@ impl error::Error for DbError {
|
|||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum ConnectError {
|
pub enum ConnectError {
|
||||||
/// An error creating `ConnectParams`.
|
/// An error creating `ConnectParams`.
|
||||||
BadConnectParams(Box<error::Error+Sync+Send>),
|
BadConnectParams(Box<error::Error + Sync + Send>),
|
||||||
/// The `ConnectParams` was missing a user.
|
/// The `ConnectParams` was missing a user.
|
||||||
MissingUser,
|
MissingUser,
|
||||||
/// An error from the Postgres server itself.
|
/// An error from the Postgres server itself.
|
||||||
@ -207,7 +207,7 @@ pub enum ConnectError {
|
|||||||
/// The Postgres server does not support SSL encryption.
|
/// The Postgres server does not support SSL encryption.
|
||||||
NoSslSupport,
|
NoSslSupport,
|
||||||
/// An error initializing the SSL session.
|
/// An error initializing the SSL session.
|
||||||
SslError(Box<error::Error+Sync+Send>),
|
SslError(Box<error::Error + Sync + Send>),
|
||||||
/// An error communicating with the server.
|
/// An error communicating with the server.
|
||||||
IoError(io::Error),
|
IoError(io::Error),
|
||||||
}
|
}
|
||||||
@ -220,7 +220,7 @@ impl fmt::Display for ConnectError {
|
|||||||
ConnectError::DbError(ref err) => write!(fmt, ": {}", err),
|
ConnectError::DbError(ref err) => write!(fmt, ": {}", err),
|
||||||
ConnectError::SslError(ref err) => write!(fmt, ": {}", err),
|
ConnectError::SslError(ref err) => write!(fmt, ": {}", err),
|
||||||
ConnectError::IoError(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::BadConnectParams(_) => "Error creating `ConnectParams`",
|
||||||
ConnectError::MissingUser => "User missing in `ConnectParams`",
|
ConnectError::MissingUser => "User missing in `ConnectParams`",
|
||||||
ConnectError::DbError(_) => "Error reported by Postgres",
|
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 => {
|
ConnectError::UnsupportedAuthentication => {
|
||||||
"The server requested an unsupported authentication method"
|
"The server requested an unsupported authentication method"
|
||||||
}
|
}
|
||||||
@ -247,7 +248,7 @@ impl error::Error for ConnectError {
|
|||||||
ConnectError::DbError(ref err) => Some(&**err),
|
ConnectError::DbError(ref err) => Some(&**err),
|
||||||
ConnectError::SslError(ref err) => Some(&**err),
|
ConnectError::SslError(ref err) => Some(&**err),
|
||||||
ConnectError::IoError(ref err) => Some(err),
|
ConnectError::IoError(ref err) => Some(err),
|
||||||
_ => None
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -280,8 +281,8 @@ pub enum ErrorPosition {
|
|||||||
/// The byte position.
|
/// The byte position.
|
||||||
position: u32,
|
position: u32,
|
||||||
/// A query generated by the Postgres server.
|
/// A query generated by the Postgres server.
|
||||||
query: String
|
query: String,
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An error encountered when communicating with the Postgres server.
|
/// 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.
|
/// An attempt was made to read from a column that does not exist.
|
||||||
InvalidColumn,
|
InvalidColumn,
|
||||||
/// An error converting between Postgres and Rust types.
|
/// 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 {
|
impl fmt::Display for Error {
|
||||||
@ -329,7 +330,7 @@ impl error::Error for Error {
|
|||||||
Error::DbError(ref err) => Some(&**err),
|
Error::DbError(ref err) => Some(&**err),
|
||||||
Error::IoError(ref err) => Some(err),
|
Error::IoError(ref err) => Some(err),
|
||||||
Error::Conversion(ref err) => Some(&**err),
|
Error::Conversion(ref err) => Some(&**err),
|
||||||
_ => None
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -26,6 +26,8 @@ pub trait NegotiateSsl {
|
|||||||
///
|
///
|
||||||
/// The host portion of the connection parameters is provided for hostname
|
/// The host portion of the connection parameters is provided for hostname
|
||||||
/// verification.
|
/// verification.
|
||||||
fn negotiate_ssl(&self, host: &str, stream: Stream)
|
fn negotiate_ssl(&self,
|
||||||
-> Result<Box<StreamWrapper>, Box<Error+Sync+Send>>;
|
host: &str,
|
||||||
|
stream: Stream)
|
||||||
|
-> Result<Box<StreamWrapper>, Box<Error + Sync + Send>>;
|
||||||
}
|
}
|
||||||
|
@ -16,8 +16,10 @@ impl StreamWrapper for SslStream<Stream> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl NegotiateSsl for SslContext {
|
impl NegotiateSsl for SslContext {
|
||||||
fn negotiate_ssl(&self, _: &str, stream: Stream)
|
fn negotiate_ssl(&self,
|
||||||
-> Result<Box<StreamWrapper>, Box<Error+Send+Sync>> {
|
_: &str,
|
||||||
|
stream: Stream)
|
||||||
|
-> Result<Box<StreamWrapper>, Box<Error + Send + Sync>> {
|
||||||
let stream = try!(SslStream::connect(self, stream));
|
let stream = try!(SslStream::connect(self, stream));
|
||||||
Ok(Box::new(stream))
|
Ok(Box::new(stream))
|
||||||
}
|
}
|
||||||
|
405
src/lib.rs
405
src/lib.rs
@ -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)]
|
#![warn(missing_docs)]
|
||||||
|
|
||||||
extern crate bufstream;
|
extern crate bufstream;
|
||||||
@ -114,7 +114,7 @@ pub enum ConnectTarget {
|
|||||||
///
|
///
|
||||||
/// Only available on Unix platforms with the `unix_socket` feature.
|
/// Only available on Unix platforms with the `unix_socket` feature.
|
||||||
#[cfg(feature = "unix_socket")]
|
#[cfg(feature = "unix_socket")]
|
||||||
Unix(PathBuf)
|
Unix(PathBuf),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Authentication information.
|
/// Authentication information.
|
||||||
@ -148,17 +148,17 @@ pub struct ConnectParams {
|
|||||||
/// A trait implemented by types that can be converted into a `ConnectParams`.
|
/// A trait implemented by types that can be converted into a `ConnectParams`.
|
||||||
pub trait IntoConnectParams {
|
pub trait IntoConnectParams {
|
||||||
/// Converts the value of `self` into a `ConnectParams`.
|
/// 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 {
|
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)
|
Ok(self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> IntoConnectParams for &'a str {
|
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) {
|
match Url::parse(self) {
|
||||||
Ok(url) => url.into_connect_params(),
|
Ok(url) => url.into_connect_params(),
|
||||||
Err(err) => return Err(err.into()),
|
Err(err) => return Err(err.into()),
|
||||||
@ -167,7 +167,7 @@ impl<'a> IntoConnectParams for &'a str {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl IntoConnectParams for Url {
|
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 {
|
let Url {
|
||||||
host,
|
host,
|
||||||
port,
|
port,
|
||||||
@ -178,11 +178,11 @@ impl IntoConnectParams for Url {
|
|||||||
|
|
||||||
#[cfg(feature = "unix_socket")]
|
#[cfg(feature = "unix_socket")]
|
||||||
fn make_unix(maybe_path: String)
|
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)))
|
Ok(ConnectTarget::Unix(PathBuf::from(maybe_path)))
|
||||||
}
|
}
|
||||||
#[cfg(not(feature = "unix_socket"))]
|
#[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())
|
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 }| {
|
let user = user.map(|url::UserInfo { user, pass }| {
|
||||||
UserInfo { user: user, password: pass }
|
UserInfo {
|
||||||
|
user: user,
|
||||||
|
password: pass,
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
let database = if path.is_empty() {
|
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
|
/// Only the host and port of the connection info are used. See
|
||||||
/// `Connection::connect` for details of the `params` argument.
|
/// `Connection::connect` for details of the `params` argument.
|
||||||
///
|
///
|
||||||
/// ## Example
|
/// # Example
|
||||||
///
|
///
|
||||||
/// ```rust,no_run
|
/// ```rust,no_run
|
||||||
/// # use postgres::{Connection, SslMode};
|
/// # use postgres::{Connection, SslMode};
|
||||||
@ -265,19 +268,21 @@ pub struct CancelData {
|
|||||||
/// thread::spawn(move || {
|
/// thread::spawn(move || {
|
||||||
/// conn.execute("SOME EXPENSIVE QUERY", &[]).unwrap();
|
/// conn.execute("SOME EXPENSIVE QUERY", &[]).unwrap();
|
||||||
/// });
|
/// });
|
||||||
/// # let _ =
|
/// postgres::cancel_query(url, &SslMode::None, cancel_data).unwrap();
|
||||||
/// postgres::cancel_query(url, &SslMode::None, cancel_data);
|
|
||||||
/// ```
|
/// ```
|
||||||
pub fn cancel_query<T>(params: T, ssl: &SslMode, data: CancelData)
|
pub fn cancel_query<T>(params: T,
|
||||||
-> result::Result<(), ConnectError>
|
ssl: &SslMode,
|
||||||
where T: IntoConnectParams {
|
data: CancelData)
|
||||||
|
-> result::Result<(), ConnectError>
|
||||||
|
where T: IntoConnectParams
|
||||||
|
{
|
||||||
let params = try!(params.into_connect_params().map_err(ConnectError::BadConnectParams));
|
let params = try!(params.into_connect_params().map_err(ConnectError::BadConnectParams));
|
||||||
let mut socket = try!(priv_io::initialize_stream(¶ms, ssl));
|
let mut socket = try!(priv_io::initialize_stream(¶ms, ssl));
|
||||||
|
|
||||||
try!(socket.write_message(&CancelRequest {
|
try!(socket.write_message(&CancelRequest {
|
||||||
code: message::CANCEL_CODE,
|
code: message::CANCEL_CODE,
|
||||||
process_id: data.process_id,
|
process_id: data.process_id,
|
||||||
secret_key: data.secret_key
|
secret_key: data.secret_key,
|
||||||
}));
|
}));
|
||||||
try!(socket.flush());
|
try!(socket.flush());
|
||||||
|
|
||||||
@ -291,7 +296,8 @@ fn bad_response() -> std_io::Error {
|
|||||||
|
|
||||||
fn desynchronized() -> std_io::Error {
|
fn desynchronized() -> std_io::Error {
|
||||||
std_io::Error::new(std_io::ErrorKind::Other,
|
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.
|
/// An enumeration of transaction isolation levels.
|
||||||
@ -353,9 +359,9 @@ pub enum SslMode {
|
|||||||
/// The connection will not use SSL.
|
/// The connection will not use SSL.
|
||||||
None,
|
None,
|
||||||
/// The connection will use SSL if the backend supports it.
|
/// 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.
|
/// The connection must use SSL.
|
||||||
Require(Box<NegotiateSsl+std::marker::Sync+Send>),
|
Require(Box<NegotiateSsl + std::marker::Sync + Send>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Debug for SslMode {
|
impl fmt::Debug for SslMode {
|
||||||
@ -399,7 +405,8 @@ impl Drop for InnerConnection {
|
|||||||
|
|
||||||
impl InnerConnection {
|
impl InnerConnection {
|
||||||
fn connect<T>(params: T, ssl: &SslMode) -> result::Result<InnerConnection, ConnectError>
|
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 params = try!(params.into_connect_params().map_err(ConnectError::BadConnectParams));
|
||||||
let stream = try!(priv_io::initialize_stream(¶ms, ssl));
|
let stream = try!(priv_io::initialize_stream(¶ms, ssl));
|
||||||
|
|
||||||
@ -412,7 +419,10 @@ impl InnerConnection {
|
|||||||
next_stmt_id: 0,
|
next_stmt_id: 0,
|
||||||
notice_handler: Box::new(LoggingNoticeHandler),
|
notice_handler: Box::new(LoggingNoticeHandler),
|
||||||
notifications: VecDeque::new(),
|
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(),
|
unknown_types: HashMap::new(),
|
||||||
cached_statements: HashMap::new(),
|
cached_statements: HashMap::new(),
|
||||||
parameters: HashMap::new(),
|
parameters: HashMap::new(),
|
||||||
@ -432,9 +442,9 @@ impl InnerConnection {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try!(conn.write_messages(&[StartupMessage {
|
try!(conn.write_messages(&[StartupMessage {
|
||||||
version: message::PROTOCOL_VERSION,
|
version: message::PROTOCOL_VERSION,
|
||||||
parameters: &options
|
parameters: &options,
|
||||||
}]));
|
}]));
|
||||||
|
|
||||||
try!(conn.handle_auth(user));
|
try!(conn.handle_auth(user));
|
||||||
|
|
||||||
@ -455,21 +465,22 @@ impl InnerConnection {
|
|||||||
Ok(conn)
|
Ok(conn)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(rustfmt, rustfmt_skip)]
|
||||||
fn setup_typeinfo_query(&mut self) -> result::Result<(), ConnectError> {
|
fn setup_typeinfo_query(&mut self) -> result::Result<(), ConnectError> {
|
||||||
match self.raw_prepare(TYPEINFO_QUERY,
|
match self.raw_prepare(TYPEINFO_QUERY,
|
||||||
"SELECT t.typname, t.typelem, r.rngsubtype, n.nspname \
|
"SELECT t.typname, t.typelem, r.rngsubtype, n.nspname \
|
||||||
FROM pg_catalog.pg_type t \
|
FROM pg_catalog.pg_type t \
|
||||||
LEFT OUTER JOIN pg_catalog.pg_range r \
|
LEFT OUTER JOIN pg_catalog.pg_range r ON \
|
||||||
ON r.rngtypid = t.oid \
|
r.rngtypid = t.oid \
|
||||||
INNER JOIN pg_catalog.pg_namespace n \
|
INNER JOIN pg_catalog.pg_namespace n ON \
|
||||||
ON t.typnamespace = n.oid \
|
t.typnamespace = n.oid \
|
||||||
WHERE t.oid = $1") {
|
WHERE t.oid = $1") {
|
||||||
Ok(..) => return Ok(()),
|
Ok(..) => return Ok(()),
|
||||||
Err(Error::IoError(e)) => return Err(ConnectError::IoError(e)),
|
Err(Error::IoError(e)) => return Err(ConnectError::IoError(e)),
|
||||||
// Range types weren't added until Postgres 9.2, so pg_range may not exist
|
// 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(ref e)) if e.code() == &SqlState::UndefinedTable => {}
|
||||||
Err(Error::DbError(e)) => return Err(ConnectError::DbError(e)),
|
Err(Error::DbError(e)) => return Err(ConnectError::DbError(e)),
|
||||||
_ => unreachable!()
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
|
|
||||||
match self.raw_prepare(TYPEINFO_QUERY,
|
match self.raw_prepare(TYPEINFO_QUERY,
|
||||||
@ -481,7 +492,7 @@ impl InnerConnection {
|
|||||||
Ok(..) => Ok(()),
|
Ok(..) => Ok(()),
|
||||||
Err(Error::IoError(e)) => Err(ConnectError::IoError(e)),
|
Err(Error::IoError(e)) => Err(ConnectError::IoError(e)),
|
||||||
Err(Error::DbError(e)) => Err(ConnectError::DbError(e)),
|
Err(Error::DbError(e)) => Err(ConnectError::DbError(e)),
|
||||||
_ => unreachable!()
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -505,12 +516,13 @@ impl InnerConnection {
|
|||||||
ParameterStatus { parameter, value } => {
|
ParameterStatus { parameter, value } => {
|
||||||
self.parameters.insert(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>> {
|
-> std::io::Result<Option<BackendMessage>> {
|
||||||
debug_assert!(!self.desynchronized);
|
debug_assert!(!self.desynchronized);
|
||||||
loop {
|
loop {
|
||||||
@ -523,7 +535,7 @@ impl InnerConnection {
|
|||||||
Some(ParameterStatus { parameter, value }) => {
|
Some(ParameterStatus { parameter, value }) => {
|
||||||
self.parameters.insert(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 {
|
self.notifications.push_back(Notification {
|
||||||
pid: pid,
|
pid: pid,
|
||||||
channel: channel,
|
channel: channel,
|
||||||
payload: payload
|
payload: payload,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
val => return Ok(val)
|
val => return Ok(val),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -548,9 +560,7 @@ impl InnerConnection {
|
|||||||
AuthenticationOk => return Ok(()),
|
AuthenticationOk => return Ok(()),
|
||||||
AuthenticationCleartextPassword => {
|
AuthenticationCleartextPassword => {
|
||||||
let pass = try!(user.password.ok_or(ConnectError::MissingPassword));
|
let pass = try!(user.password.ok_or(ConnectError::MissingPassword));
|
||||||
try!(self.write_messages(&[PasswordMessage {
|
try!(self.write_messages(&[PasswordMessage { password: &pass }]));
|
||||||
password: &pass,
|
|
||||||
}]));
|
|
||||||
}
|
}
|
||||||
AuthenticationMD5Password { salt } => {
|
AuthenticationMD5Password { salt } => {
|
||||||
let pass = try!(user.password.ok_or(ConnectError::MissingPassword));
|
let pass = try!(user.password.ok_or(ConnectError::MissingPassword));
|
||||||
@ -562,22 +572,20 @@ impl InnerConnection {
|
|||||||
let _ = hasher.input(output.as_bytes());
|
let _ = hasher.input(output.as_bytes());
|
||||||
let _ = hasher.input(&salt);
|
let _ = hasher.input(&salt);
|
||||||
let output = format!("md5{}", hasher.result_str());
|
let output = format!("md5{}", hasher.result_str());
|
||||||
try!(self.write_messages(&[PasswordMessage {
|
try!(self.write_messages(&[PasswordMessage { password: &output }]));
|
||||||
password: &output
|
|
||||||
}]));
|
|
||||||
}
|
}
|
||||||
AuthenticationKerberosV5
|
AuthenticationKerberosV5 |
|
||||||
| AuthenticationSCMCredential
|
AuthenticationSCMCredential |
|
||||||
| AuthenticationGSS
|
AuthenticationGSS |
|
||||||
| AuthenticationSSPI => return Err(ConnectError::UnsupportedAuthentication),
|
AuthenticationSSPI => return Err(ConnectError::UnsupportedAuthentication),
|
||||||
ErrorResponse { fields } => return DbError::new_connect(fields),
|
ErrorResponse { fields } => return DbError::new_connect(fields),
|
||||||
_ => return Err(ConnectError::IoError(bad_response()))
|
_ => return Err(ConnectError::IoError(bad_response())),
|
||||||
}
|
}
|
||||||
|
|
||||||
match try!(self.read_message()) {
|
match try!(self.read_message()) {
|
||||||
AuthenticationOk => Ok(()),
|
AuthenticationOk => Ok(()),
|
||||||
ErrorResponse { fields } => return DbError::new_connect(fields),
|
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>)> {
|
fn raw_prepare(&mut self, stmt_name: &str, query: &str) -> Result<(Vec<Type>, Vec<Column>)> {
|
||||||
debug!("preparing query with name `{}`: {}", stmt_name, query);
|
debug!("preparing query with name `{}`: {}", stmt_name, query);
|
||||||
|
|
||||||
try!(self.write_messages(&[
|
try!(self.write_messages(&[Parse {
|
||||||
Parse {
|
name: stmt_name,
|
||||||
name: stmt_name,
|
query: query,
|
||||||
query: query,
|
param_types: &[],
|
||||||
param_types: &[]
|
},
|
||||||
},
|
Describe {
|
||||||
Describe {
|
variant: b'S',
|
||||||
variant: b'S',
|
name: stmt_name,
|
||||||
name: stmt_name,
|
},
|
||||||
},
|
Sync]));
|
||||||
Sync]));
|
|
||||||
|
|
||||||
match try!(self.read_message()) {
|
match try!(self.read_message()) {
|
||||||
ParseComplete => {}
|
ParseComplete => {}
|
||||||
@ -617,7 +624,7 @@ impl InnerConnection {
|
|||||||
let raw_columns = match try!(self.read_message()) {
|
let raw_columns = match try!(self.read_message()) {
|
||||||
RowDescription { descriptions } => descriptions,
|
RowDescription { descriptions } => descriptions,
|
||||||
NoData => vec![],
|
NoData => vec![],
|
||||||
_ => bad_response!(self)
|
_ => bad_response!(self),
|
||||||
};
|
};
|
||||||
|
|
||||||
try!(self.wait_for_ready());
|
try!(self.wait_for_ready());
|
||||||
@ -669,16 +676,15 @@ impl InnerConnection {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn close_statement(&mut self, name: &str, type_: u8) -> Result<()> {
|
fn close_statement(&mut self, name: &str, type_: u8) -> Result<()> {
|
||||||
try!(self.write_messages(&[
|
try!(self.write_messages(&[Close {
|
||||||
Close {
|
variant: type_,
|
||||||
variant: type_,
|
name: name,
|
||||||
name: name,
|
},
|
||||||
},
|
Sync]));
|
||||||
Sync]));
|
|
||||||
let resp = match try!(self.read_message()) {
|
let resp = match try!(self.read_message()) {
|
||||||
CloseComplete => Ok(()),
|
CloseComplete => Ok(()),
|
||||||
ErrorResponse { fields } => DbError::new(fields),
|
ErrorResponse { fields } => DbError::new(fields),
|
||||||
_ => bad_response!(self)
|
_ => bad_response!(self),
|
||||||
};
|
};
|
||||||
try!(self.wait_for_ready());
|
try!(self.wait_for_ready());
|
||||||
resp
|
resp
|
||||||
@ -699,57 +705,56 @@ impl InnerConnection {
|
|||||||
IsNull::Yes => None,
|
IsNull::Yes => None,
|
||||||
IsNull::No => Some(buf),
|
IsNull::No => Some(buf),
|
||||||
};
|
};
|
||||||
try!(self.write_messages(&[
|
try!(self.write_messages(&[Bind {
|
||||||
Bind {
|
portal: "",
|
||||||
portal: "",
|
statement: TYPEINFO_QUERY,
|
||||||
statement: TYPEINFO_QUERY,
|
formats: &[1],
|
||||||
formats: &[1],
|
values: &[value],
|
||||||
values: &[value],
|
result_formats: &[1],
|
||||||
result_formats: &[1]
|
},
|
||||||
},
|
Execute {
|
||||||
Execute {
|
portal: "",
|
||||||
portal: "",
|
max_rows: 0,
|
||||||
max_rows: 0,
|
},
|
||||||
},
|
Sync]));
|
||||||
Sync]));
|
|
||||||
match try!(self.read_message()) {
|
match try!(self.read_message()) {
|
||||||
BindComplete => {}
|
BindComplete => {}
|
||||||
ErrorResponse { fields } => {
|
ErrorResponse { fields } => {
|
||||||
try!(self.wait_for_ready());
|
try!(self.wait_for_ready());
|
||||||
return DbError::new(fields);
|
return DbError::new(fields);
|
||||||
}
|
}
|
||||||
_ => bad_response!(self)
|
_ => bad_response!(self),
|
||||||
}
|
}
|
||||||
let (name, elem_oid, rngsubtype, schema): (String, Oid, Option<Oid>, String) =
|
let (name, elem_oid, rngsubtype, schema): (String, Oid, Option<Oid>, String) =
|
||||||
match try!(self.read_message()) {
|
match try!(self.read_message()) {
|
||||||
DataRow { row } => {
|
DataRow { row } => {
|
||||||
let ctx = SessionInfo::new(self);
|
let ctx = SessionInfo::new(self);
|
||||||
(try!(FromSql::from_sql_nullable(&Type::Name,
|
(try!(FromSql::from_sql_nullable(&Type::Name,
|
||||||
row[0].as_ref().map(|r| &**r).as_mut(),
|
row[0].as_ref().map(|r| &**r).as_mut(),
|
||||||
&ctx)),
|
&ctx)),
|
||||||
try!(FromSql::from_sql_nullable(&Type::Oid,
|
try!(FromSql::from_sql_nullable(&Type::Oid,
|
||||||
row[1].as_ref().map(|r| &**r).as_mut(),
|
row[1].as_ref().map(|r| &**r).as_mut(),
|
||||||
&ctx)),
|
&ctx)),
|
||||||
try!(FromSql::from_sql_nullable(&Type::Oid,
|
try!(FromSql::from_sql_nullable(&Type::Oid,
|
||||||
row[2].as_ref().map(|r| &**r).as_mut(),
|
row[2].as_ref().map(|r| &**r).as_mut(),
|
||||||
&ctx)),
|
&ctx)),
|
||||||
try!(FromSql::from_sql_nullable(&Type::Name,
|
try!(FromSql::from_sql_nullable(&Type::Name,
|
||||||
row[3].as_ref().map(|r| &**r).as_mut(),
|
row[3].as_ref().map(|r| &**r).as_mut(),
|
||||||
&ctx)))
|
&ctx)))
|
||||||
}
|
}
|
||||||
ErrorResponse { fields } => {
|
ErrorResponse { fields } => {
|
||||||
try!(self.wait_for_ready());
|
try!(self.wait_for_ready());
|
||||||
return DbError::new(fields);
|
return DbError::new(fields);
|
||||||
}
|
}
|
||||||
_ => bad_response!(self)
|
_ => bad_response!(self),
|
||||||
};
|
};
|
||||||
match try!(self.read_message()) {
|
match try!(self.read_message()) {
|
||||||
CommandComplete { .. } => {}
|
CommandComplete { .. } => {}
|
||||||
ErrorResponse { fields } => {
|
ErrorResponse { fields } => {
|
||||||
try!(self.wait_for_ready());
|
try!(self.wait_for_ready());
|
||||||
return DbError::new(fields);
|
return DbError::new(fields);
|
||||||
}
|
}
|
||||||
_ => bad_response!(self)
|
_ => bad_response!(self),
|
||||||
}
|
}
|
||||||
try!(self.wait_for_ready());
|
try!(self.wait_for_ready());
|
||||||
|
|
||||||
@ -758,7 +763,7 @@ impl InnerConnection {
|
|||||||
} else {
|
} else {
|
||||||
match rngsubtype {
|
match rngsubtype {
|
||||||
Some(oid) => Kind::Range(try!(self.get_type(oid))),
|
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<()> {
|
fn wait_for_ready(&mut self) -> Result<()> {
|
||||||
match try!(self.read_message()) {
|
match try!(self.read_message()) {
|
||||||
ReadyForQuery { .. } => Ok(()),
|
ReadyForQuery { .. } => Ok(()),
|
||||||
_ => bad_response!(self)
|
_ => bad_response!(self),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -788,16 +793,19 @@ impl InnerConnection {
|
|||||||
match try!(self.read_message()) {
|
match try!(self.read_message()) {
|
||||||
ReadyForQuery { .. } => break,
|
ReadyForQuery { .. } => break,
|
||||||
DataRow { row } => {
|
DataRow { row } => {
|
||||||
result.push(row.into_iter().map(|opt| {
|
result.push(row.into_iter()
|
||||||
opt.map(|b| String::from_utf8_lossy(&b).into_owned())
|
.map(|opt| {
|
||||||
}).collect());
|
opt.map(|b| String::from_utf8_lossy(&b).into_owned())
|
||||||
|
})
|
||||||
|
.collect());
|
||||||
}
|
}
|
||||||
CopyInResponse { .. } => {
|
CopyInResponse { .. } |
|
||||||
try!(self.write_messages(&[
|
CopyOutResponse { .. } => {
|
||||||
CopyFail {
|
try!(self.write_messages(&[CopyFail {
|
||||||
message: "COPY queries cannot be directly executed",
|
message: "COPY queries cannot be directly \
|
||||||
},
|
executed",
|
||||||
Sync]));
|
},
|
||||||
|
Sync]));
|
||||||
}
|
}
|
||||||
ErrorResponse { fields } => {
|
ErrorResponse { fields } => {
|
||||||
try!(self.wait_for_ready());
|
try!(self.wait_for_ready());
|
||||||
@ -817,25 +825,26 @@ impl InnerConnection {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn _ensure_send() {
|
fn _ensure_send() {
|
||||||
fn _is_send<T: Send>() {}
|
fn _is_send<T: Send>() {
|
||||||
|
}
|
||||||
_is_send::<Connection>();
|
_is_send::<Connection>();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A connection to a Postgres database.
|
/// A connection to a Postgres database.
|
||||||
pub struct Connection {
|
pub struct Connection {
|
||||||
conn: RefCell<InnerConnection>
|
conn: RefCell<InnerConnection>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Debug for Connection {
|
impl fmt::Debug for Connection {
|
||||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||||
let conn = self.conn.borrow();
|
let conn = self.conn.borrow();
|
||||||
fmt.debug_struct("Connection")
|
fmt.debug_struct("Connection")
|
||||||
.field("cancel_data", &conn.cancel_data)
|
.field("cancel_data", &conn.cancel_data)
|
||||||
.field("notifications", &conn.notifications.len())
|
.field("notifications", &conn.notifications.len())
|
||||||
.field("transaction_depth", &conn.trans_depth)
|
.field("transaction_depth", &conn.trans_depth)
|
||||||
.field("desynchronized", &conn.desynchronized)
|
.field("desynchronized", &conn.desynchronized)
|
||||||
.field("cached_statements", &conn.cached_statements.len())
|
.field("cached_statements", &conn.cached_statements.len())
|
||||||
.finish()
|
.finish()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -860,28 +869,27 @@ impl Connection {
|
|||||||
/// struct should be created manually and passed in. Note that Postgres
|
/// struct should be created manually and passed in. Note that Postgres
|
||||||
/// does not support SSL over Unix sockets.
|
/// does not support SSL over Unix sockets.
|
||||||
///
|
///
|
||||||
/// ## Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// ```rust,no_run
|
/// ```rust,no_run
|
||||||
/// # use postgres::{Connection, SslMode};
|
/// use postgres::{Connection, SslMode};
|
||||||
/// # fn f() -> Result<(), ::postgres::error::ConnectError> {
|
///
|
||||||
/// let url = "postgresql://postgres:hunter2@localhost:2994/foodb";
|
/// let url = "postgresql://postgres:hunter2@localhost:2994/foodb";
|
||||||
/// let conn = try!(Connection::connect(url, &SslMode::None));
|
/// let conn = Connection::connect(url, &SslMode::None).unwrap();
|
||||||
/// # Ok(()) };
|
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// ```rust,no_run
|
/// ```rust,no_run
|
||||||
/// # use postgres::{Connection, SslMode};
|
/// use postgres::{Connection, SslMode};
|
||||||
/// # fn f() -> Result<(), ::postgres::error::ConnectError> {
|
///
|
||||||
/// let url = "postgresql://postgres@%2Frun%2Fpostgres";
|
/// let url = "postgresql://postgres@%2Frun%2Fpostgres";
|
||||||
/// let conn = try!(Connection::connect(url, &SslMode::None));
|
/// let conn = Connection::connect(url, &SslMode::None).unwrap();
|
||||||
/// # Ok(()) };
|
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// ```rust,no_run
|
/// ```rust,no_run
|
||||||
/// # use postgres::{Connection, UserInfo, ConnectParams, SslMode, ConnectTarget};
|
/// use postgres::{Connection, UserInfo, ConnectParams, SslMode, ConnectTarget};
|
||||||
|
///
|
||||||
/// # #[cfg(feature = "unix_socket")]
|
/// # #[cfg(feature = "unix_socket")]
|
||||||
/// # fn f() -> Result<(), ::postgres::error::ConnectError> {
|
/// # fn f() {
|
||||||
/// # let some_crazy_path = Path::new("");
|
/// # let some_crazy_path = Path::new("");
|
||||||
/// let params = ConnectParams {
|
/// let params = ConnectParams {
|
||||||
/// target: ConnectTarget::Unix(some_crazy_path),
|
/// target: ConnectTarget::Unix(some_crazy_path),
|
||||||
@ -893,14 +901,13 @@ impl Connection {
|
|||||||
/// database: None,
|
/// database: None,
|
||||||
/// options: vec![],
|
/// options: vec![],
|
||||||
/// };
|
/// };
|
||||||
/// let conn = try!(Connection::connect(params, &SslMode::None));
|
/// let conn = Connection::connect(params, &SslMode::None).unwrap();
|
||||||
/// # Ok(()) };
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
pub fn connect<T>(params: T, ssl: &SslMode) -> result::Result<Connection, ConnectError>
|
pub fn connect<T>(params: T, ssl: &SslMode) -> result::Result<Connection, ConnectError>
|
||||||
where T: IntoConnectParams {
|
where T: IntoConnectParams
|
||||||
InnerConnection::connect(params, ssl).map(|conn| {
|
{
|
||||||
Connection { conn: RefCell::new(conn) }
|
InnerConnection::connect(params, ssl).map(|conn| Connection { conn: RefCell::new(conn) })
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets the notice handler for the connection, returning the old handler.
|
/// 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
|
/// The statement is associated with the connection that created it and may
|
||||||
/// not outlive that connection.
|
/// not outlive that connection.
|
||||||
///
|
///
|
||||||
/// ## Example
|
/// # Example
|
||||||
///
|
///
|
||||||
/// ```rust,no_run
|
/// ```rust,no_run
|
||||||
/// # use postgres::{Connection, SslMode};
|
/// # use postgres::{Connection, SslMode};
|
||||||
|
/// # let x = 10i32;
|
||||||
/// # let conn = Connection::connect("", &SslMode::None).unwrap();
|
/// # let conn = Connection::connect("", &SslMode::None).unwrap();
|
||||||
/// let maybe_stmt = conn.prepare("SELECT foo FROM bar WHERE baz = $1");
|
/// let stmt = conn.prepare("SELECT foo FROM bar WHERE baz = $1").unwrap();
|
||||||
/// let stmt = match maybe_stmt {
|
/// for row in stmt.query(&[&x]).unwrap() {
|
||||||
/// Ok(stmt) => stmt,
|
/// let foo: String = row.get(0);
|
||||||
/// Err(err) => panic!("Error preparing statement: {:?}", err)
|
/// println!("foo: {}", foo);
|
||||||
/// };
|
/// }
|
||||||
|
/// ```
|
||||||
pub fn prepare<'a>(&'a self, query: &str) -> Result<Statement<'a>> {
|
pub fn prepare<'a>(&'a self, query: &str) -> Result<Statement<'a>> {
|
||||||
self.conn.borrow_mut().prepare(query, self)
|
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
|
/// is going to be used frequently, caching it can improve performance by
|
||||||
/// reducing the number of round trips to the Postgres backend.
|
/// reducing the number of round trips to the Postgres backend.
|
||||||
///
|
///
|
||||||
/// ## Example
|
/// # Example
|
||||||
///
|
///
|
||||||
/// ```rust,no_run
|
/// ```rust,no_run
|
||||||
/// # use postgres::{Connection, SslMode};
|
/// # use postgres::{Connection, SslMode};
|
||||||
/// # fn f() -> postgres::Result<()> {
|
|
||||||
/// # let x = 10i32;
|
/// # let x = 10i32;
|
||||||
/// # let conn = Connection::connect("", &SslMode::None).unwrap();
|
/// # let conn = Connection::connect("", &SslMode::None).unwrap();
|
||||||
/// let stmt = try!(conn.prepare_cached("SELECT foo FROM bar WHERE baz = $1"));
|
/// let stmt = conn.prepare_cached("SELECT foo FROM bar WHERE baz = $1").unwrap();
|
||||||
/// for row in try!(stmt.query(&[&x])) {
|
/// for row in stmt.query(&[&x]).unwrap() {
|
||||||
/// println!("foo: {}", row.get::<_, String>(0));
|
/// let foo: String = row.get(0);
|
||||||
|
/// println!("foo: {}", foo);
|
||||||
/// }
|
/// }
|
||||||
/// # Ok(()) };
|
|
||||||
/// ```
|
/// ```
|
||||||
pub fn prepare_cached<'a>(&'a self, query: &str) -> Result<Statement<'a>> {
|
pub fn prepare_cached<'a>(&'a self, query: &str) -> Result<Statement<'a>> {
|
||||||
self.conn.borrow_mut().prepare_cached(query, self)
|
self.conn.borrow_mut().prepare_cached(query, self)
|
||||||
@ -968,32 +976,30 @@ impl Connection {
|
|||||||
/// the connection for the duration of the transaction. The transaction
|
/// the connection for the duration of the transaction. The transaction
|
||||||
/// is active until the `Transaction` object falls out of scope.
|
/// is active until the `Transaction` object falls out of scope.
|
||||||
///
|
///
|
||||||
/// ## Note
|
/// # Note
|
||||||
/// A transaction will roll back by default. The `set_commit`,
|
/// A transaction will roll back by default. The `set_commit`,
|
||||||
/// `set_rollback`, and `commit` methods alter this behavior.
|
/// `set_rollback`, and `commit` methods alter this behavior.
|
||||||
///
|
///
|
||||||
/// ## Panics
|
/// # Panics
|
||||||
///
|
///
|
||||||
/// Panics if a transaction is already active.
|
/// Panics if a transaction is already active.
|
||||||
///
|
///
|
||||||
/// ## Example
|
/// # Example
|
||||||
///
|
///
|
||||||
/// ```rust,no_run
|
/// ```rust,no_run
|
||||||
/// # use postgres::{Connection, SslMode};
|
/// # use postgres::{Connection, SslMode};
|
||||||
/// # fn foo() -> Result<(), postgres::error::Error> {
|
|
||||||
/// # let conn = Connection::connect("", &SslMode::None).unwrap();
|
/// # let conn = Connection::connect("", &SslMode::None).unwrap();
|
||||||
/// let trans = try!(conn.transaction());
|
/// let trans = conn.transaction().unwrap();
|
||||||
/// try!(trans.execute("UPDATE foo SET bar = 10", &[]));
|
/// trans.execute("UPDATE foo SET bar = 10", &[]).unwrap();
|
||||||
/// // ...
|
/// // ...
|
||||||
///
|
///
|
||||||
/// try!(trans.commit());
|
/// trans.commit().unwrap();
|
||||||
/// # Ok(())
|
|
||||||
/// # }
|
|
||||||
/// ```
|
/// ```
|
||||||
pub fn transaction<'a>(&'a self) -> Result<Transaction<'a>> {
|
pub fn transaction<'a>(&'a self) -> Result<Transaction<'a>> {
|
||||||
let mut conn = self.conn.borrow_mut();
|
let mut conn = self.conn.borrow_mut();
|
||||||
check_desync!(conn);
|
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"));
|
try!(conn.quick_query("BEGIN"));
|
||||||
conn.trans_depth += 1;
|
conn.trans_depth += 1;
|
||||||
Ok(Transaction {
|
Ok(Transaction {
|
||||||
@ -1006,7 +1012,9 @@ impl Connection {
|
|||||||
|
|
||||||
/// Sets the isolation level which will be used for future transactions.
|
/// 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.
|
/// This will not change the behavior of an active transaction.
|
||||||
pub fn set_transaction_isolation(&self, level: IsolationLevel) -> Result<()> {
|
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.
|
/// 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> {
|
pub fn transaction_isolation(&self) -> Result<IsolationLevel> {
|
||||||
let mut conn = self.conn.borrow_mut();
|
let mut conn = self.conn.borrow_mut();
|
||||||
check_desync!(conn);
|
check_desync!(conn);
|
||||||
@ -1028,13 +1038,18 @@ impl Connection {
|
|||||||
///
|
///
|
||||||
/// On success, returns the number of rows modified or 0 if not applicable.
|
/// 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
|
/// Panics if the number of parameters provided does not match the number
|
||||||
/// expected.
|
/// expected.
|
||||||
pub fn execute(&self, query: &str, params: &[&ToSql]) -> Result<u64> {
|
pub fn execute(&self, query: &str, params: &[&ToSql]) -> Result<u64> {
|
||||||
let (param_types, columns) = try!(self.conn.borrow_mut().raw_prepare("", query));
|
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)
|
stmt.execute(params)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1045,33 +1060,32 @@ impl Connection {
|
|||||||
/// execution of batches of non-dynamic statements - for example, creation
|
/// execution of batches of non-dynamic statements - for example, creation
|
||||||
/// of a schema for a fresh database.
|
/// of a schema for a fresh database.
|
||||||
///
|
///
|
||||||
/// ## Warning
|
/// # Warning
|
||||||
///
|
///
|
||||||
/// Prepared statements should be used for any SQL statement which contains
|
/// Prepared statements should be used for any SQL statement which contains
|
||||||
/// user-specified data, as it provides functionality to safely embed that
|
/// user-specified data, as it provides functionality to safely embed that
|
||||||
/// data in the statement. Do not form statements via string concatenation
|
/// data in the statement. Do not form statements via string concatenation
|
||||||
/// and feed them into this method.
|
/// and feed them into this method.
|
||||||
///
|
///
|
||||||
/// ## Example
|
/// # Example
|
||||||
///
|
///
|
||||||
/// ```rust,no_run
|
/// ```rust,no_run
|
||||||
/// # use postgres::{Connection, Result};
|
/// # use postgres::{Connection, SslMode, Result};
|
||||||
/// fn init_db(conn: &Connection) -> Result<()> {
|
/// # let conn = Connection::connect("", &SslMode::None).unwrap();
|
||||||
/// conn.batch_execute("
|
/// conn.batch_execute("
|
||||||
/// CREATE TABLE person (
|
/// CREATE TABLE person (
|
||||||
/// id SERIAL PRIMARY KEY,
|
/// id SERIAL PRIMARY KEY,
|
||||||
/// name NOT NULL
|
/// name NOT NULL
|
||||||
/// );
|
/// );
|
||||||
///
|
///
|
||||||
/// CREATE TABLE purchase (
|
/// CREATE TABLE purchase (
|
||||||
/// id SERIAL PRIMARY KEY,
|
/// id SERIAL PRIMARY KEY,
|
||||||
/// person INT NOT NULL REFERENCES person (id),
|
/// person INT NOT NULL REFERENCES person (id),
|
||||||
/// time TIMESTAMPTZ NOT NULL,
|
/// time TIMESTAMPTZ NOT NULL,
|
||||||
/// );
|
/// );
|
||||||
///
|
///
|
||||||
/// CREATE INDEX ON purchase (time);
|
/// CREATE INDEX ON purchase (time);
|
||||||
/// ")
|
/// ").unwrap();
|
||||||
/// }
|
|
||||||
/// ```
|
/// ```
|
||||||
pub fn batch_execute(&self, query: &str) -> Result<()> {
|
pub fn batch_execute(&self, query: &str) -> Result<()> {
|
||||||
self.conn.borrow_mut().quick_query(query).map(|_| ())
|
self.conn.borrow_mut().quick_query(query).map(|_| ())
|
||||||
@ -1133,9 +1147,9 @@ pub struct Transaction<'conn> {
|
|||||||
impl<'a> fmt::Debug for Transaction<'a> {
|
impl<'a> fmt::Debug for Transaction<'a> {
|
||||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||||
fmt.debug_struct("Transaction")
|
fmt.debug_struct("Transaction")
|
||||||
.field("commit", &self.commit.get())
|
.field("commit", &self.commit.get())
|
||||||
.field("depth", &self.depth)
|
.field("depth", &self.depth)
|
||||||
.finish()
|
.finish()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1186,7 +1200,7 @@ impl<'conn> Transaction<'conn> {
|
|||||||
|
|
||||||
/// Like `Connection::transaction`.
|
/// Like `Connection::transaction`.
|
||||||
///
|
///
|
||||||
/// ## Panics
|
/// # Panics
|
||||||
///
|
///
|
||||||
/// Panics if there is an active nested transaction.
|
/// Panics if there is an active nested transaction.
|
||||||
pub fn transaction<'a>(&'a self) -> Result<Transaction<'a>> {
|
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);
|
return DbError::new(fields);
|
||||||
}
|
}
|
||||||
CopyInResponse { .. } => {
|
CopyInResponse { .. } => {
|
||||||
try!(conn.write_messages(&[
|
try!(conn.write_messages(&[CopyFail {
|
||||||
CopyFail {
|
message: "COPY queries cannot be directly executed",
|
||||||
message: "COPY queries cannot be directly executed",
|
},
|
||||||
},
|
Sync]));
|
||||||
Sync]));
|
|
||||||
}
|
}
|
||||||
CopyOutResponse { .. } => {
|
CopyOutResponse { .. } => {
|
||||||
loop {
|
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(
|
return Err(Error::IoError(std_io::Error::new(std_io::ErrorKind::InvalidInput,
|
||||||
std_io::ErrorKind::InvalidInput,
|
"COPY queries cannot be directly \
|
||||||
"COPY queries cannot be directly executed")));
|
executed")));
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
conn.desynchronized = true;
|
conn.desynchronized = true;
|
||||||
@ -1384,7 +1397,8 @@ trait LazyRowsNew<'trans, 'stmt> {
|
|||||||
row_limit: i32,
|
row_limit: i32,
|
||||||
more_rows: bool,
|
more_rows: bool,
|
||||||
finished: bool,
|
finished: bool,
|
||||||
trans: &'trans Transaction<'trans>) -> LazyRows<'trans, 'stmt>;
|
trans: &'trans Transaction<'trans>)
|
||||||
|
-> LazyRows<'trans, 'stmt>;
|
||||||
}
|
}
|
||||||
|
|
||||||
trait SessionInfoNew<'a> {
|
trait SessionInfoNew<'a> {
|
||||||
@ -1397,7 +1411,8 @@ trait StatementInternals<'conn> {
|
|||||||
param_types: Vec<Type>,
|
param_types: Vec<Type>,
|
||||||
columns: Vec<Column>,
|
columns: Vec<Column>,
|
||||||
next_portal_id: Cell<u32>,
|
next_portal_id: Cell<u32>,
|
||||||
finished: bool) -> Statement<'conn>;
|
finished: bool)
|
||||||
|
-> Statement<'conn>;
|
||||||
|
|
||||||
fn conn(&self) -> &'conn Connection;
|
fn conn(&self) -> &'conn Connection;
|
||||||
}
|
}
|
||||||
|
95
src/md5.rs
95
src/md5.rs
@ -18,7 +18,7 @@ use std::iter::repeat;
|
|||||||
struct StepUp<T> {
|
struct StepUp<T> {
|
||||||
next: T,
|
next: T,
|
||||||
end: T,
|
end: T,
|
||||||
ammount: T
|
ammount: T,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl <T> Iterator for StepUp<T> where
|
impl <T> Iterator for StepUp<T> where
|
||||||
@ -47,7 +47,7 @@ impl <T> RangeExt<T> for Range<T> where
|
|||||||
StepUp {
|
StepUp {
|
||||||
next: self.start,
|
next: self.start,
|
||||||
end: self.end,
|
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.
|
/// 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());
|
assert!(dst.len() * 4 == input.len());
|
||||||
unsafe {
|
unsafe {
|
||||||
let mut x: *mut u32 = dst.get_unchecked_mut(0);
|
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
|
/// Write a u32 into a vector, which must be 4 bytes long. The value is written in little-endian
|
||||||
/// format.
|
/// 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);
|
assert!(dst.len() == 4);
|
||||||
input = input.to_le();
|
input = input.to_le();
|
||||||
unsafe {
|
unsafe {
|
||||||
@ -147,7 +147,7 @@ trait FixedBuffer {
|
|||||||
/// Get the current buffer. The buffer must already be full. This clears the buffer as well.
|
/// 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];
|
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];
|
fn current_buffer<'s>(&'s mut self) -> &'s [u8];
|
||||||
|
|
||||||
/// Get the current position of the buffer.
|
/// Get the current position of the buffer.
|
||||||
@ -247,14 +247,18 @@ struct FixedBuffer64 {
|
|||||||
buffer_idx: usize,
|
buffer_idx: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Clone for FixedBuffer64 { fn clone(&self) -> FixedBuffer64 { *self } }
|
impl Clone for FixedBuffer64 {
|
||||||
|
fn clone(&self) -> FixedBuffer64 {
|
||||||
|
*self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl FixedBuffer64 {
|
impl FixedBuffer64 {
|
||||||
/// Create a new buffer
|
/// Create a new buffer
|
||||||
fn new() -> FixedBuffer64 {
|
fn new() -> FixedBuffer64 {
|
||||||
FixedBuffer64 {
|
FixedBuffer64 {
|
||||||
buffer: [0u8; 64],
|
buffer: [0u8; 64],
|
||||||
buffer_idx: 0
|
buffer_idx: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -266,7 +270,7 @@ struct Md5State {
|
|||||||
s0: u32,
|
s0: u32,
|
||||||
s1: u32,
|
s1: u32,
|
||||||
s2: u32,
|
s2: u32,
|
||||||
s3: u32
|
s3: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Md5State {
|
impl Md5State {
|
||||||
@ -275,7 +279,7 @@ impl Md5State {
|
|||||||
s0: 0x67452301,
|
s0: 0x67452301,
|
||||||
s1: 0xefcdab89,
|
s1: 0xefcdab89,
|
||||||
s2: 0x98badcfe,
|
s2: 0x98badcfe,
|
||||||
s3: 0x10325476
|
s3: 0x10325476,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -341,8 +345,18 @@ impl Md5State {
|
|||||||
for i in (0..16).step_up(4) {
|
for i in (0..16).step_up(4) {
|
||||||
a = op_g(a, b, c, d, data[t & 0x0f].wrapping_add(C2[i]), 5);
|
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);
|
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);
|
c = op_g(c,
|
||||||
b = op_g(b, c, d, a, data[(t + 15) & 0x0f].wrapping_add(C2[i + 3]), 20);
|
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;
|
t += 20;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -361,8 +375,18 @@ impl Md5State {
|
|||||||
for i in (0..16).step_up(4) {
|
for i in (0..16).step_up(4) {
|
||||||
a = op_i(a, b, c, d, data[t & 0x0f].wrapping_add(C4[i]), 6);
|
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);
|
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);
|
c = op_i(c,
|
||||||
b = op_i(b, c, d, a, data[(t + 21) & 0x0f].wrapping_add(C4[i + 3]), 21);
|
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;
|
t += 28;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -374,28 +398,24 @@ impl Md5State {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Round 1 constants
|
// Round 1 constants
|
||||||
static C1: [u32; 16] = [
|
static C1: [u32; 16] = [0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, 0xf57c0faf, 0x4787c62a,
|
||||||
0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501,
|
0xa8304613, 0xfd469501, 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be,
|
||||||
0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821
|
0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821];
|
||||||
];
|
|
||||||
|
|
||||||
// Round 2 constants
|
// Round 2 constants
|
||||||
static C2: [u32; 16] = [
|
static C2: [u32; 16] = [0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, 0xd62f105d, 0x02441453,
|
||||||
0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8,
|
0xd8a1e681, 0xe7d3fbc8, 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed,
|
||||||
0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a
|
0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a];
|
||||||
];
|
|
||||||
|
|
||||||
// Round 3 constants
|
// Round 3 constants
|
||||||
static C3: [u32; 16] = [
|
static C3: [u32; 16] = [0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, 0xa4beea44, 0x4bdecfa9,
|
||||||
0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70,
|
0xf6bb4b60, 0xbebfbc70, 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05,
|
||||||
0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05, 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665
|
0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665];
|
||||||
];
|
|
||||||
|
|
||||||
// Round 4 constants
|
// Round 4 constants
|
||||||
static C4: [u32; 16] = [
|
static C4: [u32; 16] = [0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, 0x655b59c3, 0x8f0ccc92,
|
||||||
0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1,
|
0xffeff47d, 0x85845dd1, 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1,
|
||||||
0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391
|
0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391];
|
||||||
];
|
|
||||||
|
|
||||||
/// The MD5 Digest algorithm
|
/// The MD5 Digest algorithm
|
||||||
pub struct Md5 {
|
pub struct Md5 {
|
||||||
@ -412,7 +432,7 @@ impl Md5 {
|
|||||||
length_bytes: 0,
|
length_bytes: 0,
|
||||||
buffer: FixedBuffer64::new(),
|
buffer: FixedBuffer64::new(),
|
||||||
state: Md5State::new(),
|
state: Md5State::new(),
|
||||||
finished: false
|
finished: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -422,8 +442,9 @@ impl Md5 {
|
|||||||
// 2^64 - ie: integer overflow is OK.
|
// 2^64 - ie: integer overflow is OK.
|
||||||
self.length_bytes += input.len() as u64;
|
self.length_bytes += input.len() as u64;
|
||||||
let self_state = &mut self.state;
|
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) {
|
pub fn reset(&mut self) {
|
||||||
@ -436,7 +457,9 @@ impl Md5 {
|
|||||||
pub fn result(&mut self, out: &mut [u8]) {
|
pub fn result(&mut self, out: &mut [u8]) {
|
||||||
if !self.finished {
|
if !self.finished {
|
||||||
let self_state = &mut self.state;
|
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 << 3) as u32);
|
||||||
write_u32_le(self.buffer.next(4), (self.length_bytes >> 29) as u32);
|
write_u32_le(self.buffer.next(4), (self.length_bytes >> 29) as u32);
|
||||||
self_state.process_block(self.buffer.full_buffer());
|
self_state.process_block(self.buffer.full_buffer());
|
||||||
@ -449,12 +472,14 @@ impl Md5 {
|
|||||||
write_u32_le(&mut out[12..16], self.state.s3);
|
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 {
|
pub fn result_str(&mut self) -> String {
|
||||||
use serialize::hex::ToHex;
|
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);
|
self.result(&mut buf);
|
||||||
buf[..].to_hex()
|
buf[..].to_hex()
|
||||||
}
|
}
|
||||||
|
@ -20,14 +20,14 @@ pub enum BackendMessage {
|
|||||||
AuthenticationGSS,
|
AuthenticationGSS,
|
||||||
AuthenticationKerberosV5,
|
AuthenticationKerberosV5,
|
||||||
AuthenticationMD5Password {
|
AuthenticationMD5Password {
|
||||||
salt: [u8; 4]
|
salt: [u8; 4],
|
||||||
},
|
},
|
||||||
AuthenticationOk,
|
AuthenticationOk,
|
||||||
AuthenticationSCMCredential,
|
AuthenticationSCMCredential,
|
||||||
AuthenticationSSPI,
|
AuthenticationSSPI,
|
||||||
BackendKeyData {
|
BackendKeyData {
|
||||||
process_id: u32,
|
process_id: u32,
|
||||||
secret_key: u32
|
secret_key: u32,
|
||||||
},
|
},
|
||||||
BindComplete,
|
BindComplete,
|
||||||
CloseComplete,
|
CloseComplete,
|
||||||
@ -48,15 +48,15 @@ pub enum BackendMessage {
|
|||||||
column_formats: Vec<u16>,
|
column_formats: Vec<u16>,
|
||||||
},
|
},
|
||||||
DataRow {
|
DataRow {
|
||||||
row: Vec<Option<Vec<u8>>>
|
row: Vec<Option<Vec<u8>>>,
|
||||||
},
|
},
|
||||||
EmptyQueryResponse,
|
EmptyQueryResponse,
|
||||||
ErrorResponse {
|
ErrorResponse {
|
||||||
fields: Vec<(u8, String)>
|
fields: Vec<(u8, String)>,
|
||||||
},
|
},
|
||||||
NoData,
|
NoData,
|
||||||
NoticeResponse {
|
NoticeResponse {
|
||||||
fields: Vec<(u8, String)>
|
fields: Vec<(u8, String)>,
|
||||||
},
|
},
|
||||||
NotificationResponse {
|
NotificationResponse {
|
||||||
pid: u32,
|
pid: u32,
|
||||||
@ -64,7 +64,7 @@ pub enum BackendMessage {
|
|||||||
payload: String,
|
payload: String,
|
||||||
},
|
},
|
||||||
ParameterDescription {
|
ParameterDescription {
|
||||||
types: Vec<Oid>
|
types: Vec<Oid>,
|
||||||
},
|
},
|
||||||
ParameterStatus {
|
ParameterStatus {
|
||||||
parameter: String,
|
parameter: String,
|
||||||
@ -73,11 +73,11 @@ pub enum BackendMessage {
|
|||||||
ParseComplete,
|
ParseComplete,
|
||||||
PortalSuspended,
|
PortalSuspended,
|
||||||
ReadyForQuery {
|
ReadyForQuery {
|
||||||
_state: u8
|
_state: u8,
|
||||||
},
|
},
|
||||||
RowDescription {
|
RowDescription {
|
||||||
descriptions: Vec<RowDescriptionEntry>
|
descriptions: Vec<RowDescriptionEntry>,
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct RowDescriptionEntry {
|
pub struct RowDescriptionEntry {
|
||||||
@ -87,7 +87,7 @@ pub struct RowDescriptionEntry {
|
|||||||
pub type_oid: Oid,
|
pub type_oid: Oid,
|
||||||
pub type_size: i16,
|
pub type_size: i16,
|
||||||
pub type_modifier: i32,
|
pub type_modifier: i32,
|
||||||
pub format: i16
|
pub format: i16,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum FrontendMessage<'a> {
|
pub enum FrontendMessage<'a> {
|
||||||
@ -96,7 +96,7 @@ pub enum FrontendMessage<'a> {
|
|||||||
statement: &'a str,
|
statement: &'a str,
|
||||||
formats: &'a [i16],
|
formats: &'a [i16],
|
||||||
values: &'a [Option<Vec<u8>>],
|
values: &'a [Option<Vec<u8>>],
|
||||||
result_formats: &'a [i16]
|
result_formats: &'a [i16],
|
||||||
},
|
},
|
||||||
CancelRequest {
|
CancelRequest {
|
||||||
code: u32,
|
code: u32,
|
||||||
@ -105,43 +105,43 @@ pub enum FrontendMessage<'a> {
|
|||||||
},
|
},
|
||||||
Close {
|
Close {
|
||||||
variant: u8,
|
variant: u8,
|
||||||
name: &'a str
|
name: &'a str,
|
||||||
},
|
},
|
||||||
CopyData {
|
CopyData {
|
||||||
data: &'a [u8],
|
data: &'a [u8],
|
||||||
},
|
},
|
||||||
CopyDone,
|
CopyDone,
|
||||||
CopyFail {
|
CopyFail {
|
||||||
message: &'a str
|
message: &'a str,
|
||||||
},
|
},
|
||||||
Describe {
|
Describe {
|
||||||
variant: u8,
|
variant: u8,
|
||||||
name: &'a str
|
name: &'a str,
|
||||||
},
|
},
|
||||||
Execute {
|
Execute {
|
||||||
portal: &'a str,
|
portal: &'a str,
|
||||||
max_rows: i32
|
max_rows: i32,
|
||||||
},
|
},
|
||||||
Parse {
|
Parse {
|
||||||
name: &'a str,
|
name: &'a str,
|
||||||
query: &'a str,
|
query: &'a str,
|
||||||
param_types: &'a [Oid]
|
param_types: &'a [Oid],
|
||||||
},
|
},
|
||||||
PasswordMessage {
|
PasswordMessage {
|
||||||
password: &'a str
|
password: &'a str,
|
||||||
},
|
},
|
||||||
Query {
|
Query {
|
||||||
query: &'a str
|
query: &'a str,
|
||||||
},
|
},
|
||||||
SslRequest {
|
SslRequest {
|
||||||
code: u32
|
code: u32,
|
||||||
},
|
},
|
||||||
StartupMessage {
|
StartupMessage {
|
||||||
version: u32,
|
version: u32,
|
||||||
parameters: &'a [(String, String)]
|
parameters: &'a [(String, String)],
|
||||||
},
|
},
|
||||||
Sync,
|
Sync,
|
||||||
Terminate
|
Terminate,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
@ -158,7 +158,7 @@ impl<W: Write> WriteCStr for W {
|
|||||||
|
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub trait WriteMessage {
|
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 {
|
impl<W: Write> WriteMessage for W {
|
||||||
@ -285,8 +285,7 @@ impl<R: BufRead> ReadCStr for R {
|
|||||||
pub trait ReadMessage {
|
pub trait ReadMessage {
|
||||||
fn read_message(&mut self) -> io::Result<BackendMessage>;
|
fn read_message(&mut self) -> io::Result<BackendMessage>;
|
||||||
|
|
||||||
fn read_message_timeout(&mut self, timeout: Duration)
|
fn read_message_timeout(&mut self, timeout: Duration) -> io::Result<Option<BackendMessage>>;
|
||||||
-> io::Result<Option<BackendMessage>>;
|
|
||||||
|
|
||||||
fn finish_read_message(&mut self, ident: u8) -> io::Result<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)
|
self.finish_read_message(ident)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_message_timeout(&mut self, timeout: Duration)
|
fn read_message_timeout(&mut self, timeout: Duration) -> io::Result<Option<BackendMessage>> {
|
||||||
-> io::Result<Option<BackendMessage>> {
|
|
||||||
try!(self.set_read_timeout(Some(timeout)));
|
try!(self.set_read_timeout(Some(timeout)));
|
||||||
let ident = self.read_u8();
|
let ident = self.read_u8();
|
||||||
try!(self.set_read_timeout(None));
|
try!(self.set_read_timeout(None));
|
||||||
@ -328,16 +326,14 @@ impl<R: BufRead + ReadTimeout> ReadMessage for R {
|
|||||||
b'A' => NotificationResponse {
|
b'A' => NotificationResponse {
|
||||||
pid: try!(rdr.read_u32::<BigEndian>()),
|
pid: try!(rdr.read_u32::<BigEndian>()),
|
||||||
channel: try!(rdr.read_cstr()),
|
channel: try!(rdr.read_cstr()),
|
||||||
payload: try!(rdr.read_cstr())
|
payload: try!(rdr.read_cstr()),
|
||||||
},
|
},
|
||||||
b'c' => BCopyDone,
|
b'c' => BCopyDone,
|
||||||
b'C' => CommandComplete { tag: try!(rdr.read_cstr()) },
|
b'C' => CommandComplete { tag: try!(rdr.read_cstr()) },
|
||||||
b'd' => {
|
b'd' => {
|
||||||
let mut data = vec![];
|
let mut data = vec![];
|
||||||
try!(rdr.read_to_end(&mut data));
|
try!(rdr.read_to_end(&mut data));
|
||||||
BCopyData {
|
BCopyData { data: data }
|
||||||
data: data,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
b'D' => try!(read_data_row(&mut rdr)),
|
b'D' => try!(read_data_row(&mut rdr)),
|
||||||
b'E' => ErrorResponse { fields: try!(read_fields(&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'I' => EmptyQueryResponse,
|
||||||
b'K' => BackendKeyData {
|
b'K' => BackendKeyData {
|
||||||
process_id: try!(rdr.read_u32::<BigEndian>()),
|
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' => NoData,
|
||||||
b'N' => NoticeResponse { fields: try!(read_fields(&mut rdr)) },
|
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' => PortalSuspended,
|
||||||
b'S' => ParameterStatus {
|
b'S' => ParameterStatus {
|
||||||
parameter: try!(rdr.read_cstr()),
|
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_parameter_description(&mut rdr)),
|
||||||
b'T' => try!(read_row_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];
|
let mut salt = [0; 4];
|
||||||
try!(util::read_all(buf, &mut salt));
|
try!(util::read_all(buf, &mut salt));
|
||||||
AuthenticationMD5Password { salt: salt }
|
AuthenticationMD5Password { salt: salt }
|
||||||
},
|
}
|
||||||
6 => AuthenticationSCMCredential,
|
6 => AuthenticationSCMCredential,
|
||||||
7 => AuthenticationGSS,
|
7 => AuthenticationGSS,
|
||||||
9 => AuthenticationSSPI,
|
9 => AuthenticationSSPI,
|
||||||
|
@ -20,14 +20,14 @@ pub struct Notification {
|
|||||||
|
|
||||||
/// An iterator over asynchronous notifications.
|
/// An iterator over asynchronous notifications.
|
||||||
pub struct Notifications<'conn> {
|
pub struct Notifications<'conn> {
|
||||||
conn: &'conn Connection
|
conn: &'conn Connection,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> fmt::Debug for Notifications<'a> {
|
impl<'a> fmt::Debug for Notifications<'a> {
|
||||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||||
fmt.debug_struct("Notifications")
|
fmt.debug_struct("Notifications")
|
||||||
.field("pending", &self.len())
|
.field("pending", &self.len())
|
||||||
.finish()
|
.finish()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -45,9 +45,7 @@ impl<'conn> Notifications<'conn> {
|
|||||||
/// `None` if more notifications are received. However, those notifications
|
/// `None` if more notifications are received. However, those notifications
|
||||||
/// will not be registered until the connection is used in some way.
|
/// will not be registered until the connection is used in some way.
|
||||||
pub fn iter<'a>(&'a self) -> Iter<'a> {
|
pub fn iter<'a>(&'a self) -> Iter<'a> {
|
||||||
Iter {
|
Iter { conn: self.conn }
|
||||||
conn: self.conn,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns an iterator over notifications that blocks until one is
|
/// Returns an iterator over notifications that blocks until one is
|
||||||
@ -55,9 +53,7 @@ impl<'conn> Notifications<'conn> {
|
|||||||
///
|
///
|
||||||
/// The iterator will never return `None`.
|
/// The iterator will never return `None`.
|
||||||
pub fn blocking_iter<'a>(&'a self) -> BlockingIter<'a> {
|
pub fn blocking_iter<'a>(&'a self) -> BlockingIter<'a> {
|
||||||
BlockingIter {
|
BlockingIter { conn: self.conn }
|
||||||
conn: self.conn,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns an iterator over notifications that blocks for a limited time
|
/// 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> {
|
impl<'conn> NotificationsNew<'conn> for Notifications<'conn> {
|
||||||
fn new(conn: &'conn Connection) -> Notifications<'conn> {
|
fn new(conn: &'conn Connection) -> Notifications<'conn> {
|
||||||
Notifications {
|
Notifications { conn: conn }
|
||||||
conn: conn,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -129,11 +123,11 @@ impl<'a> Iterator for BlockingIter<'a> {
|
|||||||
Some(Ok(Notification {
|
Some(Ok(Notification {
|
||||||
pid: pid,
|
pid: pid,
|
||||||
channel: channel,
|
channel: channel,
|
||||||
payload: payload
|
payload: payload,
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
Err(err) => Some(Err(Error::IoError(err))),
|
Err(err) => Some(Err(Error::IoError(err))),
|
||||||
_ => unreachable!()
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -164,12 +158,12 @@ impl<'a> Iterator for TimeoutIter<'a> {
|
|||||||
Some(Ok(Notification {
|
Some(Ok(Notification {
|
||||||
pid: pid,
|
pid: pid,
|
||||||
channel: channel,
|
channel: channel,
|
||||||
payload: payload
|
payload: payload,
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
Ok(None) => None,
|
Ok(None) => None,
|
||||||
Err(err) => Some(Err(Error::IoError(err))),
|
Err(err) => Some(Err(Error::IoError(err))),
|
||||||
_ => unreachable!()
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,7 @@ use std::os::unix::io::{AsRawFd, RawFd};
|
|||||||
use std::os::windows::io::{AsRawSocket, RawSocket};
|
use std::os::windows::io::{AsRawSocket, RawSocket};
|
||||||
|
|
||||||
use {SslMode, ConnectParams, ConnectTarget};
|
use {SslMode, ConnectParams, ConnectTarget};
|
||||||
use error::{ConnectError};
|
use error::ConnectError;
|
||||||
use io::{NegotiateSsl, StreamWrapper};
|
use io::{NegotiateSsl, StreamWrapper};
|
||||||
use message::{self, WriteMessage};
|
use message::{self, WriteMessage};
|
||||||
use message::FrontendMessage::SslRequest;
|
use message::FrontendMessage::SslRequest;
|
||||||
@ -28,7 +28,8 @@ pub trait ReadTimeout {
|
|||||||
impl ReadTimeout for BufStream<Box<StreamWrapper>> {
|
impl ReadTimeout for BufStream<Box<StreamWrapper>> {
|
||||||
fn set_read_timeout(&self, timeout: Option<Duration>) -> io::Result<()> {
|
fn set_read_timeout(&self, timeout: Option<Duration>) -> io::Result<()> {
|
||||||
match self.get_ref().get_ref().0 {
|
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")]
|
#[cfg(feature = "unix_socket")]
|
||||||
InternalStream::Unix(ref s) => s.set_read_timeout(timeout),
|
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)
|
pub fn initialize_stream(params: &ConnectParams,
|
||||||
-> Result<Box<StreamWrapper>, ConnectError> {
|
ssl: &SslMode)
|
||||||
|
-> Result<Box<StreamWrapper>, ConnectError> {
|
||||||
let mut socket = Stream(try!(open_socket(params)));
|
let mut socket = Stream(try!(open_socket(params)));
|
||||||
|
|
||||||
let (ssl_required, negotiator) = match *ssl {
|
let (ssl_required, negotiator) = match *ssl {
|
||||||
@ -161,11 +163,11 @@ pub fn initialize_stream(params: &ConnectParams, ssl: &SslMode)
|
|||||||
let host = match params.target {
|
let host = match params.target {
|
||||||
ConnectTarget::Tcp(ref host) => host,
|
ConnectTarget::Tcp(ref host) => host,
|
||||||
#[cfg(feature = "unix_socket")]
|
#[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) {
|
match negotiator.negotiate_ssl(host, socket) {
|
||||||
Ok(stream) => Ok(stream),
|
Ok(stream) => Ok(stream),
|
||||||
Err(err) => Err(ConnectError::SslError(err))
|
Err(err) => Err(ConnectError::SslError(err)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
86
src/rows.rs
86
src/rows.rs
@ -7,13 +7,7 @@ use std::borrow::Cow;
|
|||||||
use std::slice;
|
use std::slice;
|
||||||
use std::vec;
|
use std::vec;
|
||||||
|
|
||||||
use {Result,
|
use {Result, Transaction, read_rows, DbErrorNew, SessionInfoNew, RowsNew, LazyRowsNew,
|
||||||
Transaction,
|
|
||||||
read_rows,
|
|
||||||
DbErrorNew,
|
|
||||||
SessionInfoNew,
|
|
||||||
RowsNew,
|
|
||||||
LazyRowsNew,
|
|
||||||
StatementInternals};
|
StatementInternals};
|
||||||
use types::{FromSql, SessionInfo};
|
use types::{FromSql, SessionInfo};
|
||||||
use stmt::{Statement, Column};
|
use stmt::{Statement, Column};
|
||||||
@ -38,9 +32,9 @@ impl<'a> RowsNew<'a> for Rows<'a> {
|
|||||||
impl<'a> fmt::Debug for Rows<'a> {
|
impl<'a> fmt::Debug for Rows<'a> {
|
||||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||||
fmt.debug_struct("Rows")
|
fmt.debug_struct("Rows")
|
||||||
.field("columns", &self.columns())
|
.field("columns", &self.columns())
|
||||||
.field("rows", &self.data.len())
|
.field("rows", &self.data.len())
|
||||||
.finish()
|
.finish()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -71,7 +65,7 @@ impl<'stmt> Rows<'stmt> {
|
|||||||
pub fn iter<'a>(&'a self) -> Iter<'a> {
|
pub fn iter<'a>(&'a self) -> Iter<'a> {
|
||||||
Iter {
|
Iter {
|
||||||
stmt: self.stmt,
|
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> {
|
fn into_iter(self) -> IntoIter<'stmt> {
|
||||||
IntoIter {
|
IntoIter {
|
||||||
stmt: self.stmt,
|
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.
|
/// A single result row of a query.
|
||||||
pub struct Row<'a> {
|
pub struct Row<'a> {
|
||||||
stmt: &'a Statement<'a>,
|
stmt: &'a Statement<'a>,
|
||||||
data: Cow<'a, [Option<Vec<u8>>]>
|
data: Cow<'a, [Option<Vec<u8>>]>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> fmt::Debug for Row<'a> {
|
impl<'a> fmt::Debug for Row<'a> {
|
||||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||||
fmt.debug_struct("Row")
|
fmt.debug_struct("Row")
|
||||||
.field("statement", self.stmt)
|
.field("statement", self.stmt)
|
||||||
.finish()
|
.finish()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -201,14 +195,18 @@ impl<'a> Row<'a> {
|
|||||||
///
|
///
|
||||||
/// Returns an `Error` value if the index does not reference a column or
|
/// Returns an `Error` value if the index does not reference a column or
|
||||||
/// the return type is not compatible with the Postgres type.
|
/// 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 idx = try!(idx.idx(self.stmt).ok_or(Error::InvalidColumn));
|
||||||
let ty = self.stmt.columns()[idx].type_();
|
let ty = self.stmt.columns()[idx].type_();
|
||||||
if !<T as FromSql>::accepts(ty) {
|
if !<T as FromSql>::accepts(ty) {
|
||||||
return Err(Error::WrongType(ty.clone()));
|
return Err(Error::WrongType(ty.clone()));
|
||||||
}
|
}
|
||||||
let conn = self.stmt.conn().conn.borrow();
|
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))
|
&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
|
/// A field can be accessed by the name or index of its column, though
|
||||||
/// access by index is more efficient. Rows are 0-indexed.
|
/// 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
|
/// Panics if the index does not reference a column or the return type is
|
||||||
/// not compatible with the Postgres type.
|
/// not compatible with the Postgres type.
|
||||||
///
|
///
|
||||||
/// ## Example
|
/// # Example
|
||||||
///
|
///
|
||||||
/// ```rust,no_run
|
/// ```rust,no_run
|
||||||
/// # use postgres::{Connection, SslMode};
|
/// # use postgres::{Connection, SslMode};
|
||||||
/// # let conn = Connection::connect("", &SslMode::None).unwrap();
|
/// # let conn = Connection::connect("", &SslMode::None).unwrap();
|
||||||
/// # let stmt = conn.prepare("").unwrap();
|
/// let stmt = conn.prepare("SELECT foo, bar from BAZ").unwrap();
|
||||||
/// # let mut result = stmt.query(&[]).unwrap();
|
/// for row in stmt.query(&[]).unwrap() {
|
||||||
/// # let row = result.iter().next().unwrap();
|
/// let foo: i32 = row.get(0);
|
||||||
/// let foo: i32 = row.get(0);
|
/// let bar: String = row.get("bar");
|
||||||
/// 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()) {
|
match self.get_opt(idx.clone()) {
|
||||||
Ok(ok) => ok,
|
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.
|
/// Retrieves the specified field as a raw buffer of Postgres data.
|
||||||
///
|
///
|
||||||
/// ## Panics
|
/// # Panics
|
||||||
///
|
///
|
||||||
/// Panics if the index does not reference a column.
|
/// 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) {
|
match idx.idx(self.stmt) {
|
||||||
Some(idx) => self.data[idx].as_ref().map(|e| &**e),
|
Some(idx) => self.data[idx].as_ref().map(|e| &**e),
|
||||||
None => panic!("invalid index {:?}", idx),
|
None => panic!("invalid index {:?}", idx),
|
||||||
@ -303,7 +307,8 @@ impl<'trans, 'stmt> LazyRowsNew<'trans, 'stmt> for LazyRows<'trans, 'stmt> {
|
|||||||
row_limit: i32,
|
row_limit: i32,
|
||||||
more_rows: bool,
|
more_rows: bool,
|
||||||
finished: bool,
|
finished: bool,
|
||||||
trans: &'trans Transaction<'trans>) -> LazyRows<'trans, 'stmt> {
|
trans: &'trans Transaction<'trans>)
|
||||||
|
-> LazyRows<'trans, 'stmt> {
|
||||||
LazyRows {
|
LazyRows {
|
||||||
stmt: stmt,
|
stmt: stmt,
|
||||||
data: data,
|
data: data,
|
||||||
@ -311,7 +316,7 @@ impl<'trans, 'stmt> LazyRowsNew<'trans, 'stmt> for LazyRows<'trans, 'stmt> {
|
|||||||
row_limit: row_limit,
|
row_limit: row_limit,
|
||||||
more_rows: more_rows,
|
more_rows: more_rows,
|
||||||
finished: finished,
|
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> {
|
impl<'a, 'b> fmt::Debug for LazyRows<'a, 'b> {
|
||||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||||
fmt.debug_struct("LazyRows")
|
fmt.debug_struct("LazyRows")
|
||||||
.field("name", &self.name)
|
.field("name", &self.name)
|
||||||
.field("row_limit", &self.row_limit)
|
.field("row_limit", &self.row_limit)
|
||||||
.field("remaining_rows", &self.data.len())
|
.field("remaining_rows", &self.data.len())
|
||||||
.field("more_rows", &self.more_rows)
|
.field("more_rows", &self.more_rows)
|
||||||
.finish()
|
.finish()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -345,12 +350,11 @@ impl<'trans, 'stmt> LazyRows<'trans, 'stmt> {
|
|||||||
fn execute(&mut self) -> Result<()> {
|
fn execute(&mut self) -> Result<()> {
|
||||||
let mut conn = self.stmt.conn().conn.borrow_mut();
|
let mut conn = self.stmt.conn().conn.borrow_mut();
|
||||||
|
|
||||||
try!(conn.write_messages(&[
|
try!(conn.write_messages(&[Execute {
|
||||||
Execute {
|
portal: &self.name,
|
||||||
portal: &self.name,
|
max_rows: self.row_limit,
|
||||||
max_rows: self.row_limit
|
},
|
||||||
},
|
Sync]));
|
||||||
Sync]));
|
|
||||||
read_rows(&mut conn, &mut self.data).map(|more_rows| self.more_rows = more_rows)
|
read_rows(&mut conn, &mut self.data).map(|more_rows| self.more_rows = more_rows)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
140
src/stmt.rs
140
src/stmt.rs
@ -28,10 +28,10 @@ pub struct Statement<'conn> {
|
|||||||
impl<'a> fmt::Debug for Statement<'a> {
|
impl<'a> fmt::Debug for Statement<'a> {
|
||||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||||
fmt.debug_struct("Statement")
|
fmt.debug_struct("Statement")
|
||||||
.field("name", &self.name)
|
.field("name", &self.name)
|
||||||
.field("parameter_types", &self.param_types)
|
.field("parameter_types", &self.param_types)
|
||||||
.field("columns", &self.columns)
|
.field("columns", &self.columns)
|
||||||
.finish()
|
.finish()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -47,7 +47,8 @@ impl<'conn> StatementInternals<'conn> for Statement<'conn> {
|
|||||||
param_types: Vec<Type>,
|
param_types: Vec<Type>,
|
||||||
columns: Vec<Column>,
|
columns: Vec<Column>,
|
||||||
next_portal_id: Cell<u32>,
|
next_portal_id: Cell<u32>,
|
||||||
finished: bool) -> Statement<'conn> {
|
finished: bool)
|
||||||
|
-> Statement<'conn> {
|
||||||
Statement {
|
Statement {
|
||||||
conn: conn,
|
conn: conn,
|
||||||
name: name,
|
name: name,
|
||||||
@ -81,7 +82,9 @@ impl<'conn> Statement<'conn> {
|
|||||||
"expected {} parameters but got {}",
|
"expected {} parameters but got {}",
|
||||||
self.param_types.len(),
|
self.param_types.len(),
|
||||||
params.len());
|
params.len());
|
||||||
debug!("executing statement {} with parameters: {:?}", self.name, params);
|
debug!("executing statement {} with parameters: {:?}",
|
||||||
|
self.name,
|
||||||
|
params);
|
||||||
let mut values = vec![];
|
let mut values = vec![];
|
||||||
for (param, ty) in params.iter().zip(self.param_types.iter()) {
|
for (param, ty) in params.iter().zip(self.param_types.iter()) {
|
||||||
let mut buf = vec![];
|
let mut buf = vec![];
|
||||||
@ -89,21 +92,20 @@ impl<'conn> Statement<'conn> {
|
|||||||
IsNull::Yes => values.push(None),
|
IsNull::Yes => values.push(None),
|
||||||
IsNull::No => values.push(Some(buf)),
|
IsNull::No => values.push(Some(buf)),
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
try!(conn.write_messages(&[
|
try!(conn.write_messages(&[Bind {
|
||||||
Bind {
|
portal: portal_name,
|
||||||
portal: portal_name,
|
statement: &self.name,
|
||||||
statement: &self.name,
|
formats: &[1],
|
||||||
formats: &[1],
|
values: &values,
|
||||||
values: &values,
|
result_formats: &[1],
|
||||||
result_formats: &[1]
|
},
|
||||||
},
|
Execute {
|
||||||
Execute {
|
portal: portal_name,
|
||||||
portal: portal_name,
|
max_rows: row_limit,
|
||||||
max_rows: row_limit
|
},
|
||||||
},
|
Sync]));
|
||||||
Sync]));
|
|
||||||
|
|
||||||
match try!(conn.read_message()) {
|
match try!(conn.read_message()) {
|
||||||
BindComplete => Ok(()),
|
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)> {
|
-> Result<(VecDeque<Vec<Option<Vec<u8>>>>, bool)> {
|
||||||
try!(self.inner_execute(portal_name, row_limit, params));
|
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.
|
/// 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
|
/// Panics if the number of parameters provided does not match the number
|
||||||
/// expected.
|
/// expected.
|
||||||
///
|
///
|
||||||
/// ## Example
|
/// # Example
|
||||||
///
|
///
|
||||||
/// ```rust,no_run
|
/// ```rust,no_run
|
||||||
/// # use postgres::{Connection, SslMode};
|
/// # use postgres::{Connection, SslMode};
|
||||||
@ -154,10 +159,8 @@ impl<'conn> Statement<'conn> {
|
|||||||
/// # let bar = 1i32;
|
/// # let bar = 1i32;
|
||||||
/// # let baz = true;
|
/// # let baz = true;
|
||||||
/// let stmt = conn.prepare("UPDATE foo SET bar = $1 WHERE baz = $2").unwrap();
|
/// let stmt = conn.prepare("UPDATE foo SET bar = $1 WHERE baz = $2").unwrap();
|
||||||
/// match stmt.execute(&[&bar, &baz]) {
|
/// let rows_updated = stmt.execute(&[&bar, &baz]).unwrap();
|
||||||
/// Ok(count) => println!("{} row(s) updated", count),
|
/// println!("{} rows updated", rows_updated);
|
||||||
/// Err(err) => println!("Error executing query: {:?}", err)
|
|
||||||
/// }
|
|
||||||
/// ```
|
/// ```
|
||||||
pub fn execute(&self, params: &[&ToSql]) -> Result<u64> {
|
pub fn execute(&self, params: &[&ToSql]) -> Result<u64> {
|
||||||
check_desync!(self.conn);
|
check_desync!(self.conn);
|
||||||
@ -181,11 +184,11 @@ impl<'conn> Statement<'conn> {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
CopyInResponse { .. } => {
|
CopyInResponse { .. } => {
|
||||||
try!(conn.write_messages(&[
|
try!(conn.write_messages(&[CopyFail {
|
||||||
CopyFail {
|
message: "COPY queries cannot be directly \
|
||||||
message: "COPY queries cannot be directly executed",
|
executed",
|
||||||
},
|
},
|
||||||
Sync]));
|
Sync]));
|
||||||
}
|
}
|
||||||
CopyOutResponse { .. } => {
|
CopyOutResponse { .. } => {
|
||||||
loop {
|
loop {
|
||||||
@ -214,32 +217,26 @@ impl<'conn> Statement<'conn> {
|
|||||||
|
|
||||||
/// Executes the prepared statement, returning the resulting rows.
|
/// Executes the prepared statement, returning the resulting rows.
|
||||||
///
|
///
|
||||||
/// ## Panics
|
/// # Panics
|
||||||
///
|
///
|
||||||
/// Panics if the number of parameters provided does not match the number
|
/// Panics if the number of parameters provided does not match the number
|
||||||
/// expected.
|
/// expected.
|
||||||
///
|
///
|
||||||
/// ## Example
|
/// # Example
|
||||||
///
|
///
|
||||||
/// ```rust,no_run
|
/// ```rust,no_run
|
||||||
/// # use postgres::{Connection, SslMode};
|
/// # use postgres::{Connection, SslMode};
|
||||||
/// # let conn = Connection::connect("", &SslMode::None).unwrap();
|
/// # let conn = Connection::connect("", &SslMode::None).unwrap();
|
||||||
/// let stmt = conn.prepare("SELECT foo FROM bar WHERE baz = $1").unwrap();
|
/// let stmt = conn.prepare("SELECT foo FROM bar WHERE baz = $1").unwrap();
|
||||||
/// # let baz = true;
|
/// # let baz = true;
|
||||||
/// let rows = match stmt.query(&[&baz]) {
|
/// for row in stmt.query(&[&baz]).unwrap() {
|
||||||
/// Ok(rows) => rows,
|
|
||||||
/// Err(err) => panic!("Error running query: {:?}", err)
|
|
||||||
/// };
|
|
||||||
/// for row in &rows {
|
|
||||||
/// let foo: i32 = row.get("foo");
|
/// let foo: i32 = row.get("foo");
|
||||||
/// println!("foo: {}", foo);
|
/// println!("foo: {}", foo);
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
pub fn query<'a>(&'a self, params: &[&ToSql]) -> Result<Rows<'a>> {
|
pub fn query<'a>(&'a self, params: &[&ToSql]) -> Result<Rows<'a>> {
|
||||||
check_desync!(self.conn);
|
check_desync!(self.conn);
|
||||||
self.inner_query("", 0, params).map(|(buf, _)| {
|
self.inner_query("", 0, params).map(|(buf, _)| Rows::new(self, buf.into_iter().collect()))
|
||||||
Rows::new(self, buf.into_iter().collect())
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Executes the prepared statement, returning a lazily loaded iterator
|
/// 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
|
/// object representing the active transaction must be passed to
|
||||||
/// `lazy_query`.
|
/// `lazy_query`.
|
||||||
///
|
///
|
||||||
/// ## Panics
|
/// # Panics
|
||||||
///
|
///
|
||||||
/// Panics if the provided `Transaction` is not associated with the same
|
/// Panics if the provided `Transaction` is not associated with the same
|
||||||
/// `Connection` as this `Statement`, if the `Transaction` is not
|
/// `Connection` as this `Statement`, if the `Transaction` is not
|
||||||
@ -318,9 +315,10 @@ impl<'conn> Statement<'conn> {
|
|||||||
loop {
|
loop {
|
||||||
match try!(conn.read_message()) {
|
match try!(conn.read_message()) {
|
||||||
ReadyForQuery { .. } => {
|
ReadyForQuery { .. } => {
|
||||||
return Err(Error::IoError(io::Error::new(
|
return Err(Error::IoError(io::Error::new(io::ErrorKind::InvalidInput,
|
||||||
io::ErrorKind::InvalidInput,
|
"called `copy_in` on a \
|
||||||
"called `copy_in` on a non-`COPY FROM STDIN` statement")));
|
non-`COPY FROM STDIN` \
|
||||||
|
statement")));
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
@ -339,20 +337,15 @@ impl<'conn> Statement<'conn> {
|
|||||||
match fill_copy_buf(&mut buf, r, &info) {
|
match fill_copy_buf(&mut buf, r, &info) {
|
||||||
Ok(0) => break,
|
Ok(0) => break,
|
||||||
Ok(len) => {
|
Ok(len) => {
|
||||||
try_desync!(info.conn, info.conn.stream.write_message(
|
try_desync!(info.conn,
|
||||||
&CopyData {
|
info.conn.stream.write_message(&CopyData { data: &buf[..len] }));
|
||||||
data: &buf[..len],
|
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
try!(info.conn.write_messages(&[
|
try!(info.conn.write_messages(&[CopyFail { message: "" }, CopyDone, Sync]));
|
||||||
CopyFail {
|
|
||||||
message: "",
|
|
||||||
},
|
|
||||||
CopyDone,
|
|
||||||
Sync]));
|
|
||||||
match try!(info.conn.read_message()) {
|
match try!(info.conn.read_message()) {
|
||||||
ErrorResponse { .. } => { /* expected from the CopyFail */ }
|
ErrorResponse { .. } => {
|
||||||
|
// expected from the CopyFail
|
||||||
|
}
|
||||||
_ => {
|
_ => {
|
||||||
info.conn.desynchronized = true;
|
info.conn.desynchronized = true;
|
||||||
return Err(Error::IoError(bad_response()));
|
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();
|
/// INSERT INTO people (id, name) VALUES (1, 'john'), (2, 'jane');").unwrap();
|
||||||
/// let stmt = conn.prepare("COPY people TO STDOUT").unwrap();
|
/// let stmt = conn.prepare("COPY people TO STDOUT").unwrap();
|
||||||
/// let mut buf = vec![];
|
/// 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");
|
/// 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> {
|
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()) {
|
let (format, column_formats) = match try!(conn.read_message()) {
|
||||||
CopyOutResponse { format, column_formats } => (format, column_formats),
|
CopyOutResponse { format, column_formats } => (format, column_formats),
|
||||||
CopyInResponse { .. } => {
|
CopyInResponse { .. } => {
|
||||||
try!(conn.write_messages(&[
|
try!(conn.write_messages(&[CopyFail { message: "" }, CopyDone, Sync]));
|
||||||
CopyFail {
|
|
||||||
message: "",
|
|
||||||
},
|
|
||||||
CopyDone,
|
|
||||||
Sync]));
|
|
||||||
match try!(conn.read_message()) {
|
match try!(conn.read_message()) {
|
||||||
ErrorResponse { .. } => { /* expected from the CopyFail */ }
|
ErrorResponse { .. } => {
|
||||||
|
// expected from the CopyFail
|
||||||
|
}
|
||||||
_ => {
|
_ => {
|
||||||
conn.desynchronized = true;
|
conn.desynchronized = true;
|
||||||
return Err(Error::IoError(bad_response()));
|
return Err(Error::IoError(bad_response()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
try!(conn.wait_for_ready());
|
try!(conn.wait_for_ready());
|
||||||
return Err(Error::IoError(io::Error::new(
|
return Err(Error::IoError(io::Error::new(io::ErrorKind::InvalidInput,
|
||||||
io::ErrorKind::InvalidInput,
|
"called `copy_out` on a non-`COPY TO \
|
||||||
"called `copy_out` on a non-`COPY TO STDOUT` statement")));
|
STDOUT` statement")));
|
||||||
}
|
}
|
||||||
ErrorResponse { fields } => {
|
ErrorResponse { fields } => {
|
||||||
try!(conn.wait_for_ready());
|
try!(conn.wait_for_ready());
|
||||||
@ -437,9 +427,10 @@ impl<'conn> Statement<'conn> {
|
|||||||
loop {
|
loop {
|
||||||
match try!(conn.read_message()) {
|
match try!(conn.read_message()) {
|
||||||
ReadyForQuery { .. } => {
|
ReadyForQuery { .. } => {
|
||||||
return Err(Error::IoError(io::Error::new(
|
return Err(Error::IoError(io::Error::new(io::ErrorKind::InvalidInput,
|
||||||
io::ErrorKind::InvalidInput,
|
"called `copy_out` on a \
|
||||||
"called `copy_out` on a non-`COPY TO STDOUT` statement")));
|
non-`COPY TO STDOUT` \
|
||||||
|
statement")));
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
@ -472,7 +463,7 @@ impl<'conn> Statement<'conn> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
BCopyDone => {},
|
BCopyDone => {}
|
||||||
CommandComplete { tag } => {
|
CommandComplete { tag } => {
|
||||||
count = util::parse_update_count(tag);
|
count = util::parse_update_count(tag);
|
||||||
break;
|
break;
|
||||||
@ -512,8 +503,7 @@ impl<'conn> Statement<'conn> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fill_copy_buf<R: ReadWithInfo>(buf: &mut [u8], r: &mut R, info: &CopyInfo)
|
fn fill_copy_buf<R: ReadWithInfo>(buf: &mut [u8], r: &mut R, info: &CopyInfo) -> io::Result<usize> {
|
||||||
-> io::Result<usize> {
|
|
||||||
let mut nread = 0;
|
let mut nread = 0;
|
||||||
while nread < buf.len() {
|
while nread < buf.len() {
|
||||||
match r.read_with_info(&mut buf[nread..], info) {
|
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)]
|
#[derive(PartialEq, Eq, Clone, Debug)]
|
||||||
pub struct Column {
|
pub struct Column {
|
||||||
name: String,
|
name: String,
|
||||||
type_: Type
|
type_: Type,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ColumnNew for Column {
|
impl ColumnNew for Column {
|
||||||
|
@ -3,7 +3,8 @@ extern crate chrono;
|
|||||||
use std::error;
|
use std::error;
|
||||||
use std::io::prelude::*;
|
use std::io::prelude::*;
|
||||||
use byteorder::{ReadBytesExt, WriteBytesExt, BigEndian};
|
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 Result;
|
||||||
use error::Error;
|
use error::Error;
|
||||||
@ -23,11 +24,15 @@ impl FromSql for NaiveDateTime {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ToSql 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() {
|
let time = match (*self - base()).num_microseconds() {
|
||||||
Some(time) => time,
|
Some(time) => time,
|
||||||
None => {
|
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));
|
return Err(Error::Conversion(err));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -49,8 +54,11 @@ impl FromSql for DateTime<UTC> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ToSql for DateTime<UTC> {
|
impl ToSql for DateTime<UTC> {
|
||||||
fn to_sql<W: Write+?Sized>(&self, type_: &Type, mut w: &mut W, info: &SessionInfo)
|
fn to_sql<W: Write + ?Sized>(&self,
|
||||||
-> Result<IsNull> {
|
type_: &Type,
|
||||||
|
mut w: &mut W,
|
||||||
|
info: &SessionInfo)
|
||||||
|
-> Result<IsNull> {
|
||||||
self.naive_utc().to_sql(type_, w, info)
|
self.naive_utc().to_sql(type_, w, info)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -68,8 +76,11 @@ impl FromSql for DateTime<Local> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ToSql for DateTime<Local> {
|
impl ToSql for DateTime<Local> {
|
||||||
fn to_sql<W: Write+?Sized>(&self, type_: &Type, mut w: &mut W, info: &SessionInfo)
|
fn to_sql<W: Write + ?Sized>(&self,
|
||||||
-> Result<IsNull> {
|
type_: &Type,
|
||||||
|
mut w: &mut W,
|
||||||
|
info: &SessionInfo)
|
||||||
|
-> Result<IsNull> {
|
||||||
self.with_timezone(&UTC).to_sql(type_, w, info)
|
self.with_timezone(&UTC).to_sql(type_, w, info)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -78,7 +89,9 @@ impl ToSql for DateTime<Local> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl FromSql for DateTime<FixedOffset> {
|
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>> {
|
-> Result<DateTime<FixedOffset>> {
|
||||||
let utc = try!(DateTime::<UTC>::from_sql(type_, raw, info));
|
let utc = try!(DateTime::<UTC>::from_sql(type_, raw, info));
|
||||||
Ok(utc.with_timezone(&FixedOffset::east(0)))
|
Ok(utc.with_timezone(&FixedOffset::east(0)))
|
||||||
@ -88,8 +101,11 @@ impl FromSql for DateTime<FixedOffset> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ToSql for DateTime<FixedOffset> {
|
impl ToSql for DateTime<FixedOffset> {
|
||||||
fn to_sql<W: Write+?Sized>(&self, type_: &Type, mut w: &mut W, info: &SessionInfo)
|
fn to_sql<W: Write + ?Sized>(&self,
|
||||||
-> Result<IsNull> {
|
type_: &Type,
|
||||||
|
mut w: &mut W,
|
||||||
|
info: &SessionInfo)
|
||||||
|
-> Result<IsNull> {
|
||||||
self.with_timezone(&UTC).to_sql(type_, w, info)
|
self.with_timezone(&UTC).to_sql(type_, w, info)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -107,10 +123,14 @@ impl FromSql for NaiveDate {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ToSql 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();
|
let jd = (*self - base().date()).num_days();
|
||||||
if jd > i32::max_value() as i64 || jd < i32::min_value() as i64 {
|
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));
|
return Err(Error::Conversion(err));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -132,12 +152,16 @@ impl FromSql for NaiveTime {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ToSql 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 delta = *self - NaiveTime::from_hms(0, 0, 0);
|
||||||
let time = match delta.num_microseconds() {
|
let time = match delta.num_microseconds() {
|
||||||
Some(time) => time,
|
Some(time) => time,
|
||||||
None => {
|
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));
|
return Err(Error::Conversion(err));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
417
src/types/mod.rs
417
src/types/mod.rs
@ -37,7 +37,7 @@ macro_rules! to_sql_checked {
|
|||||||
if !<Self as $crate::types::ToSql>::accepts(ty) {
|
if !<Self as $crate::types::ToSql>::accepts(ty) {
|
||||||
return Err($crate::error::Error::WrongType(ty.clone()));
|
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> {
|
impl<'a> SessionInfoNew<'a> for SessionInfo<'a> {
|
||||||
fn new(conn: &'a InnerConnection) -> SessionInfo<'a> {
|
fn new(conn: &'a InnerConnection) -> SessionInfo<'a> {
|
||||||
SessionInfo {
|
SessionInfo { conn: conn }
|
||||||
conn: conn
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -176,317 +174,317 @@ macro_rules! make_postgres_type {
|
|||||||
|
|
||||||
// Values from pg_type.h
|
// Values from pg_type.h
|
||||||
make_postgres_type! {
|
make_postgres_type! {
|
||||||
#[doc="BOOL - boolean, 'true'/'false'"]
|
/// BOOL - boolean, 'true'/'false'
|
||||||
16: "bool" => Bool: Kind::Simple,
|
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,
|
17: "bytea" => Bytea: Kind::Simple,
|
||||||
#[doc="\"char\" - single character"]
|
/// "char" - single character
|
||||||
18: "char" => Char: Kind::Simple,
|
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,
|
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,
|
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,
|
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),
|
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,
|
23: "int4" => Int4: Kind::Simple,
|
||||||
#[doc="REGPROC - registered procedure"]
|
/// REGPROC - registered procedure
|
||||||
24: "regproc" => Regproc: Kind::Simple,
|
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,
|
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,
|
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,
|
27: "tid" => Tid: Kind::Simple,
|
||||||
#[doc="XID - transaction id"]
|
/// XID - transaction id
|
||||||
28: "xid" => Xid: Kind::Simple,
|
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,
|
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),
|
30: "oidvector" => OidVector: Kind::Array(Type::Oid),
|
||||||
#[doc="PG_TYPE"]
|
/// PG_TYPE
|
||||||
71: "pg_type" => PgType: Kind::Simple,
|
71: "pg_type" => PgType: Kind::Simple,
|
||||||
#[doc="PG_ATTRIBUTE"]
|
/// PG_ATTRIBUTE
|
||||||
75: "pg_attribute" => PgAttribute: Kind::Simple,
|
75: "pg_attribute" => PgAttribute: Kind::Simple,
|
||||||
#[doc="PG_PROC"]
|
/// PG_PROC
|
||||||
81: "pg_proc" => PgProc: Kind::Simple,
|
81: "pg_proc" => PgProc: Kind::Simple,
|
||||||
#[doc="PG_CLASS"]
|
/// PG_CLASS
|
||||||
83: "pg_class" => PgClass: Kind::Simple,
|
83: "pg_class" => PgClass: Kind::Simple,
|
||||||
#[doc="JSON"]
|
/// JSON
|
||||||
114: "json" => Json: Kind::Simple,
|
114: "json" => Json: Kind::Simple,
|
||||||
#[doc="XML - XML content"]
|
/// XML - XML content
|
||||||
142: "xml" => Xml: Kind::Simple,
|
142: "xml" => Xml: Kind::Simple,
|
||||||
#[doc="XML[]"]
|
/// XML[]
|
||||||
143: "_xml" => XmlArray: Kind::Array(Type::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,
|
194: "pg_node_tree" => PgNodeTree: Kind::Simple,
|
||||||
#[doc="JSON[]"]
|
/// JSON[]
|
||||||
199: "_json" => JsonArray: Kind::Array(Type::Json),
|
199: "_json" => JsonArray: Kind::Array(Type::Json),
|
||||||
#[doc="SMGR - storage manager"]
|
/// SMGR - storage manager
|
||||||
210: "smgr" => Smgr: Kind::Simple,
|
210: "smgr" => Smgr: Kind::Simple,
|
||||||
#[doc="POINT - geometric point '(x, y)'"]
|
/// POINT - geometric point '(x, y)'
|
||||||
600: "point" => Point: Kind::Simple,
|
600: "point" => Point: Kind::Simple,
|
||||||
#[doc="LSEG - geometric line segment '(pt1,pt2)'"]
|
/// LSEG - geometric line segment '(pt1,pt2)'
|
||||||
601: "lseg" => Lseg: Kind::Simple,
|
601: "lseg" => Lseg: Kind::Simple,
|
||||||
#[doc="PATH - geometric path '(pt1,...)'"]
|
/// PATH - geometric path '(pt1,...)'
|
||||||
602: "path" => Path: Kind::Simple,
|
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,
|
603: "box" => Box: Kind::Simple,
|
||||||
#[doc="POLYGON - geometric polygon '(pt1,...)'"]
|
/// POLYGON - geometric polygon '(pt1,...)'
|
||||||
604: "polygon" => Polygon: Kind::Simple,
|
604: "polygon" => Polygon: Kind::Simple,
|
||||||
#[doc="LINE - geometric line"]
|
/// LINE - geometric line
|
||||||
628: "line" => Line: Kind::Simple,
|
628: "line" => Line: Kind::Simple,
|
||||||
#[doc="LINE[]"]
|
/// LINE[]
|
||||||
629: "_line" => LineArray: Kind::Array(Type::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,
|
650: "cidr" => Cidr: Kind::Simple,
|
||||||
#[doc="CIDR[]"]
|
/// CIDR[]
|
||||||
651: "_cidr" => CidrArray: Kind::Array(Type::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,
|
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,
|
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,
|
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,
|
703: "reltime" => Reltime: Kind::Simple,
|
||||||
#[doc="TINTERVAL - (abstime,abstime), time interval"]
|
/// TINTERVAL - (abstime,abstime), time interval
|
||||||
704: "tinterval" => Tinterval: Kind::Simple,
|
704: "tinterval" => Tinterval: Kind::Simple,
|
||||||
#[doc="UNKNOWN"]
|
/// UNKNOWN
|
||||||
705: "unknown" => Unknown: Kind::Simple,
|
705: "unknown" => Unknown: Kind::Simple,
|
||||||
#[doc="CIRCLE - geometric circle '(center,radius)'"]
|
/// CIRCLE - geometric circle '(center,radius)'
|
||||||
718: "circle" => Circle: Kind::Simple,
|
718: "circle" => Circle: Kind::Simple,
|
||||||
#[doc="CIRCLE[]"]
|
/// CIRCLE[]
|
||||||
719: "_circle" => CircleArray: Kind::Array(Type::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,
|
790: "money" => Money: Kind::Simple,
|
||||||
#[doc="MONEY[]"]
|
/// MONEY[]
|
||||||
791: "_money" => MoneyArray: Kind::Array(Type::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,
|
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,
|
869: "inet" => Inet: Kind::Simple,
|
||||||
#[doc="BOOL[]"]
|
/// BOOL[]
|
||||||
1000: "_bool" => BoolArray: Kind::Array(Type::Bool),
|
1000: "_bool" => BoolArray: Kind::Array(Type::Bool),
|
||||||
#[doc="BYTEA[]"]
|
/// BYTEA[]
|
||||||
1001: "_bytea" => ByteaArray: Kind::Array(Type::Bytea),
|
1001: "_bytea" => ByteaArray: Kind::Array(Type::Bytea),
|
||||||
#[doc="\"char\"[]"]
|
/// "char"[]
|
||||||
1002: "_char" => CharArray: Kind::Array(Type::Char),
|
1002: "_char" => CharArray: Kind::Array(Type::Char),
|
||||||
#[doc="NAME[]"]
|
/// NAME[]
|
||||||
1003: "_name" => NameArray: Kind::Array(Type::Name),
|
1003: "_name" => NameArray: Kind::Array(Type::Name),
|
||||||
#[doc="INT2[]"]
|
/// INT2[]
|
||||||
1005: "_int2" => Int2Array: Kind::Array(Type::Int2),
|
1005: "_int2" => Int2Array: Kind::Array(Type::Int2),
|
||||||
#[doc="INT2VECTOR[]"]
|
/// INT2VECTOR[]
|
||||||
1006: "_int2vector" => Int2VectorArray: Kind::Array(Type::Int2Vector),
|
1006: "_int2vector" => Int2VectorArray: Kind::Array(Type::Int2Vector),
|
||||||
#[doc="INT4[]"]
|
/// INT4[]
|
||||||
1007: "_int4" => Int4Array: Kind::Array(Type::Int4),
|
1007: "_int4" => Int4Array: Kind::Array(Type::Int4),
|
||||||
#[doc="REGPROC[]"]
|
/// REGPROC[]
|
||||||
1008: "_regproc" => RegprocArray: Kind::Array(Type::Regproc),
|
1008: "_regproc" => RegprocArray: Kind::Array(Type::Regproc),
|
||||||
#[doc="TEXT[]"]
|
/// TEXT[]
|
||||||
1009: "_text" => TextArray: Kind::Array(Type::Text),
|
1009: "_text" => TextArray: Kind::Array(Type::Text),
|
||||||
#[doc="TID[]"]
|
/// TID[]
|
||||||
1010: "_tid" => TidArray: Kind::Array(Type::Tid),
|
1010: "_tid" => TidArray: Kind::Array(Type::Tid),
|
||||||
#[doc="XID[]"]
|
/// XID[]
|
||||||
1011: "_xid" => XidArray: Kind::Array(Type::Xid),
|
1011: "_xid" => XidArray: Kind::Array(Type::Xid),
|
||||||
#[doc="CID[]"]
|
/// CID[]
|
||||||
1012: "_cid" => CidArray: Kind::Array(Type::Cid),
|
1012: "_cid" => CidArray: Kind::Array(Type::Cid),
|
||||||
#[doc="OIDVECTOR[]"]
|
/// OIDVECTOR[]
|
||||||
1013: "_oidvector" => OidVectorArray: Kind::Array(Type::OidVector),
|
1013: "_oidvector" => OidVectorArray: Kind::Array(Type::OidVector),
|
||||||
#[doc="BPCHAR[]"]
|
/// BPCHAR[]
|
||||||
1014: "_bpchar" => BpcharArray: Kind::Array(Type::Bpchar),
|
1014: "_bpchar" => BpcharArray: Kind::Array(Type::Bpchar),
|
||||||
#[doc="VARCHAR[]"]
|
/// VARCHAR[]
|
||||||
1015: "_varchar" => VarcharArray: Kind::Array(Type::Varchar),
|
1015: "_varchar" => VarcharArray: Kind::Array(Type::Varchar),
|
||||||
#[doc="INT8[]"]
|
/// INT8[]
|
||||||
1016: "_int8" => Int8Array: Kind::Array(Type::Int8),
|
1016: "_int8" => Int8Array: Kind::Array(Type::Int8),
|
||||||
#[doc="POINT[]"]
|
/// POINT[]
|
||||||
1017: "_point" => PointArray: Kind::Array(Type::Point),
|
1017: "_point" => PointArray: Kind::Array(Type::Point),
|
||||||
#[doc="LSEG[]"]
|
/// LSEG[]
|
||||||
1018: "_lseg" => LsegArray: Kind::Array(Type::Lseg),
|
1018: "_lseg" => LsegArray: Kind::Array(Type::Lseg),
|
||||||
#[doc="PATH[]"]
|
/// PATH[]
|
||||||
1019: "_path" => PathArray: Kind::Array(Type::Path),
|
1019: "_path" => PathArray: Kind::Array(Type::Path),
|
||||||
#[doc="BOX[]"]
|
/// BOX[]
|
||||||
1020: "_box" => BoxArray: Kind::Array(Type::Box),
|
1020: "_box" => BoxArray: Kind::Array(Type::Box),
|
||||||
#[doc="FLOAT4[]"]
|
/// FLOAT4[]
|
||||||
1021: "_float4" => Float4Array: Kind::Array(Type::Float4),
|
1021: "_float4" => Float4Array: Kind::Array(Type::Float4),
|
||||||
#[doc="FLOAT8[]"]
|
/// FLOAT8[]
|
||||||
1022: "_float8" => Float8Array: Kind::Array(Type::Float8),
|
1022: "_float8" => Float8Array: Kind::Array(Type::Float8),
|
||||||
#[doc="ABSTIME[]"]
|
/// ABSTIME[]
|
||||||
1023: "_abstime" => AbstimeArray: Kind::Array(Type::Abstime),
|
1023: "_abstime" => AbstimeArray: Kind::Array(Type::Abstime),
|
||||||
#[doc="RELTIME[]"]
|
/// RELTIME[]
|
||||||
1024: "_reltime" => ReltimeArray: Kind::Array(Type::Reltime),
|
1024: "_reltime" => ReltimeArray: Kind::Array(Type::Reltime),
|
||||||
#[doc="TINTERVAL[]"]
|
/// TINTERVAL[]
|
||||||
1025: "_tinterval" => TintervalArray: Kind::Array(Type::Tinterval),
|
1025: "_tinterval" => TintervalArray: Kind::Array(Type::Tinterval),
|
||||||
#[doc="POLYGON[]"]
|
/// POLYGON[]
|
||||||
1027: "_polygon" => PolygonArray: Kind::Array(Type::Polygon),
|
1027: "_polygon" => PolygonArray: Kind::Array(Type::Polygon),
|
||||||
#[doc="OID[]"]
|
/// OID[]
|
||||||
1028: "_oid" => OidArray: Kind::Array(Type::Oid),
|
1028: "_oid" => OidArray: Kind::Array(Type::Oid),
|
||||||
#[doc="ACLITEM - access control list"]
|
/// ACLITEM - access control list
|
||||||
1033: "aclitem" => Aclitem: Kind::Simple,
|
1033: "aclitem" => Aclitem: Kind::Simple,
|
||||||
#[doc="ACLITEM[]"]
|
/// ACLITEM[]
|
||||||
1034: "_aclitem" => AclitemArray: Kind::Array(Type::Aclitem),
|
1034: "_aclitem" => AclitemArray: Kind::Array(Type::Aclitem),
|
||||||
#[doc="MACADDR[]"]
|
/// MACADDR[]
|
||||||
1040: "_macaddr" => MacaddrArray: Kind::Array(Type::Macaddr),
|
1040: "_macaddr" => MacaddrArray: Kind::Array(Type::Macaddr),
|
||||||
#[doc="INET[]"]
|
/// INET[]
|
||||||
1041: "_inet" => InetArray: Kind::Array(Type::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,
|
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,
|
1043: "varchar" => Varchar: Kind::Simple,
|
||||||
#[doc="DATE - date"]
|
/// DATE - date
|
||||||
1082: "date" => Date: Kind::Simple,
|
1082: "date" => Date: Kind::Simple,
|
||||||
#[doc="TIME - time of day"]
|
/// TIME - time of day
|
||||||
1083: "time" => Time: Kind::Simple,
|
1083: "time" => Time: Kind::Simple,
|
||||||
#[doc="TIMESTAMP - date and time"]
|
/// TIMESTAMP - date and time
|
||||||
1114: "timestamp" => Timestamp: Kind::Simple,
|
1114: "timestamp" => Timestamp: Kind::Simple,
|
||||||
#[doc="TIMESTAMP[]"]
|
/// TIMESTAMP[]
|
||||||
1115: "_timestamp" => TimestampArray: Kind::Array(Type::Timestamp),
|
1115: "_timestamp" => TimestampArray: Kind::Array(Type::Timestamp),
|
||||||
#[doc="DATE[]"]
|
/// DATE[]
|
||||||
1182: "_date" => DateArray: Kind::Array(Type::Date),
|
1182: "_date" => DateArray: Kind::Array(Type::Date),
|
||||||
#[doc="TIME[]"]
|
/// TIME[]
|
||||||
1183: "_time" => TimeArray: Kind::Array(Type::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,
|
1184: "timestamptz" => TimestampTZ: Kind::Simple,
|
||||||
#[doc="TIMESTAMPTZ[]"]
|
/// TIMESTAMPTZ[]
|
||||||
1185: "_timestamptz" => TimestampTZArray: Kind::Array(Type::TimestampTZ),
|
1185: "_timestamptz" => TimestampTZArray: Kind::Array(Type::TimestampTZ),
|
||||||
#[doc="INTERVAL - @ <number> <units>, time interval"]
|
/// INTERVAL - @ <number> <units>, time interval
|
||||||
1186: "interval" => Interval: Kind::Simple,
|
1186: "interval" => Interval: Kind::Simple,
|
||||||
#[doc="INTERVAL[]"]
|
/// INTERVAL[]
|
||||||
1187: "_interval" => IntervalArray: Kind::Array(Type::Interval),
|
1187: "_interval" => IntervalArray: Kind::Array(Type::Interval),
|
||||||
#[doc="NUMERIC[]"]
|
/// NUMERIC[]
|
||||||
1231: "_numeric" => NumericArray: Kind::Array(Type::Numeric),
|
1231: "_numeric" => NumericArray: Kind::Array(Type::Numeric),
|
||||||
#[doc="CSTRING[]"]
|
/// CSTRING[]
|
||||||
1263: "_cstring" => CstringArray: Kind::Array(Type::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,
|
1266: "timetz" => Timetz: Kind::Simple,
|
||||||
#[doc="TIMETZ[]"]
|
/// TIMETZ[]
|
||||||
1270: "_timetz" => TimetzArray: Kind::Array(Type::Timetz),
|
1270: "_timetz" => TimetzArray: Kind::Array(Type::Timetz),
|
||||||
#[doc="BIT - fixed-length bit string"]
|
/// BIT - fixed-length bit string
|
||||||
1560: "bit" => Bit: Kind::Simple,
|
1560: "bit" => Bit: Kind::Simple,
|
||||||
#[doc="BIT[]"]
|
/// BIT[]
|
||||||
1561: "_bit" => BitArray: Kind::Array(Type::Bit),
|
1561: "_bit" => BitArray: Kind::Array(Type::Bit),
|
||||||
#[doc="VARBIT - variable-length bit string"]
|
/// VARBIT - variable-length bit string
|
||||||
1562: "varbit" => Varbit: Kind::Simple,
|
1562: "varbit" => Varbit: Kind::Simple,
|
||||||
#[doc="VARBIT[]"]
|
/// VARBIT[]
|
||||||
1563: "_varbit" => VarbitArray: Kind::Array(Type::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,
|
1700: "numeric" => Numeric: Kind::Simple,
|
||||||
#[doc="REFCURSOR - reference to cursor (portal name)"]
|
/// REFCURSOR - reference to cursor (portal name)
|
||||||
1790: "refcursor" => Refcursor: Kind::Simple,
|
1790: "refcursor" => Refcursor: Kind::Simple,
|
||||||
#[doc="REFCURSOR[]"]
|
/// REFCURSOR[]
|
||||||
2201: "_refcursor" => RefcursorArray: Kind::Array(Type::Refcursor),
|
2201: "_refcursor" => RefcursorArray: Kind::Array(Type::Refcursor),
|
||||||
#[doc="REGPROCEDURE - registered procedure (with args)"]
|
/// REGPROCEDURE - registered procedure (with args)
|
||||||
2202: "regprocedure" => Regprocedure: Kind::Simple,
|
2202: "regprocedure" => Regprocedure: Kind::Simple,
|
||||||
#[doc="REGOPER - registered operator"]
|
/// REGOPER - registered operator
|
||||||
2203: "regoper" => Regoper: Kind::Simple,
|
2203: "regoper" => Regoper: Kind::Simple,
|
||||||
#[doc="REGOPERATOR - registered operator (with args)"]
|
/// REGOPERATOR - registered operator (with args)
|
||||||
2204: "regoperator" => Regoperator: Kind::Simple,
|
2204: "regoperator" => Regoperator: Kind::Simple,
|
||||||
#[doc="REGCLASS - registered class"]
|
/// REGCLASS - registered class
|
||||||
2205: "regclass" => Regclass: Kind::Simple,
|
2205: "regclass" => Regclass: Kind::Simple,
|
||||||
#[doc="REGTYPE - registered type"]
|
/// REGTYPE - registered type
|
||||||
2206: "regtype" => Regtype: Kind::Simple,
|
2206: "regtype" => Regtype: Kind::Simple,
|
||||||
#[doc="REGPROCEDURE[]"]
|
/// REGPROCEDURE[]
|
||||||
2207: "_regprocedure" => RegprocedureArray: Kind::Array(Type::Regprocedure),
|
2207: "_regprocedure" => RegprocedureArray: Kind::Array(Type::Regprocedure),
|
||||||
#[doc="REGOPER[]"]
|
/// REGOPER[]
|
||||||
2208: "_regoper" => RegoperArray: Kind::Array(Type::Regoper),
|
2208: "_regoper" => RegoperArray: Kind::Array(Type::Regoper),
|
||||||
#[doc="REGOPERATOR[]"]
|
/// REGOPERATOR[]
|
||||||
2209: "_regoperator" => RegoperatorArray: Kind::Array(Type::Regoperator),
|
2209: "_regoperator" => RegoperatorArray: Kind::Array(Type::Regoperator),
|
||||||
#[doc="REGCLASS[]"]
|
/// REGCLASS[]
|
||||||
2210: "_regclass" => RegclassArray: Kind::Array(Type::Regclass),
|
2210: "_regclass" => RegclassArray: Kind::Array(Type::Regclass),
|
||||||
#[doc="REGTYPE[]"]
|
/// REGTYPE[]
|
||||||
2211: "_regtype" => RegtypeArray: Kind::Array(Type::Regtype),
|
2211: "_regtype" => RegtypeArray: Kind::Array(Type::Regtype),
|
||||||
#[doc="RECORD"]
|
/// RECORD
|
||||||
2249: "record" => Record: Kind::Simple,
|
2249: "record" => Record: Kind::Simple,
|
||||||
#[doc="CSTRING"]
|
/// CSTRING
|
||||||
2275: "cstring" => Cstring: Kind::Simple,
|
2275: "cstring" => Cstring: Kind::Simple,
|
||||||
#[doc="ANY"]
|
/// ANY
|
||||||
2276: "any" => Any: Kind::Simple,
|
2276: "any" => Any: Kind::Simple,
|
||||||
#[doc="ANYARRAY"]
|
/// ANYARRAY
|
||||||
2277: "anyarray" => AnyArray: Kind::Array(Type::Any),
|
2277: "anyarray" => AnyArray: Kind::Array(Type::Any),
|
||||||
#[doc="VOID"]
|
/// VOID
|
||||||
2278: "void" => Void: Kind::Simple,
|
2278: "void" => Void: Kind::Simple,
|
||||||
#[doc="TRIGGER"]
|
/// TRIGGER
|
||||||
2279: "trigger" => Trigger: Kind::Simple,
|
2279: "trigger" => Trigger: Kind::Simple,
|
||||||
#[doc="LANGUAGE_HANDLER"]
|
/// LANGUAGE_HANDLER
|
||||||
2280: "language_handler" => LanguageHandler: Kind::Simple,
|
2280: "language_handler" => LanguageHandler: Kind::Simple,
|
||||||
#[doc="INTERNAL"]
|
/// INTERNAL
|
||||||
2281: "internal" => Internal: Kind::Simple,
|
2281: "internal" => Internal: Kind::Simple,
|
||||||
#[doc="OPAQUE"]
|
/// OPAQUE
|
||||||
2282: "opaque" => Opaque: Kind::Simple,
|
2282: "opaque" => Opaque: Kind::Simple,
|
||||||
#[doc="ANYELEMENT"]
|
/// ANYELEMENT
|
||||||
2283: "anyelement" => Anyelement: Kind::Simple,
|
2283: "anyelement" => Anyelement: Kind::Simple,
|
||||||
#[doc="RECORD[]"]
|
/// RECORD[]
|
||||||
2287: "_record" => RecordArray: Kind::Array(Type::Record),
|
2287: "_record" => RecordArray: Kind::Array(Type::Record),
|
||||||
#[doc="ANYNONARRAY"]
|
/// ANYNONARRAY
|
||||||
2776: "anynonarray" => Anynonarray: Kind::Simple,
|
2776: "anynonarray" => Anynonarray: Kind::Simple,
|
||||||
#[doc="TXID_SNAPSHOT[]"]
|
/// TXID_SNAPSHOT[]
|
||||||
2949: "_txid_snapshot" => TxidSnapshotArray: Kind::Array(Type::TxidSnapshot),
|
2949: "_txid_snapshot" => TxidSnapshotArray: Kind::Array(Type::TxidSnapshot),
|
||||||
#[doc="UUID - UUID datatype"]
|
/// UUID - UUID datatype
|
||||||
2950: "uuid" => Uuid: Kind::Simple,
|
2950: "uuid" => Uuid: Kind::Simple,
|
||||||
#[doc="TXID_SNAPSHOT - txid snapshot"]
|
/// TXID_SNAPSHOT - txid snapshot
|
||||||
2970: "txid_snapshot" => TxidSnapshot: Kind::Simple,
|
2970: "txid_snapshot" => TxidSnapshot: Kind::Simple,
|
||||||
#[doc="UUID[]"]
|
/// UUID[]
|
||||||
2951: "_uuid" => UuidArray: Kind::Array(Type::Uuid),
|
2951: "_uuid" => UuidArray: Kind::Array(Type::Uuid),
|
||||||
#[doc="FDW_HANDLER"]
|
/// FDW_HANDLER
|
||||||
3115: "fdw_handler" => FdwHandler: Kind::Simple,
|
3115: "fdw_handler" => FdwHandler: Kind::Simple,
|
||||||
#[doc="PG_LSN - PostgreSQL LSN datatype"]
|
/// PG_LSN - PostgreSQL LSN datatype
|
||||||
3220: "pg_lsn" => PgLsn: Kind::Simple,
|
3220: "pg_lsn" => PgLsn: Kind::Simple,
|
||||||
#[doc="PG_LSN[]"]
|
/// PG_LSN[]
|
||||||
3221: "_pg_lsn" => PgLsnArray: Kind::Array(Type::PgLsn),
|
3221: "_pg_lsn" => PgLsnArray: Kind::Array(Type::PgLsn),
|
||||||
#[doc="ANYENUM"]
|
/// ANYENUM
|
||||||
3500: "anyenum" => Anyenum: Kind::Simple,
|
3500: "anyenum" => Anyenum: Kind::Simple,
|
||||||
#[doc="TSVECTOR - text representation for text search"]
|
/// TSVECTOR - text representation for text search
|
||||||
3614: "tsvector" => Tsvector: Kind::Simple,
|
3614: "tsvector" => Tsvector: Kind::Simple,
|
||||||
#[doc="TSQUERY - query representation for text search"]
|
/// TSQUERY - query representation for text search
|
||||||
3615: "tsquery" => Tsquery: Kind::Simple,
|
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,
|
3642: "gtsvector" => Gtsvector: Kind::Simple,
|
||||||
#[doc="TSVECTOR[]"]
|
/// TSVECTOR[]
|
||||||
3643: "_tsvector" => TsvectorArray: Kind::Array(Type::Tsvector),
|
3643: "_tsvector" => TsvectorArray: Kind::Array(Type::Tsvector),
|
||||||
#[doc="GTSVECTOR[]"]
|
/// GTSVECTOR[]
|
||||||
3644: "_gtsvector" => GtsvectorArray: Kind::Array(Type::Gtsvector),
|
3644: "_gtsvector" => GtsvectorArray: Kind::Array(Type::Gtsvector),
|
||||||
#[doc="TSQUERY[]"]
|
/// TSQUERY[]
|
||||||
3645: "_tsquery" => TsqueryArray: Kind::Array(Type::Tsquery),
|
3645: "_tsquery" => TsqueryArray: Kind::Array(Type::Tsquery),
|
||||||
#[doc="REGCONFIG - registered text search configuration"]
|
/// REGCONFIG - registered text search configuration
|
||||||
3734: "regconfig" => Regconfig: Kind::Simple,
|
3734: "regconfig" => Regconfig: Kind::Simple,
|
||||||
#[doc="REGCONFIG[]"]
|
/// REGCONFIG[]
|
||||||
3735: "_regconfig" => RegconfigArray: Kind::Array(Type::Regconfig),
|
3735: "_regconfig" => RegconfigArray: Kind::Array(Type::Regconfig),
|
||||||
#[doc="REGDICTIONARY - registered text search dictionary"]
|
/// REGDICTIONARY - registered text search dictionary
|
||||||
3769: "regdictionary" => Regdictionary: Kind::Simple,
|
3769: "regdictionary" => Regdictionary: Kind::Simple,
|
||||||
#[doc="REGDICTIONARY[]"]
|
/// REGDICTIONARY[]
|
||||||
3770: "_regdictionary" => RegdictionaryArray: Kind::Array(Type::Regdictionary),
|
3770: "_regdictionary" => RegdictionaryArray: Kind::Array(Type::Regdictionary),
|
||||||
#[doc="JSONB"]
|
/// JSONB
|
||||||
3802: "jsonb" => Jsonb: Kind::Simple,
|
3802: "jsonb" => Jsonb: Kind::Simple,
|
||||||
#[doc="ANYRANGE"]
|
/// ANYRANGE
|
||||||
3831: "anyrange" => Anyrange: Kind::Simple,
|
3831: "anyrange" => Anyrange: Kind::Simple,
|
||||||
#[doc="JSONB[]"]
|
/// JSONB[]
|
||||||
3807: "_jsonb" => JsonbArray: Kind::Array(Type::Jsonb),
|
3807: "_jsonb" => JsonbArray: Kind::Array(Type::Jsonb),
|
||||||
#[doc="INT4RANGE - range of integers"]
|
/// INT4RANGE - range of integers
|
||||||
3904: "int4range" => Int4Range: Kind::Range(Type::Int4),
|
3904: "int4range" => Int4Range: Kind::Range(Type::Int4),
|
||||||
#[doc="INT4RANGE[]"]
|
/// INT4RANGE[]
|
||||||
3905: "_int4range" => Int4RangeArray: Kind::Array(Type::Int4Range),
|
3905: "_int4range" => Int4RangeArray: Kind::Array(Type::Int4Range),
|
||||||
#[doc="NUMRANGE - range of numerics"]
|
/// NUMRANGE - range of numerics
|
||||||
3906: "numrange" => NumRange: Kind::Range(Type::Numeric),
|
3906: "numrange" => NumRange: Kind::Range(Type::Numeric),
|
||||||
#[doc="NUMRANGE[]"]
|
/// NUMRANGE[]
|
||||||
3907: "_numrange" => NumRangeArray: Kind::Array(Type::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),
|
3908: "tsrange" => TsRange: Kind::Range(Type::Timestamp),
|
||||||
#[doc="TSRANGE[]"]
|
/// TSRANGE[]
|
||||||
3909: "_tsrange" => TsRangeArray: Kind::Array(Type::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),
|
3910: "tstzrange" => TstzRange: Kind::Range(Type::TimestampTZ),
|
||||||
#[doc="TSTZRANGE[]"]
|
/// TSTZRANGE[]
|
||||||
3911: "_tstzrange" => TstzRangeArray: Kind::Array(Type::TstzRange),
|
3911: "_tstzrange" => TstzRangeArray: Kind::Array(Type::TstzRange),
|
||||||
#[doc="DATERANGE - range of dates"]
|
/// DATERANGE - range of dates
|
||||||
3912: "daterange" => DateRange: Kind::Range(Type::Date),
|
3912: "daterange" => DateRange: Kind::Range(Type::Date),
|
||||||
#[doc="DATERANGE[]"]
|
/// DATERANGE[]
|
||||||
3913: "_daterange" => DateRangeArray: Kind::Array(Type::DateRange),
|
3913: "_daterange" => DateRangeArray: Kind::Array(Type::DateRange),
|
||||||
#[doc="INT8RANGE - range of bigints"]
|
/// INT8RANGE - range of bigints
|
||||||
3926: "int8range" => Int8Range: Kind::Range(Type::Int8),
|
3926: "int8range" => Int8Range: Kind::Range(Type::Int8),
|
||||||
#[doc="INT8RANGE[]"]
|
/// INT8RANGE[]
|
||||||
3927: "_int8range" => Int8RangeArray: Kind::Array(Type::Int8Range),
|
3927: "_int8range" => Int8RangeArray: Kind::Array(Type::Int8Range),
|
||||||
#[doc="EVENT_TRIGGER"]
|
/// EVENT_TRIGGER
|
||||||
3838: "event_trigger" => EventTrigger: Kind::Simple
|
3838: "event_trigger" => EventTrigger: Kind::Simple
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -596,7 +594,9 @@ impl error::Error for WasNull {
|
|||||||
/// nullable Postgres value.
|
/// nullable Postgres value.
|
||||||
pub trait FromSql: Sized {
|
pub trait FromSql: Sized {
|
||||||
/// ### Deprecated
|
/// ### 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> {
|
-> Result<Self> {
|
||||||
match raw {
|
match raw {
|
||||||
Some(raw) => FromSql::from_sql(ty, raw, ctx),
|
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);
|
primitive_from!(f64, read_f64, Type::Float8);
|
||||||
|
|
||||||
impl FromSql for HashMap<String, Option<String>> {
|
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>>> {
|
-> Result<HashMap<String, Option<String>>> {
|
||||||
let mut map = HashMap::new();
|
let mut map = HashMap::new();
|
||||||
|
|
||||||
@ -740,7 +742,7 @@ impl FromSql for HashMap<String, Option<String>> {
|
|||||||
fn accepts(ty: &Type) -> bool {
|
fn accepts(ty: &Type) -> bool {
|
||||||
match *ty {
|
match *ty {
|
||||||
Type::Other(ref u) if u.name() == "hstore" => true,
|
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
|
/// `NULL`. If this is the case, implementations **must not** write
|
||||||
/// anything to `out`.
|
/// anything to `out`.
|
||||||
fn to_sql<W: ?Sized>(&self, ty: &Type, out: &mut W, ctx: &SessionInfo) -> Result<IsNull>
|
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
|
/// Determines if a value of this type can be converted to the specified
|
||||||
/// Postgres `Type`.
|
/// Postgres `Type`.
|
||||||
@ -821,34 +824,33 @@ pub trait ToSql: fmt::Debug {
|
|||||||
///
|
///
|
||||||
/// *All* implementations of this method should be generated by the
|
/// *All* implementations of this method should be generated by the
|
||||||
/// `to_sql_checked!()` macro.
|
/// `to_sql_checked!()` macro.
|
||||||
fn to_sql_checked(&self, ty: &Type, out: &mut Write, ctx: &SessionInfo)
|
fn to_sql_checked(&self, ty: &Type, out: &mut Write, ctx: &SessionInfo) -> Result<IsNull>;
|
||||||
-> Result<IsNull>;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, T> ToSql for &'a T where T: ToSql {
|
impl<'a, T> ToSql for &'a T where T: ToSql {
|
||||||
fn to_sql_checked(&self, ty: &Type, out: &mut Write, ctx: &SessionInfo)
|
to_sql_checked!();
|
||||||
-> Result<IsNull> {
|
|
||||||
if !<&'a T as ToSql>::accepts(ty) {
|
|
||||||
return Err(Error::WrongType(ty.clone()));
|
|
||||||
}
|
|
||||||
self.to_sql(ty, out, ctx)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
fn to_sql<W: Write + ?Sized>(&self,
|
||||||
fn to_sql<W: Write + ?Sized>(&self, ty: &Type, out: &mut W, ctx: &SessionInfo) -> Result<IsNull> {
|
ty: &Type,
|
||||||
|
out: &mut W,
|
||||||
|
ctx: &SessionInfo)
|
||||||
|
-> Result<IsNull> {
|
||||||
(*self).to_sql(ty, out, ctx)
|
(*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> {
|
impl<T: ToSql> ToSql for Option<T> {
|
||||||
to_sql_checked!();
|
to_sql_checked!();
|
||||||
|
|
||||||
fn to_sql<W: Write+?Sized>(&self, ty: &Type, out: &mut W, ctx: &SessionInfo)
|
fn to_sql<W: Write + ?Sized>(&self,
|
||||||
-> Result<IsNull> {
|
ty: &Type,
|
||||||
|
out: &mut W,
|
||||||
|
ctx: &SessionInfo)
|
||||||
|
-> Result<IsNull> {
|
||||||
match *self {
|
match *self {
|
||||||
Some(ref val) => val.to_sql(ty, out, ctx),
|
Some(ref val) => val.to_sql(ty, out, ctx),
|
||||||
None => Ok(IsNull::Yes),
|
None => Ok(IsNull::Yes),
|
||||||
@ -863,8 +865,11 @@ impl<T: ToSql> ToSql for Option<T> {
|
|||||||
impl ToSql for bool {
|
impl ToSql for bool {
|
||||||
to_sql_checked!();
|
to_sql_checked!();
|
||||||
|
|
||||||
fn to_sql<W: Write+?Sized>(&self, _: &Type, mut w: &mut W, _: &SessionInfo)
|
fn to_sql<W: Write + ?Sized>(&self,
|
||||||
-> Result<IsNull> {
|
_: &Type,
|
||||||
|
mut w: &mut W,
|
||||||
|
_: &SessionInfo)
|
||||||
|
-> Result<IsNull> {
|
||||||
try!(w.write_u8(*self as u8));
|
try!(w.write_u8(*self as u8));
|
||||||
Ok(IsNull::No)
|
Ok(IsNull::No)
|
||||||
}
|
}
|
||||||
@ -873,17 +878,9 @@ impl ToSql for bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> ToSql for &'a [u8] {
|
impl<'a> ToSql for &'a [u8] {
|
||||||
// FIXME should use to_sql_checked!() but blocked on rust-lang/rust#24308
|
to_sql_checked!();
|
||||||
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)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn to_sql<W: Write+?Sized>(&self, _: &Type, w: &mut W, _: &SessionInfo)
|
fn to_sql<W: Write + ?Sized>(&self, _: &Type, w: &mut W, _: &SessionInfo) -> Result<IsNull> {
|
||||||
-> Result<IsNull> {
|
|
||||||
try!(w.write_all(*self));
|
try!(w.write_all(*self));
|
||||||
Ok(IsNull::No)
|
Ok(IsNull::No)
|
||||||
}
|
}
|
||||||
@ -894,8 +891,7 @@ impl<'a> ToSql for &'a [u8] {
|
|||||||
impl ToSql for Vec<u8> {
|
impl ToSql for Vec<u8> {
|
||||||
to_sql_checked!();
|
to_sql_checked!();
|
||||||
|
|
||||||
fn to_sql<W: Write+?Sized>(&self, ty: &Type, w: &mut W, ctx: &SessionInfo)
|
fn to_sql<W: Write + ?Sized>(&self, ty: &Type, w: &mut W, ctx: &SessionInfo) -> Result<IsNull> {
|
||||||
-> Result<IsNull> {
|
|
||||||
<&[u8] as ToSql>::to_sql(&&**self, ty, w, ctx)
|
<&[u8] as ToSql>::to_sql(&&**self, ty, w, ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -905,17 +901,9 @@ impl ToSql for Vec<u8> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> ToSql for &'a str {
|
impl<'a> ToSql for &'a str {
|
||||||
// FIXME should use to_sql_checked!() but blocked on rust-lang/rust#24308
|
to_sql_checked!();
|
||||||
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)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn to_sql<W: Write+?Sized>(&self, _: &Type, w: &mut W, _: &SessionInfo)
|
fn to_sql<W: Write + ?Sized>(&self, _: &Type, w: &mut W, _: &SessionInfo) -> Result<IsNull> {
|
||||||
-> Result<IsNull> {
|
|
||||||
try!(w.write_all(self.as_bytes()));
|
try!(w.write_all(self.as_bytes()));
|
||||||
Ok(IsNull::No)
|
Ok(IsNull::No)
|
||||||
}
|
}
|
||||||
@ -932,8 +920,7 @@ impl<'a> ToSql for &'a str {
|
|||||||
impl ToSql for String {
|
impl ToSql for String {
|
||||||
to_sql_checked!();
|
to_sql_checked!();
|
||||||
|
|
||||||
fn to_sql<W: Write+?Sized>(&self, ty: &Type, w: &mut W, ctx: &SessionInfo)
|
fn to_sql<W: Write + ?Sized>(&self, ty: &Type, w: &mut W, ctx: &SessionInfo) -> Result<IsNull> {
|
||||||
-> Result<IsNull> {
|
|
||||||
<&str as ToSql>::to_sql(&&**self, ty, w, ctx)
|
<&str as ToSql>::to_sql(&&**self, ty, w, ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -945,8 +932,11 @@ impl ToSql for String {
|
|||||||
impl ToSql for i8 {
|
impl ToSql for i8 {
|
||||||
to_sql_checked!();
|
to_sql_checked!();
|
||||||
|
|
||||||
fn to_sql<W: Write+?Sized>(&self, _: &Type, mut w: &mut W, _: &SessionInfo)
|
fn to_sql<W: Write + ?Sized>(&self,
|
||||||
-> Result<IsNull> {
|
_: &Type,
|
||||||
|
mut w: &mut W,
|
||||||
|
_: &SessionInfo)
|
||||||
|
-> Result<IsNull> {
|
||||||
try!(w.write_i8(*self));
|
try!(w.write_i8(*self));
|
||||||
Ok(IsNull::No)
|
Ok(IsNull::No)
|
||||||
}
|
}
|
||||||
@ -980,8 +970,11 @@ to_primitive!(f64, write_f64, Type::Float8);
|
|||||||
impl ToSql for HashMap<String, Option<String>> {
|
impl ToSql for HashMap<String, Option<String>> {
|
||||||
to_sql_checked!();
|
to_sql_checked!();
|
||||||
|
|
||||||
fn to_sql<W: Write+?Sized>(&self, _: &Type, mut w: &mut W, _: &SessionInfo)
|
fn to_sql<W: Write + ?Sized>(&self,
|
||||||
-> Result<IsNull> {
|
_: &Type,
|
||||||
|
mut w: &mut W,
|
||||||
|
_: &SessionInfo)
|
||||||
|
-> Result<IsNull> {
|
||||||
try!(w.write_i32::<BigEndian>(try!(downcast(self.len()))));
|
try!(w.write_i32::<BigEndian>(try!(downcast(self.len()))));
|
||||||
|
|
||||||
for (key, val) in self {
|
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_i32::<BigEndian>(try!(downcast(val.len()))));
|
||||||
try!(w.write_all(val.as_bytes()));
|
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> {
|
fn downcast(len: usize) -> Result<i32> {
|
||||||
if len > i32::max_value() as usize {
|
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))
|
Err(Error::Conversion(err))
|
||||||
} else {
|
} else {
|
||||||
Ok(len as i32)
|
Ok(len as i32)
|
||||||
|
@ -12,7 +12,8 @@ impl FromSql for json::Json {
|
|||||||
if let Type::Jsonb = *ty {
|
if let Type::Jsonb = *ty {
|
||||||
// We only support version 1 of the jsonb binary format
|
// We only support version 1 of the jsonb binary format
|
||||||
if try!(raw.read_u8()) != 1 {
|
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));
|
return Err(Error::Conversion(err));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -23,8 +24,11 @@ impl FromSql for json::Json {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ToSql for json::Json {
|
impl ToSql for json::Json {
|
||||||
fn to_sql<W: Write+?Sized>(&self, ty: &Type, mut out: &mut W, _: &SessionInfo)
|
fn to_sql<W: Write + ?Sized>(&self,
|
||||||
-> Result<IsNull> {
|
ty: &Type,
|
||||||
|
mut out: &mut W,
|
||||||
|
_: &SessionInfo)
|
||||||
|
-> Result<IsNull> {
|
||||||
if let Type::Jsonb = *ty {
|
if let Type::Jsonb = *ty {
|
||||||
try!(out.write_u8(1));
|
try!(out.write_u8(1));
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,8 @@ impl FromSql for Value {
|
|||||||
if let Type::Jsonb = *ty {
|
if let Type::Jsonb = *ty {
|
||||||
// We only support version 1 of the jsonb binary format
|
// We only support version 1 of the jsonb binary format
|
||||||
if try!(raw.read_u8()) != 1 {
|
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));
|
return Err(Error::Conversion(err));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -25,8 +26,11 @@ impl FromSql for Value {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ToSql for Value {
|
impl ToSql for Value {
|
||||||
fn to_sql<W: Write+?Sized>(&self, ty: &Type, mut out: &mut W, _: &SessionInfo)
|
fn to_sql<W: Write + ?Sized>(&self,
|
||||||
-> Result<IsNull> {
|
ty: &Type,
|
||||||
|
mut out: &mut W,
|
||||||
|
_: &SessionInfo)
|
||||||
|
-> Result<IsNull> {
|
||||||
if let Type::Jsonb = *ty {
|
if let Type::Jsonb = *ty {
|
||||||
try!(out.write_u8(1));
|
try!(out.write_u8(1));
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,8 @@ impl FromSql for Value {
|
|||||||
if let Type::Jsonb = *ty {
|
if let Type::Jsonb = *ty {
|
||||||
// We only support version 1 of the jsonb binary format
|
// We only support version 1 of the jsonb binary format
|
||||||
if try!(raw.read_u8()) != 1 {
|
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));
|
return Err(Error::Conversion(err));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -25,8 +26,11 @@ impl FromSql for Value {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ToSql for Value {
|
impl ToSql for Value {
|
||||||
fn to_sql<W: Write+?Sized>(&self, ty: &Type, mut out: &mut W, _: &SessionInfo)
|
fn to_sql<W: Write + ?Sized>(&self,
|
||||||
-> Result<IsNull> {
|
ty: &Type,
|
||||||
|
mut out: &mut W,
|
||||||
|
_: &SessionInfo)
|
||||||
|
-> Result<IsNull> {
|
||||||
if let Type::Jsonb = *ty {
|
if let Type::Jsonb = *ty {
|
||||||
try!(out.write_u8(1));
|
try!(out.write_u8(1));
|
||||||
}
|
}
|
||||||
|
@ -38,7 +38,11 @@ impl<'a, T: 'a + ToSql> ToSql for Slice<'a, T> {
|
|||||||
self.to_sql(ty, out, ctx)
|
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() {
|
let member_type = match ty.kind() {
|
||||||
&Kind::Array(ref member) => member,
|
&Kind::Array(ref member) => member,
|
||||||
_ => panic!("expected array type"),
|
_ => panic!("expected array type"),
|
||||||
|
@ -31,7 +31,11 @@ impl FromSql for Timespec {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ToSql 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;
|
let t = (self.sec - TIME_SEC_CONVERSION) * USEC_PER_SEC + self.nsec as i64 / NSEC_PER_USEC;
|
||||||
try!(w.write_i64::<BigEndian>(t));
|
try!(w.write_i64::<BigEndian>(t));
|
||||||
Ok(IsNull::No)
|
Ok(IsNull::No)
|
||||||
|
@ -18,7 +18,7 @@ impl FromSql for Uuid {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ToSql 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()));
|
try!(w.write_all(self.as_bytes()));
|
||||||
Ok(IsNull::No)
|
Ok(IsNull::No)
|
||||||
}
|
}
|
||||||
|
335
src/url.rs
335
src/url.rs
@ -23,12 +23,12 @@ pub struct Url {
|
|||||||
pub struct Path {
|
pub struct Path {
|
||||||
pub path: String,
|
pub path: String,
|
||||||
pub query: Query,
|
pub query: Query,
|
||||||
pub fragment: Option<String>
|
pub fragment: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct UserInfo {
|
pub struct UserInfo {
|
||||||
pub user: String,
|
pub user: String,
|
||||||
pub pass: Option<String>
|
pub pass: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type Query = Vec<(String, String)>;
|
pub type Query = Vec<(String, String)>;
|
||||||
@ -47,7 +47,7 @@ impl Url {
|
|||||||
user: user,
|
user: user,
|
||||||
host: host,
|
host: host,
|
||||||
port: port,
|
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 (query, fragment) = try!(get_query_fragment(rest));
|
||||||
|
|
||||||
let url = Url::new(scheme.to_owned(),
|
let url = Url::new(scheme.to_owned(),
|
||||||
userinfo,
|
userinfo,
|
||||||
host.to_owned(),
|
host.to_owned(),
|
||||||
port,
|
port,
|
||||||
path,
|
path,
|
||||||
query,
|
query,
|
||||||
fragment);
|
fragment);
|
||||||
Ok(url)
|
Ok(url)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Path {
|
impl Path {
|
||||||
pub fn new(path: String,
|
pub fn new(path: String, query: Query, fragment: Option<String>) -> Path {
|
||||||
query: Query,
|
|
||||||
fragment: Option<String>)
|
|
||||||
-> Path {
|
|
||||||
Path {
|
Path {
|
||||||
path: path,
|
path: path,
|
||||||
query: query,
|
query: query,
|
||||||
@ -94,14 +91,21 @@ impl Path {
|
|||||||
// query and fragment
|
// query and fragment
|
||||||
let (query, fragment) = try!(get_query_fragment(&rest));
|
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 {
|
impl UserInfo {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn new(user: String, pass: Option<String>) -> UserInfo {
|
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()) {
|
let bytes = match (iter.next(), iter.next()) {
|
||||||
(Some(one), Some(two)) => [one, two],
|
(Some(one), Some(two)) => [one, two],
|
||||||
_ => return Err(format!("Malformed input: found '%' \
|
_ => return Err(format!("Malformed input: found '%' without two \
|
||||||
without two trailing bytes")),
|
trailing bytes")),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Only decode some characters if full_url:
|
// Only decode some characters if full_url:
|
||||||
match str::from_utf8(&bytes).unwrap().from_hex().unwrap()[0] as char {
|
match str::from_utf8(&bytes).unwrap().from_hex().unwrap()[0] as char {
|
||||||
// gen-delims:
|
// gen-delims:
|
||||||
':' | '/' | '?' | '#' | '[' | ']' | '@' |
|
':' |
|
||||||
|
'/' |
|
||||||
// sub-delims:
|
'?' |
|
||||||
'!' | '$' | '&' | '"' | '(' | ')' | '*' |
|
'#' |
|
||||||
'+' | ',' | ';' | '='
|
'[' |
|
||||||
if full_url => {
|
']' |
|
||||||
|
'@' |
|
||||||
|
'!' |
|
||||||
|
'$' |
|
||||||
|
'&' |
|
||||||
|
'"' |
|
||||||
|
'(' |
|
||||||
|
')' |
|
||||||
|
'*' |
|
||||||
|
'+' |
|
||||||
|
',' |
|
||||||
|
';' |
|
||||||
|
'=' if full_url => {
|
||||||
out.push('%');
|
out.push('%');
|
||||||
out.push(bytes[0] as char);
|
out.push(bytes[0] as char);
|
||||||
out.push(bytes[1] 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),
|
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> {
|
fn query_from_str(rawquery: &str) -> DecodeResult<Query> {
|
||||||
let mut query: Query = vec!();
|
let mut query: Query = vec![];
|
||||||
if !rawquery.is_empty() {
|
if !rawquery.is_empty() {
|
||||||
for p in rawquery.split('&') {
|
for p in rawquery.split('&') {
|
||||||
let (k, v) = split_char_first(p, '=');
|
let (k, v) = split_char_first(p, '=');
|
||||||
query.push((try!(decode_component(k)),
|
query.push((try!(decode_component(k)), try!(decode_component(v))));
|
||||||
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)> {
|
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 {
|
let result = match c {
|
||||||
'A' ... 'Z'
|
'A'...'Z' |
|
||||||
| 'a' ... 'z' => continue,
|
'a'...'z' => continue,
|
||||||
'0' ... '9' | '+' | '-' | '.' => {
|
'0'...'9' | '+' | '-' | '.' => {
|
||||||
if i != 0 { continue }
|
if i != 0 {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
Err("url: Scheme must begin with a letter.".to_owned())
|
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 {
|
if i == 0 {
|
||||||
Err("url: Scheme cannot be empty.".to_owned())
|
Err("url: Scheme cannot be empty.".to_owned())
|
||||||
} else {
|
} 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()),
|
_ => 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
|
// returns userinfo, host, port, and unparsed part, or an error
|
||||||
fn get_authority(rawurl: &str) ->
|
fn get_authority(rawurl: &str) -> DecodeResult<(Option<UserInfo>, &str, Option<u16>, &str)> {
|
||||||
DecodeResult<(Option<UserInfo>, &str, Option<u16>, &str)> {
|
|
||||||
enum State {
|
enum State {
|
||||||
Start, // starting state
|
Start, // starting state
|
||||||
PassHostPort, // could be in user or port
|
PassHostPort, // could be in user or port
|
||||||
Ip6Port, // either in ipv6 host or port
|
Ip6Port, // either in ipv6 host or port
|
||||||
Ip6Host, // are in an ipv6 host
|
Ip6Host, // are in an ipv6 host
|
||||||
InHost, // are in a host - may be ipv6, but don't know yet
|
InHost, // are in a host - may be ipv6, but don't know yet
|
||||||
InPort // are in port
|
InPort, // are in port
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, PartialEq)]
|
#[derive(Clone, PartialEq)]
|
||||||
enum Input {
|
enum Input {
|
||||||
Digit, // all digits
|
Digit, // all digits
|
||||||
Hex, // digits and letters a-f
|
Hex, // digits and letters a-f
|
||||||
Unreserved // all other legal characters
|
Unreserved, // all other legal characters
|
||||||
}
|
}
|
||||||
|
|
||||||
if !rawurl.starts_with("//") {
|
if !rawurl.starts_with("//") {
|
||||||
@ -235,23 +251,35 @@ fn get_authority(rawurl: &str) ->
|
|||||||
let mut begin = 2;
|
let mut begin = 2;
|
||||||
let mut end = len;
|
let mut end = len;
|
||||||
|
|
||||||
for (i,c) in rawurl.chars().enumerate()
|
for (i, c) in rawurl.chars()
|
||||||
// ignore the leading '//' handled by early return
|
.enumerate()
|
||||||
.skip(2) {
|
.skip(2) {
|
||||||
// deal with input class first
|
// deal with input class first
|
||||||
match c {
|
match c {
|
||||||
'0' ... '9' => (),
|
'0'...'9' => (),
|
||||||
'A' ... 'F'
|
'A'...'F' |
|
||||||
| 'a' ... 'f' => {
|
'a'...'f' => {
|
||||||
if input == Input::Digit {
|
if input == Input::Digit {
|
||||||
input = Input::Hex;
|
input = Input::Hex;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
'G' ... 'Z'
|
'G'...'Z' |
|
||||||
| 'g' ... 'z'
|
'g'...'z' |
|
||||||
| '-' | '.' | '_' | '~' | '%'
|
'-' |
|
||||||
| '&' |'\'' | '(' | ')' | '+'
|
'.' |
|
||||||
| '!' | '*' | ',' | ';' | '=' => input = Input::Unreserved,
|
'_' |
|
||||||
|
'~' |
|
||||||
|
'%' |
|
||||||
|
'&' |
|
||||||
|
'\'' |
|
||||||
|
'(' |
|
||||||
|
')' |
|
||||||
|
'+' |
|
||||||
|
'!' |
|
||||||
|
'*' |
|
||||||
|
',' |
|
||||||
|
';' |
|
||||||
|
'=' => input = Input::Unreserved,
|
||||||
':' | '@' | '?' | '#' | '/' => {
|
':' | '@' | '?' | '#' | '/' => {
|
||||||
// separators, don't change anything
|
// separators, don't change anything
|
||||||
}
|
}
|
||||||
@ -260,97 +288,96 @@ fn get_authority(rawurl: &str) ->
|
|||||||
|
|
||||||
// now process states
|
// now process states
|
||||||
match c {
|
match c {
|
||||||
':' => {
|
':' => {
|
||||||
colon_count += 1;
|
colon_count += 1;
|
||||||
match st {
|
match st {
|
||||||
State::Start => {
|
State::Start => {
|
||||||
pos = i;
|
pos = i;
|
||||||
st = State::PassHostPort;
|
st = State::PassHostPort;
|
||||||
}
|
}
|
||||||
State::PassHostPort => {
|
State::PassHostPort => {
|
||||||
// multiple colons means ipv6 address.
|
// multiple colons means ipv6 address.
|
||||||
if input == Input::Unreserved {
|
if input == Input::Unreserved {
|
||||||
return Err(
|
return Err("Illegal characters in IPv6 address.".to_owned());
|
||||||
"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;
|
input = Input::Digit; // reset input class
|
||||||
}
|
|
||||||
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
|
colon_count = 0; // reset count
|
||||||
match st {
|
match st {
|
||||||
State::Start => {
|
State::Start => {
|
||||||
let user = try!(decode_component(&rawurl[begin..i]));
|
let user = try!(decode_component(&rawurl[begin..i]));
|
||||||
userinfo = Some(UserInfo::new(user, None));
|
userinfo = Some(UserInfo::new(user, None));
|
||||||
st = State::InHost;
|
st = State::InHost;
|
||||||
}
|
}
|
||||||
State::PassHostPort => {
|
State::PassHostPort => {
|
||||||
let user = try!(decode_component(&rawurl[begin..pos]));
|
let user = try!(decode_component(&rawurl[begin..pos]));
|
||||||
let pass = try!(decode_component(&rawurl[pos+1..i]));
|
let pass = try!(decode_component(&rawurl[pos + 1..i]));
|
||||||
userinfo = Some(UserInfo::new(user, Some(pass)));
|
userinfo = Some(UserInfo::new(user, Some(pass)));
|
||||||
st = State::InHost;
|
st = State::InHost;
|
||||||
}
|
}
|
||||||
_ => return Err("Invalid '@' in authority.".to_owned()),
|
_ => return Err("Invalid '@' in authority.".to_owned()),
|
||||||
|
}
|
||||||
|
begin = i + 1;
|
||||||
}
|
}
|
||||||
begin = i+1;
|
|
||||||
}
|
|
||||||
|
|
||||||
'?' | '#' | '/' => {
|
'?' | '#' | '/' => {
|
||||||
end = i;
|
end = i;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
_ => ()
|
_ => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// finish up
|
// finish up
|
||||||
match st {
|
match st {
|
||||||
State::Start => host = &rawurl[begin..end],
|
State::Start => host = &rawurl[begin..end],
|
||||||
State::PassHostPort
|
State::PassHostPort |
|
||||||
| State::Ip6Port => {
|
State::Ip6Port => {
|
||||||
if input != Input::Digit {
|
if input != Input::Digit {
|
||||||
return Err("Non-digit characters in port.".to_owned());
|
return Err("Non-digit characters in port.".to_owned());
|
||||||
|
}
|
||||||
|
host = &rawurl[begin..pos];
|
||||||
|
port = Some(&rawurl[pos + 1..end]);
|
||||||
}
|
}
|
||||||
host = &rawurl[begin..pos];
|
State::Ip6Host |
|
||||||
port = Some(&rawurl[pos+1..end]);
|
State::InHost => host = &rawurl[begin..end],
|
||||||
}
|
State::InPort => {
|
||||||
State::Ip6Host
|
if input != Input::Digit {
|
||||||
| State::InHost => host = &rawurl[begin..end],
|
return Err("Non-digit characters in port.".to_owned());
|
||||||
State::InPort => {
|
}
|
||||||
if input != Input::Digit {
|
port = Some(&rawurl[pos + 1..end]);
|
||||||
return Err("Non-digit characters in port.".to_owned());
|
|
||||||
}
|
}
|
||||||
port = Some(&rawurl[pos+1..end]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let rest = &rawurl[end..len];
|
let rest = &rawurl[end..len];
|
||||||
@ -359,8 +386,8 @@ fn get_authority(rawurl: &str) ->
|
|||||||
None => None,
|
None => None,
|
||||||
opt => match opt.and_then(|p| FromStr::from_str(p).ok()) {
|
opt => match opt.and_then(|p| FromStr::from_str(p).ok()) {
|
||||||
None => return Err(format!("Failed to parse port: {:?}", port)),
|
None => return Err(format!("Failed to parse port: {:?}", port)),
|
||||||
opt => opt
|
opt => opt,
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok((userinfo, host, port, rest))
|
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)> {
|
fn get_path(rawurl: &str, is_authority: bool) -> DecodeResult<(String, &str)> {
|
||||||
let len = rawurl.len();
|
let len = rawurl.len();
|
||||||
let mut end = len;
|
let mut end = len;
|
||||||
for (i,c) in rawurl.chars().enumerate() {
|
for (i, c) in rawurl.chars().enumerate() {
|
||||||
match c {
|
match c {
|
||||||
'A' ... 'Z'
|
'A'...'Z' |
|
||||||
| 'a' ... 'z'
|
'a'...'z' |
|
||||||
| '0' ... '9'
|
'0'...'9' |
|
||||||
| '&' |'\'' | '(' | ')' | '.'
|
'&' |
|
||||||
| '@' | ':' | '%' | '/' | '+'
|
'\'' |
|
||||||
| '!' | '*' | ',' | ';' | '='
|
'(' |
|
||||||
| '_' | '-' | '~' => continue,
|
')' |
|
||||||
'?' | '#' => {
|
'.' |
|
||||||
end = i;
|
'@' |
|
||||||
break;
|
':' |
|
||||||
}
|
'%' |
|
||||||
_ => return Err("Invalid character in path.".to_owned())
|
'/' |
|
||||||
|
'+' |
|
||||||
|
'!' |
|
||||||
|
'*' |
|
||||||
|
',' |
|
||||||
|
';' |
|
||||||
|
'=' |
|
||||||
|
'_' |
|
||||||
|
'-' |
|
||||||
|
'~' => continue,
|
||||||
|
'?' | '#' => {
|
||||||
|
end = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
_ => return Err("Invalid character in path.".to_owned()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if is_authority && end != 0 && !rawurl.starts_with("/") {
|
if is_authority && end != 0 && !rawurl.starts_with("/") {
|
||||||
Err("Non-empty path must begin with \
|
Err("Non-empty path must begin with '/' in presence of authority.".to_owned())
|
||||||
'/' in presence of authority.".to_owned())
|
|
||||||
} else {
|
} else {
|
||||||
Ok((try!(decode_component(&rawurl[0..end])), &rawurl[end..len]))
|
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
|
// Parse the fragment if available
|
||||||
let fragment = match raw_fragment {
|
let fragment = match raw_fragment {
|
||||||
"" => None,
|
"" => None,
|
||||||
raw => Some(try!(decode_component(raw)))
|
raw => Some(try!(decode_component(raw))),
|
||||||
};
|
};
|
||||||
|
|
||||||
match before_fragment.chars().next() {
|
match before_fragment.chars().next() {
|
||||||
Some('?') => Ok((try!(query_from_str(&before_fragment[1..])), fragment)),
|
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)),
|
_ => Err(format!("Query didn't start with '?': '{}..'", before_fragment)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -426,4 +466,3 @@ impl FromStr for Path {
|
|||||||
Path::parse(s)
|
Path::parse(s)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user