2014-07-03 05:23:17 +00:00
|
|
|
//! Rust-Postgres is a pure-Rust frontend for the popular PostgreSQL database. It
|
|
|
|
//! exposes a high level interface in the vein of JDBC or Go's `database/sql`
|
|
|
|
//! package.
|
|
|
|
//!
|
|
|
|
//! ```rust,no_run
|
2015-01-09 19:20:43 +00:00
|
|
|
//! # #![allow(unstable)]
|
2014-07-03 05:23:17 +00:00
|
|
|
//! extern crate postgres;
|
|
|
|
//! extern crate time;
|
|
|
|
//!
|
|
|
|
//! use time::Timespec;
|
|
|
|
//!
|
2014-11-17 21:46:33 +00:00
|
|
|
//! use postgres::{Connection, SslMode};
|
2014-07-03 05:23:17 +00:00
|
|
|
//!
|
|
|
|
//! struct Person {
|
|
|
|
//! id: i32,
|
|
|
|
//! name: String,
|
|
|
|
//! time_created: Timespec,
|
|
|
|
//! data: Option<Vec<u8>>
|
|
|
|
//! }
|
|
|
|
//!
|
|
|
|
//! fn main() {
|
2014-11-17 21:46:33 +00:00
|
|
|
//! let conn = Connection::connect("postgresql://postgres@localhost", &SslMode::None)
|
2014-11-01 23:38:52 +00:00
|
|
|
//! .unwrap();
|
2014-07-03 05:23:17 +00:00
|
|
|
//!
|
|
|
|
//! conn.execute("CREATE TABLE person (
|
|
|
|
//! id SERIAL PRIMARY KEY,
|
|
|
|
//! name VARCHAR NOT NULL,
|
|
|
|
//! time_created TIMESTAMP NOT NULL,
|
|
|
|
//! data BYTEA
|
2014-11-25 20:59:31 +00:00
|
|
|
//! )", &[]).unwrap();
|
2014-07-03 05:23:17 +00:00
|
|
|
//! let me = Person {
|
|
|
|
//! id: 0,
|
2014-12-23 17:10:16 +00:00
|
|
|
//! name: "Steven".to_string(),
|
2014-07-03 05:23:17 +00:00
|
|
|
//! time_created: time::get_time(),
|
|
|
|
//! data: None
|
|
|
|
//! };
|
2014-12-10 05:35:52 +00:00
|
|
|
//! conn.execute("INSERT INTO person (name, time_created, data) VALUES ($1, $2, $3)",
|
2014-08-30 09:57:46 +00:00
|
|
|
//! &[&me.name, &me.time_created, &me.data]).unwrap();
|
2014-07-03 05:23:17 +00:00
|
|
|
//!
|
|
|
|
//! let stmt = conn.prepare("SELECT id, name, time_created, data FROM person")
|
|
|
|
//! .unwrap();
|
2014-11-25 20:59:31 +00:00
|
|
|
//! for row in stmt.query(&[]).unwrap() {
|
2014-07-03 05:23:17 +00:00
|
|
|
//! let person = Person {
|
2014-10-26 06:43:59 +00:00
|
|
|
//! id: row.get(0),
|
|
|
|
//! name: row.get(1),
|
|
|
|
//! time_created: row.get(2),
|
|
|
|
//! data: row.get(3)
|
2014-07-03 05:23:17 +00:00
|
|
|
//! };
|
|
|
|
//! println!("Found person {}", person.name);
|
|
|
|
//! }
|
|
|
|
//! }
|
|
|
|
//! ```
|
2014-10-26 20:11:14 +00:00
|
|
|
#![doc(html_root_url="https://sfackler.github.io/doc")]
|
2015-01-12 22:01:35 +00:00
|
|
|
#![feature(plugin, unsafe_destructor)]
|
2014-10-31 15:51:27 +00:00
|
|
|
#![warn(missing_docs)]
|
2015-01-09 18:50:54 +00:00
|
|
|
#![allow(unstable)]
|
2013-10-08 04:11:54 +00:00
|
|
|
|
2015-01-07 16:23:40 +00:00
|
|
|
#[macro_use]
|
2014-12-10 05:35:52 +00:00
|
|
|
extern crate log;
|
2014-02-15 23:03:35 +00:00
|
|
|
extern crate openssl;
|
2014-04-01 06:51:42 +00:00
|
|
|
extern crate phf;
|
2015-01-07 16:23:40 +00:00
|
|
|
#[plugin] #[no_link]
|
2014-04-23 05:10:06 +00:00
|
|
|
extern crate phf_mac;
|
2014-12-19 01:08:58 +00:00
|
|
|
extern crate "rustc-serialize" as serialize;
|
2014-12-03 04:34:46 +00:00
|
|
|
extern crate time;
|
2013-08-04 02:17:32 +00:00
|
|
|
|
2014-11-28 20:24:34 +00:00
|
|
|
use openssl::crypto::hash::{HashType, Hasher};
|
2014-11-28 23:54:37 +00:00
|
|
|
use openssl::ssl::{SslContext, MaybeSslStream};
|
2014-02-14 03:26:52 +00:00
|
|
|
use serialize::hex::ToHex;
|
2014-12-23 17:10:16 +00:00
|
|
|
use std::borrow::ToOwned;
|
2014-02-08 02:17:40 +00:00
|
|
|
use std::cell::{Cell, RefCell};
|
2014-12-03 04:57:32 +00:00
|
|
|
use std::cmp::max;
|
2014-11-02 18:40:03 +00:00
|
|
|
use std::collections::{RingBuf, HashMap};
|
2014-12-10 05:35:52 +00:00
|
|
|
use std::fmt;
|
2014-12-03 04:57:32 +00:00
|
|
|
use std::io::{BufferedStream, IoResult, IoError, IoErrorKind};
|
2014-05-04 19:21:52 +00:00
|
|
|
use std::io::net::ip::Port;
|
2014-02-12 07:42:46 +00:00
|
|
|
use std::mem;
|
2014-11-01 23:12:05 +00:00
|
|
|
use std::result;
|
2014-12-10 05:35:52 +00:00
|
|
|
use std::time::Duration;
|
|
|
|
use url::Url;
|
2013-08-04 02:17:32 +00:00
|
|
|
|
2014-12-10 05:35:52 +00:00
|
|
|
pub use error::{Error, ConnectError, SqlState, DbError, ErrorPosition};
|
|
|
|
#[doc(inline)]
|
|
|
|
pub use types::{Oid, Type, ToSql, FromSql};
|
2014-12-03 04:34:46 +00:00
|
|
|
use io::{InternalStream, Timeout};
|
2014-11-04 05:47:53 +00:00
|
|
|
use message::BackendMessage::*;
|
2014-12-10 05:35:52 +00:00
|
|
|
use message::FrontendMessage::*;
|
|
|
|
use message::{FrontendMessage, BackendMessage, RowDescriptionEntry};
|
2014-02-16 02:59:16 +00:00
|
|
|
use message::{WriteMessage, ReadMessage};
|
2013-07-25 07:10:18 +00:00
|
|
|
|
2015-01-07 16:23:40 +00:00
|
|
|
#[macro_use]
|
2014-07-07 02:02:22 +00:00
|
|
|
mod macros;
|
2014-02-10 06:45:26 +00:00
|
|
|
|
2014-12-10 05:35:52 +00:00
|
|
|
mod error;
|
2014-05-04 19:21:52 +00:00
|
|
|
mod io;
|
2014-02-16 02:59:16 +00:00
|
|
|
mod message;
|
2014-10-15 15:35:41 +00:00
|
|
|
mod url;
|
2014-09-30 05:56:43 +00:00
|
|
|
mod util;
|
2014-10-15 15:35:41 +00:00
|
|
|
pub mod types;
|
2014-02-16 02:59:16 +00:00
|
|
|
|
2014-11-01 23:02:50 +00:00
|
|
|
const CANARY: u32 = 0xdeadbeef;
|
2015-01-22 08:04:58 +00:00
|
|
|
const TYPEINFO_QUERY: &'static str = "t";
|
2013-10-21 00:32:14 +00:00
|
|
|
|
2014-12-14 19:39:26 +00:00
|
|
|
/// A type alias of the result returned by many methods.
|
2014-11-04 06:24:11 +00:00
|
|
|
pub type Result<T> = result::Result<T, Error>;
|
2014-04-03 04:26:41 +00:00
|
|
|
|
2014-04-21 05:27:55 +00:00
|
|
|
/// Specifies the target server to connect to.
|
2015-01-10 04:48:47 +00:00
|
|
|
#[derive(Clone, Show)]
|
2014-11-01 23:13:01 +00:00
|
|
|
pub enum ConnectTarget {
|
2014-04-21 05:27:55 +00:00
|
|
|
/// Connect via TCP to the specified host.
|
2014-11-04 05:41:35 +00:00
|
|
|
Tcp(String),
|
2014-04-21 05:27:55 +00:00
|
|
|
/// Connect via a Unix domain socket in the specified directory.
|
2014-11-04 05:41:35 +00:00
|
|
|
Unix(Path)
|
2014-04-21 05:27:55 +00:00
|
|
|
}
|
|
|
|
|
2014-07-26 00:24:10 +00:00
|
|
|
/// Authentication information
|
2015-01-10 04:48:47 +00:00
|
|
|
#[derive(Clone, Show)]
|
2014-11-01 23:14:08 +00:00
|
|
|
pub struct UserInfo {
|
2014-07-26 00:24:10 +00:00
|
|
|
/// The username
|
|
|
|
pub user: String,
|
|
|
|
/// An optional password
|
|
|
|
pub password: Option<String>,
|
|
|
|
}
|
|
|
|
|
2014-04-21 05:27:55 +00:00
|
|
|
/// Information necessary to open a new connection to a Postgres server.
|
2015-01-10 04:48:47 +00:00
|
|
|
#[derive(Clone, Show)]
|
2014-11-01 23:15:30 +00:00
|
|
|
pub struct ConnectParams {
|
2014-04-21 05:27:55 +00:00
|
|
|
/// The target server
|
2014-11-01 23:13:01 +00:00
|
|
|
pub target: ConnectTarget,
|
2014-04-22 05:53:14 +00:00
|
|
|
/// The target port.
|
|
|
|
///
|
|
|
|
/// Defaults to 5432 if not specified.
|
|
|
|
pub port: Option<Port>,
|
2014-04-21 05:27:55 +00:00
|
|
|
/// The user to login as.
|
|
|
|
///
|
2014-11-02 18:38:45 +00:00
|
|
|
/// `Connection::connect` requires a user but `cancel_query` does not.
|
2014-11-01 23:14:08 +00:00
|
|
|
pub user: Option<UserInfo>,
|
2014-04-21 05:27:55 +00:00
|
|
|
/// The database to connect to. Defaults the value of `user`.
|
2014-05-26 03:38:40 +00:00
|
|
|
pub database: Option<String>,
|
2014-04-21 05:27:55 +00:00
|
|
|
/// Runtime parameters to be passed to the Postgres backend.
|
2014-05-26 03:38:40 +00:00
|
|
|
pub options: Vec<(String, String)>,
|
2014-04-21 05:27:55 +00:00
|
|
|
}
|
|
|
|
|
2014-11-02 18:38:45 +00:00
|
|
|
/// A trait implemented by types that can be converted into a `ConnectParams`.
|
2014-04-21 05:27:55 +00:00
|
|
|
pub trait IntoConnectParams {
|
2014-11-01 23:15:30 +00:00
|
|
|
/// Converts the value of `self` into a `ConnectParams`.
|
2014-11-04 06:24:11 +00:00
|
|
|
fn into_connect_params(self) -> result::Result<ConnectParams, ConnectError>;
|
2014-04-21 05:27:55 +00:00
|
|
|
}
|
|
|
|
|
2014-11-01 23:15:30 +00:00
|
|
|
impl IntoConnectParams for ConnectParams {
|
2014-11-04 06:24:11 +00:00
|
|
|
fn into_connect_params(self) -> result::Result<ConnectParams, ConnectError> {
|
2014-04-21 05:27:55 +00:00
|
|
|
Ok(self)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a> IntoConnectParams for &'a str {
|
2014-11-04 06:24:11 +00:00
|
|
|
fn into_connect_params(self) -> result::Result<ConnectParams, ConnectError> {
|
2014-07-07 13:41:43 +00:00
|
|
|
match Url::parse(self) {
|
2014-05-17 03:47:03 +00:00
|
|
|
Ok(url) => url.into_connect_params(),
|
2014-11-17 21:46:33 +00:00
|
|
|
Err(err) => return Err(ConnectError::InvalidUrl(err)),
|
2014-05-17 03:47:03 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl IntoConnectParams for Url {
|
2014-11-04 06:24:11 +00:00
|
|
|
fn into_connect_params(self) -> result::Result<ConnectParams, ConnectError> {
|
2014-04-21 05:27:55 +00:00
|
|
|
let Url {
|
|
|
|
host,
|
|
|
|
port,
|
|
|
|
user,
|
2014-07-07 13:41:43 +00:00
|
|
|
path: url::Path { path, query: options, .. },
|
2014-04-21 05:27:55 +00:00
|
|
|
..
|
2014-05-17 03:47:03 +00:00
|
|
|
} = self;
|
2014-04-21 05:27:55 +00:00
|
|
|
|
2014-12-03 05:44:34 +00:00
|
|
|
let maybe_path = try!(url::decode_component(&*host).map_err(ConnectError::InvalidUrl));
|
|
|
|
let target = if maybe_path.starts_with("/") {
|
2014-11-04 05:41:35 +00:00
|
|
|
ConnectTarget::Unix(Path::new(maybe_path))
|
2014-04-21 05:27:55 +00:00
|
|
|
} else {
|
2014-11-04 05:41:35 +00:00
|
|
|
ConnectTarget::Tcp(host)
|
2014-04-21 05:27:55 +00:00
|
|
|
};
|
|
|
|
|
2014-11-02 18:38:45 +00:00
|
|
|
let user = user.map(|url::UserInfo { user, pass }| {
|
|
|
|
UserInfo { user: user, password: pass }
|
|
|
|
});
|
2014-04-21 05:27:55 +00:00
|
|
|
|
2014-11-19 18:11:23 +00:00
|
|
|
// path contains the leading /
|
2014-12-23 17:10:16 +00:00
|
|
|
let database = path.slice_shift_char().map(|(_, path)| path.to_owned());
|
2014-04-21 05:27:55 +00:00
|
|
|
|
2014-11-01 23:15:30 +00:00
|
|
|
Ok(ConnectParams {
|
2014-04-22 05:53:14 +00:00
|
|
|
target: target,
|
2014-04-21 05:27:55 +00:00
|
|
|
port: port,
|
|
|
|
user: user,
|
|
|
|
database: database,
|
|
|
|
options: options,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-09-30 02:12:20 +00:00
|
|
|
/// Trait for types that can handle Postgres notice messages
|
2014-12-09 07:43:01 +00:00
|
|
|
pub trait NoticeHandler: Send {
|
2013-09-30 02:12:20 +00:00
|
|
|
/// Handle a Postgres notice message
|
2014-11-04 06:24:11 +00:00
|
|
|
fn handle(&mut self, notice: DbError);
|
2013-09-12 02:57:26 +00:00
|
|
|
}
|
|
|
|
|
2013-09-30 05:22:10 +00:00
|
|
|
/// A notice handler which logs at the `info` level.
|
2013-09-30 02:12:20 +00:00
|
|
|
///
|
2014-11-01 23:21:47 +00:00
|
|
|
/// This is the default handler used by a `Connection`.
|
2015-01-10 04:48:47 +00:00
|
|
|
#[derive(Copy, Show)]
|
2013-09-12 02:57:26 +00:00
|
|
|
pub struct DefaultNoticeHandler;
|
|
|
|
|
2014-11-01 23:16:50 +00:00
|
|
|
impl NoticeHandler for DefaultNoticeHandler {
|
2014-11-04 06:24:11 +00:00
|
|
|
fn handle(&mut self, notice: DbError) {
|
2013-10-21 04:06:12 +00:00
|
|
|
info!("{}: {}", notice.severity, notice.message);
|
2013-09-12 02:57:26 +00:00
|
|
|
}
|
2013-08-28 06:23:36 +00:00
|
|
|
}
|
|
|
|
|
2013-10-15 05:41:03 +00:00
|
|
|
/// An asynchronous notification
|
2015-01-10 04:48:47 +00:00
|
|
|
#[derive(Clone, Show)]
|
2014-11-01 23:18:09 +00:00
|
|
|
pub struct Notification {
|
2013-10-15 05:41:03 +00:00
|
|
|
/// The process ID of the notifying backend process
|
2014-08-16 03:14:46 +00:00
|
|
|
pub pid: u32,
|
2013-10-15 05:41:03 +00:00
|
|
|
/// The name of the channel that the notify has been raised on
|
2014-05-26 03:38:40 +00:00
|
|
|
pub channel: String,
|
2013-10-15 05:41:03 +00:00
|
|
|
/// The "payload" string passed from the notifying process
|
2014-05-26 03:38:40 +00:00
|
|
|
pub payload: String,
|
2013-10-15 05:41:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// An iterator over asynchronous notifications
|
2014-11-01 23:18:09 +00:00
|
|
|
pub struct Notifications<'conn> {
|
2014-11-01 23:21:47 +00:00
|
|
|
conn: &'conn Connection
|
2013-10-15 05:41:03 +00:00
|
|
|
}
|
|
|
|
|
2015-01-10 04:48:47 +00:00
|
|
|
impl<'a> fmt::Show for Notifications<'a> {
|
|
|
|
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
|
|
|
write!(fmt, "Notifications")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-01-04 16:08:53 +00:00
|
|
|
impl<'conn> Iterator for Notifications<'conn> {
|
|
|
|
type Item = Notification;
|
|
|
|
|
2013-10-15 05:41:03 +00:00
|
|
|
/// Returns the oldest pending notification or `None` if there are none.
|
|
|
|
///
|
2014-07-30 02:48:56 +00:00
|
|
|
/// ## Note
|
2013-10-15 05:41:03 +00:00
|
|
|
///
|
|
|
|
/// `next` may return `Some` notification after returning `None` if a new
|
|
|
|
/// notification was received.
|
2014-11-01 23:18:09 +00:00
|
|
|
fn next(&mut self) -> Option<Notification> {
|
2014-03-23 04:20:22 +00:00
|
|
|
self.conn.conn.borrow_mut().notifications.pop_front()
|
2013-10-15 05:41:03 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-11-26 02:30:28 +00:00
|
|
|
impl<'conn> Notifications<'conn> {
|
|
|
|
/// Returns the oldest pending notification.
|
|
|
|
///
|
|
|
|
/// If no notifications are pending, blocks until one arrives.
|
|
|
|
pub fn next_block(&mut self) -> Result<Notification> {
|
|
|
|
if let Some(notification) = self.next() {
|
|
|
|
return Ok(notification);
|
|
|
|
}
|
|
|
|
|
2014-12-03 04:34:46 +00:00
|
|
|
let mut conn = self.conn.conn.borrow_mut();
|
|
|
|
check_desync!(conn);
|
|
|
|
match try!(conn.read_message_with_notification()) {
|
2014-11-26 02:30:28 +00:00
|
|
|
NotificationResponse { pid, channel, payload } => {
|
|
|
|
Ok(Notification {
|
|
|
|
pid: pid,
|
|
|
|
channel: channel,
|
|
|
|
payload: payload
|
|
|
|
})
|
|
|
|
}
|
|
|
|
_ => unreachable!()
|
|
|
|
}
|
|
|
|
}
|
2014-12-03 04:34:46 +00:00
|
|
|
|
|
|
|
/// Returns the oldest pending notification
|
|
|
|
///
|
|
|
|
/// If no notifications are pending, blocks for up to `timeout` time, after
|
|
|
|
/// which an `IoError` with the `TimedOut` kind is returned.
|
2014-12-04 03:55:05 +00:00
|
|
|
///
|
|
|
|
/// ## Example
|
|
|
|
///
|
|
|
|
/// ```rust,no_run
|
2015-01-09 19:20:43 +00:00
|
|
|
/// # #![allow(unstable)]
|
2014-12-04 03:55:05 +00:00
|
|
|
/// use std::io::{IoError, IoErrorKind};
|
|
|
|
/// use std::time::Duration;
|
|
|
|
///
|
|
|
|
/// use postgres::Error;
|
|
|
|
///
|
|
|
|
/// # let conn = postgres::Connection::connect("", &postgres::SslMode::None).unwrap();
|
|
|
|
/// match conn.notifications().next_block_for(Duration::seconds(2)) {
|
|
|
|
/// Ok(notification) => println!("notification: {}", notification.payload),
|
|
|
|
/// Err(Error::IoError(IoError { kind: IoErrorKind::TimedOut, .. })) => {
|
|
|
|
/// println!("Wait for notification timed out");
|
|
|
|
/// }
|
2015-01-09 19:20:43 +00:00
|
|
|
/// Err(e) => println!("Other error: {:?}", e),
|
2014-12-04 03:55:05 +00:00
|
|
|
/// }
|
|
|
|
/// ```
|
2014-12-03 04:34:46 +00:00
|
|
|
pub fn next_block_for(&mut self, timeout: Duration) -> Result<Notification> {
|
2014-12-04 02:57:04 +00:00
|
|
|
fn now() -> i64 {
|
|
|
|
(time::precise_time_ns() / 100_000) as i64
|
|
|
|
}
|
|
|
|
|
2014-12-03 04:34:46 +00:00
|
|
|
if let Some(notification) = self.next() {
|
|
|
|
return Ok(notification);
|
|
|
|
}
|
|
|
|
|
|
|
|
let mut conn = self.conn.conn.borrow_mut();
|
|
|
|
check_desync!(conn);
|
|
|
|
|
2014-12-04 02:57:04 +00:00
|
|
|
let end = now() + timeout.num_milliseconds();
|
2014-12-03 04:34:46 +00:00
|
|
|
loop {
|
2014-12-04 03:55:05 +00:00
|
|
|
let timeout = max(0, end - now()) as u64;
|
2014-12-03 04:57:32 +00:00
|
|
|
conn.stream.set_read_timeout(Some(timeout));
|
2014-12-03 04:34:46 +00:00
|
|
|
match conn.read_one_message() {
|
|
|
|
Ok(Some(NotificationResponse { pid, channel, payload })) => {
|
|
|
|
return Ok(Notification {
|
|
|
|
pid: pid,
|
|
|
|
channel: channel,
|
|
|
|
payload: payload
|
|
|
|
})
|
|
|
|
}
|
|
|
|
Ok(Some(_)) => unreachable!(),
|
|
|
|
Ok(None) => {}
|
|
|
|
Err(e @ IoError { kind: IoErrorKind::TimedOut, .. }) => {
|
|
|
|
conn.desynchronized = false;
|
|
|
|
return Err(Error::IoError(e));
|
|
|
|
}
|
|
|
|
Err(e) => return Err(Error::IoError(e)),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2014-11-26 02:30:28 +00:00
|
|
|
}
|
|
|
|
|
2013-10-21 00:32:14 +00:00
|
|
|
/// Contains information necessary to cancel queries for a session
|
2015-01-10 04:48:47 +00:00
|
|
|
#[derive(Copy, Clone, Show)]
|
2014-11-01 23:19:02 +00:00
|
|
|
pub struct CancelData {
|
2013-10-21 00:32:14 +00:00
|
|
|
/// The process ID of the session
|
2014-08-16 03:14:46 +00:00
|
|
|
pub process_id: u32,
|
2013-10-21 00:32:14 +00:00
|
|
|
/// The secret key for the session
|
2014-08-16 03:14:46 +00:00
|
|
|
pub secret_key: u32,
|
2013-10-21 00:32:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Attempts to cancel an in-progress query.
|
|
|
|
///
|
|
|
|
/// The backend provides no information about whether a cancellation attempt
|
|
|
|
/// was successful or not. An error will only be returned if the driver was
|
|
|
|
/// unable to connect to the database.
|
|
|
|
///
|
2014-11-03 00:48:38 +00:00
|
|
|
/// A `CancelData` object can be created via `Connection::cancel_data`. The
|
|
|
|
/// object can cancel any query made on that connection.
|
2014-03-09 22:22:20 +00:00
|
|
|
///
|
2014-08-21 05:40:11 +00:00
|
|
|
/// Only the host and port of the connection info are used. See
|
2014-11-01 23:21:47 +00:00
|
|
|
/// `Connection::connect` for details of the `params` argument.
|
2014-03-31 02:21:51 +00:00
|
|
|
///
|
2014-07-30 02:48:56 +00:00
|
|
|
/// ## Example
|
2014-03-09 22:22:20 +00:00
|
|
|
///
|
2014-03-10 17:06:40 +00:00
|
|
|
/// ```rust,no_run
|
2015-01-09 19:20:43 +00:00
|
|
|
/// # #![allow(unstable)]
|
2014-11-17 21:46:33 +00:00
|
|
|
/// # use postgres::{Connection, SslMode};
|
2014-12-21 18:52:48 +00:00
|
|
|
/// # use std::thread::Thread;
|
2014-03-09 22:22:20 +00:00
|
|
|
/// # let url = "";
|
2014-11-17 21:46:33 +00:00
|
|
|
/// let conn = Connection::connect(url, &SslMode::None).unwrap();
|
2014-03-09 22:22:20 +00:00
|
|
|
/// let cancel_data = conn.cancel_data();
|
2014-12-21 18:52:48 +00:00
|
|
|
/// Thread::spawn(move || {
|
2014-11-19 19:36:47 +00:00
|
|
|
/// conn.execute("SOME EXPENSIVE QUERY", &[]).unwrap();
|
2015-01-09 19:20:43 +00:00
|
|
|
/// });
|
2014-03-09 22:22:20 +00:00
|
|
|
/// # let _ =
|
2014-11-17 21:46:33 +00:00
|
|
|
/// postgres::cancel_query(url, &SslMode::None, cancel_data);
|
2014-03-09 22:22:20 +00:00
|
|
|
/// ```
|
2014-11-01 23:19:02 +00:00
|
|
|
pub fn cancel_query<T>(params: T, ssl: &SslMode, data: CancelData)
|
2014-11-04 06:24:11 +00:00
|
|
|
-> result::Result<(), ConnectError> where T: IntoConnectParams {
|
2014-04-21 05:27:55 +00:00
|
|
|
let params = try!(params.into_connect_params());
|
2014-09-06 23:33:43 +00:00
|
|
|
let mut socket = try!(io::initialize_stream(¶ms, ssl));
|
2013-10-21 00:32:14 +00:00
|
|
|
|
2014-11-17 06:54:57 +00:00
|
|
|
try!(socket.write_message(&CancelRequest {
|
2013-10-21 00:32:14 +00:00
|
|
|
code: message::CANCEL_CODE,
|
|
|
|
process_id: data.process_id,
|
|
|
|
secret_key: data.secret_key
|
2014-02-07 06:59:33 +00:00
|
|
|
}));
|
2014-11-17 06:54:57 +00:00
|
|
|
try!(socket.flush());
|
2013-10-21 00:32:14 +00:00
|
|
|
|
2013-12-06 07:20:50 +00:00
|
|
|
Ok(())
|
2013-10-21 00:32:14 +00:00
|
|
|
}
|
|
|
|
|
2015-01-23 06:24:47 +00:00
|
|
|
#[derive(Clone)]
|
|
|
|
struct CachedStatement {
|
|
|
|
name: String,
|
|
|
|
param_types: Vec<Type>,
|
|
|
|
result_desc: Vec<ResultDescription>,
|
|
|
|
}
|
|
|
|
|
2014-11-01 23:21:47 +00:00
|
|
|
struct InnerConnection {
|
2014-04-21 05:27:55 +00:00
|
|
|
stream: BufferedStream<MaybeSslStream<InternalStream>>,
|
2015-01-09 18:50:54 +00:00
|
|
|
next_stmt_id: usize,
|
2014-12-09 07:43:01 +00:00
|
|
|
notice_handler: Box<NoticeHandler>,
|
2014-11-01 23:18:09 +00:00
|
|
|
notifications: RingBuf<Notification>,
|
2014-11-01 23:19:02 +00:00
|
|
|
cancel_data: CancelData,
|
2015-01-22 06:11:43 +00:00
|
|
|
unknown_types: HashMap<Oid, Type>,
|
2015-01-23 06:24:47 +00:00
|
|
|
cached_statements: HashMap<String, CachedStatement>,
|
2014-02-10 06:45:26 +00:00
|
|
|
desynchronized: bool,
|
2014-02-10 07:55:16 +00:00
|
|
|
finished: bool,
|
2014-05-19 02:34:01 +00:00
|
|
|
trans_depth: u32,
|
2014-04-08 03:52:41 +00:00
|
|
|
canary: u32,
|
2013-08-29 06:19:53 +00:00
|
|
|
}
|
|
|
|
|
2014-11-01 23:21:47 +00:00
|
|
|
impl Drop for InnerConnection {
|
2013-09-18 05:06:47 +00:00
|
|
|
fn drop(&mut self) {
|
2014-02-10 07:55:16 +00:00
|
|
|
if !self.finished {
|
2014-04-07 06:37:17 +00:00
|
|
|
let _ = self.finish_inner();
|
2014-02-10 07:55:16 +00:00
|
|
|
}
|
2013-08-29 06:19:53 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-11-01 23:21:47 +00:00
|
|
|
impl InnerConnection {
|
2014-11-18 02:20:48 +00:00
|
|
|
fn connect<T>(params: T, ssl: &SslMode) -> result::Result<InnerConnection, ConnectError>
|
2014-08-17 20:57:58 +00:00
|
|
|
where T: IntoConnectParams {
|
2014-04-21 05:27:55 +00:00
|
|
|
let params = try!(params.into_connect_params());
|
2014-05-04 19:21:52 +00:00
|
|
|
let stream = try!(io::initialize_stream(¶ms, ssl));
|
2014-04-19 09:04:37 +00:00
|
|
|
|
2014-12-02 05:28:58 +00:00
|
|
|
let ConnectParams { user, database, mut options, .. } = params;
|
2014-04-21 05:27:55 +00:00
|
|
|
|
2014-11-17 21:46:33 +00:00
|
|
|
let user = try!(user.ok_or(ConnectError::MissingUser));
|
2014-04-21 05:27:55 +00:00
|
|
|
|
2014-11-01 23:21:47 +00:00
|
|
|
let mut conn = InnerConnection {
|
2014-05-28 04:07:58 +00:00
|
|
|
stream: BufferedStream::new(stream),
|
|
|
|
next_stmt_id: 0,
|
2015-01-09 18:26:24 +00:00
|
|
|
notice_handler: Box::new(DefaultNoticeHandler),
|
2014-05-28 04:07:58 +00:00
|
|
|
notifications: RingBuf::new(),
|
2014-11-01 23:19:02 +00:00
|
|
|
cancel_data: CancelData { process_id: 0, secret_key: 0 },
|
2014-05-28 04:07:58 +00:00
|
|
|
unknown_types: HashMap::new(),
|
2015-01-23 06:24:47 +00:00
|
|
|
cached_statements: HashMap::new(),
|
2014-05-28 04:07:58 +00:00
|
|
|
desynchronized: false,
|
|
|
|
finished: false,
|
|
|
|
trans_depth: 0,
|
|
|
|
canary: CANARY,
|
|
|
|
};
|
|
|
|
|
2014-12-23 17:10:16 +00:00
|
|
|
options.push(("client_encoding".to_owned(), "UTF8".to_owned()));
|
2013-09-09 04:33:41 +00:00
|
|
|
// Postgres uses the value of TimeZone as the time zone for TIMESTAMP
|
|
|
|
// WITH TIME ZONE values. Timespec converts to GMT internally.
|
2014-12-23 17:10:16 +00:00
|
|
|
options.push(("TimeZone".to_owned(), "GMT".to_owned()));
|
2013-08-27 05:06:53 +00:00
|
|
|
// We have to clone here since we need the user again for auth
|
2014-12-23 17:10:16 +00:00
|
|
|
options.push(("user".to_owned(), user.user.clone()));
|
2014-12-02 05:28:58 +00:00
|
|
|
if let Some(database) = database {
|
2014-12-23 17:10:16 +00:00
|
|
|
options.push(("database".to_owned(), database));
|
2014-04-21 05:27:55 +00:00
|
|
|
}
|
2014-04-18 21:29:51 +00:00
|
|
|
|
2014-11-19 17:58:30 +00:00
|
|
|
try!(conn.write_messages(&[StartupMessage {
|
2013-09-09 05:40:08 +00:00
|
|
|
version: message::PROTOCOL_VERSION,
|
2014-12-03 05:44:34 +00:00
|
|
|
parameters: &*options
|
2014-02-07 04:58:47 +00:00
|
|
|
}]));
|
2013-08-26 05:08:37 +00:00
|
|
|
|
2014-07-26 00:24:10 +00:00
|
|
|
try!(conn.handle_auth(user));
|
2013-08-04 02:17:32 +00:00
|
|
|
|
2013-08-22 05:52:15 +00:00
|
|
|
loop {
|
2014-11-17 06:54:57 +00:00
|
|
|
match try!(conn.read_message()) {
|
2013-10-21 00:32:14 +00:00
|
|
|
BackendKeyData { process_id, secret_key } => {
|
|
|
|
conn.cancel_data.process_id = process_id;
|
|
|
|
conn.cancel_data.secret_key = secret_key;
|
|
|
|
}
|
2013-11-29 18:30:03 +00:00
|
|
|
ReadyForQuery { .. } => break,
|
2014-11-04 06:24:11 +00:00
|
|
|
ErrorResponse { fields } => return DbError::new_connect(fields),
|
2014-11-21 05:47:13 +00:00
|
|
|
_ => return Err(ConnectError::BadResponse),
|
2013-09-09 03:35:24 +00:00
|
|
|
}
|
2013-08-05 00:48:48 +00:00
|
|
|
}
|
2013-08-23 05:24:14 +00:00
|
|
|
|
2015-01-22 08:04:58 +00:00
|
|
|
try!(conn.setup_typeinfo_query());
|
|
|
|
|
|
|
|
Ok(conn)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn setup_typeinfo_query(&mut self) -> result::Result<(), ConnectError> {
|
|
|
|
match self.raw_prepare(TYPEINFO_QUERY,
|
|
|
|
"SELECT t.typname, t.typelem, r.rngsubtype \
|
|
|
|
FROM pg_catalog.pg_type t \
|
|
|
|
LEFT OUTER JOIN pg_catalog.pg_range r \
|
|
|
|
ON r.rngtypid = t.oid \
|
|
|
|
WHERE t.oid = $1") {
|
|
|
|
Ok(..) => return Ok(()),
|
2014-12-15 00:43:17 +00:00
|
|
|
Err(Error::IoError(e)) => return Err(ConnectError::IoError(e)),
|
2015-01-22 08:04:58 +00:00
|
|
|
// Range types weren't added until Postgres 9.2, so pg_range may not exist
|
|
|
|
Err(Error::DbError(DbError { code: SqlState::UndefinedTable, .. })) => {}
|
2014-12-15 00:43:17 +00:00
|
|
|
Err(Error::DbError(e)) => return Err(ConnectError::DbError(e)),
|
|
|
|
_ => unreachable!()
|
|
|
|
}
|
|
|
|
|
2015-01-22 08:04:58 +00:00
|
|
|
match self.raw_prepare(TYPEINFO_QUERY,
|
|
|
|
"SELECT typname, typelem, NULL::OID FROM pg_catalog.pg_type \
|
|
|
|
WHERE oid = $1") {
|
|
|
|
Ok(..) => Ok(()),
|
|
|
|
Err(Error::IoError(e)) => Err(ConnectError::IoError(e)),
|
|
|
|
Err(Error::DbError(e)) => Err(ConnectError::DbError(e)),
|
|
|
|
_ => unreachable!()
|
|
|
|
}
|
2013-08-05 00:48:48 +00:00
|
|
|
}
|
|
|
|
|
2014-08-20 04:49:27 +00:00
|
|
|
fn write_messages(&mut self, messages: &[FrontendMessage]) -> IoResult<()> {
|
2014-07-26 03:15:24 +00:00
|
|
|
debug_assert!(!self.desynchronized);
|
2013-11-10 04:58:38 +00:00
|
|
|
for message in messages.iter() {
|
2014-07-10 19:35:57 +00:00
|
|
|
try_desync!(self, self.stream.write_message(message));
|
2013-07-25 07:10:18 +00:00
|
|
|
}
|
2014-07-10 19:35:57 +00:00
|
|
|
Ok(try_desync!(self, self.stream.flush()))
|
2013-08-22 06:41:26 +00:00
|
|
|
}
|
2013-08-04 02:17:32 +00:00
|
|
|
|
2014-12-03 04:34:46 +00:00
|
|
|
fn read_one_message(&mut self) -> IoResult<Option<BackendMessage>> {
|
2014-07-26 03:15:24 +00:00
|
|
|
debug_assert!(!self.desynchronized);
|
2014-12-03 04:34:46 +00:00
|
|
|
match try_desync!(self, self.stream.read_message()) {
|
|
|
|
NoticeResponse { fields } => {
|
|
|
|
if let Ok(err) = DbError::new_raw(fields) {
|
|
|
|
self.notice_handler.handle(err);
|
2014-11-26 02:30:28 +00:00
|
|
|
}
|
2014-12-03 04:34:46 +00:00
|
|
|
Ok(None)
|
|
|
|
}
|
|
|
|
ParameterStatus { parameter, value } => {
|
|
|
|
debug!("Parameter {} = {}", parameter, value);
|
|
|
|
Ok(None)
|
|
|
|
}
|
|
|
|
val => Ok(Some(val))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn read_message_with_notification(&mut self) -> IoResult<BackendMessage> {
|
|
|
|
loop {
|
|
|
|
if let Some(msg) = try!(self.read_one_message()) {
|
|
|
|
return Ok(msg);
|
2014-11-26 02:30:28 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn read_message(&mut self) -> IoResult<BackendMessage> {
|
|
|
|
loop {
|
|
|
|
match try!(self.read_message_with_notification()) {
|
2014-08-16 02:50:11 +00:00
|
|
|
NotificationResponse { pid, channel, payload } => {
|
2014-11-07 16:54:10 +00:00
|
|
|
self.notifications.push_back(Notification {
|
2013-10-15 05:41:03 +00:00
|
|
|
pid: pid,
|
|
|
|
channel: channel,
|
|
|
|
payload: payload
|
2014-08-16 02:50:11 +00:00
|
|
|
})
|
|
|
|
}
|
2014-02-10 06:45:26 +00:00
|
|
|
val => return Ok(val)
|
2013-09-09 03:35:24 +00:00
|
|
|
}
|
2013-08-04 05:21:16 +00:00
|
|
|
}
|
2013-08-22 06:41:26 +00:00
|
|
|
}
|
|
|
|
|
2014-11-04 06:24:11 +00:00
|
|
|
fn handle_auth(&mut self, user: UserInfo) -> result::Result<(), ConnectError> {
|
2014-11-17 06:54:57 +00:00
|
|
|
match try!(self.read_message()) {
|
2014-02-07 04:58:47 +00:00
|
|
|
AuthenticationOk => return Ok(()),
|
2013-08-27 04:19:24 +00:00
|
|
|
AuthenticationCleartextPassword => {
|
2014-11-17 21:46:33 +00:00
|
|
|
let pass = try!(user.password.ok_or(ConnectError::MissingPassword));
|
2014-11-19 17:58:30 +00:00
|
|
|
try!(self.write_messages(&[PasswordMessage {
|
2014-12-03 05:44:34 +00:00
|
|
|
password: &*pass,
|
2014-04-01 06:51:42 +00:00
|
|
|
}]));
|
2013-09-09 03:35:24 +00:00
|
|
|
}
|
2013-11-06 06:04:12 +00:00
|
|
|
AuthenticationMD5Password { salt } => {
|
2014-11-17 21:46:33 +00:00
|
|
|
let pass = try!(user.password.ok_or(ConnectError::MissingPassword));
|
2014-11-28 20:24:34 +00:00
|
|
|
let mut hasher = Hasher::new(HashType::MD5);
|
2014-04-22 05:53:14 +00:00
|
|
|
hasher.update(pass.as_bytes());
|
2014-07-26 00:24:10 +00:00
|
|
|
hasher.update(user.user.as_bytes());
|
2014-12-03 05:44:34 +00:00
|
|
|
let output = hasher.finalize().to_hex();
|
2014-11-28 20:24:34 +00:00
|
|
|
let mut hasher = Hasher::new(HashType::MD5);
|
2014-01-03 01:13:52 +00:00
|
|
|
hasher.update(output.as_bytes());
|
2014-11-19 17:58:30 +00:00
|
|
|
hasher.update(&salt);
|
2014-12-03 05:44:34 +00:00
|
|
|
let output = format!("md5{}", hasher.finalize().to_hex());
|
2014-11-19 17:58:30 +00:00
|
|
|
try!(self.write_messages(&[PasswordMessage {
|
2014-12-03 05:44:34 +00:00
|
|
|
password: &*output
|
2014-04-01 06:51:42 +00:00
|
|
|
}]));
|
2013-11-06 06:04:12 +00:00
|
|
|
}
|
|
|
|
AuthenticationKerberosV5
|
2013-09-12 05:02:32 +00:00
|
|
|
| AuthenticationSCMCredential
|
|
|
|
| AuthenticationGSS
|
2014-11-17 21:46:33 +00:00
|
|
|
| AuthenticationSSPI => return Err(ConnectError::UnsupportedAuthentication),
|
2014-11-04 06:24:11 +00:00
|
|
|
ErrorResponse { fields } => return DbError::new_connect(fields),
|
2014-11-29 01:35:37 +00:00
|
|
|
_ => return Err(ConnectError::BadResponse)
|
2013-09-09 03:35:24 +00:00
|
|
|
}
|
2013-08-27 04:19:24 +00:00
|
|
|
|
2014-11-17 06:54:57 +00:00
|
|
|
match try!(self.read_message()) {
|
2014-02-07 04:58:47 +00:00
|
|
|
AuthenticationOk => Ok(()),
|
2014-11-04 06:24:11 +00:00
|
|
|
ErrorResponse { fields } => return DbError::new_connect(fields),
|
2014-11-29 01:35:37 +00:00
|
|
|
_ => return Err(ConnectError::BadResponse)
|
2013-09-09 03:35:24 +00:00
|
|
|
}
|
2013-08-26 05:08:37 +00:00
|
|
|
}
|
|
|
|
|
2014-12-09 07:43:01 +00:00
|
|
|
fn set_notice_handler(&mut self, handler: Box<NoticeHandler>) -> Box<NoticeHandler> {
|
2014-02-11 03:20:53 +00:00
|
|
|
mem::replace(&mut self.notice_handler, handler)
|
2013-08-27 05:06:53 +00:00
|
|
|
}
|
|
|
|
|
2014-12-02 05:28:58 +00:00
|
|
|
fn raw_prepare(&mut self, stmt_name: &str, query: &str)
|
|
|
|
-> Result<(Vec<Type>, Vec<ResultDescription>)> {
|
2014-11-19 17:58:30 +00:00
|
|
|
try!(self.write_messages(&[
|
2013-11-10 04:58:38 +00:00
|
|
|
Parse {
|
2014-12-03 06:56:56 +00:00
|
|
|
name: stmt_name,
|
2013-09-02 17:27:09 +00:00
|
|
|
query: query,
|
2014-11-19 17:58:30 +00:00
|
|
|
param_types: &[]
|
2013-09-02 17:27:09 +00:00
|
|
|
},
|
2013-11-10 04:58:38 +00:00
|
|
|
Describe {
|
2014-09-06 23:33:43 +00:00
|
|
|
variant: b'S',
|
2014-12-03 06:56:56 +00:00
|
|
|
name: stmt_name,
|
2013-09-02 17:27:09 +00:00
|
|
|
},
|
2014-02-07 04:58:47 +00:00
|
|
|
Sync]));
|
2013-08-22 06:41:26 +00:00
|
|
|
|
2014-11-17 06:54:57 +00:00
|
|
|
match try!(self.read_message()) {
|
2013-10-25 05:30:34 +00:00
|
|
|
ParseComplete => {}
|
2013-08-29 05:33:27 +00:00
|
|
|
ErrorResponse { fields } => {
|
2014-02-22 07:18:39 +00:00
|
|
|
try!(self.wait_for_ready());
|
2014-11-04 06:24:11 +00:00
|
|
|
return DbError::new(fields);
|
2013-09-04 03:07:10 +00:00
|
|
|
}
|
2014-07-10 19:35:57 +00:00
|
|
|
_ => bad_response!(self),
|
2013-09-09 03:35:24 +00:00
|
|
|
}
|
2013-08-22 06:41:26 +00:00
|
|
|
|
2015-01-22 06:11:43 +00:00
|
|
|
let raw_param_types = match try!(self.read_message()) {
|
|
|
|
ParameterDescription { types } => types,
|
2014-07-10 19:35:57 +00:00
|
|
|
_ => bad_response!(self),
|
2013-09-09 03:35:24 +00:00
|
|
|
};
|
2013-08-22 06:41:26 +00:00
|
|
|
|
2015-01-22 06:11:43 +00:00
|
|
|
let raw_result_desc = match try!(self.read_message()) {
|
|
|
|
RowDescription { descriptions } => descriptions,
|
2014-05-26 18:41:18 +00:00
|
|
|
NoData => vec![],
|
2014-07-10 19:35:57 +00:00
|
|
|
_ => bad_response!(self)
|
2013-09-09 03:35:24 +00:00
|
|
|
};
|
2013-08-17 22:09:26 +00:00
|
|
|
|
2014-02-22 07:18:39 +00:00
|
|
|
try!(self.wait_for_ready());
|
2013-08-22 06:41:26 +00:00
|
|
|
|
2015-01-22 06:11:43 +00:00
|
|
|
let mut param_types = vec![];
|
|
|
|
for oid in raw_param_types.into_iter() {
|
|
|
|
param_types.push(try!(self.get_type(oid)));
|
|
|
|
}
|
|
|
|
|
|
|
|
let mut result_desc = vec![];
|
|
|
|
for RowDescriptionEntry { name, type_oid, .. } in raw_result_desc.into_iter() {
|
|
|
|
result_desc.push(ResultDescription {
|
|
|
|
name: name,
|
|
|
|
ty: try!(self.get_type(type_oid)),
|
|
|
|
});
|
2014-12-02 06:24:31 +00:00
|
|
|
}
|
2013-12-04 08:18:28 +00:00
|
|
|
|
2014-12-02 05:28:58 +00:00
|
|
|
Ok((param_types, result_desc))
|
|
|
|
}
|
|
|
|
|
|
|
|
fn make_stmt_name(&mut self) -> String {
|
|
|
|
let stmt_name = format!("s{}", self.next_stmt_id);
|
|
|
|
self.next_stmt_id += 1;
|
|
|
|
stmt_name
|
2014-09-30 05:56:43 +00:00
|
|
|
}
|
|
|
|
|
2014-11-03 00:48:38 +00:00
|
|
|
fn prepare<'a>(&mut self, query: &str, conn: &'a Connection) -> Result<Statement<'a>> {
|
2014-12-02 05:28:58 +00:00
|
|
|
let stmt_name = self.make_stmt_name();
|
|
|
|
let (param_types, result_desc) = try!(self.raw_prepare(&*stmt_name, query));
|
2014-11-01 23:24:24 +00:00
|
|
|
Ok(Statement {
|
2014-03-26 04:01:38 +00:00
|
|
|
conn: conn,
|
|
|
|
name: stmt_name,
|
|
|
|
param_types: param_types,
|
|
|
|
result_desc: result_desc,
|
|
|
|
next_portal_id: Cell::new(0),
|
2014-04-26 06:14:55 +00:00
|
|
|
finished: false,
|
2014-03-26 04:01:38 +00:00
|
|
|
})
|
2013-08-22 06:41:26 +00:00
|
|
|
}
|
|
|
|
|
2015-01-23 06:24:47 +00:00
|
|
|
fn prepare_cached<'a>(&mut self, query: &str, conn: &'a Connection) -> Result<Statement<'a>> {
|
|
|
|
let stmt = self.cached_statements.get(query).map(|e| e.clone());
|
|
|
|
|
|
|
|
let CachedStatement { name, param_types, result_desc } = match stmt {
|
|
|
|
Some(stmt) => stmt,
|
|
|
|
None => {
|
|
|
|
let stmt_name = self.make_stmt_name();
|
|
|
|
let (param_types, result_desc) = try!(self.raw_prepare(&*stmt_name, query));
|
|
|
|
let stmt = CachedStatement {
|
|
|
|
name: stmt_name,
|
|
|
|
param_types: param_types,
|
|
|
|
result_desc: result_desc,
|
|
|
|
};
|
|
|
|
self.cached_statements.insert(query.to_owned(), stmt.clone());
|
|
|
|
stmt
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
Ok(Statement {
|
|
|
|
conn: conn,
|
|
|
|
name: name,
|
|
|
|
param_types: param_types,
|
|
|
|
result_desc: result_desc,
|
|
|
|
next_portal_id: Cell::new(0),
|
|
|
|
finished: true, // << !
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2014-11-01 23:21:47 +00:00
|
|
|
fn prepare_copy_in<'a>(&mut self, table: &str, rows: &[&str], conn: &'a Connection)
|
2014-11-01 23:26:03 +00:00
|
|
|
-> Result<CopyInStatement<'a>> {
|
2014-11-20 04:54:32 +00:00
|
|
|
let mut query = vec![];
|
2014-11-20 18:54:40 +00:00
|
|
|
let _ = write!(&mut query, "SELECT ");
|
2014-12-02 06:24:31 +00:00
|
|
|
let _ = util::comma_join(&mut query, rows.iter().cloned());
|
2014-11-20 18:54:40 +00:00
|
|
|
let _ = write!(&mut query, " FROM {}", table);
|
2014-11-20 04:54:32 +00:00
|
|
|
let query = String::from_utf8(query).unwrap();
|
2014-12-03 05:44:34 +00:00
|
|
|
let (_, result_desc) = try!(self.raw_prepare("", &*query));
|
2014-12-02 05:28:58 +00:00
|
|
|
let column_types = result_desc.into_iter().map(|desc| desc.ty).collect();
|
2014-09-30 05:56:43 +00:00
|
|
|
|
2014-11-20 04:54:32 +00:00
|
|
|
let mut query = vec![];
|
2014-11-20 18:54:40 +00:00
|
|
|
let _ = write!(&mut query, "COPY {} (", table);
|
2014-12-02 06:24:31 +00:00
|
|
|
let _ = util::comma_join(&mut query, rows.iter().cloned());
|
2014-11-20 18:54:40 +00:00
|
|
|
let _ = write!(&mut query, ") FROM STDIN WITH (FORMAT binary)");
|
2014-11-20 04:54:32 +00:00
|
|
|
let query = String::from_utf8(query).unwrap();
|
2014-12-02 05:28:58 +00:00
|
|
|
let stmt_name = self.make_stmt_name();
|
2014-12-03 05:44:34 +00:00
|
|
|
try!(self.raw_prepare(&*stmt_name, &*query));
|
2014-09-30 05:56:43 +00:00
|
|
|
|
2014-11-01 23:26:03 +00:00
|
|
|
Ok(CopyInStatement {
|
2014-09-30 05:56:43 +00:00
|
|
|
conn: conn,
|
|
|
|
name: stmt_name,
|
|
|
|
column_types: column_types,
|
|
|
|
finished: false,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2014-11-28 23:01:01 +00:00
|
|
|
fn close_statement(&mut self, name: &str, type_: u8) -> Result<()> {
|
2014-11-19 17:58:30 +00:00
|
|
|
try!(self.write_messages(&[
|
2014-09-30 05:56:43 +00:00
|
|
|
Close {
|
2014-11-28 23:01:01 +00:00
|
|
|
variant: type_,
|
|
|
|
name: name,
|
2014-09-30 05:56:43 +00:00
|
|
|
},
|
|
|
|
Sync]));
|
2014-11-28 23:01:01 +00:00
|
|
|
let resp = match try!(self.read_message()) {
|
|
|
|
CloseComplete => Ok(()),
|
2014-11-28 23:54:37 +00:00
|
|
|
ErrorResponse { fields } => DbError::new(fields),
|
2014-11-29 01:35:37 +00:00
|
|
|
_ => bad_response!(self)
|
2014-11-28 23:01:01 +00:00
|
|
|
};
|
|
|
|
try!(self.wait_for_ready());
|
|
|
|
resp
|
2014-09-30 05:56:43 +00:00
|
|
|
}
|
|
|
|
|
2015-01-22 06:11:43 +00:00
|
|
|
fn get_type(&mut self, oid: Oid) -> Result<Type> {
|
|
|
|
if let Some(ty) = Type::from_oid(oid) {
|
|
|
|
return Ok(ty);
|
2014-03-30 23:19:04 +00:00
|
|
|
}
|
2014-08-16 02:50:11 +00:00
|
|
|
|
2015-01-22 06:11:43 +00:00
|
|
|
if let Some(ty) = self.unknown_types.get(&oid) {
|
|
|
|
return Ok(ty.clone());
|
2013-12-04 08:18:28 +00:00
|
|
|
}
|
2015-01-22 06:11:43 +00:00
|
|
|
|
2014-12-15 00:43:17 +00:00
|
|
|
// Ew @ doing this manually :(
|
|
|
|
try!(self.write_messages(&[
|
|
|
|
Bind {
|
|
|
|
portal: "",
|
2015-01-22 08:04:58 +00:00
|
|
|
statement: TYPEINFO_QUERY,
|
2014-12-15 00:43:17 +00:00
|
|
|
formats: &[1],
|
|
|
|
values: &[try!(oid.to_sql(&Type::Oid))],
|
|
|
|
result_formats: &[1]
|
|
|
|
},
|
|
|
|
Execute {
|
|
|
|
portal: "",
|
|
|
|
max_rows: 0,
|
|
|
|
},
|
|
|
|
Sync]));
|
|
|
|
match try!(self.read_message()) {
|
|
|
|
BindComplete => {}
|
|
|
|
ErrorResponse { fields } => {
|
|
|
|
try!(self.wait_for_ready());
|
|
|
|
return DbError::new(fields);
|
|
|
|
}
|
|
|
|
_ => bad_response!(self)
|
|
|
|
}
|
2015-01-22 08:04:58 +00:00
|
|
|
let (name, elem_oid, rngsubtype): (String, Oid, Option<Oid>) =
|
|
|
|
match try!(self.read_message()) {
|
2015-01-22 06:11:43 +00:00
|
|
|
DataRow { row } => {
|
|
|
|
(try!(FromSql::from_sql(&Type::Name, row[0].as_ref().map(|r| &**r))),
|
2015-01-22 08:04:58 +00:00
|
|
|
try!(FromSql::from_sql(&Type::Oid, row[1].as_ref().map(|r| &**r))),
|
|
|
|
try!(FromSql::from_sql(&Type::Oid, row[2].as_ref().map(|r| &**r))))
|
2015-01-22 06:11:43 +00:00
|
|
|
}
|
2014-12-15 00:43:17 +00:00
|
|
|
ErrorResponse { fields } => {
|
|
|
|
try!(self.wait_for_ready());
|
|
|
|
return DbError::new(fields);
|
|
|
|
}
|
|
|
|
_ => bad_response!(self)
|
|
|
|
};
|
|
|
|
match try!(self.read_message()) {
|
|
|
|
CommandComplete { .. } => {}
|
|
|
|
ErrorResponse { fields } => {
|
|
|
|
try!(self.wait_for_ready());
|
|
|
|
return DbError::new(fields);
|
|
|
|
}
|
|
|
|
_ => bad_response!(self)
|
|
|
|
}
|
|
|
|
try!(self.wait_for_ready());
|
2015-01-22 06:11:43 +00:00
|
|
|
|
2015-01-22 08:04:58 +00:00
|
|
|
let elem_oid = if elem_oid != 0 {
|
|
|
|
Some(elem_oid)
|
2015-01-22 06:11:43 +00:00
|
|
|
} else {
|
2015-01-22 08:04:58 +00:00
|
|
|
rngsubtype
|
|
|
|
};
|
|
|
|
let element_type = match elem_oid {
|
|
|
|
Some(oid) => Some(Box::new(try!(self.get_type(oid)))),
|
|
|
|
None => None,
|
2015-01-22 06:11:43 +00:00
|
|
|
};
|
|
|
|
let type_ = Type::Unknown {
|
|
|
|
oid: oid,
|
|
|
|
name: name,
|
|
|
|
element_type: element_type,
|
|
|
|
};
|
|
|
|
self.unknown_types.insert(oid, type_.clone());
|
|
|
|
Ok(type_)
|
2013-12-04 08:18:28 +00:00
|
|
|
}
|
|
|
|
|
2014-03-30 23:19:04 +00:00
|
|
|
fn is_desynchronized(&self) -> bool {
|
|
|
|
self.desynchronized
|
|
|
|
}
|
|
|
|
|
2014-04-08 03:52:41 +00:00
|
|
|
fn canary(&self) -> u32 {
|
|
|
|
self.canary
|
|
|
|
}
|
|
|
|
|
2014-11-01 23:12:05 +00:00
|
|
|
fn wait_for_ready(&mut self) -> Result<()> {
|
2014-11-17 06:54:57 +00:00
|
|
|
match try!(self.read_message()) {
|
2014-02-07 04:58:47 +00:00
|
|
|
ReadyForQuery { .. } => Ok(()),
|
2014-07-10 19:35:57 +00:00
|
|
|
_ => bad_response!(self)
|
2013-09-20 04:06:45 +00:00
|
|
|
}
|
|
|
|
}
|
2013-12-04 07:48:46 +00:00
|
|
|
|
2014-11-01 23:12:05 +00:00
|
|
|
fn quick_query(&mut self, query: &str) -> Result<Vec<Vec<Option<String>>>> {
|
2014-02-10 07:55:16 +00:00
|
|
|
check_desync!(self);
|
2014-11-19 17:58:30 +00:00
|
|
|
try!(self.write_messages(&[Query { query: query }]));
|
2013-12-04 07:48:46 +00:00
|
|
|
|
2014-05-26 18:41:18 +00:00
|
|
|
let mut result = vec![];
|
2013-12-04 07:48:46 +00:00
|
|
|
loop {
|
2014-11-17 06:54:57 +00:00
|
|
|
match try!(self.read_message()) {
|
2013-12-04 07:48:46 +00:00
|
|
|
ReadyForQuery { .. } => break,
|
2014-04-26 21:46:38 +00:00
|
|
|
DataRow { row } => {
|
2014-09-18 05:57:23 +00:00
|
|
|
result.push(row.into_iter().map(|opt| {
|
2014-12-23 17:10:16 +00:00
|
|
|
opt.map(|b| String::from_utf8_lossy(&*b).into_owned())
|
2014-05-16 02:27:19 +00:00
|
|
|
}).collect());
|
2014-04-26 21:46:38 +00:00
|
|
|
}
|
2014-10-06 00:31:25 +00:00
|
|
|
CopyInResponse { .. } => {
|
2014-11-19 17:58:30 +00:00
|
|
|
try!(self.write_messages(&[
|
2014-10-06 00:31:25 +00:00
|
|
|
CopyFail {
|
|
|
|
message: "COPY queries cannot be directly executed",
|
|
|
|
},
|
|
|
|
Sync]));
|
|
|
|
}
|
2014-02-12 07:09:27 +00:00
|
|
|
ErrorResponse { fields } => {
|
2014-02-22 07:18:39 +00:00
|
|
|
try!(self.wait_for_ready());
|
2014-11-04 06:24:11 +00:00
|
|
|
return DbError::new(fields);
|
2014-02-12 07:09:27 +00:00
|
|
|
}
|
2013-12-04 07:48:46 +00:00
|
|
|
_ => {}
|
|
|
|
}
|
|
|
|
}
|
2014-02-07 04:58:47 +00:00
|
|
|
Ok(result)
|
2013-12-04 07:48:46 +00:00
|
|
|
}
|
2014-02-10 07:55:16 +00:00
|
|
|
|
2014-11-01 23:12:05 +00:00
|
|
|
fn finish_inner(&mut self) -> Result<()> {
|
2014-02-10 07:55:16 +00:00
|
|
|
check_desync!(self);
|
2014-04-08 03:52:41 +00:00
|
|
|
self.canary = 0;
|
2014-11-19 17:58:30 +00:00
|
|
|
try!(self.write_messages(&[Terminate]));
|
2014-04-26 06:14:55 +00:00
|
|
|
Ok(())
|
2014-02-10 07:55:16 +00:00
|
|
|
}
|
2013-09-20 04:06:45 +00:00
|
|
|
}
|
|
|
|
|
2013-09-30 02:12:20 +00:00
|
|
|
/// A connection to a Postgres database.
|
2014-11-01 23:21:47 +00:00
|
|
|
pub struct Connection {
|
|
|
|
conn: RefCell<InnerConnection>
|
2013-10-01 07:40:46 +00:00
|
|
|
}
|
2013-09-20 04:06:45 +00:00
|
|
|
|
2015-01-10 04:48:47 +00:00
|
|
|
impl fmt::Show for Connection {
|
|
|
|
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
|
|
|
let conn = self.conn.borrow();
|
|
|
|
write!(fmt,
|
|
|
|
"Connection {{ cancel_data: {:?}, notifications: {:?}, transaction_depth: {:?}, \
|
|
|
|
desynchronized: {:?} }}", conn.cancel_data, conn.notifications.len(),
|
|
|
|
conn.trans_depth, conn.desynchronized)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-11-01 23:21:47 +00:00
|
|
|
impl Connection {
|
2014-03-28 04:08:22 +00:00
|
|
|
/// Creates a new connection to a Postgres database.
|
2013-09-30 02:12:20 +00:00
|
|
|
///
|
2014-04-21 05:27:55 +00:00
|
|
|
/// Most applications can use a URL string in the normal format:
|
2013-09-30 02:12:20 +00:00
|
|
|
///
|
2014-03-09 06:01:24 +00:00
|
|
|
/// ```notrust
|
2014-04-21 05:27:55 +00:00
|
|
|
/// postgresql://user[:password]@host[:port][/database][?param1=val1[[¶m2=val2]...]]
|
2013-09-30 02:12:20 +00:00
|
|
|
/// ```
|
|
|
|
///
|
|
|
|
/// The password may be omitted if not required. The default Postgres port
|
|
|
|
/// (5432) is used if none is specified. The database name defaults to the
|
|
|
|
/// username if not specified.
|
2014-03-09 22:22:20 +00:00
|
|
|
///
|
2014-04-21 05:27:55 +00:00
|
|
|
/// To connect to the server via Unix sockets, `host` should be set to the
|
2014-04-21 05:53:54 +00:00
|
|
|
/// absolute path of the directory containing the socket file. Since `/` is
|
|
|
|
/// a reserved character in URLs, the path should be URL encoded. If the
|
2014-11-01 23:15:30 +00:00
|
|
|
/// path contains non-UTF 8 characters, a `ConnectParams` struct
|
2014-08-19 05:02:16 +00:00
|
|
|
/// should be created manually and passed in. Note that Postgres does not
|
|
|
|
/// support SSL over Unix sockets.
|
2014-04-21 05:27:55 +00:00
|
|
|
///
|
2014-07-30 02:48:56 +00:00
|
|
|
/// ## Examples
|
2014-03-09 22:22:20 +00:00
|
|
|
///
|
2014-03-10 17:06:40 +00:00
|
|
|
/// ```rust,no_run
|
2015-01-01 05:40:21 +00:00
|
|
|
/// # use postgres::{Connection, SslMode, ConnectError};
|
|
|
|
/// # fn f() -> Result<(), ConnectError> {
|
2014-04-21 05:27:55 +00:00
|
|
|
/// let url = "postgresql://postgres:hunter2@localhost:2994/foodb";
|
2014-11-17 21:46:33 +00:00
|
|
|
/// let conn = try!(Connection::connect(url, &SslMode::None));
|
2014-08-20 04:49:27 +00:00
|
|
|
/// # Ok(()) };
|
2014-03-09 22:22:20 +00:00
|
|
|
/// ```
|
2014-04-18 21:29:51 +00:00
|
|
|
///
|
2014-04-19 18:10:27 +00:00
|
|
|
/// ```rust,no_run
|
2015-01-01 05:40:21 +00:00
|
|
|
/// # use postgres::{Connection, SslMode, ConnectError};
|
|
|
|
/// # fn f() -> Result<(), ConnectError> {
|
2014-04-22 05:53:14 +00:00
|
|
|
/// let url = "postgresql://postgres@%2Frun%2Fpostgres";
|
2014-11-17 21:46:33 +00:00
|
|
|
/// let conn = try!(Connection::connect(url, &SslMode::None));
|
2014-08-20 04:49:27 +00:00
|
|
|
/// # Ok(()) };
|
2014-04-18 21:29:51 +00:00
|
|
|
/// ```
|
2014-04-22 05:53:14 +00:00
|
|
|
///
|
|
|
|
/// ```rust,no_run
|
2015-01-09 19:20:43 +00:00
|
|
|
/// # #![allow(unstable)]
|
2015-01-01 05:40:21 +00:00
|
|
|
/// # use postgres::{Connection, UserInfo, ConnectParams, SslMode, ConnectTarget, ConnectError};
|
|
|
|
/// # fn f() -> Result<(), ConnectError> {
|
2014-04-22 05:53:14 +00:00
|
|
|
/// # let some_crazy_path = Path::new("");
|
2014-11-01 23:15:30 +00:00
|
|
|
/// let params = ConnectParams {
|
2014-11-04 05:41:35 +00:00
|
|
|
/// target: ConnectTarget::Unix(some_crazy_path),
|
2014-04-22 05:53:14 +00:00
|
|
|
/// port: None,
|
2014-11-01 23:14:08 +00:00
|
|
|
/// user: Some(UserInfo {
|
2014-12-23 17:10:16 +00:00
|
|
|
/// user: "postgres".to_string(),
|
2014-07-26 00:24:10 +00:00
|
|
|
/// password: None
|
|
|
|
/// }),
|
2014-04-22 05:53:14 +00:00
|
|
|
/// database: None,
|
2014-05-26 18:41:18 +00:00
|
|
|
/// options: vec![],
|
2014-04-22 05:53:14 +00:00
|
|
|
/// };
|
2014-11-17 21:46:33 +00:00
|
|
|
/// let conn = try!(Connection::connect(params, &SslMode::None));
|
2014-08-20 04:49:27 +00:00
|
|
|
/// # Ok(()) };
|
2014-04-22 05:53:14 +00:00
|
|
|
/// ```
|
2014-11-04 06:24:11 +00:00
|
|
|
pub fn connect<T>(params: T, ssl: &SslMode) -> result::Result<Connection, ConnectError>
|
2014-08-17 20:57:58 +00:00
|
|
|
where T: IntoConnectParams {
|
2014-11-01 23:21:47 +00:00
|
|
|
InnerConnection::connect(params, ssl).map(|conn| {
|
|
|
|
Connection { conn: RefCell::new(conn) }
|
2014-08-19 05:02:16 +00:00
|
|
|
})
|
2014-04-18 21:29:51 +00:00
|
|
|
}
|
|
|
|
|
2013-09-30 02:12:20 +00:00
|
|
|
/// Sets the notice handler for the connection, returning the old handler.
|
2014-12-09 07:43:01 +00:00
|
|
|
pub fn set_notice_handler(&self, handler: Box<NoticeHandler>) -> Box<NoticeHandler> {
|
2014-03-19 04:00:06 +00:00
|
|
|
self.conn.borrow_mut().set_notice_handler(handler)
|
2013-09-20 04:06:45 +00:00
|
|
|
}
|
|
|
|
|
2013-10-15 05:41:03 +00:00
|
|
|
/// Returns an iterator over asynchronous notification messages.
|
|
|
|
///
|
|
|
|
/// Use the `LISTEN` command to register this connection for notifications.
|
2014-11-01 23:18:09 +00:00
|
|
|
pub fn notifications<'a>(&'a self) -> Notifications<'a> {
|
|
|
|
Notifications { conn: self }
|
2013-10-15 05:41:03 +00:00
|
|
|
}
|
|
|
|
|
2014-03-28 04:08:22 +00:00
|
|
|
/// Creates a new prepared statement.
|
2013-09-30 02:12:20 +00:00
|
|
|
///
|
|
|
|
/// A statement may contain parameters, specified by `$n` where `n` is the
|
|
|
|
/// index of the parameter in the list provided at execution time,
|
|
|
|
/// 1-indexed.
|
|
|
|
///
|
|
|
|
/// The statement is associated with the connection that created it and may
|
|
|
|
/// not outlive that connection.
|
2014-03-09 22:22:20 +00:00
|
|
|
///
|
2014-07-30 02:48:56 +00:00
|
|
|
/// ## Example
|
2014-03-09 22:22:20 +00:00
|
|
|
///
|
2014-03-10 17:06:40 +00:00
|
|
|
/// ```rust,no_run
|
2014-11-17 21:46:33 +00:00
|
|
|
/// # use postgres::{Connection, SslMode};
|
|
|
|
/// # let conn = Connection::connect("", &SslMode::None).unwrap();
|
2014-03-28 04:08:22 +00:00
|
|
|
/// let maybe_stmt = conn.prepare("SELECT foo FROM bar WHERE baz = $1");
|
2014-03-09 22:22:20 +00:00
|
|
|
/// let stmt = match maybe_stmt {
|
|
|
|
/// Ok(stmt) => stmt,
|
2015-01-09 19:20:43 +00:00
|
|
|
/// Err(err) => panic!("Error preparing statement: {:?}", err)
|
2014-03-09 22:22:20 +00:00
|
|
|
/// };
|
2014-11-01 23:24:24 +00:00
|
|
|
pub fn prepare<'a>(&'a self, query: &str) -> Result<Statement<'a>> {
|
2015-01-23 06:24:47 +00:00
|
|
|
self.conn.borrow_mut().prepare(query, self)
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Creates cached prepared statement.
|
|
|
|
///
|
|
|
|
/// Like `prepare`, except that the statement is only prepared once and
|
|
|
|
/// then cached. If the same statement is going to be used frequently,
|
|
|
|
/// caching it can improve performance by reducing the number of round
|
|
|
|
/// trips to the Postgres backend.
|
|
|
|
///
|
|
|
|
/// ## Example
|
|
|
|
///
|
|
|
|
/// ```rust,no_run
|
|
|
|
/// # use postgres::{Connection, SslMode};
|
|
|
|
/// # fn f() -> postgres::Result<()> {
|
|
|
|
/// # let x = 10i32;
|
|
|
|
/// # let conn = Connection::connect("", &SslMode::None).unwrap();
|
|
|
|
/// let stmt = try!(conn.prepare_cached("SELECT foo FROM bar WHERE baz = $1"));
|
|
|
|
/// for row in try!(stmt.query(&[&x])) {
|
|
|
|
/// println!("foo: {}", row.get::<_, String>(0));
|
|
|
|
/// }
|
|
|
|
/// # Ok(()) };
|
|
|
|
/// ```
|
|
|
|
pub fn prepare_cached<'a>(&'a self, query: &str) -> Result<Statement<'a>> {
|
|
|
|
self.conn.borrow_mut().prepare_cached(query, self)
|
2013-09-20 04:06:45 +00:00
|
|
|
}
|
|
|
|
|
2014-09-30 07:01:15 +00:00
|
|
|
/// Creates a new COPY FROM STDIN prepared statement.
|
|
|
|
///
|
|
|
|
/// These statements provide a method to efficiently bulk-upload data to
|
|
|
|
/// the database.
|
2014-09-30 05:56:43 +00:00
|
|
|
pub fn prepare_copy_in<'a>(&'a self, table: &str, rows: &[&str])
|
2014-11-01 23:26:03 +00:00
|
|
|
-> Result<CopyInStatement<'a>> {
|
2015-01-23 06:24:47 +00:00
|
|
|
self.conn.borrow_mut().prepare_copy_in(table, rows, self)
|
2014-09-30 05:56:43 +00:00
|
|
|
}
|
|
|
|
|
2014-03-28 04:08:22 +00:00
|
|
|
/// Begins a new transaction.
|
2013-09-30 02:12:20 +00:00
|
|
|
///
|
2014-11-01 23:25:11 +00:00
|
|
|
/// Returns a `Transaction` object which should be used instead of
|
2013-10-14 01:58:31 +00:00
|
|
|
/// the connection for the duration of the transaction. The transaction
|
2014-11-01 23:25:11 +00:00
|
|
|
/// is active until the `Transaction` object falls out of scope.
|
2014-07-26 05:41:10 +00:00
|
|
|
///
|
2014-07-30 02:48:56 +00:00
|
|
|
/// ## Note
|
2014-10-06 03:49:09 +00:00
|
|
|
/// A transaction will roll back by default. The `set_commit`,
|
|
|
|
/// `set_rollback`, and `commit` methods alter this behavior.
|
2014-03-09 22:22:20 +00:00
|
|
|
///
|
2014-07-30 02:48:56 +00:00
|
|
|
/// ## Example
|
2014-03-09 22:22:20 +00:00
|
|
|
///
|
2014-03-10 17:06:40 +00:00
|
|
|
/// ```rust,no_run
|
2014-11-17 21:46:33 +00:00
|
|
|
/// # use postgres::{Connection, SslMode};
|
2014-11-04 06:24:11 +00:00
|
|
|
/// # fn foo() -> Result<(), postgres::Error> {
|
2014-11-17 21:46:33 +00:00
|
|
|
/// # let conn = Connection::connect("", &SslMode::None).unwrap();
|
2014-03-28 04:08:22 +00:00
|
|
|
/// let trans = try!(conn.transaction());
|
2014-11-19 19:36:47 +00:00
|
|
|
/// try!(trans.execute("UPDATE foo SET bar = 10", &[]));
|
2014-07-26 05:41:10 +00:00
|
|
|
/// // ...
|
2014-03-09 22:22:20 +00:00
|
|
|
///
|
2014-10-06 03:47:48 +00:00
|
|
|
/// try!(trans.commit());
|
2014-03-09 22:22:20 +00:00
|
|
|
/// # Ok(())
|
|
|
|
/// # }
|
|
|
|
/// ```
|
2014-11-01 23:25:11 +00:00
|
|
|
pub fn transaction<'a>(&'a self) -> Result<Transaction<'a>> {
|
2014-09-13 05:07:10 +00:00
|
|
|
let mut conn = self.conn.borrow_mut();
|
|
|
|
check_desync!(conn);
|
|
|
|
if conn.trans_depth != 0 {
|
2014-11-21 05:47:13 +00:00
|
|
|
return Err(Error::WrongTransaction);
|
2014-05-19 02:34:01 +00:00
|
|
|
}
|
2014-09-13 05:07:10 +00:00
|
|
|
try!(conn.quick_query("BEGIN"));
|
|
|
|
conn.trans_depth += 1;
|
2014-11-01 23:25:11 +00:00
|
|
|
Ok(Transaction {
|
2013-08-27 05:40:23 +00:00
|
|
|
conn: self,
|
2014-07-26 05:41:10 +00:00
|
|
|
commit: Cell::new(false),
|
2014-05-19 02:34:01 +00:00
|
|
|
depth: 1,
|
2014-02-10 07:55:16 +00:00
|
|
|
finished: false,
|
2014-02-10 06:45:26 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2013-12-29 03:24:52 +00:00
|
|
|
/// A convenience function for queries that are only run once.
|
2013-09-30 02:12:20 +00:00
|
|
|
///
|
|
|
|
/// If an error is returned, it could have come from either the preparation
|
|
|
|
/// or execution of the statement.
|
|
|
|
///
|
|
|
|
/// On success, returns the number of rows modified or 0 if not applicable.
|
2015-01-09 18:50:54 +00:00
|
|
|
pub fn execute(&self, query: &str, params: &[&ToSql]) -> Result<usize> {
|
2014-12-02 06:24:31 +00:00
|
|
|
let (param_types, result_desc) = try!(self.conn.borrow_mut().raw_prepare("", query));
|
|
|
|
let stmt = Statement {
|
|
|
|
conn: self,
|
2014-12-23 17:10:16 +00:00
|
|
|
name: "".to_owned(),
|
2014-12-02 06:24:31 +00:00
|
|
|
param_types: param_types,
|
|
|
|
result_desc: result_desc,
|
|
|
|
next_portal_id: Cell::new(0),
|
|
|
|
finished: true, // << !!
|
|
|
|
};
|
|
|
|
stmt.execute(params)
|
2013-09-01 18:06:33 +00:00
|
|
|
}
|
|
|
|
|
2014-06-08 23:07:15 +00:00
|
|
|
/// Execute a sequence of SQL statements.
|
|
|
|
///
|
|
|
|
/// Statements should be separated by `;` characters. If an error occurs,
|
|
|
|
/// execution of the sequence will stop at that point. This is intended for
|
|
|
|
/// execution of batches of non-dynamic statements - for example, creation
|
|
|
|
/// of a schema for a fresh database.
|
|
|
|
///
|
2014-07-30 02:48:56 +00:00
|
|
|
/// ## Warning
|
2014-06-08 23:07:15 +00:00
|
|
|
///
|
|
|
|
/// Prepared statements should be used for any SQL statement which contains
|
|
|
|
/// user-specified data, as it provides functionality to safely embed that
|
|
|
|
/// data in the statment. Do not form statements via string concatenation
|
|
|
|
/// and feed them into this method.
|
|
|
|
///
|
2014-07-30 02:48:56 +00:00
|
|
|
/// ## Example
|
2014-06-08 23:07:15 +00:00
|
|
|
///
|
2014-06-08 23:12:27 +00:00
|
|
|
/// ```rust,no_run
|
2014-11-01 23:21:47 +00:00
|
|
|
/// # use postgres::{Connection, Result};
|
|
|
|
/// fn init_db(conn: &Connection) -> Result<()> {
|
2014-07-26 00:56:43 +00:00
|
|
|
/// conn.batch_execute("
|
2014-06-08 23:07:15 +00:00
|
|
|
/// CREATE TABLE person (
|
|
|
|
/// id SERIAL PRIMARY KEY,
|
|
|
|
/// name NOT NULL
|
|
|
|
/// );
|
|
|
|
///
|
|
|
|
/// CREATE TABLE purchase (
|
|
|
|
/// id SERIAL PRIMARY KEY,
|
|
|
|
/// person INT NOT NULL REFERENCES person (id),
|
|
|
|
/// time TIMESTAMPTZ NOT NULL,
|
|
|
|
/// );
|
|
|
|
///
|
|
|
|
/// CREATE INDEX ON purchase (time);
|
2014-07-26 00:56:43 +00:00
|
|
|
/// ")
|
2014-06-08 23:07:15 +00:00
|
|
|
/// }
|
|
|
|
/// ```
|
2014-11-01 23:12:05 +00:00
|
|
|
pub fn batch_execute(&self, query: &str) -> Result<()> {
|
2015-01-23 06:24:47 +00:00
|
|
|
self.conn.borrow_mut().quick_query(query).map(|_| ())
|
2014-06-08 23:07:15 +00:00
|
|
|
}
|
|
|
|
|
2013-10-21 00:32:14 +00:00
|
|
|
/// Returns information used to cancel pending queries.
|
|
|
|
///
|
|
|
|
/// Used with the `cancel_query` function. The object returned can be used
|
|
|
|
/// to cancel any query executed by the connection it was created from.
|
2014-11-01 23:19:02 +00:00
|
|
|
pub fn cancel_data(&self) -> CancelData {
|
2014-03-19 04:00:06 +00:00
|
|
|
self.conn.borrow().cancel_data
|
2013-10-21 00:32:14 +00:00
|
|
|
}
|
|
|
|
|
2014-02-10 06:45:26 +00:00
|
|
|
/// Returns whether or not the stream has been desynchronized due to an
|
|
|
|
/// error in the communication channel with the server.
|
|
|
|
///
|
|
|
|
/// If this has occurred, all further queries will immediately return an
|
|
|
|
/// error.
|
|
|
|
pub fn is_desynchronized(&self) -> bool {
|
2014-03-19 04:00:06 +00:00
|
|
|
self.conn.borrow().is_desynchronized()
|
2014-02-10 06:45:26 +00:00
|
|
|
}
|
|
|
|
|
2014-02-10 07:55:16 +00:00
|
|
|
/// Consumes the connection, closing it.
|
|
|
|
///
|
2014-11-03 00:48:38 +00:00
|
|
|
/// Functionally equivalent to the `Drop` implementation for `Connection`
|
|
|
|
/// except that it returns any error encountered to the caller.
|
2014-11-01 23:12:05 +00:00
|
|
|
pub fn finish(self) -> Result<()> {
|
2014-03-19 04:00:06 +00:00
|
|
|
let mut conn = self.conn.borrow_mut();
|
|
|
|
conn.finished = true;
|
|
|
|
conn.finish_inner()
|
2014-02-10 07:55:16 +00:00
|
|
|
}
|
|
|
|
|
2014-04-08 03:52:41 +00:00
|
|
|
fn canary(&self) -> u32 {
|
2014-04-10 04:28:20 +00:00
|
|
|
self.conn.borrow().canary()
|
2014-04-08 03:52:41 +00:00
|
|
|
}
|
|
|
|
|
2014-02-07 04:58:47 +00:00
|
|
|
fn write_messages(&self, messages: &[FrontendMessage]) -> IoResult<()> {
|
2014-03-19 04:00:06 +00:00
|
|
|
self.conn.borrow_mut().write_messages(messages)
|
2013-08-17 22:09:26 +00:00
|
|
|
}
|
|
|
|
}
|
2013-08-18 02:09:56 +00:00
|
|
|
|
2013-11-10 04:58:38 +00:00
|
|
|
/// Specifies the SSL support requested for a new connection
|
2015-01-17 06:32:25 +00:00
|
|
|
#[derive(Show)]
|
2013-11-11 02:13:32 +00:00
|
|
|
pub enum SslMode {
|
2013-11-10 04:58:38 +00:00
|
|
|
/// The connection will not use SSL
|
2014-11-17 21:46:33 +00:00
|
|
|
None,
|
2013-11-10 04:58:38 +00:00
|
|
|
/// The connection will use SSL if the backend supports it
|
2014-11-17 21:46:33 +00:00
|
|
|
Prefer(SslContext),
|
2013-11-10 04:58:38 +00:00
|
|
|
/// The connection must use SSL
|
2014-11-17 21:46:33 +00:00
|
|
|
Require(SslContext)
|
2013-11-10 04:58:38 +00:00
|
|
|
}
|
|
|
|
|
2014-05-19 02:46:21 +00:00
|
|
|
/// Represents a transaction on a database connection.
|
|
|
|
///
|
2014-07-26 05:41:10 +00:00
|
|
|
/// The transaction will roll back by default.
|
2014-11-01 23:25:11 +00:00
|
|
|
pub struct Transaction<'conn> {
|
2014-11-01 23:21:47 +00:00
|
|
|
conn: &'conn Connection,
|
2014-04-01 06:51:42 +00:00
|
|
|
commit: Cell<bool>,
|
2014-05-19 02:34:01 +00:00
|
|
|
depth: u32,
|
2014-04-01 06:51:42 +00:00
|
|
|
finished: bool,
|
2013-09-16 05:35:30 +00:00
|
|
|
}
|
|
|
|
|
2015-01-10 04:48:47 +00:00
|
|
|
impl<'a> fmt::Show for Transaction<'a> {
|
|
|
|
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
|
|
|
write!(fmt, "Transaction {{ connection: {:?}, commit: {:?}, depth: {:?} }}",
|
|
|
|
self.conn, self.commit.get(), self.depth)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-09-16 05:35:30 +00:00
|
|
|
#[unsafe_destructor]
|
2014-11-01 23:25:11 +00:00
|
|
|
impl<'conn> Drop for Transaction<'conn> {
|
2013-09-18 05:06:47 +00:00
|
|
|
fn drop(&mut self) {
|
2014-02-10 07:55:16 +00:00
|
|
|
if !self.finished {
|
2014-04-07 06:37:17 +00:00
|
|
|
let _ = self.finish_inner();
|
2014-02-10 07:55:16 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-11-01 23:25:11 +00:00
|
|
|
impl<'conn> Transaction<'conn> {
|
2014-11-01 23:12:05 +00:00
|
|
|
fn finish_inner(&mut self) -> Result<()> {
|
2014-09-13 05:07:10 +00:00
|
|
|
let mut conn = self.conn.conn.borrow_mut();
|
|
|
|
debug_assert!(self.depth == conn.trans_depth);
|
2014-07-26 05:41:10 +00:00
|
|
|
let query = match (self.commit.get(), self.depth != 1) {
|
|
|
|
(false, true) => "ROLLBACK TO sp",
|
|
|
|
(false, false) => "ROLLBACK",
|
|
|
|
(true, true) => "RELEASE sp",
|
|
|
|
(true, false) => "COMMIT",
|
2014-05-18 18:37:52 +00:00
|
|
|
};
|
2014-09-13 05:07:10 +00:00
|
|
|
conn.trans_depth -= 1;
|
|
|
|
conn.quick_query(query).map(|_| ())
|
2013-09-16 05:35:30 +00:00
|
|
|
}
|
2013-08-27 05:40:23 +00:00
|
|
|
|
2014-11-01 23:21:47 +00:00
|
|
|
/// Like `Connection::prepare`.
|
2014-12-02 06:42:36 +00:00
|
|
|
pub fn prepare(&self, query: &str) -> Result<Statement<'conn>> {
|
2015-01-23 06:24:47 +00:00
|
|
|
self.conn.prepare(query)
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Like `Connection::prepare_cached`.
|
|
|
|
///
|
|
|
|
/// Note that the statement will be cached for the duration of the
|
|
|
|
/// connection, not just the duration of this transaction.
|
|
|
|
pub fn prepare_cached(&self, query: &str) -> Result<Statement<'conn>> {
|
|
|
|
self.conn.prepare_cached(query)
|
2013-09-01 18:06:33 +00:00
|
|
|
}
|
|
|
|
|
2014-11-01 23:21:47 +00:00
|
|
|
/// Like `Connection::prepare_copy_in`.
|
2014-12-03 06:56:56 +00:00
|
|
|
pub fn prepare_copy_in(&self, table: &str, cols: &[&str]) -> Result<CopyInStatement<'conn>> {
|
2015-01-23 06:24:47 +00:00
|
|
|
self.conn.prepare_copy_in(table, cols)
|
2014-09-30 06:49:58 +00:00
|
|
|
}
|
|
|
|
|
2014-11-01 23:21:47 +00:00
|
|
|
/// Like `Connection::execute`.
|
2015-01-09 18:50:54 +00:00
|
|
|
pub fn execute(&self, query: &str, params: &[&ToSql]) -> Result<usize> {
|
2014-12-02 06:24:31 +00:00
|
|
|
self.conn.execute(query, params)
|
2013-09-30 02:12:20 +00:00
|
|
|
}
|
|
|
|
|
2014-11-01 23:21:47 +00:00
|
|
|
/// Like `Connection::batch_execute`.
|
2014-11-01 23:12:05 +00:00
|
|
|
pub fn batch_execute(&self, query: &str) -> Result<()> {
|
2015-01-23 06:24:47 +00:00
|
|
|
self.conn.batch_execute(query)
|
2014-06-08 23:07:15 +00:00
|
|
|
}
|
|
|
|
|
2014-11-01 23:21:47 +00:00
|
|
|
/// Like `Connection::transaction`.
|
2014-11-01 23:25:11 +00:00
|
|
|
pub fn transaction<'a>(&'a self) -> Result<Transaction<'a>> {
|
2014-09-13 05:07:10 +00:00
|
|
|
let mut conn = self.conn.conn.borrow_mut();
|
|
|
|
check_desync!(conn);
|
|
|
|
if conn.trans_depth != self.depth {
|
2014-11-21 05:47:13 +00:00
|
|
|
return Err(Error::WrongTransaction);
|
2014-05-19 02:34:01 +00:00
|
|
|
}
|
2014-09-13 05:07:10 +00:00
|
|
|
try!(conn.quick_query("SAVEPOINT sp"));
|
|
|
|
conn.trans_depth += 1;
|
2014-11-01 23:25:11 +00:00
|
|
|
Ok(Transaction {
|
2013-09-05 06:28:44 +00:00
|
|
|
conn: self.conn,
|
2014-07-26 05:41:10 +00:00
|
|
|
commit: Cell::new(false),
|
2014-05-19 02:34:01 +00:00
|
|
|
depth: self.depth + 1,
|
2014-02-10 07:55:16 +00:00
|
|
|
finished: false,
|
2014-02-10 06:45:26 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2015-01-23 06:52:29 +00:00
|
|
|
#[deprecated = "call `lazy_query` on Statement instead"]
|
|
|
|
#[allow(missing_docs)]
|
2014-07-30 02:50:44 +00:00
|
|
|
pub fn lazy_query<'trans, 'stmt>(&'trans self,
|
2014-11-01 23:24:24 +00:00
|
|
|
stmt: &'stmt Statement,
|
2014-07-30 02:50:44 +00:00
|
|
|
params: &[&ToSql],
|
|
|
|
row_limit: i32)
|
2014-11-01 23:28:38 +00:00
|
|
|
-> Result<LazyRows<'trans, 'stmt>> {
|
2015-01-23 06:52:29 +00:00
|
|
|
stmt.lazy_query(self, params, row_limit)
|
2014-07-30 02:50:44 +00:00
|
|
|
}
|
|
|
|
|
2013-09-30 02:12:20 +00:00
|
|
|
/// Determines if the transaction is currently set to commit or roll back.
|
2013-08-27 05:40:23 +00:00
|
|
|
pub fn will_commit(&self) -> bool {
|
2014-02-10 06:45:26 +00:00
|
|
|
self.commit.get()
|
2013-08-27 05:40:23 +00:00
|
|
|
}
|
|
|
|
|
2013-09-30 02:12:20 +00:00
|
|
|
/// Sets the transaction to commit at its completion.
|
2013-08-27 05:40:23 +00:00
|
|
|
pub fn set_commit(&self) {
|
2014-02-10 06:45:26 +00:00
|
|
|
self.commit.set(true);
|
2013-08-27 05:40:23 +00:00
|
|
|
}
|
|
|
|
|
2013-09-30 02:12:20 +00:00
|
|
|
/// Sets the transaction to roll back at its completion.
|
2013-08-27 05:40:23 +00:00
|
|
|
pub fn set_rollback(&self) {
|
2014-02-10 06:45:26 +00:00
|
|
|
self.commit.set(false);
|
2013-08-27 05:40:23 +00:00
|
|
|
}
|
2014-02-10 07:55:16 +00:00
|
|
|
|
2014-07-26 05:41:10 +00:00
|
|
|
/// A convenience method which consumes and commits a transaction.
|
2014-11-01 23:12:05 +00:00
|
|
|
pub fn commit(self) -> Result<()> {
|
2014-07-26 05:41:10 +00:00
|
|
|
self.set_commit();
|
|
|
|
self.finish()
|
|
|
|
}
|
|
|
|
|
2014-02-10 07:55:16 +00:00
|
|
|
/// Consumes the transaction, commiting or rolling it back as appropriate.
|
|
|
|
///
|
2014-12-03 06:56:56 +00:00
|
|
|
/// Functionally equivalent to the `Drop` implementation of `Transaction`
|
|
|
|
/// except that it returns any error to the caller.
|
2014-11-01 23:12:05 +00:00
|
|
|
pub fn finish(mut self) -> Result<()> {
|
2014-02-10 07:55:16 +00:00
|
|
|
self.finished = true;
|
|
|
|
self.finish_inner()
|
|
|
|
}
|
2013-08-27 05:40:23 +00:00
|
|
|
}
|
|
|
|
|
2014-03-26 04:01:38 +00:00
|
|
|
/// A prepared statement
|
2014-11-01 23:24:24 +00:00
|
|
|
pub struct Statement<'conn> {
|
2014-11-01 23:21:47 +00:00
|
|
|
conn: &'conn Connection,
|
2014-05-26 03:38:40 +00:00
|
|
|
name: String,
|
2014-11-04 05:29:16 +00:00
|
|
|
param_types: Vec<Type>,
|
2014-04-01 06:51:42 +00:00
|
|
|
result_desc: Vec<ResultDescription>,
|
2015-01-09 18:50:54 +00:00
|
|
|
next_portal_id: Cell<usize>,
|
2014-04-26 06:14:55 +00:00
|
|
|
finished: bool,
|
2014-03-26 04:01:38 +00:00
|
|
|
}
|
|
|
|
|
2015-01-10 04:48:47 +00:00
|
|
|
impl<'a> fmt::Show for Statement<'a> {
|
|
|
|
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
|
|
|
write!(fmt,
|
2015-01-10 07:58:21 +00:00
|
|
|
"Statement {{ connection: {:?}, name: {:?}, parameter_types: {:?}, \
|
2015-01-10 04:48:47 +00:00
|
|
|
result_descriptions: {:?} }}",
|
|
|
|
self.conn,
|
|
|
|
self.name,
|
|
|
|
self.param_types,
|
|
|
|
self.result_desc)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-03-26 04:01:38 +00:00
|
|
|
#[unsafe_destructor]
|
2014-11-01 23:24:24 +00:00
|
|
|
impl<'conn> Drop for Statement<'conn> {
|
2014-03-26 04:01:38 +00:00
|
|
|
fn drop(&mut self) {
|
2015-01-23 06:33:35 +00:00
|
|
|
let _ = self.finish_inner();
|
2014-03-26 04:01:38 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-11-01 23:24:24 +00:00
|
|
|
impl<'conn> Statement<'conn> {
|
2014-11-01 23:12:05 +00:00
|
|
|
fn finish_inner(&mut self) -> Result<()> {
|
2015-01-23 06:33:35 +00:00
|
|
|
if !self.finished {
|
|
|
|
self.finished = true;
|
|
|
|
let mut conn = self.conn.conn.borrow_mut();
|
|
|
|
check_desync!(conn);
|
|
|
|
conn.close_statement(&*self.name, b'S')
|
|
|
|
} else {
|
|
|
|
Ok(())
|
|
|
|
}
|
2014-03-26 04:01:38 +00:00
|
|
|
}
|
|
|
|
|
2014-11-18 02:20:48 +00:00
|
|
|
fn inner_execute(&self, portal_name: &str, row_limit: i32, params: &[&ToSql]) -> Result<()> {
|
2014-09-13 05:07:10 +00:00
|
|
|
let mut conn = self.conn.conn.borrow_mut();
|
2014-03-28 04:39:03 +00:00
|
|
|
if self.param_types.len() != params.len() {
|
2014-11-21 05:47:13 +00:00
|
|
|
return Err(Error::WrongParamCount {
|
2014-03-28 04:39:03 +00:00
|
|
|
expected: self.param_types.len(),
|
|
|
|
actual: params.len(),
|
|
|
|
});
|
|
|
|
}
|
2014-05-26 18:41:18 +00:00
|
|
|
let mut values = vec![];
|
2014-06-19 06:56:57 +00:00
|
|
|
for (param, ty) in params.iter().zip(self.param_types.iter()) {
|
2014-10-14 04:12:25 +00:00
|
|
|
values.push(try!(param.to_sql(ty)));
|
2014-03-26 04:01:38 +00:00
|
|
|
};
|
|
|
|
|
2014-11-19 17:58:30 +00:00
|
|
|
try!(conn.write_messages(&[
|
2014-03-26 04:01:38 +00:00
|
|
|
Bind {
|
|
|
|
portal: portal_name,
|
2014-12-03 05:44:34 +00:00
|
|
|
statement: &*self.name,
|
2014-11-19 17:58:30 +00:00
|
|
|
formats: &[1],
|
2014-12-03 05:44:34 +00:00
|
|
|
values: &*values,
|
2014-11-19 17:58:30 +00:00
|
|
|
result_formats: &[1]
|
2014-03-26 04:01:38 +00:00
|
|
|
},
|
|
|
|
Execute {
|
|
|
|
portal: portal_name,
|
2014-06-07 07:14:08 +00:00
|
|
|
max_rows: row_limit
|
2014-03-26 04:01:38 +00:00
|
|
|
},
|
|
|
|
Sync]));
|
|
|
|
|
2014-11-17 06:54:57 +00:00
|
|
|
match try!(conn.read_message()) {
|
2014-03-26 04:01:38 +00:00
|
|
|
BindComplete => Ok(()),
|
|
|
|
ErrorResponse { fields } => {
|
2014-09-30 00:43:21 +00:00
|
|
|
try!(conn.wait_for_ready());
|
2014-11-04 06:24:11 +00:00
|
|
|
DbError::new(fields)
|
2014-03-26 04:01:38 +00:00
|
|
|
}
|
2014-07-07 02:02:22 +00:00
|
|
|
_ => {
|
2014-09-13 05:07:10 +00:00
|
|
|
conn.desynchronized = true;
|
2014-11-21 05:47:13 +00:00
|
|
|
Err(Error::BadResponse)
|
2014-07-07 02:02:22 +00:00
|
|
|
}
|
2014-03-26 04:01:38 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-01-23 06:52:29 +00:00
|
|
|
fn inner_lazy_query<'a>(&'a self, row_limit: i32, params: &[&ToSql]) -> Result<Rows<'a>> {
|
2014-03-26 04:01:38 +00:00
|
|
|
let id = self.next_portal_id.get();
|
|
|
|
self.next_portal_id.set(id + 1);
|
2014-05-24 03:08:14 +00:00
|
|
|
let portal_name = format!("{}p{}", self.name, id);
|
2014-03-26 04:01:38 +00:00
|
|
|
|
2014-12-03 05:44:34 +00:00
|
|
|
try!(self.inner_execute(&*portal_name, row_limit, params));
|
2014-03-26 04:01:38 +00:00
|
|
|
|
2014-11-01 23:27:30 +00:00
|
|
|
let mut result = Rows {
|
2014-03-26 04:01:38 +00:00
|
|
|
stmt: self,
|
|
|
|
name: portal_name,
|
|
|
|
data: RingBuf::new(),
|
|
|
|
row_limit: row_limit,
|
|
|
|
more_rows: true,
|
|
|
|
finished: false,
|
|
|
|
};
|
2014-12-19 18:43:42 +00:00
|
|
|
try!(result.read_rows());
|
2014-03-26 04:01:38 +00:00
|
|
|
|
|
|
|
Ok(result)
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns a slice containing the expected parameter types.
|
2014-11-04 05:29:16 +00:00
|
|
|
pub fn param_types(&self) -> &[Type] {
|
2014-12-03 05:44:34 +00:00
|
|
|
&*self.param_types
|
2014-03-26 04:01:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns a slice describing the columns of the result of the query.
|
2014-07-22 05:46:40 +00:00
|
|
|
pub fn result_descriptions(&self) -> &[ResultDescription] {
|
2014-12-03 05:44:34 +00:00
|
|
|
&*self.result_desc
|
2014-03-26 04:01:38 +00:00
|
|
|
}
|
|
|
|
|
2014-03-28 04:08:22 +00:00
|
|
|
/// Executes the prepared statement, returning the number of rows modified.
|
2014-03-26 04:01:38 +00:00
|
|
|
///
|
|
|
|
/// If the statement does not modify any rows (e.g. SELECT), 0 is returned.
|
|
|
|
///
|
2014-07-30 02:48:56 +00:00
|
|
|
/// ## Example
|
2014-03-26 04:01:38 +00:00
|
|
|
///
|
|
|
|
/// ```rust,no_run
|
2014-11-17 21:46:33 +00:00
|
|
|
/// # use postgres::{Connection, SslMode};
|
|
|
|
/// # let conn = Connection::connect("", &SslMode::None).unwrap();
|
2014-03-26 04:01:38 +00:00
|
|
|
/// # let bar = 1i32;
|
|
|
|
/// # let baz = true;
|
2014-03-28 04:08:22 +00:00
|
|
|
/// let stmt = conn.prepare("UPDATE foo SET bar = $1 WHERE baz = $2").unwrap();
|
2014-08-30 09:57:46 +00:00
|
|
|
/// match stmt.execute(&[&bar, &baz]) {
|
2014-03-26 04:01:38 +00:00
|
|
|
/// Ok(count) => println!("{} row(s) updated", count),
|
2015-01-09 19:20:43 +00:00
|
|
|
/// Err(err) => println!("Error executing query: {:?}", err)
|
2014-03-26 04:01:38 +00:00
|
|
|
/// }
|
2014-12-03 06:56:56 +00:00
|
|
|
/// ```
|
2015-01-09 18:50:54 +00:00
|
|
|
pub fn execute(&self, params: &[&ToSql]) -> Result<usize> {
|
2014-03-26 04:01:38 +00:00
|
|
|
check_desync!(self.conn);
|
|
|
|
try!(self.inner_execute("", 0, params));
|
|
|
|
|
2014-09-13 05:07:10 +00:00
|
|
|
let mut conn = self.conn.conn.borrow_mut();
|
2014-03-26 04:01:38 +00:00
|
|
|
let num;
|
|
|
|
loop {
|
2014-11-17 06:54:57 +00:00
|
|
|
match try!(conn.read_message()) {
|
2014-03-26 04:01:38 +00:00
|
|
|
DataRow { .. } => {}
|
|
|
|
ErrorResponse { fields } => {
|
2014-09-13 05:07:10 +00:00
|
|
|
try!(conn.wait_for_ready());
|
2014-11-04 06:24:11 +00:00
|
|
|
return DbError::new(fields);
|
2014-03-26 04:01:38 +00:00
|
|
|
}
|
|
|
|
CommandComplete { tag } => {
|
2014-09-30 07:11:23 +00:00
|
|
|
num = util::parse_update_count(tag);
|
2014-03-26 04:01:38 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
EmptyQueryResponse => {
|
|
|
|
num = 0;
|
|
|
|
break;
|
|
|
|
}
|
2014-09-30 04:05:42 +00:00
|
|
|
CopyInResponse { .. } => {
|
2014-11-19 17:58:30 +00:00
|
|
|
try!(conn.write_messages(&[
|
2014-09-30 04:05:42 +00:00
|
|
|
CopyFail {
|
|
|
|
message: "COPY queries cannot be directly executed",
|
|
|
|
},
|
|
|
|
Sync]));
|
|
|
|
}
|
2014-07-07 02:02:22 +00:00
|
|
|
_ => {
|
2014-09-13 05:07:10 +00:00
|
|
|
conn.desynchronized = true;
|
2014-11-21 05:47:13 +00:00
|
|
|
return Err(Error::BadResponse);
|
2014-07-07 02:02:22 +00:00
|
|
|
}
|
2014-03-26 04:01:38 +00:00
|
|
|
}
|
|
|
|
}
|
2014-09-13 05:07:10 +00:00
|
|
|
try!(conn.wait_for_ready());
|
2014-03-26 04:01:38 +00:00
|
|
|
|
|
|
|
Ok(num)
|
|
|
|
}
|
|
|
|
|
2014-03-28 04:08:22 +00:00
|
|
|
/// Executes the prepared statement, returning an iterator over the
|
|
|
|
/// resulting rows.
|
2014-03-26 04:01:38 +00:00
|
|
|
///
|
2014-07-30 02:48:56 +00:00
|
|
|
/// ## Example
|
2014-03-26 04:01:38 +00:00
|
|
|
///
|
|
|
|
/// ```rust,no_run
|
2014-11-17 21:46:33 +00:00
|
|
|
/// # use postgres::{Connection, SslMode};
|
|
|
|
/// # let conn = Connection::connect("", &SslMode::None).unwrap();
|
2014-03-28 04:08:22 +00:00
|
|
|
/// let stmt = conn.prepare("SELECT foo FROM bar WHERE baz = $1").unwrap();
|
2014-03-26 04:01:38 +00:00
|
|
|
/// # let baz = true;
|
2014-08-30 09:57:46 +00:00
|
|
|
/// let mut rows = match stmt.query(&[&baz]) {
|
2014-03-26 04:01:38 +00:00
|
|
|
/// Ok(rows) => rows,
|
2015-01-09 19:20:43 +00:00
|
|
|
/// Err(err) => panic!("Error running query: {:?}", err)
|
2014-03-26 04:01:38 +00:00
|
|
|
/// };
|
|
|
|
/// for row in rows {
|
2014-07-10 19:35:57 +00:00
|
|
|
/// let foo: i32 = row.get("foo");
|
2014-03-26 04:01:38 +00:00
|
|
|
/// println!("foo: {}", foo);
|
|
|
|
/// }
|
|
|
|
/// ```
|
2014-11-01 23:27:30 +00:00
|
|
|
pub fn query<'a>(&'a self, params: &[&ToSql]) -> Result<Rows<'a>> {
|
2014-03-26 04:01:38 +00:00
|
|
|
check_desync!(self.conn);
|
2015-01-23 06:52:29 +00:00
|
|
|
self.inner_lazy_query(0, params)
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Executes the prepared statement, returning a lazily loaded iterator
|
|
|
|
/// over the resulting rows.
|
|
|
|
///
|
|
|
|
/// No more than `row_limit` rows will be stored in memory at a time. Rows
|
|
|
|
/// will be pulled from the database in batches of `row_limit` as needed.
|
|
|
|
/// If `row_limit` is less than or equal to 0, `lazy_query` is equivalent
|
|
|
|
/// to `query`.
|
|
|
|
///
|
|
|
|
/// This can only be called inside of a transaction, and the `Transaction`
|
|
|
|
/// object representing the active transaction must be passed to
|
|
|
|
/// `lazy_query`.
|
|
|
|
pub fn lazy_query<'trans, 'stmt>(&'stmt self,
|
|
|
|
trans: &'trans Transaction,
|
|
|
|
params: &[&ToSql],
|
|
|
|
row_limit: i32)
|
|
|
|
-> Result<LazyRows<'trans, 'stmt>> {
|
|
|
|
if self.conn as *const _ != trans.conn as *const _ {
|
|
|
|
return Err(Error::WrongConnection);
|
|
|
|
}
|
|
|
|
let conn = self.conn.conn.borrow();
|
|
|
|
check_desync!(conn);
|
|
|
|
if conn.trans_depth != trans.depth {
|
|
|
|
return Err(Error::WrongTransaction);
|
|
|
|
}
|
|
|
|
drop(conn);
|
|
|
|
self.inner_lazy_query(row_limit, params).map(|result| {
|
|
|
|
LazyRows {
|
|
|
|
_trans: trans,
|
|
|
|
result: result
|
|
|
|
}
|
|
|
|
})
|
2014-03-26 04:01:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Consumes the statement, clearing it from the Postgres session.
|
|
|
|
///
|
2014-08-19 05:02:16 +00:00
|
|
|
/// Functionally identical to the `Drop` implementation of the
|
2014-11-01 23:24:24 +00:00
|
|
|
/// `Statement` except that it returns any error to the caller.
|
2014-11-01 23:12:05 +00:00
|
|
|
pub fn finish(mut self) -> Result<()> {
|
2014-03-26 04:01:38 +00:00
|
|
|
self.finish_inner()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Information about a column of the result of a query.
|
2015-01-10 04:48:47 +00:00
|
|
|
#[derive(PartialEq, Eq, Clone, Show)]
|
2014-03-26 04:01:38 +00:00
|
|
|
pub struct ResultDescription {
|
|
|
|
/// The name of the column
|
2014-05-26 03:38:40 +00:00
|
|
|
pub name: String,
|
2014-03-26 04:01:38 +00:00
|
|
|
/// The type of the data in the column
|
2014-11-04 05:29:16 +00:00
|
|
|
pub ty: Type
|
2014-03-26 04:01:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// An iterator over the resulting rows of a query.
|
2014-11-01 23:27:30 +00:00
|
|
|
pub struct Rows<'stmt> {
|
2014-11-01 23:24:24 +00:00
|
|
|
stmt: &'stmt Statement<'stmt>,
|
2014-05-26 03:38:40 +00:00
|
|
|
name: String,
|
2014-04-08 03:02:05 +00:00
|
|
|
data: RingBuf<Vec<Option<Vec<u8>>>>,
|
2014-06-07 23:01:50 +00:00
|
|
|
row_limit: i32,
|
2014-04-01 06:51:42 +00:00
|
|
|
more_rows: bool,
|
|
|
|
finished: bool,
|
2014-03-26 04:01:38 +00:00
|
|
|
}
|
|
|
|
|
2015-01-10 04:48:47 +00:00
|
|
|
impl<'a> fmt::Show for Rows<'a> {
|
|
|
|
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
|
|
|
write!(fmt, "Rows {{ statement: {:?}, name: {:?}, remaining_rows: {:?} }}",
|
|
|
|
self.stmt, self.name, self.data.len())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-03-26 04:01:38 +00:00
|
|
|
#[unsafe_destructor]
|
2014-11-01 23:27:30 +00:00
|
|
|
impl<'stmt> Drop for Rows<'stmt> {
|
2014-03-26 04:01:38 +00:00
|
|
|
fn drop(&mut self) {
|
|
|
|
if !self.finished {
|
2014-04-07 06:37:17 +00:00
|
|
|
let _ = self.finish_inner();
|
2014-03-26 04:01:38 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-11-01 23:27:30 +00:00
|
|
|
impl<'stmt> Rows<'stmt> {
|
2014-11-01 23:12:05 +00:00
|
|
|
fn finish_inner(&mut self) -> Result<()> {
|
2014-09-13 05:07:10 +00:00
|
|
|
let mut conn = self.stmt.conn.conn.borrow_mut();
|
|
|
|
check_desync!(conn);
|
2014-12-03 05:44:34 +00:00
|
|
|
conn.close_statement(&*self.name, b'P')
|
2014-03-26 04:01:38 +00:00
|
|
|
}
|
|
|
|
|
2014-11-01 23:12:05 +00:00
|
|
|
fn read_rows(&mut self) -> Result<()> {
|
2014-09-13 05:07:10 +00:00
|
|
|
let mut conn = self.stmt.conn.conn.borrow_mut();
|
2014-03-26 04:01:38 +00:00
|
|
|
loop {
|
2014-11-17 06:54:57 +00:00
|
|
|
match try!(conn.read_message()) {
|
2014-08-16 02:50:11 +00:00
|
|
|
EmptyQueryResponse | CommandComplete { .. } => {
|
2014-03-26 04:01:38 +00:00
|
|
|
self.more_rows = false;
|
|
|
|
break;
|
2014-12-03 06:56:56 +00:00
|
|
|
}
|
2014-03-26 04:01:38 +00:00
|
|
|
PortalSuspended => {
|
|
|
|
self.more_rows = true;
|
|
|
|
break;
|
2014-12-03 06:56:56 +00:00
|
|
|
}
|
2014-11-07 16:54:10 +00:00
|
|
|
DataRow { row } => self.data.push_back(row),
|
2014-07-25 01:00:28 +00:00
|
|
|
ErrorResponse { fields } => {
|
2014-09-13 05:07:10 +00:00
|
|
|
try!(conn.wait_for_ready());
|
2014-11-04 06:24:11 +00:00
|
|
|
return DbError::new(fields);
|
2014-07-25 01:00:28 +00:00
|
|
|
}
|
2014-09-30 04:05:42 +00:00
|
|
|
CopyInResponse { .. } => {
|
2014-11-19 17:58:30 +00:00
|
|
|
try!(conn.write_messages(&[
|
2014-09-30 04:05:42 +00:00
|
|
|
CopyFail {
|
|
|
|
message: "COPY queries cannot be directly executed",
|
|
|
|
},
|
|
|
|
Sync]));
|
|
|
|
}
|
2014-07-07 02:02:22 +00:00
|
|
|
_ => {
|
2014-09-13 05:07:10 +00:00
|
|
|
conn.desynchronized = true;
|
2014-11-21 05:47:13 +00:00
|
|
|
return Err(Error::BadResponse);
|
2014-07-07 02:02:22 +00:00
|
|
|
}
|
2014-03-26 04:01:38 +00:00
|
|
|
}
|
|
|
|
}
|
2014-09-13 05:07:10 +00:00
|
|
|
conn.wait_for_ready()
|
2014-03-26 04:01:38 +00:00
|
|
|
}
|
|
|
|
|
2014-11-01 23:12:05 +00:00
|
|
|
fn execute(&mut self) -> Result<()> {
|
2014-11-19 17:58:30 +00:00
|
|
|
try!(self.stmt.conn.write_messages(&[
|
2014-03-26 04:01:38 +00:00
|
|
|
Execute {
|
2014-12-03 05:44:34 +00:00
|
|
|
portal: &*self.name,
|
2014-06-07 07:14:08 +00:00
|
|
|
max_rows: self.row_limit
|
2014-03-26 04:01:38 +00:00
|
|
|
},
|
|
|
|
Sync]));
|
|
|
|
self.read_rows()
|
|
|
|
}
|
|
|
|
|
2014-11-26 18:50:31 +00:00
|
|
|
/// Returns a slice describing the columns of the `Rows`.
|
|
|
|
pub fn result_descriptions(&self) -> &'stmt [ResultDescription] {
|
|
|
|
self.stmt.result_descriptions()
|
|
|
|
}
|
|
|
|
|
2014-11-01 23:27:30 +00:00
|
|
|
/// Consumes the `Rows`, cleaning up associated state.
|
2014-03-26 04:01:38 +00:00
|
|
|
///
|
2014-11-01 23:27:30 +00:00
|
|
|
/// Functionally identical to the `Drop` implementation on `Rows`
|
2014-08-19 05:02:16 +00:00
|
|
|
/// except that it returns any error to the caller.
|
2014-11-01 23:12:05 +00:00
|
|
|
pub fn finish(mut self) -> Result<()> {
|
2014-03-26 04:01:38 +00:00
|
|
|
self.finished = true;
|
|
|
|
self.finish_inner()
|
|
|
|
}
|
|
|
|
|
2014-11-01 23:27:30 +00:00
|
|
|
fn try_next(&mut self) -> Option<Result<Row<'stmt>>> {
|
2014-03-26 04:01:38 +00:00
|
|
|
if self.data.is_empty() && self.more_rows {
|
2014-10-14 04:12:25 +00:00
|
|
|
if let Err(err) = self.execute() {
|
|
|
|
return Some(Err(err));
|
2014-03-28 04:20:04 +00:00
|
|
|
}
|
2014-03-26 04:01:38 +00:00
|
|
|
}
|
|
|
|
|
2014-11-03 00:48:38 +00:00
|
|
|
self.data.pop_front().map(|row| Ok(Row { stmt: self.stmt, data: row }))
|
2014-03-26 04:01:38 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-01-04 16:08:53 +00:00
|
|
|
impl<'stmt> Iterator for Rows<'stmt> {
|
|
|
|
type Item = Row<'stmt>;
|
|
|
|
|
2014-04-03 05:56:16 +00:00
|
|
|
#[inline]
|
2014-11-01 23:27:30 +00:00
|
|
|
fn next(&mut self) -> Option<Row<'stmt>> {
|
2014-03-28 04:20:04 +00:00
|
|
|
// we'll never hit the network on a non-lazy result
|
|
|
|
self.try_next().map(|r| r.unwrap())
|
2014-03-26 04:01:38 +00:00
|
|
|
}
|
|
|
|
|
2014-04-03 05:56:16 +00:00
|
|
|
#[inline]
|
2015-01-09 18:50:54 +00:00
|
|
|
fn size_hint(&self) -> (usize, Option<usize>) {
|
2014-03-26 04:01:38 +00:00
|
|
|
let lower = self.data.len();
|
|
|
|
let upper = if self.more_rows {
|
2014-11-21 05:48:05 +00:00
|
|
|
None
|
2014-03-26 04:01:38 +00:00
|
|
|
} else {
|
|
|
|
Some(lower)
|
|
|
|
};
|
|
|
|
(lower, upper)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// A single result row of a query.
|
2014-11-01 23:27:30 +00:00
|
|
|
pub struct Row<'stmt> {
|
2014-11-01 23:24:24 +00:00
|
|
|
stmt: &'stmt Statement<'stmt>,
|
2014-04-08 03:02:05 +00:00
|
|
|
data: Vec<Option<Vec<u8>>>
|
2014-03-26 04:01:38 +00:00
|
|
|
}
|
|
|
|
|
2015-01-10 04:48:47 +00:00
|
|
|
impl<'a> fmt::Show for Row<'a> {
|
|
|
|
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
|
|
|
write!(fmt, "Row {{ statement: {:?} }}", self.stmt)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-11-01 23:27:30 +00:00
|
|
|
impl<'stmt> Row<'stmt> {
|
2014-11-01 22:50:25 +00:00
|
|
|
/// Returns the number of values in the row
|
2015-01-09 18:50:54 +00:00
|
|
|
pub fn len(&self) -> usize {
|
2014-11-01 22:50:25 +00:00
|
|
|
self.data.len()
|
|
|
|
}
|
|
|
|
|
2014-11-26 18:50:31 +00:00
|
|
|
/// Returns a slice describing the columns of the `Row`.
|
|
|
|
pub fn result_descriptions(&self) -> &'stmt [ResultDescription] {
|
|
|
|
self.stmt.result_descriptions()
|
|
|
|
}
|
|
|
|
|
2014-03-30 00:01:41 +00:00
|
|
|
/// Retrieves the contents of a field of the row.
|
|
|
|
///
|
|
|
|
/// A field can be accessed by the name or index of its column, though
|
2014-06-30 06:05:26 +00:00
|
|
|
/// access by index is more efficient. Rows are 0-indexed.
|
2014-03-30 00:01:41 +00:00
|
|
|
///
|
|
|
|
/// Returns an `Error` value if the index does not reference a column or
|
|
|
|
/// the return type is not compatible with the Postgres type.
|
2014-11-01 23:12:05 +00:00
|
|
|
pub fn get_opt<I, T>(&self, idx: I) -> Result<T> where I: RowIndex, T: FromSql {
|
2014-11-21 05:47:13 +00:00
|
|
|
let idx = try!(idx.idx(self.stmt).ok_or(Error::InvalidColumn));
|
2014-12-23 02:45:09 +00:00
|
|
|
FromSql::from_sql(&self.stmt.result_desc[idx].ty, self.data[idx].as_ref().map(|e| &**e))
|
2014-03-30 00:01:41 +00:00
|
|
|
}
|
2014-03-26 04:01:38 +00:00
|
|
|
|
2014-07-10 19:35:57 +00:00
|
|
|
/// Retrieves the contents of a field of the row.
|
2014-03-30 00:01:41 +00:00
|
|
|
///
|
|
|
|
/// A field can be accessed by the name or index of its column, though
|
2014-06-30 05:53:03 +00:00
|
|
|
/// access by index is more efficient. Rows are 0-indexed.
|
2014-03-30 00:01:41 +00:00
|
|
|
///
|
2014-07-30 02:48:56 +00:00
|
|
|
/// ## Failure
|
2014-03-30 00:01:41 +00:00
|
|
|
///
|
|
|
|
/// Fails if the index does not reference a column or the return type is
|
|
|
|
/// not compatible with the Postgres type.
|
|
|
|
///
|
2014-07-30 02:48:56 +00:00
|
|
|
/// ## Example
|
2014-03-30 00:01:41 +00:00
|
|
|
///
|
|
|
|
/// ```rust,no_run
|
2014-11-17 21:46:33 +00:00
|
|
|
/// # use postgres::{Connection, SslMode};
|
|
|
|
/// # let conn = Connection::connect("", &SslMode::None).unwrap();
|
2014-03-30 00:01:41 +00:00
|
|
|
/// # let stmt = conn.prepare("").unwrap();
|
2014-11-19 19:36:47 +00:00
|
|
|
/// # let mut result = stmt.query(&[]).unwrap();
|
2014-03-30 00:01:41 +00:00
|
|
|
/// # let row = result.next().unwrap();
|
2014-07-10 19:35:57 +00:00
|
|
|
/// let foo: i32 = row.get(0u);
|
|
|
|
/// let bar: String = row.get("bar");
|
2014-03-30 00:01:41 +00:00
|
|
|
/// ```
|
2014-08-17 20:57:58 +00:00
|
|
|
pub fn get<I, T>(&self, idx: I) -> T where I: RowIndex + fmt::Show + Clone, T: FromSql {
|
2014-07-10 19:35:57 +00:00
|
|
|
match self.get_opt(idx.clone()) {
|
2014-03-30 00:01:41 +00:00
|
|
|
Ok(ok) => ok,
|
2015-01-09 18:50:54 +00:00
|
|
|
Err(err) => panic!("error retrieving column {:?}: {:?}", idx, err)
|
2014-03-30 00:01:41 +00:00
|
|
|
}
|
2014-03-26 04:01:38 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// A trait implemented by types that can index into columns of a row.
|
2014-03-31 02:21:51 +00:00
|
|
|
pub trait RowIndex {
|
2014-03-30 00:01:41 +00:00
|
|
|
/// Returns the index of the appropriate column, or `None` if no such
|
|
|
|
/// column exists.
|
2015-01-09 18:50:54 +00:00
|
|
|
fn idx(&self, stmt: &Statement) -> Option<usize>;
|
2014-03-26 04:01:38 +00:00
|
|
|
}
|
|
|
|
|
2015-01-09 18:50:54 +00:00
|
|
|
impl RowIndex for usize {
|
2014-03-26 04:01:38 +00:00
|
|
|
#[inline]
|
2015-01-09 18:50:54 +00:00
|
|
|
fn idx(&self, stmt: &Statement) -> Option<usize> {
|
2014-12-06 18:41:49 +00:00
|
|
|
if *self >= stmt.result_desc.len() {
|
2014-11-21 05:48:05 +00:00
|
|
|
None
|
2014-03-30 00:01:41 +00:00
|
|
|
} else {
|
2014-06-30 05:53:03 +00:00
|
|
|
Some(*self)
|
2014-03-30 00:01:41 +00:00
|
|
|
}
|
2014-03-26 04:01:38 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a> RowIndex for &'a str {
|
2014-05-18 18:37:52 +00:00
|
|
|
#[inline]
|
2015-01-09 18:50:54 +00:00
|
|
|
fn idx(&self, stmt: &Statement) -> Option<usize> {
|
2014-12-06 21:30:37 +00:00
|
|
|
stmt.result_descriptions().iter().position(|d| d.name == *self)
|
2014-03-26 04:01:38 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// A lazily-loaded iterator over the resulting rows of a query
|
2014-11-01 23:28:38 +00:00
|
|
|
pub struct LazyRows<'trans, 'stmt> {
|
2014-11-01 23:27:30 +00:00
|
|
|
result: Rows<'stmt>,
|
2014-11-01 23:25:11 +00:00
|
|
|
_trans: &'trans Transaction<'trans>,
|
2014-03-26 04:01:38 +00:00
|
|
|
}
|
|
|
|
|
2015-01-10 04:48:47 +00:00
|
|
|
impl<'a, 'b> fmt::Show for LazyRows<'a, 'b> {
|
|
|
|
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
|
|
|
write!(fmt,
|
|
|
|
"LazyRows {{ statement: {:?}, name: {:?}, row_limit: {:?}, remaining_rows: {:?}, \
|
|
|
|
more_rows: {:?} }}",
|
|
|
|
self.result.stmt,
|
|
|
|
self.result.name,
|
|
|
|
self.result.row_limit,
|
|
|
|
self.result.data.len(),
|
|
|
|
self.result.more_rows)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-11-01 23:28:38 +00:00
|
|
|
impl<'trans, 'stmt> LazyRows<'trans, 'stmt> {
|
2014-11-01 23:27:30 +00:00
|
|
|
/// Like `Rows::finish`.
|
2014-11-01 23:12:05 +00:00
|
|
|
pub fn finish(self) -> Result<()> {
|
2014-03-26 04:01:38 +00:00
|
|
|
self.result.finish()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-01-04 16:08:53 +00:00
|
|
|
impl<'trans, 'stmt> Iterator for LazyRows<'trans, 'stmt> {
|
|
|
|
type Item = Result<Row<'stmt>>;
|
|
|
|
|
2014-11-01 23:27:30 +00:00
|
|
|
fn next(&mut self) -> Option<Result<Row<'stmt>>> {
|
2014-03-28 04:20:04 +00:00
|
|
|
self.result.try_next()
|
2014-03-26 04:01:38 +00:00
|
|
|
}
|
|
|
|
|
2015-01-09 18:50:54 +00:00
|
|
|
fn size_hint(&self) -> (usize, Option<usize>) {
|
2014-03-26 04:01:38 +00:00
|
|
|
self.result.size_hint()
|
|
|
|
}
|
|
|
|
}
|
2014-09-30 05:56:43 +00:00
|
|
|
|
2014-09-30 07:11:23 +00:00
|
|
|
/// A prepared COPY FROM STDIN statement
|
2014-11-01 23:26:03 +00:00
|
|
|
pub struct CopyInStatement<'a> {
|
2014-11-01 23:21:47 +00:00
|
|
|
conn: &'a Connection,
|
2014-09-30 05:56:43 +00:00
|
|
|
name: String,
|
2014-11-04 05:29:16 +00:00
|
|
|
column_types: Vec<Type>,
|
2014-09-30 05:56:43 +00:00
|
|
|
finished: bool,
|
|
|
|
}
|
|
|
|
|
2015-01-10 04:48:47 +00:00
|
|
|
impl<'a> fmt::Show for CopyInStatement<'a> {
|
|
|
|
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
|
|
|
write!(fmt, "CopyInStatement {{ connection: {:?}, name: {:?}, column_types: {:?} }}",
|
|
|
|
self.conn, self.name, self.column_types)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-09-30 05:56:43 +00:00
|
|
|
#[unsafe_destructor]
|
2014-11-01 23:26:03 +00:00
|
|
|
impl<'a> Drop for CopyInStatement<'a> {
|
2014-09-30 05:56:43 +00:00
|
|
|
fn drop(&mut self) {
|
|
|
|
if !self.finished {
|
|
|
|
let _ = self.finish_inner();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-01-22 04:25:01 +00:00
|
|
|
/// An `Iterator` variant which returns borrowed values.
|
|
|
|
pub trait StreamIterator {
|
|
|
|
/// Returns the next value, or `None` if there is none.
|
|
|
|
fn next<'a>(&'a mut self) -> Option<&'a (ToSql + 'a)>;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// An adapter type implementing `StreamIterator` for a `Vec<Box<ToSql>>`.
|
|
|
|
pub struct VecStreamIterator<'a> {
|
|
|
|
v: Vec<Box<ToSql + 'a>>,
|
|
|
|
idx: usize,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a> VecStreamIterator<'a> {
|
|
|
|
/// Creates a new `VecStreamIterator`.
|
|
|
|
pub fn new(v: Vec<Box<ToSql + 'a>>) -> VecStreamIterator<'a> {
|
|
|
|
VecStreamIterator {
|
|
|
|
v: v,
|
|
|
|
idx: 0,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns the underlying `Vec`.
|
|
|
|
pub fn into_inner(self) -> Vec<Box<ToSql + 'a>> {
|
|
|
|
self.v
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a> StreamIterator for VecStreamIterator<'a> {
|
|
|
|
fn next<'b>(&'b mut self) -> Option<&'b (ToSql + 'b)> {
|
|
|
|
match self.v.get_mut(self.idx) {
|
|
|
|
Some(mut e) => {
|
|
|
|
self.idx += 1;
|
|
|
|
Some(&mut **e)
|
|
|
|
},
|
|
|
|
None => None,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-11-01 23:26:03 +00:00
|
|
|
impl<'a> CopyInStatement<'a> {
|
2014-11-01 23:12:05 +00:00
|
|
|
fn finish_inner(&mut self) -> Result<()> {
|
2014-09-30 05:56:43 +00:00
|
|
|
let mut conn = self.conn.conn.borrow_mut();
|
|
|
|
check_desync!(conn);
|
2014-12-03 05:44:34 +00:00
|
|
|
conn.close_statement(&*self.name, b'S')
|
2014-09-30 05:56:43 +00:00
|
|
|
}
|
|
|
|
|
2014-09-30 07:15:17 +00:00
|
|
|
/// Returns a slice containing the expected column types.
|
2014-11-04 05:29:16 +00:00
|
|
|
pub fn column_types(&self) -> &[Type] {
|
2014-12-03 05:44:34 +00:00
|
|
|
&*self.column_types
|
2014-09-30 07:15:17 +00:00
|
|
|
}
|
|
|
|
|
2014-09-30 07:11:23 +00:00
|
|
|
/// Executes the prepared statement.
|
|
|
|
///
|
2015-01-22 04:25:01 +00:00
|
|
|
/// The `rows` argument is an `Iterator` returning `StreamIterator` values,
|
|
|
|
/// each one of which provides values for a row of input. This setup is
|
|
|
|
/// designed to allow callers to avoid having to maintain the entire row
|
|
|
|
/// set in memory.
|
2014-09-30 07:11:23 +00:00
|
|
|
///
|
|
|
|
/// Returns the number of rows copied.
|
2015-01-22 04:29:22 +00:00
|
|
|
pub fn execute<I, J>(&self, mut rows: I) -> Result<usize>
|
2015-01-22 04:25:01 +00:00
|
|
|
where I: Iterator<Item=J>, J: StreamIterator {
|
2014-09-30 05:56:43 +00:00
|
|
|
let mut conn = self.conn.conn.borrow_mut();
|
|
|
|
|
2014-11-19 17:58:30 +00:00
|
|
|
try!(conn.write_messages(&[
|
2014-09-30 05:56:43 +00:00
|
|
|
Bind {
|
|
|
|
portal: "",
|
2014-12-03 05:44:34 +00:00
|
|
|
statement: &*self.name,
|
2014-11-19 17:58:30 +00:00
|
|
|
formats: &[],
|
|
|
|
values: &[],
|
|
|
|
result_formats: &[]
|
2014-09-30 05:56:43 +00:00
|
|
|
},
|
|
|
|
Execute {
|
|
|
|
portal: "",
|
|
|
|
max_rows: 0,
|
|
|
|
},
|
|
|
|
Sync]));
|
|
|
|
|
2014-11-17 06:54:57 +00:00
|
|
|
match try!(conn.read_message()) {
|
2014-09-30 05:56:43 +00:00
|
|
|
BindComplete => {},
|
|
|
|
ErrorResponse { fields } => {
|
|
|
|
try!(conn.wait_for_ready());
|
2014-11-04 06:24:11 +00:00
|
|
|
return DbError::new(fields);
|
2014-09-30 05:56:43 +00:00
|
|
|
}
|
|
|
|
_ => {
|
|
|
|
conn.desynchronized = true;
|
2014-11-21 05:47:13 +00:00
|
|
|
return Err(Error::BadResponse);
|
2014-09-30 05:56:43 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-11-17 06:54:57 +00:00
|
|
|
match try!(conn.read_message()) {
|
2014-09-30 05:56:43 +00:00
|
|
|
CopyInResponse { .. } => {}
|
|
|
|
_ => {
|
|
|
|
conn.desynchronized = true;
|
2014-11-21 05:47:13 +00:00
|
|
|
return Err(Error::BadResponse);
|
2014-09-30 05:56:43 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-11-20 04:54:32 +00:00
|
|
|
let mut buf = vec![];
|
2014-09-30 05:56:43 +00:00
|
|
|
let _ = buf.write(b"PGCOPY\n\xff\r\n\x00");
|
|
|
|
let _ = buf.write_be_i32(0);
|
|
|
|
let _ = buf.write_be_i32(0);
|
|
|
|
|
2014-10-01 21:40:43 +00:00
|
|
|
'l: for mut row in rows {
|
2014-09-30 05:56:43 +00:00
|
|
|
let _ = buf.write_be_i16(self.column_types.len() as i16);
|
|
|
|
|
2014-09-30 06:32:57 +00:00
|
|
|
let mut types = self.column_types.iter();
|
|
|
|
loop {
|
|
|
|
match (row.next(), types.next()) {
|
|
|
|
(Some(val), Some(ty)) => {
|
2014-10-26 03:26:45 +00:00
|
|
|
match val.to_sql(ty) {
|
2014-11-21 05:48:05 +00:00
|
|
|
Ok(None) => {
|
2014-09-30 06:32:57 +00:00
|
|
|
let _ = buf.write_be_i32(-1);
|
|
|
|
}
|
2014-10-26 03:26:45 +00:00
|
|
|
Ok(Some(val)) => {
|
2014-09-30 06:32:57 +00:00
|
|
|
let _ = buf.write_be_i32(val.len() as i32);
|
2014-12-03 05:44:34 +00:00
|
|
|
let _ = buf.write(&*val);
|
2014-09-30 06:32:57 +00:00
|
|
|
}
|
2014-10-26 03:26:45 +00:00
|
|
|
Err(err) => {
|
|
|
|
// FIXME this is not the right way to handle this
|
2014-11-17 06:54:57 +00:00
|
|
|
try_desync!(conn, conn.stream.write_message(
|
2014-10-26 03:26:45 +00:00
|
|
|
&CopyFail {
|
2015-01-10 04:48:47 +00:00
|
|
|
message: &*format!("{}", err),
|
2014-10-26 03:26:45 +00:00
|
|
|
}));
|
|
|
|
break 'l;
|
|
|
|
}
|
2014-09-30 06:32:57 +00:00
|
|
|
}
|
2014-09-30 05:56:43 +00:00
|
|
|
}
|
2014-11-21 05:48:05 +00:00
|
|
|
(Some(_), None) | (None, Some(_)) => {
|
2014-11-17 06:54:57 +00:00
|
|
|
try_desync!(conn, conn.stream.write_message(
|
2014-09-30 06:32:57 +00:00
|
|
|
&CopyFail {
|
|
|
|
message: "Invalid column count",
|
|
|
|
}));
|
2014-10-01 21:40:43 +00:00
|
|
|
break 'l;
|
2014-09-30 05:56:43 +00:00
|
|
|
}
|
2014-11-21 05:48:05 +00:00
|
|
|
(None, None) => break
|
2014-09-30 05:56:43 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-11-17 06:54:57 +00:00
|
|
|
try_desync!(conn, conn.stream.write_message(
|
2014-09-30 06:09:39 +00:00
|
|
|
&CopyData {
|
2014-12-03 05:44:34 +00:00
|
|
|
data: &*buf
|
2014-09-30 06:09:39 +00:00
|
|
|
}));
|
2014-11-20 04:54:32 +00:00
|
|
|
buf.clear();
|
2014-09-30 05:56:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
let _ = buf.write_be_i16(-1);
|
2014-11-19 17:58:30 +00:00
|
|
|
try!(conn.write_messages(&[
|
2014-10-01 21:40:43 +00:00
|
|
|
CopyData {
|
2014-12-03 05:44:34 +00:00
|
|
|
data: &*buf,
|
2014-10-01 21:40:43 +00:00
|
|
|
},
|
|
|
|
CopyDone,
|
|
|
|
Sync]));
|
2014-09-30 05:56:43 +00:00
|
|
|
|
2014-11-17 06:54:57 +00:00
|
|
|
let num = match try!(conn.read_message()) {
|
2014-09-30 07:11:23 +00:00
|
|
|
CommandComplete { tag } => util::parse_update_count(tag),
|
2014-09-30 05:56:43 +00:00
|
|
|
ErrorResponse { fields } => {
|
|
|
|
try!(conn.wait_for_ready());
|
2014-11-04 06:24:11 +00:00
|
|
|
return DbError::new(fields);
|
2014-09-30 05:56:43 +00:00
|
|
|
}
|
|
|
|
_ => {
|
|
|
|
conn.desynchronized = true;
|
2014-11-21 05:47:13 +00:00
|
|
|
return Err(Error::BadResponse);
|
2014-09-30 05:56:43 +00:00
|
|
|
}
|
2014-09-30 07:11:23 +00:00
|
|
|
};
|
2014-09-30 05:56:43 +00:00
|
|
|
|
2014-09-30 07:11:23 +00:00
|
|
|
try!(conn.wait_for_ready());
|
|
|
|
Ok(num)
|
2014-09-30 05:56:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Consumes the statement, clearing it from the Postgres session.
|
|
|
|
///
|
|
|
|
/// Functionally identical to the `Drop` implementation of the
|
2014-11-01 23:26:03 +00:00
|
|
|
/// `CopyInStatement` except that it returns any error to the
|
2014-09-30 05:56:43 +00:00
|
|
|
/// caller.
|
2014-11-01 23:12:05 +00:00
|
|
|
pub fn finish(mut self) -> Result<()> {
|
2014-09-30 05:56:43 +00:00
|
|
|
self.finished = true;
|
|
|
|
self.finish_inner()
|
|
|
|
}
|
|
|
|
}
|
2014-10-09 03:29:26 +00:00
|
|
|
|
|
|
|
/// A trait allowing abstraction over connections and transactions
|
|
|
|
pub trait GenericConnection {
|
2014-11-01 23:21:47 +00:00
|
|
|
/// Like `Connection::prepare`.
|
2014-11-01 23:24:24 +00:00
|
|
|
fn prepare<'a>(&'a self, query: &str) -> Result<Statement<'a>>;
|
2014-10-09 03:29:26 +00:00
|
|
|
|
2015-01-23 06:24:47 +00:00
|
|
|
/// Like `Connection::prepare_cached`.
|
|
|
|
fn prepare_cached<'a>(&'a self, query: &str) -> Result<Statement<'a>>;
|
|
|
|
|
2014-11-01 23:21:47 +00:00
|
|
|
/// Like `Connection::execute`.
|
2015-01-09 18:50:54 +00:00
|
|
|
fn execute(&self, query: &str, params: &[&ToSql]) -> Result<usize>;
|
2014-10-09 03:29:26 +00:00
|
|
|
|
2014-11-01 23:21:47 +00:00
|
|
|
/// Like `Connection::prepare_copy_in`.
|
2014-10-09 03:29:26 +00:00
|
|
|
fn prepare_copy_in<'a>(&'a self, table: &str, columns: &[&str])
|
2014-11-01 23:26:03 +00:00
|
|
|
-> Result<CopyInStatement<'a>>;
|
2014-10-09 03:29:26 +00:00
|
|
|
|
2014-11-01 23:21:47 +00:00
|
|
|
/// Like `Connection::transaction`.
|
2014-11-01 23:25:11 +00:00
|
|
|
fn transaction<'a>(&'a self) -> Result<Transaction<'a>>;
|
2014-10-09 03:29:26 +00:00
|
|
|
|
2014-11-01 23:21:47 +00:00
|
|
|
/// Like `Connection::batch_execute`.
|
2014-11-01 23:12:05 +00:00
|
|
|
fn batch_execute(&self, query: &str) -> Result<()>;
|
2014-10-09 03:29:26 +00:00
|
|
|
}
|
|
|
|
|
2014-11-01 23:21:47 +00:00
|
|
|
impl GenericConnection for Connection {
|
2014-11-01 23:24:24 +00:00
|
|
|
fn prepare<'a>(&'a self, query: &str) -> Result<Statement<'a>> {
|
2014-10-09 03:29:26 +00:00
|
|
|
self.prepare(query)
|
|
|
|
}
|
|
|
|
|
2015-01-23 06:24:47 +00:00
|
|
|
fn prepare_cached<'a>(&'a self, query: &str) -> Result<Statement<'a>> {
|
|
|
|
self.prepare_cached(query)
|
|
|
|
}
|
|
|
|
|
2015-01-09 18:50:54 +00:00
|
|
|
fn execute(&self, query: &str, params: &[&ToSql]) -> Result<usize> {
|
2014-11-27 19:16:14 +00:00
|
|
|
self.execute(query, params)
|
|
|
|
}
|
|
|
|
|
2014-11-01 23:25:11 +00:00
|
|
|
fn transaction<'a>(&'a self) -> Result<Transaction<'a>> {
|
2014-10-09 03:29:26 +00:00
|
|
|
self.transaction()
|
|
|
|
}
|
|
|
|
|
|
|
|
fn prepare_copy_in<'a>(&'a self, table: &str, columns: &[&str])
|
2014-11-01 23:26:03 +00:00
|
|
|
-> Result<CopyInStatement<'a>> {
|
2014-10-09 03:29:26 +00:00
|
|
|
self.prepare_copy_in(table, columns)
|
|
|
|
}
|
|
|
|
|
2014-11-01 23:12:05 +00:00
|
|
|
fn batch_execute(&self, query: &str) -> Result<()> {
|
2014-10-09 03:29:26 +00:00
|
|
|
self.batch_execute(query)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-11-01 23:25:11 +00:00
|
|
|
impl<'a> GenericConnection for Transaction<'a> {
|
2014-12-18 00:23:24 +00:00
|
|
|
fn prepare<'b>(&'b self, query: &str) -> Result<Statement<'b>> {
|
2014-10-09 03:29:26 +00:00
|
|
|
self.prepare(query)
|
|
|
|
}
|
|
|
|
|
2015-01-23 06:24:47 +00:00
|
|
|
fn prepare_cached<'b>(&'b self, query: &str) -> Result<Statement<'b>> {
|
|
|
|
self.prepare_cached(query)
|
|
|
|
}
|
|
|
|
|
2015-01-09 18:50:54 +00:00
|
|
|
fn execute(&self, query: &str, params: &[&ToSql]) -> Result<usize> {
|
2014-11-27 19:16:14 +00:00
|
|
|
self.execute(query, params)
|
|
|
|
}
|
|
|
|
|
2014-12-18 00:23:24 +00:00
|
|
|
fn transaction<'b>(&'b self) -> Result<Transaction<'b>> {
|
2014-10-09 03:29:26 +00:00
|
|
|
self.transaction()
|
|
|
|
}
|
|
|
|
|
2014-12-18 00:23:24 +00:00
|
|
|
fn prepare_copy_in<'b>(&'b self, table: &str, columns: &[&str])
|
|
|
|
-> Result<CopyInStatement<'b>> {
|
2014-10-09 03:29:26 +00:00
|
|
|
self.prepare_copy_in(table, columns)
|
|
|
|
}
|
|
|
|
|
2014-11-01 23:12:05 +00:00
|
|
|
fn batch_execute(&self, query: &str) -> Result<()> {
|
2014-10-09 03:29:26 +00:00
|
|
|
self.batch_execute(query)
|
|
|
|
}
|
|
|
|
}
|