2015-12-13 04:21:44 +00:00
|
|
|
//! A pure-Rust frontend for the popular PostgreSQL database.
|
2014-07-03 05:23:17 +00:00
|
|
|
//!
|
|
|
|
//! ```rust,no_run
|
|
|
|
//! extern crate postgres;
|
|
|
|
//!
|
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,
|
|
|
|
//! data: Option<Vec<u8>>
|
|
|
|
//! }
|
|
|
|
//!
|
|
|
|
//! fn main() {
|
2015-12-06 00:15:19 +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,
|
|
|
|
//! data BYTEA
|
2014-11-25 20:59:31 +00:00
|
|
|
//! )", &[]).unwrap();
|
2014-07-03 05:23:17 +00:00
|
|
|
//! let me = Person {
|
|
|
|
//! id: 0,
|
2015-09-28 05:19:02 +00:00
|
|
|
//! name: "Steven".to_owned(),
|
2014-07-03 05:23:17 +00:00
|
|
|
//! data: None
|
|
|
|
//! };
|
2015-02-08 03:52:45 +00:00
|
|
|
//! conn.execute("INSERT INTO person (name, data) VALUES ($1, $2)",
|
|
|
|
//! &[&me.name, &me.data]).unwrap();
|
2014-07-03 05:23:17 +00:00
|
|
|
//!
|
2015-12-06 20:10:54 +00:00
|
|
|
//! for row in &conn.query("SELECT id, name, data FROM person", &[]).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),
|
2015-02-08 03:52:45 +00:00
|
|
|
//! data: row.get(2)
|
2014-07-03 05:23:17 +00:00
|
|
|
//! };
|
|
|
|
//! println!("Found person {}", person.name);
|
|
|
|
//! }
|
|
|
|
//! }
|
|
|
|
//! ```
|
2016-03-31 16:33:31 +00:00
|
|
|
#![doc(html_root_url="https://sfackler.github.io/rust-postgres/doc/v0.11.6")]
|
2014-10-31 15:51:27 +00:00
|
|
|
#![warn(missing_docs)]
|
2016-02-20 23:05:48 +00:00
|
|
|
#![allow(unknown_lints, needless_lifetimes)] // for clippy
|
2016-03-30 04:24:45 +00:00
|
|
|
#![cfg_attr(all(unix, feature = "nightly"), feature(unix_socket))]
|
2013-10-08 04:11:54 +00:00
|
|
|
|
2015-05-05 18:40:14 +00:00
|
|
|
extern crate bufstream;
|
2015-02-05 04:39:30 +00:00
|
|
|
extern crate byteorder;
|
2015-12-06 22:27:03 +00:00
|
|
|
extern crate hex;
|
2015-01-07 16:23:40 +00:00
|
|
|
#[macro_use]
|
2014-12-10 05:35:52 +00:00
|
|
|
extern crate log;
|
2014-04-01 06:51:42 +00:00
|
|
|
extern crate phf;
|
2015-02-26 17:02:32 +00:00
|
|
|
#[cfg(feature = "unix_socket")]
|
|
|
|
extern crate unix_socket;
|
2015-10-21 05:37:52 +00:00
|
|
|
extern crate net2;
|
2015-02-26 17:02:32 +00:00
|
|
|
|
2015-05-05 18:40:14 +00:00
|
|
|
use bufstream::BufStream;
|
2015-06-10 02:55:28 +00:00
|
|
|
use md5::Md5;
|
2015-04-23 05:03:09 +00:00
|
|
|
use std::ascii::AsciiExt;
|
2014-02-08 02:17:40 +00:00
|
|
|
use std::cell::{Cell, RefCell};
|
2015-02-20 21:56:03 +00:00
|
|
|
use std::collections::{VecDeque, HashMap};
|
2015-06-16 05:20:09 +00:00
|
|
|
use std::error::Error as StdError;
|
2014-12-10 05:35:52 +00:00
|
|
|
use std::fmt;
|
2015-04-28 05:26:20 +00:00
|
|
|
use std::io as std_io;
|
2015-02-26 17:02:32 +00:00
|
|
|
use std::io::prelude::*;
|
2014-02-12 07:42:46 +00:00
|
|
|
use std::mem;
|
2014-11-01 23:12:05 +00:00
|
|
|
use std::result;
|
2016-01-03 05:02:54 +00:00
|
|
|
use std::sync::Arc;
|
2015-10-21 06:13:26 +00:00
|
|
|
use std::time::Duration;
|
2016-03-30 04:24:45 +00:00
|
|
|
#[cfg(any(feature = "unix_socket", all(unix, feature = "nightly")))]
|
2015-02-26 17:02:32 +00:00
|
|
|
use std::path::PathBuf;
|
2013-08-04 02:17:32 +00:00
|
|
|
|
2016-02-24 07:43:28 +00:00
|
|
|
// FIXME remove in 0.12
|
|
|
|
pub use transaction::Transaction;
|
|
|
|
|
2015-05-26 05:47:25 +00:00
|
|
|
use error::{Error, ConnectError, SqlState, DbError};
|
2015-05-13 22:02:07 +00:00
|
|
|
use io::{StreamWrapper, NegotiateSsl};
|
2016-04-05 05:35:45 +00:00
|
|
|
use message::{Frontend, Backend, RowDescriptionEntry};
|
2014-02-16 02:59:16 +00:00
|
|
|
use message::{WriteMessage, ReadMessage};
|
2015-09-19 03:55:01 +00:00
|
|
|
use notification::{Notifications, Notification};
|
2015-05-30 05:54:10 +00:00
|
|
|
use rows::{Rows, LazyRows};
|
2015-09-19 03:21:13 +00:00
|
|
|
use stmt::{Statement, Column};
|
2016-02-16 07:11:01 +00:00
|
|
|
use types::{IsNull, Kind, Type, SessionInfo, Oid, Other, WrongType, ToSql, FromSql, Field};
|
2015-09-19 03:21:13 +00:00
|
|
|
use url::Url;
|
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
|
|
|
|
2015-08-16 04:39:46 +00:00
|
|
|
mod md5;
|
2014-02-16 02:59:16 +00:00
|
|
|
mod message;
|
2015-04-28 05:26:20 +00:00
|
|
|
mod priv_io;
|
2014-10-15 15:35:41 +00:00
|
|
|
mod url;
|
2015-08-16 04:39:46 +00:00
|
|
|
pub mod error;
|
|
|
|
pub mod io;
|
2016-02-24 07:43:28 +00:00
|
|
|
pub mod notification;
|
2015-05-30 05:54:10 +00:00
|
|
|
pub mod rows;
|
2015-08-16 06:21:39 +00:00
|
|
|
pub mod stmt;
|
2016-02-24 07:43:28 +00:00
|
|
|
pub mod transaction;
|
2015-08-16 04:39:46 +00:00
|
|
|
pub mod types;
|
2014-02-16 02:59:16 +00:00
|
|
|
|
2016-02-16 07:11:01 +00:00
|
|
|
const TYPEINFO_QUERY: &'static str = "__typeinfo";
|
2016-02-18 06:22:31 +00:00
|
|
|
const TYPEINFO_ENUM_QUERY: &'static str = "__typeinfo_enum";
|
2016-02-20 23:21:24 +00:00
|
|
|
const TYPEINFO_COMPOSITE_QUERY: &'static str = "__typeinfo_composite";
|
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-24 07:31:17 +00:00
|
|
|
#[derive(Clone, Debug)]
|
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.
|
2015-02-26 17:02:32 +00:00
|
|
|
///
|
2016-03-27 20:02:04 +00:00
|
|
|
/// Requires the `unix_socket` or `nightly` feature.
|
2016-03-30 04:24:45 +00:00
|
|
|
#[cfg(any(feature = "unix_socket", all(unix, feature = "nightly")))]
|
2015-11-16 03:51:04 +00:00
|
|
|
Unix(PathBuf),
|
2014-04-21 05:27:55 +00:00
|
|
|
}
|
|
|
|
|
2015-04-08 06:57:22 +00:00
|
|
|
/// Authentication information.
|
2015-01-24 07:31:17 +00:00
|
|
|
#[derive(Clone, Debug)]
|
2014-11-01 23:14:08 +00:00
|
|
|
pub struct UserInfo {
|
2016-02-11 06:57:41 +00:00
|
|
|
/// The username.
|
2014-07-26 00:24:10 +00:00
|
|
|
pub user: String,
|
2016-02-11 06:57:41 +00:00
|
|
|
/// An optional password.
|
2014-07-26 00:24:10 +00:00
|
|
|
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-24 07:31:17 +00:00
|
|
|
#[derive(Clone, Debug)]
|
2014-11-01 23:15:30 +00:00
|
|
|
pub struct ConnectParams {
|
2016-02-11 06:57:41 +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.
|
2015-02-26 17:02:32 +00:00
|
|
|
pub port: Option<u16>,
|
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>,
|
2016-02-11 06:57:41 +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`.
|
2016-04-05 05:53:34 +00:00
|
|
|
fn into_connect_params(self) -> result::Result<ConnectParams, Box<StdError + Sync + Send>>;
|
2014-04-21 05:27:55 +00:00
|
|
|
}
|
|
|
|
|
2014-11-01 23:15:30 +00:00
|
|
|
impl IntoConnectParams for ConnectParams {
|
2016-04-05 05:53:34 +00:00
|
|
|
fn into_connect_params(self) -> result::Result<ConnectParams, Box<StdError + Sync + Send>> {
|
2014-04-21 05:27:55 +00:00
|
|
|
Ok(self)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a> IntoConnectParams for &'a str {
|
2016-04-05 05:53:34 +00:00
|
|
|
fn into_connect_params(self) -> result::Result<ConnectParams, Box<StdError + Sync + Send>> {
|
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(),
|
2016-02-20 23:05:48 +00:00
|
|
|
Err(err) => Err(err.into()),
|
2014-05-17 03:47:03 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl IntoConnectParams for Url {
|
2016-04-05 05:53:34 +00:00
|
|
|
fn into_connect_params(self) -> result::Result<ConnectParams, Box<StdError + Sync + Send>> {
|
2016-03-30 04:24:45 +00:00
|
|
|
#[cfg(any(feature = "unix_socket", all(unix, feature = "nightly")))]
|
2015-06-16 05:20:09 +00:00
|
|
|
fn make_unix(maybe_path: String)
|
2016-04-05 05:53:34 +00:00
|
|
|
-> result::Result<ConnectTarget, Box<StdError + Sync + Send>> {
|
2015-05-30 22:32:10 +00:00
|
|
|
Ok(ConnectTarget::Unix(PathBuf::from(maybe_path)))
|
2015-02-26 17:02:32 +00:00
|
|
|
}
|
2016-03-30 04:24:45 +00:00
|
|
|
#[cfg(not(any(feature = "unix_socket", all(unix, feature = "nightly"))))]
|
2016-04-05 05:53:34 +00:00
|
|
|
fn make_unix(_: String) -> result::Result<ConnectTarget, Box<StdError + Sync + Send>> {
|
2016-03-30 04:24:45 +00:00
|
|
|
Err("unix socket support requires the `unix_socket` or `nightly` features".into())
|
2015-02-26 17:02:32 +00:00
|
|
|
}
|
|
|
|
|
2016-02-22 04:02:34 +00:00
|
|
|
let Url { host, port, user, path: url::Path { mut path, query: options, .. }, .. } = self;
|
2016-02-20 23:05:48 +00:00
|
|
|
|
2015-06-16 05:20:09 +00:00
|
|
|
let maybe_path = try!(url::decode_component(&host));
|
2016-02-20 23:05:48 +00:00
|
|
|
let target = if maybe_path.starts_with('/') {
|
2015-02-26 17:02:32 +00:00
|
|
|
try!(make_unix(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 }| {
|
2015-11-16 03:51:04 +00:00
|
|
|
UserInfo {
|
|
|
|
user: user,
|
|
|
|
password: pass,
|
|
|
|
}
|
2014-11-02 18:38:45 +00:00
|
|
|
});
|
2014-04-21 05:27:55 +00:00
|
|
|
|
2015-03-29 22:23:38 +00:00
|
|
|
let database = if path.is_empty() {
|
|
|
|
None
|
|
|
|
} else {
|
|
|
|
// path contains the leading /
|
|
|
|
path.remove(0);
|
|
|
|
Some(path)
|
|
|
|
};
|
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
|
2016-03-05 20:04:43 +00:00
|
|
|
///
|
|
|
|
/// It is implemented for all `Send + FnMut(DbError)` closures.
|
2015-02-22 23:05:19 +00:00
|
|
|
pub trait HandleNotice: Send {
|
2013-09-30 02:12:20 +00:00
|
|
|
/// Handle a Postgres notice message
|
2015-02-22 23:05:19 +00:00
|
|
|
fn handle_notice(&mut self, notice: DbError);
|
2013-09-12 02:57:26 +00:00
|
|
|
}
|
|
|
|
|
2016-03-05 20:04:43 +00:00
|
|
|
impl<F: Send + FnMut(DbError)> HandleNotice for F {
|
|
|
|
fn handle_notice(&mut self, notice: DbError) {
|
|
|
|
self(notice)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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-04-03 15:46:02 +00:00
|
|
|
#[derive(Copy, Clone, Debug)]
|
2015-02-22 23:05:19 +00:00
|
|
|
pub struct LoggingNoticeHandler;
|
2013-09-12 02:57:26 +00:00
|
|
|
|
2015-02-22 23:05:19 +00:00
|
|
|
impl HandleNotice for LoggingNoticeHandler {
|
|
|
|
fn handle_notice(&mut self, notice: DbError) {
|
2015-12-13 04:30:50 +00:00
|
|
|
info!("{}: {}", notice.severity, notice.message);
|
2013-09-12 02:57:26 +00:00
|
|
|
}
|
2013-08-28 06:23:36 +00:00
|
|
|
}
|
|
|
|
|
2015-05-02 22:55:53 +00:00
|
|
|
/// Contains information necessary to cancel queries for a session.
|
2015-01-24 07:31:17 +00:00
|
|
|
#[derive(Copy, Clone, Debug)]
|
2014-11-01 23:19:02 +00:00
|
|
|
pub struct CancelData {
|
2015-05-02 22:55:53 +00:00
|
|
|
/// The process ID of the session.
|
2014-08-16 03:14:46 +00:00
|
|
|
pub process_id: u32,
|
2015-05-02 22:55:53 +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
|
|
|
///
|
2015-11-29 05:05:13 +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};
|
2015-03-26 02:11:40 +00:00
|
|
|
/// # use std::thread;
|
2014-03-09 22:22:20 +00:00
|
|
|
/// # let url = "";
|
2015-12-06 00:15:19 +00:00
|
|
|
/// let conn = Connection::connect(url, SslMode::None).unwrap();
|
2014-03-09 22:22:20 +00:00
|
|
|
/// let cancel_data = conn.cancel_data();
|
2015-03-26 02:11:40 +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
|
|
|
/// });
|
2015-12-07 07:38:26 +00:00
|
|
|
/// postgres::cancel_query(url, SslMode::None, &cancel_data).unwrap();
|
2014-03-09 22:22:20 +00:00
|
|
|
/// ```
|
2015-11-16 03:51:04 +00:00
|
|
|
pub fn cancel_query<T>(params: T,
|
2015-12-06 00:15:19 +00:00
|
|
|
ssl: SslMode,
|
2015-12-07 07:38:26 +00:00
|
|
|
data: &CancelData)
|
2015-11-16 03:51:04 +00:00
|
|
|
-> result::Result<(), ConnectError>
|
|
|
|
where T: IntoConnectParams
|
|
|
|
{
|
2016-01-02 23:50:11 +00:00
|
|
|
let params = try!(params.into_connect_params().map_err(ConnectError::ConnectParams));
|
2015-04-28 05:26:20 +00:00
|
|
|
let mut socket = try!(priv_io::initialize_stream(¶ms, ssl));
|
2013-10-21 00:32:14 +00:00
|
|
|
|
2016-04-05 05:51:56 +00:00
|
|
|
try!(socket.write_message(&Frontend::CancelRequest {
|
2013-10-21 00:32:14 +00:00
|
|
|
code: message::CANCEL_CODE,
|
|
|
|
process_id: data.process_id,
|
2015-11-16 03:51:04 +00:00
|
|
|
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-05-23 04:20:56 +00:00
|
|
|
fn bad_response() -> std_io::Error {
|
|
|
|
std_io::Error::new(std_io::ErrorKind::InvalidInput,
|
|
|
|
"the server returned an unexpected response")
|
|
|
|
}
|
|
|
|
|
2015-05-26 06:27:12 +00:00
|
|
|
fn desynchronized() -> std_io::Error {
|
|
|
|
std_io::Error::new(std_io::ErrorKind::Other,
|
2015-11-16 03:51:04 +00:00
|
|
|
"communication with the server has desynchronized due to an earlier IO \
|
|
|
|
error")
|
2015-05-26 06:27:12 +00:00
|
|
|
}
|
|
|
|
|
2015-04-23 05:03:09 +00:00
|
|
|
/// An enumeration of transaction isolation levels.
|
|
|
|
///
|
2015-04-23 05:20:21 +00:00
|
|
|
/// See the [Postgres documentation](http://www.postgresql.org/docs/9.4/static/transaction-iso.html)
|
2015-04-23 05:03:09 +00:00
|
|
|
/// for full details on the semantics of each level.
|
|
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
|
|
pub enum IsolationLevel {
|
|
|
|
/// The "read uncommitted" level.
|
|
|
|
///
|
|
|
|
/// In current versions of Postgres, this behaves identically to
|
|
|
|
/// `ReadCommitted`.
|
|
|
|
ReadUncommitted,
|
|
|
|
/// The "read committed" level.
|
|
|
|
///
|
|
|
|
/// This is the default isolation level in Postgres.
|
|
|
|
ReadCommitted,
|
|
|
|
/// The "repeatable read" level.
|
|
|
|
RepeatableRead,
|
|
|
|
/// The "serializable" level.
|
|
|
|
Serializable,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl IsolationLevel {
|
2016-02-24 08:01:22 +00:00
|
|
|
fn to_sql(&self) -> &'static str {
|
2015-04-23 05:03:09 +00:00
|
|
|
match *self {
|
2016-02-24 08:01:22 +00:00
|
|
|
IsolationLevel::ReadUncommitted => "READ UNCOMMITTED",
|
|
|
|
IsolationLevel::ReadCommitted => "READ COMMITTED",
|
|
|
|
IsolationLevel::RepeatableRead => "REPEATABLE READ",
|
|
|
|
IsolationLevel::Serializable => "SERIALIZABLE",
|
2015-04-23 05:03:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn parse(raw: &str) -> Result<IsolationLevel> {
|
|
|
|
if raw.eq_ignore_ascii_case("READ UNCOMMITTED") {
|
|
|
|
Ok(IsolationLevel::ReadUncommitted)
|
|
|
|
} else if raw.eq_ignore_ascii_case("READ COMMITTED") {
|
|
|
|
Ok(IsolationLevel::ReadCommitted)
|
|
|
|
} else if raw.eq_ignore_ascii_case("REPEATABLE READ") {
|
|
|
|
Ok(IsolationLevel::RepeatableRead)
|
|
|
|
} else if raw.eq_ignore_ascii_case("SERIALIZABLE") {
|
|
|
|
Ok(IsolationLevel::Serializable)
|
|
|
|
} else {
|
2015-12-26 03:14:09 +00:00
|
|
|
Err(Error::Io(bad_response()))
|
2015-04-23 05:03:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-04-28 05:26:20 +00:00
|
|
|
/// Specifies the SSL support requested for a new connection.
|
2015-12-14 06:46:24 +00:00
|
|
|
#[derive(Debug)]
|
2015-12-06 00:15:19 +00:00
|
|
|
pub enum SslMode<'a> {
|
2015-04-28 05:26:20 +00:00
|
|
|
/// The connection will not use SSL.
|
|
|
|
None,
|
|
|
|
/// The connection will use SSL if the backend supports it.
|
2015-12-06 00:15:19 +00:00
|
|
|
Prefer(&'a NegotiateSsl),
|
2015-04-28 05:26:20 +00:00
|
|
|
/// The connection must use SSL.
|
2015-12-06 00:15:19 +00:00
|
|
|
Require(&'a NegotiateSsl),
|
2015-04-28 05:26:20 +00:00
|
|
|
}
|
|
|
|
|
2016-01-03 05:02:54 +00:00
|
|
|
struct StatementInfo {
|
2015-01-23 06:24:47 +00:00
|
|
|
name: String,
|
|
|
|
param_types: Vec<Type>,
|
2015-02-06 07:08:53 +00:00
|
|
|
columns: Vec<Column>,
|
2015-01-23 06:24:47 +00:00
|
|
|
}
|
|
|
|
|
2014-11-01 23:21:47 +00:00
|
|
|
struct InnerConnection {
|
2015-04-28 04:20:52 +00:00
|
|
|
stream: BufStream<Box<StreamWrapper>>,
|
2015-02-22 23:05:19 +00:00
|
|
|
notice_handler: Box<HandleNotice>,
|
2015-02-20 21:56:03 +00:00
|
|
|
notifications: VecDeque<Notification>,
|
2014-11-01 23:19:02 +00:00
|
|
|
cancel_data: CancelData,
|
2016-01-03 04:07:33 +00:00
|
|
|
unknown_types: HashMap<Oid, Other>,
|
2016-01-03 05:02:54 +00:00
|
|
|
cached_statements: HashMap<String, Arc<StatementInfo>>,
|
2015-02-16 04:22:56 +00:00
|
|
|
parameters: HashMap<String, String>,
|
2015-01-29 04:35:17 +00:00
|
|
|
next_stmt_id: u32,
|
2014-05-19 02:34:01 +00:00
|
|
|
trans_depth: u32,
|
2015-01-29 04:35:17 +00:00
|
|
|
desynchronized: bool,
|
|
|
|
finished: bool,
|
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 {
|
2015-12-06 00:15:19 +00:00
|
|
|
fn connect<T>(params: T, ssl: SslMode) -> result::Result<InnerConnection, ConnectError>
|
2015-11-16 03:51:04 +00:00
|
|
|
where T: IntoConnectParams
|
|
|
|
{
|
2016-01-02 23:50:11 +00:00
|
|
|
let params = try!(params.into_connect_params().map_err(ConnectError::ConnectParams));
|
2015-04-28 05:26:20 +00:00
|
|
|
let stream = try!(priv_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
|
|
|
|
2016-01-02 23:50:11 +00:00
|
|
|
let user = match user {
|
|
|
|
Some(user) => user,
|
|
|
|
None => {
|
2016-04-05 05:55:13 +00:00
|
|
|
return Err(ConnectError::ConnectParams("User missing from connection parameters".into()));
|
2016-01-02 23:50:11 +00:00
|
|
|
}
|
|
|
|
};
|
2014-04-21 05:27:55 +00:00
|
|
|
|
2014-11-01 23:21:47 +00:00
|
|
|
let mut conn = InnerConnection {
|
2015-02-26 17:02:32 +00:00
|
|
|
stream: BufStream::new(stream),
|
2014-05-28 04:07:58 +00:00
|
|
|
next_stmt_id: 0,
|
2015-02-22 23:05:19 +00:00
|
|
|
notice_handler: Box::new(LoggingNoticeHandler),
|
2015-02-20 21:56:03 +00:00
|
|
|
notifications: VecDeque::new(),
|
2015-11-16 03:51:04 +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(),
|
2015-02-16 04:22:56 +00:00
|
|
|
parameters: HashMap::new(),
|
2014-05-28 04:07:58 +00:00
|
|
|
desynchronized: false,
|
|
|
|
finished: false,
|
|
|
|
trans_depth: 0,
|
|
|
|
};
|
|
|
|
|
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.
|
2015-05-14 05:59:25 +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
|
|
|
|
2016-04-05 05:51:56 +00:00
|
|
|
try!(conn.write_messages(&[Frontend::StartupMessage {
|
2015-11-16 03:51:04 +00:00
|
|
|
version: message::PROTOCOL_VERSION,
|
|
|
|
parameters: &options,
|
|
|
|
}]));
|
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()) {
|
2016-04-05 05:51:56 +00:00
|
|
|
Backend::BackendKeyData { process_id, secret_key } => {
|
2013-10-21 00:32:14 +00:00
|
|
|
conn.cancel_data.process_id = process_id;
|
|
|
|
conn.cancel_data.secret_key = secret_key;
|
|
|
|
}
|
2016-04-05 05:51:56 +00:00
|
|
|
Backend::ReadyForQuery { .. } => break,
|
|
|
|
Backend::ErrorResponse { fields } => return DbError::new_connect(fields),
|
2015-12-26 03:14:09 +00:00
|
|
|
_ => return Err(ConnectError::Io(bad_response())),
|
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)
|
|
|
|
}
|
|
|
|
|
2015-11-16 03:51:04 +00:00
|
|
|
#[cfg_attr(rustfmt, rustfmt_skip)]
|
2015-01-22 08:04:58 +00:00
|
|
|
fn setup_typeinfo_query(&mut self) -> result::Result<(), ConnectError> {
|
2016-02-18 06:22:31 +00:00
|
|
|
match self.raw_prepare(TYPEINFO_ENUM_QUERY,
|
|
|
|
"SELECT enumlabel \
|
|
|
|
FROM pg_catalog.pg_enum \
|
|
|
|
WHERE enumtypid = $1 \
|
|
|
|
ORDER BY enumsortorder") {
|
|
|
|
Ok(..) => {}
|
|
|
|
Err(Error::Io(e)) => return Err(ConnectError::Io(e)),
|
2016-03-31 04:31:33 +00:00
|
|
|
// Old versions of Postgres and things like Redshift don't support enums
|
|
|
|
Err(Error::Db(ref e)) if e.code == SqlState::UndefinedTable => {}
|
2016-02-18 06:22:31 +00:00
|
|
|
Err(Error::Db(e)) => return Err(ConnectError::Db(e)),
|
|
|
|
Err(Error::Conversion(_)) => unreachable!(),
|
|
|
|
}
|
|
|
|
|
2016-02-20 23:21:24 +00:00
|
|
|
match self.raw_prepare(TYPEINFO_COMPOSITE_QUERY,
|
2016-02-16 07:11:01 +00:00
|
|
|
"SELECT attname, atttypid \
|
|
|
|
FROM pg_catalog.pg_attribute \
|
|
|
|
WHERE attrelid = $1 \
|
2016-02-18 06:22:31 +00:00
|
|
|
AND NOT attisdropped \
|
|
|
|
AND attnum > 0 \
|
2016-02-16 07:11:01 +00:00
|
|
|
ORDER BY attnum") {
|
|
|
|
Ok(..) => {}
|
|
|
|
Err(Error::Io(e)) => return Err(ConnectError::Io(e)),
|
2016-03-31 04:31:33 +00:00
|
|
|
// Old versions of Postgres and things like Redshift don't support composites
|
|
|
|
Err(Error::Db(ref e)) if e.code == SqlState::UndefinedTable => {}
|
2016-02-16 07:11:01 +00:00
|
|
|
Err(Error::Db(e)) => return Err(ConnectError::Db(e)),
|
|
|
|
Err(Error::Conversion(_)) => unreachable!(),
|
|
|
|
}
|
|
|
|
|
2015-01-22 08:04:58 +00:00
|
|
|
match self.raw_prepare(TYPEINFO_QUERY,
|
2016-02-14 05:51:37 +00:00
|
|
|
"SELECT t.typname, t.typtype, t.typelem, r.rngsubtype, \
|
2016-02-16 07:11:01 +00:00
|
|
|
t.typbasetype, n.nspname, t.typrelid \
|
2015-01-22 08:04:58 +00:00
|
|
|
FROM pg_catalog.pg_type t \
|
2015-11-16 03:51:04 +00:00
|
|
|
LEFT OUTER JOIN pg_catalog.pg_range r ON \
|
|
|
|
r.rngtypid = t.oid \
|
|
|
|
INNER JOIN pg_catalog.pg_namespace n ON \
|
|
|
|
t.typnamespace = n.oid \
|
2015-01-22 08:04:58 +00:00
|
|
|
WHERE t.oid = $1") {
|
|
|
|
Ok(..) => return Ok(()),
|
2015-12-26 03:14:09 +00:00
|
|
|
Err(Error::Io(e)) => return Err(ConnectError::Io(e)),
|
2015-12-13 04:30:50 +00:00
|
|
|
// Range types weren't added until Postgres 9.2, so pg_range may not exist
|
2015-12-26 03:14:09 +00:00
|
|
|
Err(Error::Db(ref e)) if e.code == SqlState::UndefinedTable => {}
|
|
|
|
Err(Error::Db(e)) => return Err(ConnectError::Db(e)),
|
2015-12-28 04:14:04 +00:00
|
|
|
Err(Error::Conversion(_)) => unreachable!(),
|
2014-12-15 00:43:17 +00:00
|
|
|
}
|
|
|
|
|
2015-01-22 08:04:58 +00:00
|
|
|
match self.raw_prepare(TYPEINFO_QUERY,
|
2016-02-14 05:51:37 +00:00
|
|
|
"SELECT t.typname, t.typtype, t.typelem, NULL::OID, t.typbasetype, \
|
2016-02-17 19:26:43 +00:00
|
|
|
n.nspname, t.typrelid \
|
2015-09-26 20:23:55 +00:00
|
|
|
FROM pg_catalog.pg_type t \
|
|
|
|
INNER JOIN pg_catalog.pg_namespace n \
|
|
|
|
ON t.typnamespace = n.oid \
|
|
|
|
WHERE t.oid = $1") {
|
2015-01-22 08:04:58 +00:00
|
|
|
Ok(..) => Ok(()),
|
2015-12-26 03:14:09 +00:00
|
|
|
Err(Error::Io(e)) => Err(ConnectError::Io(e)),
|
|
|
|
Err(Error::Db(e)) => Err(ConnectError::Db(e)),
|
2015-12-28 04:14:04 +00:00
|
|
|
Err(Error::Conversion(_)) => unreachable!(),
|
2015-01-22 08:04:58 +00:00
|
|
|
}
|
2013-08-05 00:48:48 +00:00
|
|
|
}
|
|
|
|
|
2016-04-05 05:35:45 +00:00
|
|
|
fn write_messages(&mut self, messages: &[Frontend]) -> std_io::Result<()> {
|
2014-07-26 03:15:24 +00:00
|
|
|
debug_assert!(!self.desynchronized);
|
2015-02-03 17:06:52 +00:00
|
|
|
for message in messages {
|
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
|
|
|
|
2016-04-05 05:35:45 +00:00
|
|
|
fn read_message_with_notification(&mut self) -> std_io::Result<Backend> {
|
2015-06-23 06:47:28 +00:00
|
|
|
debug_assert!(!self.desynchronized);
|
2014-12-03 04:34:46 +00:00
|
|
|
loop {
|
2015-06-23 06:47:28 +00:00
|
|
|
match try_desync!(self, self.stream.read_message()) {
|
2016-04-05 05:51:56 +00:00
|
|
|
Backend::NoticeResponse { fields } => {
|
2015-06-23 06:47:28 +00:00
|
|
|
if let Ok(err) = DbError::new_raw(fields) {
|
|
|
|
self.notice_handler.handle_notice(err);
|
|
|
|
}
|
|
|
|
}
|
2016-04-05 05:51:56 +00:00
|
|
|
Backend::ParameterStatus { parameter, value } => {
|
2015-06-23 06:47:28 +00:00
|
|
|
self.parameters.insert(parameter, value);
|
|
|
|
}
|
2015-11-16 03:51:04 +00:00
|
|
|
val => return Ok(val),
|
2014-11-26 02:30:28 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-11-16 03:51:04 +00:00
|
|
|
fn read_message_with_notification_timeout(&mut self,
|
|
|
|
timeout: Duration)
|
2016-04-05 05:35:45 +00:00
|
|
|
-> std::io::Result<Option<Backend>> {
|
2015-10-21 06:13:26 +00:00
|
|
|
debug_assert!(!self.desynchronized);
|
|
|
|
loop {
|
|
|
|
match try_desync!(self, self.stream.read_message_timeout(timeout)) {
|
2016-04-05 05:51:56 +00:00
|
|
|
Some(Backend::NoticeResponse { fields }) => {
|
2015-10-21 06:13:26 +00:00
|
|
|
if let Ok(err) = DbError::new_raw(fields) {
|
|
|
|
self.notice_handler.handle_notice(err);
|
|
|
|
}
|
|
|
|
}
|
2016-04-05 05:51:56 +00:00
|
|
|
Some(Backend::ParameterStatus { parameter, value }) => {
|
2015-10-21 06:13:26 +00:00
|
|
|
self.parameters.insert(parameter, value);
|
|
|
|
}
|
2015-11-16 03:51:04 +00:00
|
|
|
val => return Ok(val),
|
2015-10-21 06:13:26 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-12-27 17:13:42 +00:00
|
|
|
fn read_message_with_notification_nonblocking(&mut self)
|
2016-04-05 05:35:45 +00:00
|
|
|
-> std::io::Result<Option<Backend>> {
|
2015-12-27 17:13:42 +00:00
|
|
|
debug_assert!(!self.desynchronized);
|
|
|
|
loop {
|
|
|
|
match try_desync!(self, self.stream.read_message_nonblocking()) {
|
2016-04-05 05:51:56 +00:00
|
|
|
Some(Backend::NoticeResponse { fields }) => {
|
2015-12-27 17:13:42 +00:00
|
|
|
if let Ok(err) = DbError::new_raw(fields) {
|
|
|
|
self.notice_handler.handle_notice(err);
|
|
|
|
}
|
|
|
|
}
|
2016-04-05 05:51:56 +00:00
|
|
|
Some(Backend::ParameterStatus { parameter, value }) => {
|
2015-12-27 17:13:42 +00:00
|
|
|
self.parameters.insert(parameter, value);
|
|
|
|
}
|
|
|
|
val => return Ok(val),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-04-05 05:35:45 +00:00
|
|
|
fn read_message(&mut self) -> std_io::Result<Backend> {
|
2014-11-26 02:30:28 +00:00
|
|
|
loop {
|
|
|
|
match try!(self.read_message_with_notification()) {
|
2016-04-05 05:51:56 +00:00
|
|
|
Backend::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,
|
2015-11-16 03:51:04 +00:00
|
|
|
payload: payload,
|
2014-08-16 02:50:11 +00:00
|
|
|
})
|
|
|
|
}
|
2015-11-16 03:51:04 +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()) {
|
2016-04-05 05:51:56 +00:00
|
|
|
Backend::AuthenticationOk => return Ok(()),
|
|
|
|
Backend::AuthenticationCleartextPassword => {
|
2016-01-02 23:50:11 +00:00
|
|
|
let pass = try!(user.password.ok_or_else(|| {
|
|
|
|
ConnectError::ConnectParams("a password was requested but not provided".into())
|
|
|
|
}));
|
2016-04-05 05:51:56 +00:00
|
|
|
try!(self.write_messages(&[Frontend::PasswordMessage { password: &pass }]));
|
2013-09-09 03:35:24 +00:00
|
|
|
}
|
2016-04-05 05:51:56 +00:00
|
|
|
Backend::AuthenticationMD5Password { salt } => {
|
2016-01-02 23:50:11 +00:00
|
|
|
let pass = try!(user.password.ok_or_else(|| {
|
|
|
|
ConnectError::ConnectParams("a password was requested but not provided".into())
|
|
|
|
}));
|
2015-04-28 05:52:06 +00:00
|
|
|
let mut hasher = Md5::new();
|
2015-12-29 22:16:15 +00:00
|
|
|
hasher.input(pass.as_bytes());
|
|
|
|
hasher.input(user.user.as_bytes());
|
2015-04-28 05:52:06 +00:00
|
|
|
let output = hasher.result_str();
|
|
|
|
hasher.reset();
|
2015-12-29 22:16:15 +00:00
|
|
|
hasher.input(output.as_bytes());
|
|
|
|
hasher.input(&salt);
|
2015-04-28 05:52:06 +00:00
|
|
|
let output = format!("md5{}", hasher.result_str());
|
2016-04-05 05:51:56 +00:00
|
|
|
try!(self.write_messages(&[Frontend::PasswordMessage { password: &output }]));
|
2013-11-06 06:04:12 +00:00
|
|
|
}
|
2016-04-05 05:51:56 +00:00
|
|
|
Backend::AuthenticationKerberosV5 |
|
|
|
|
Backend::AuthenticationSCMCredential |
|
|
|
|
Backend::AuthenticationGSS |
|
|
|
|
Backend::AuthenticationSSPI => {
|
2016-01-02 23:50:11 +00:00
|
|
|
return Err(ConnectError::Io(std_io::Error::new(std_io::ErrorKind::Other,
|
|
|
|
"unsupported authentication")))
|
|
|
|
}
|
2016-04-05 05:51:56 +00:00
|
|
|
Backend::ErrorResponse { fields } => return DbError::new_connect(fields),
|
2015-12-26 03:14:09 +00:00
|
|
|
_ => return Err(ConnectError::Io(bad_response())),
|
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()) {
|
2016-04-05 05:51:56 +00:00
|
|
|
Backend::AuthenticationOk => Ok(()),
|
|
|
|
Backend::ErrorResponse { fields } => DbError::new_connect(fields),
|
2016-02-20 23:05:48 +00:00
|
|
|
_ => Err(ConnectError::Io(bad_response())),
|
2013-09-09 03:35:24 +00:00
|
|
|
}
|
2013-08-26 05:08:37 +00:00
|
|
|
}
|
|
|
|
|
2015-02-22 23:05:19 +00:00
|
|
|
fn set_notice_handler(&mut self, handler: Box<HandleNotice>) -> Box<HandleNotice> {
|
2014-02-11 03:20:53 +00:00
|
|
|
mem::replace(&mut self.notice_handler, handler)
|
2013-08-27 05:06:53 +00:00
|
|
|
}
|
|
|
|
|
2015-05-18 04:04:44 +00:00
|
|
|
fn raw_prepare(&mut self, stmt_name: &str, query: &str) -> Result<(Vec<Type>, Vec<Column>)> {
|
2015-03-31 03:18:47 +00:00
|
|
|
debug!("preparing query with name `{}`: {}", stmt_name, query);
|
|
|
|
|
2016-04-05 05:51:56 +00:00
|
|
|
try!(self.write_messages(&[Frontend::Parse {
|
2015-11-16 03:51:04 +00:00
|
|
|
name: stmt_name,
|
|
|
|
query: query,
|
|
|
|
param_types: &[],
|
|
|
|
},
|
2016-04-05 05:51:56 +00:00
|
|
|
Frontend::Describe {
|
2015-11-16 03:51:04 +00:00
|
|
|
variant: b'S',
|
|
|
|
name: stmt_name,
|
|
|
|
},
|
2016-04-05 05:51:56 +00:00
|
|
|
Frontend::Sync]));
|
2013-08-22 06:41:26 +00:00
|
|
|
|
2014-11-17 06:54:57 +00:00
|
|
|
match try!(self.read_message()) {
|
2016-04-05 05:51:56 +00:00
|
|
|
Backend::ParseComplete => {}
|
|
|
|
Backend::ErrorResponse { fields } => {
|
2014-02-22 07:18:39 +00:00
|
|
|
try!(self.wait_for_ready());
|
2015-05-23 02:51:44 +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()) {
|
2016-04-05 05:51:56 +00:00
|
|
|
Backend::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-02-06 07:08:53 +00:00
|
|
|
let raw_columns = match try!(self.read_message()) {
|
2016-04-05 05:51:56 +00:00
|
|
|
Backend::RowDescription { descriptions } => descriptions,
|
|
|
|
Backend::NoData => vec![],
|
2015-11-16 03:51:04 +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![];
|
2015-02-03 17:06:52 +00:00
|
|
|
for oid in raw_param_types {
|
2015-01-22 06:11:43 +00:00
|
|
|
param_types.push(try!(self.get_type(oid)));
|
|
|
|
}
|
|
|
|
|
2015-02-06 07:08:53 +00:00
|
|
|
let mut columns = vec![];
|
|
|
|
for RowDescriptionEntry { name, type_oid, .. } in raw_columns {
|
2015-08-16 04:39:46 +00:00
|
|
|
columns.push(Column::new(name, try!(self.get_type(type_oid))));
|
2014-12-02 06:24:31 +00:00
|
|
|
}
|
2013-12-04 08:18:28 +00:00
|
|
|
|
2015-02-06 07:08:53 +00:00
|
|
|
Ok((param_types, columns))
|
2014-12-02 05:28:58 +00:00
|
|
|
}
|
|
|
|
|
2016-02-16 06:16:26 +00:00
|
|
|
fn read_rows(&mut self, buf: &mut VecDeque<Vec<Option<Vec<u8>>>>) -> Result<bool> {
|
|
|
|
let more_rows;
|
|
|
|
loop {
|
|
|
|
match try!(self.read_message()) {
|
2016-04-05 05:51:56 +00:00
|
|
|
Backend::EmptyQueryResponse | Backend::CommandComplete { .. } => {
|
2016-02-16 06:16:26 +00:00
|
|
|
more_rows = false;
|
|
|
|
break;
|
|
|
|
}
|
2016-04-05 05:51:56 +00:00
|
|
|
Backend::PortalSuspended => {
|
2016-02-16 06:16:26 +00:00
|
|
|
more_rows = true;
|
|
|
|
break;
|
|
|
|
}
|
2016-04-05 05:51:56 +00:00
|
|
|
Backend::DataRow { row } => buf.push_back(row),
|
|
|
|
Backend::ErrorResponse { fields } => {
|
2016-02-16 06:16:26 +00:00
|
|
|
try!(self.wait_for_ready());
|
|
|
|
return DbError::new(fields);
|
|
|
|
}
|
2016-04-05 05:51:56 +00:00
|
|
|
Backend::CopyInResponse { .. } => {
|
|
|
|
try!(self.write_messages(&[Frontend::CopyFail {
|
2016-02-22 04:02:34 +00:00
|
|
|
message: "COPY queries cannot be directly \
|
|
|
|
executed",
|
2016-02-16 06:16:26 +00:00
|
|
|
},
|
2016-04-05 05:51:56 +00:00
|
|
|
Frontend::Sync]));
|
2016-02-16 06:16:26 +00:00
|
|
|
}
|
2016-04-05 05:51:56 +00:00
|
|
|
Backend::CopyOutResponse { .. } => {
|
2016-02-16 06:16:26 +00:00
|
|
|
loop {
|
2016-04-05 05:51:56 +00:00
|
|
|
if let Backend::ReadyForQuery { .. } = try!(self.read_message()) {
|
2016-02-20 23:05:48 +00:00
|
|
|
break;
|
2016-02-16 06:16:26 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return Err(Error::Io(std_io::Error::new(std_io::ErrorKind::InvalidInput,
|
|
|
|
"COPY queries cannot be directly \
|
|
|
|
executed")));
|
|
|
|
}
|
|
|
|
_ => {
|
|
|
|
self.desynchronized = true;
|
|
|
|
return Err(Error::Io(bad_response()));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
try!(self.wait_for_ready());
|
|
|
|
Ok(more_rows)
|
|
|
|
}
|
|
|
|
|
2016-02-16 06:25:52 +00:00
|
|
|
fn raw_execute(&mut self,
|
|
|
|
stmt_name: &str,
|
|
|
|
portal_name: &str,
|
|
|
|
row_limit: i32,
|
|
|
|
param_types: &[Type],
|
|
|
|
params: &[&ToSql])
|
|
|
|
-> Result<()> {
|
|
|
|
assert!(param_types.len() == params.len(),
|
|
|
|
"expected {} parameters but got {}",
|
|
|
|
param_types.len(),
|
|
|
|
params.len());
|
2016-02-22 04:02:34 +00:00
|
|
|
debug!("executing statement {} with parameters: {:?}",
|
|
|
|
stmt_name,
|
|
|
|
params);
|
2016-02-16 06:25:52 +00:00
|
|
|
let mut values = vec![];
|
|
|
|
for (param, ty) in params.iter().zip(param_types) {
|
|
|
|
let mut buf = vec![];
|
|
|
|
match try!(param.to_sql_checked(ty, &mut buf, &SessionInfo::new(self))) {
|
|
|
|
IsNull::Yes => values.push(None),
|
|
|
|
IsNull::No => values.push(Some(buf)),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-04-05 05:51:56 +00:00
|
|
|
try!(self.write_messages(&[Frontend::Bind {
|
2016-02-16 06:25:52 +00:00
|
|
|
portal: portal_name,
|
|
|
|
statement: &stmt_name,
|
|
|
|
formats: &[1],
|
|
|
|
values: &values,
|
|
|
|
result_formats: &[1],
|
|
|
|
},
|
2016-04-05 05:51:56 +00:00
|
|
|
Frontend::Execute {
|
2016-02-16 06:25:52 +00:00
|
|
|
portal: portal_name,
|
|
|
|
max_rows: row_limit,
|
|
|
|
},
|
2016-04-05 05:51:56 +00:00
|
|
|
Frontend::Sync]));
|
2016-02-16 06:25:52 +00:00
|
|
|
|
|
|
|
match try!(self.read_message()) {
|
2016-04-05 05:51:56 +00:00
|
|
|
Backend::BindComplete => Ok(()),
|
|
|
|
Backend::ErrorResponse { fields } => {
|
2016-02-16 06:25:52 +00:00
|
|
|
try!(self.wait_for_ready());
|
|
|
|
DbError::new(fields)
|
|
|
|
}
|
|
|
|
_ => {
|
|
|
|
self.desynchronized = true;
|
|
|
|
Err(Error::Io(bad_response()))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-12-02 05:28:58 +00:00
|
|
|
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();
|
2015-02-06 07:08:53 +00:00
|
|
|
let (param_types, columns) = try!(self.raw_prepare(&stmt_name, query));
|
2016-01-03 05:02:54 +00:00
|
|
|
let info = Arc::new(StatementInfo {
|
|
|
|
name: stmt_name,
|
|
|
|
param_types: param_types,
|
|
|
|
columns: columns,
|
|
|
|
});
|
|
|
|
Ok(Statement::new(conn, info, Cell::new(0), false))
|
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>> {
|
2016-01-03 05:02:54 +00:00
|
|
|
let info = self.cached_statements.get(query).cloned();
|
2015-01-23 06:24:47 +00:00
|
|
|
|
2016-01-03 05:02:54 +00:00
|
|
|
let info = match info {
|
|
|
|
Some(info) => info,
|
2015-01-23 06:24:47 +00:00
|
|
|
None => {
|
|
|
|
let stmt_name = self.make_stmt_name();
|
2015-02-06 07:08:53 +00:00
|
|
|
let (param_types, columns) = try!(self.raw_prepare(&stmt_name, query));
|
2016-01-03 05:02:54 +00:00
|
|
|
let info = Arc::new(StatementInfo {
|
2015-01-23 06:24:47 +00:00
|
|
|
name: stmt_name,
|
|
|
|
param_types: param_types,
|
2015-02-06 07:08:53 +00:00
|
|
|
columns: columns,
|
2016-01-03 05:02:54 +00:00
|
|
|
});
|
|
|
|
self.cached_statements.insert(query.to_owned(), info.clone());
|
|
|
|
info
|
2015-01-23 06:24:47 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2016-01-03 05:02:54 +00:00
|
|
|
Ok(Statement::new(conn, info, Cell::new(0), true))
|
2015-01-23 06:24:47 +00:00
|
|
|
}
|
|
|
|
|
2014-11-28 23:01:01 +00:00
|
|
|
fn close_statement(&mut self, name: &str, type_: u8) -> Result<()> {
|
2016-04-05 05:51:56 +00:00
|
|
|
try!(self.write_messages(&[Frontend::Close {
|
2015-11-16 03:51:04 +00:00
|
|
|
variant: type_,
|
|
|
|
name: name,
|
|
|
|
},
|
2016-04-05 05:51:56 +00:00
|
|
|
Frontend::Sync]));
|
2014-11-28 23:01:01 +00:00
|
|
|
let resp = match try!(self.read_message()) {
|
2016-04-05 05:51:56 +00:00
|
|
|
Backend::CloseComplete => Ok(()),
|
|
|
|
Backend::ErrorResponse { fields } => DbError::new(fields),
|
2015-11-16 03:51:04 +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> {
|
2015-09-27 05:57:36 +00:00
|
|
|
if let Some(ty) = Type::from_oid(oid) {
|
2015-01-22 06:11:43 +00:00
|
|
|
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) {
|
2016-01-03 04:07:33 +00:00
|
|
|
return Ok(Type::Other(ty.clone()));
|
2013-12-04 08:18:28 +00:00
|
|
|
}
|
2015-01-22 06:11:43 +00:00
|
|
|
|
2016-02-20 23:20:25 +00:00
|
|
|
let ty = try!(self.read_type(oid));
|
|
|
|
self.unknown_types.insert(oid, ty.clone());
|
|
|
|
Ok(Type::Other(ty))
|
|
|
|
}
|
|
|
|
|
|
|
|
fn read_type(&mut self, oid: Oid) -> Result<Other> {
|
2016-02-16 06:29:22 +00:00
|
|
|
try!(self.raw_execute(TYPEINFO_QUERY, "", 0, &[Type::Oid], &[&oid]));
|
|
|
|
let mut rows = VecDeque::new();
|
|
|
|
try!(self.read_rows(&mut rows));
|
|
|
|
let row = rows.pop_front().unwrap();
|
|
|
|
|
2016-02-16 07:11:01 +00:00
|
|
|
let (name, type_, elem_oid, rngsubtype, basetype, schema, relid) = {
|
2016-02-16 06:29:22 +00:00
|
|
|
let ctx = SessionInfo::new(self);
|
2016-02-22 04:02:34 +00:00
|
|
|
let name = try!(String::from_sql(&Type::Name, &mut &**row[0].as_ref().unwrap(), &ctx));
|
|
|
|
let type_ = try!(i8::from_sql(&Type::Char, &mut &**row[1].as_ref().unwrap(), &ctx));
|
|
|
|
let elem_oid = try!(Oid::from_sql(&Type::Oid, &mut &**row[2].as_ref().unwrap(), &ctx));
|
2016-02-16 06:29:22 +00:00
|
|
|
let rngsubtype = match row[3] {
|
|
|
|
Some(ref data) => try!(Option::<Oid>::from_sql(&Type::Oid, &mut &**data, &ctx)),
|
|
|
|
None => try!(Option::<Oid>::from_sql_null(&Type::Oid, &ctx)),
|
|
|
|
};
|
2016-02-22 04:02:34 +00:00
|
|
|
let basetype = try!(Oid::from_sql(&Type::Oid, &mut &**row[4].as_ref().unwrap(), &ctx));
|
2016-02-16 06:29:22 +00:00
|
|
|
let schema = try!(String::from_sql(&Type::Name,
|
|
|
|
&mut &**row[5].as_ref().unwrap(),
|
|
|
|
&ctx));
|
2016-02-22 04:02:34 +00:00
|
|
|
let relid = try!(Oid::from_sql(&Type::Oid, &mut &**row[6].as_ref().unwrap(), &ctx));
|
2016-02-16 07:11:01 +00:00
|
|
|
(name, type_, elem_oid, rngsubtype, basetype, schema, relid)
|
2015-11-15 01:05:31 +00:00
|
|
|
};
|
2015-01-22 06:11:43 +00:00
|
|
|
|
2016-02-14 05:51:37 +00:00
|
|
|
let kind = if type_ == b'e' as i8 {
|
2016-02-20 23:20:25 +00:00
|
|
|
Kind::Enum(try!(self.read_enum_variants(oid)))
|
2016-02-14 05:51:37 +00:00
|
|
|
} else if type_ == b'p' as i8 {
|
|
|
|
Kind::Pseudo
|
|
|
|
} else if basetype != 0 {
|
2016-01-23 04:00:42 +00:00
|
|
|
Kind::Domain(try!(self.get_type(basetype)))
|
|
|
|
} else if elem_oid != 0 {
|
2015-02-14 20:46:18 +00:00
|
|
|
Kind::Array(try!(self.get_type(elem_oid)))
|
2016-02-16 07:11:01 +00:00
|
|
|
} else if relid != 0 {
|
2016-02-20 23:20:25 +00:00
|
|
|
Kind::Composite(try!(self.read_composite_fields(relid)))
|
2015-01-22 06:11:43 +00:00
|
|
|
} else {
|
2015-02-14 20:46:18 +00:00
|
|
|
match rngsubtype {
|
|
|
|
Some(oid) => Kind::Range(try!(self.get_type(oid))),
|
2015-11-16 03:51:04 +00:00
|
|
|
None => Kind::Simple,
|
2015-02-14 20:46:18 +00:00
|
|
|
}
|
2015-01-22 06:11:43 +00:00
|
|
|
};
|
2015-02-14 20:46:18 +00:00
|
|
|
|
2016-02-20 23:20:25 +00:00
|
|
|
Ok(Other::new(name, oid, kind, schema))
|
|
|
|
}
|
|
|
|
|
|
|
|
fn read_enum_variants(&mut self, oid: Oid) -> Result<Vec<String>> {
|
|
|
|
try!(self.raw_execute(TYPEINFO_ENUM_QUERY, "", 0, &[Type::Oid], &[&oid]));
|
|
|
|
let mut rows = VecDeque::new();
|
|
|
|
try!(self.read_rows(&mut rows));
|
|
|
|
|
|
|
|
let ctx = SessionInfo::new(self);
|
|
|
|
let mut variants = vec![];
|
|
|
|
for row in rows {
|
|
|
|
variants.push(try!(String::from_sql(&Type::Name,
|
|
|
|
&mut &**row[0].as_ref().unwrap(),
|
|
|
|
&ctx)));
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(variants)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn read_composite_fields(&mut self, relid: Oid) -> Result<Vec<Field>> {
|
2016-02-20 23:21:24 +00:00
|
|
|
try!(self.raw_execute(TYPEINFO_COMPOSITE_QUERY, "", 0, &[Type::Oid], &[&relid]));
|
2016-02-20 23:20:25 +00:00
|
|
|
let mut rows = VecDeque::new();
|
|
|
|
try!(self.read_rows(&mut rows));
|
|
|
|
|
|
|
|
let mut fields = vec![];
|
|
|
|
for row in rows {
|
|
|
|
let (name, type_) = {
|
|
|
|
let ctx = SessionInfo::new(self);
|
|
|
|
let name = try!(String::from_sql(&Type::Name,
|
|
|
|
&mut &**row[0].as_ref().unwrap(),
|
|
|
|
&ctx));
|
2016-02-22 04:02:34 +00:00
|
|
|
let type_ = try!(Oid::from_sql(&Type::Oid, &mut &**row[1].as_ref().unwrap(), &ctx));
|
2016-02-20 23:20:25 +00:00
|
|
|
(name, type_)
|
|
|
|
};
|
|
|
|
let type_ = try!(self.get_type(type_));
|
|
|
|
fields.push(Field::new(name, type_));
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(fields)
|
2013-12-04 08:18:28 +00:00
|
|
|
}
|
|
|
|
|
2014-03-30 23:19:04 +00:00
|
|
|
fn is_desynchronized(&self) -> bool {
|
|
|
|
self.desynchronized
|
|
|
|
}
|
|
|
|
|
2016-02-20 23:26:33 +00:00
|
|
|
#[allow(needless_return)]
|
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()) {
|
2016-04-05 05:51:56 +00:00
|
|
|
Backend::ReadyForQuery { .. } => Ok(()),
|
2015-11-16 03:51:04 +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);
|
2015-03-31 03:18:47 +00:00
|
|
|
debug!("executing query: {}", query);
|
2016-04-05 05:51:56 +00:00
|
|
|
try!(self.write_messages(&[Frontend::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()) {
|
2016-04-05 05:51:56 +00:00
|
|
|
Backend::ReadyForQuery { .. } => break,
|
|
|
|
Backend::DataRow { row } => {
|
2015-11-16 03:51:04 +00:00
|
|
|
result.push(row.into_iter()
|
|
|
|
.map(|opt| {
|
|
|
|
opt.map(|b| String::from_utf8_lossy(&b).into_owned())
|
|
|
|
})
|
|
|
|
.collect());
|
2014-04-26 21:46:38 +00:00
|
|
|
}
|
2016-04-05 05:51:56 +00:00
|
|
|
Backend::CopyInResponse { .. } => {
|
|
|
|
try!(self.write_messages(&[Frontend::CopyFail {
|
2015-11-16 03:51:04 +00:00
|
|
|
message: "COPY queries cannot be directly \
|
|
|
|
executed",
|
|
|
|
},
|
2016-04-05 05:51:56 +00:00
|
|
|
Frontend::Sync]));
|
2014-10-06 00:31:25 +00:00
|
|
|
}
|
2016-04-05 05:51:56 +00:00
|
|
|
Backend::ErrorResponse { fields } => {
|
2014-02-22 07:18:39 +00:00
|
|
|
try!(self.wait_for_ready());
|
2015-05-23 02:51:44 +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);
|
2016-04-05 05:51:56 +00:00
|
|
|
try!(self.write_messages(&[Frontend::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
|
|
|
}
|
|
|
|
|
2015-07-22 14:41:40 +00:00
|
|
|
fn _ensure_send() {
|
2015-12-05 22:44:40 +00:00
|
|
|
fn _is_send<T: Send>() {}
|
2015-07-22 14:41:40 +00:00
|
|
|
_is_send::<Connection>();
|
|
|
|
}
|
|
|
|
|
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 {
|
2015-11-16 03:51:04 +00:00
|
|
|
conn: RefCell<InnerConnection>,
|
2013-10-01 07:40:46 +00:00
|
|
|
}
|
2013-09-20 04:06:45 +00:00
|
|
|
|
2015-01-23 18:44:15 +00:00
|
|
|
impl fmt::Debug for Connection {
|
2015-01-10 04:48:47 +00:00
|
|
|
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
|
|
|
let conn = self.conn.borrow();
|
2015-09-19 05:55:32 +00:00
|
|
|
fmt.debug_struct("Connection")
|
2015-12-14 07:27:12 +00:00
|
|
|
.field("stream", &conn.stream.get_ref())
|
2015-11-16 03:51:04 +00:00
|
|
|
.field("cancel_data", &conn.cancel_data)
|
|
|
|
.field("notifications", &conn.notifications.len())
|
|
|
|
.field("transaction_depth", &conn.trans_depth)
|
|
|
|
.field("desynchronized", &conn.desynchronized)
|
|
|
|
.field("cached_statements", &conn.cached_statements.len())
|
|
|
|
.finish()
|
2015-01-10 04:48:47 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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
|
|
|
///
|
2016-03-27 20:06:12 +00:00
|
|
|
/// Connection via Unix sockets is supported with either the `unix_socket`
|
|
|
|
/// or `nightly` features. To connect to the server via Unix sockets, `host`
|
|
|
|
/// should be set to the absolute path of the directory containing the
|
|
|
|
/// socket file. Since `/` is a reserved character in URLs, the path should
|
|
|
|
/// be URL encoded. If the path contains non-UTF 8 characters, a
|
|
|
|
/// `ConnectParams` struct 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
|
|
|
///
|
2015-11-29 05:05:13 +00:00
|
|
|
/// # Examples
|
2014-03-09 22:22:20 +00:00
|
|
|
///
|
2014-03-10 17:06:40 +00:00
|
|
|
/// ```rust,no_run
|
2015-11-30 04:00:25 +00:00
|
|
|
/// use postgres::{Connection, SslMode};
|
|
|
|
///
|
2014-04-21 05:27:55 +00:00
|
|
|
/// let url = "postgresql://postgres:hunter2@localhost:2994/foodb";
|
2015-12-06 00:15:19 +00:00
|
|
|
/// let conn = Connection::connect(url, SslMode::None).unwrap();
|
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-11-30 04:00:25 +00:00
|
|
|
/// use postgres::{Connection, SslMode};
|
|
|
|
///
|
2014-04-22 05:53:14 +00:00
|
|
|
/// let url = "postgresql://postgres@%2Frun%2Fpostgres";
|
2015-12-06 00:15:19 +00:00
|
|
|
/// let conn = Connection::connect(url, SslMode::None).unwrap();
|
2014-04-18 21:29:51 +00:00
|
|
|
/// ```
|
2014-04-22 05:53:14 +00:00
|
|
|
///
|
|
|
|
/// ```rust,no_run
|
2015-11-30 04:00:25 +00:00
|
|
|
/// use postgres::{Connection, UserInfo, ConnectParams, SslMode, ConnectTarget};
|
2015-12-21 04:34:55 +00:00
|
|
|
/// # use std::path::PathBuf;
|
2015-11-30 04:00:25 +00:00
|
|
|
///
|
2015-02-26 17:02:32 +00:00
|
|
|
/// # #[cfg(feature = "unix_socket")]
|
2015-11-30 04:00:25 +00:00
|
|
|
/// # fn f() {
|
2015-12-21 04:34:55 +00:00
|
|
|
/// # let some_crazy_path = PathBuf::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 {
|
2015-09-28 05:19:02 +00:00
|
|
|
/// user: "postgres".to_owned(),
|
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
|
|
|
/// };
|
2015-12-06 00:15:19 +00:00
|
|
|
/// let conn = Connection::connect(params, SslMode::None).unwrap();
|
2015-11-30 04:00:25 +00:00
|
|
|
/// # }
|
2014-04-22 05:53:14 +00:00
|
|
|
/// ```
|
2015-12-06 00:15:19 +00:00
|
|
|
pub fn connect<T>(params: T, ssl: SslMode) -> result::Result<Connection, ConnectError>
|
2015-11-16 03:51:04 +00:00
|
|
|
where T: IntoConnectParams
|
|
|
|
{
|
|
|
|
InnerConnection::connect(params, ssl).map(|conn| Connection { conn: RefCell::new(conn) })
|
2014-04-18 21:29:51 +00:00
|
|
|
}
|
|
|
|
|
2015-12-07 00:46:06 +00:00
|
|
|
/// Executes a statement, returning the number of rows modified.
|
2015-12-07 00:08:37 +00:00
|
|
|
///
|
2015-12-07 00:46:06 +00:00
|
|
|
/// A statement may contain parameters, specified by `$n` where `n` is the
|
|
|
|
/// index of the parameter in the list provided, 1-indexed.
|
|
|
|
///
|
|
|
|
/// If the statement does not modify any rows (e.g. SELECT), 0 is returned.
|
2015-12-07 00:08:37 +00:00
|
|
|
///
|
2015-12-07 00:46:06 +00:00
|
|
|
/// If the same statement will be repeatedly executed (perhaps with
|
|
|
|
/// different query parameters), consider using the `prepare` and
|
|
|
|
/// `prepare_cached` methods.
|
2015-12-07 00:08:37 +00:00
|
|
|
///
|
|
|
|
/// # Panics
|
|
|
|
///
|
|
|
|
/// Panics if the number of parameters provided does not match the number
|
|
|
|
/// expected.
|
2015-12-07 00:46:06 +00:00
|
|
|
///
|
|
|
|
/// # Example
|
|
|
|
///
|
|
|
|
/// ```rust,no_run
|
|
|
|
/// # use postgres::{Connection, SslMode};
|
|
|
|
/// # let conn = Connection::connect("", SslMode::None).unwrap();
|
|
|
|
/// # let bar = 1i32;
|
|
|
|
/// # let baz = true;
|
|
|
|
/// let rows_updated = conn.execute("UPDATE foo SET bar = $1 WHERE baz = $2", &[&bar, &baz])
|
|
|
|
/// .unwrap();
|
|
|
|
/// println!("{} rows updated", rows_updated);
|
|
|
|
/// ```
|
2015-12-07 00:08:37 +00:00
|
|
|
pub fn execute(&self, query: &str, params: &[&ToSql]) -> Result<u64> {
|
|
|
|
let (param_types, columns) = try!(self.conn.borrow_mut().raw_prepare("", query));
|
2016-01-03 05:02:54 +00:00
|
|
|
let info = Arc::new(StatementInfo {
|
|
|
|
name: String::new(),
|
|
|
|
param_types: param_types,
|
|
|
|
columns: columns,
|
|
|
|
});
|
|
|
|
let stmt = Statement::new(self, info, Cell::new(0), true);
|
2015-12-07 00:08:37 +00:00
|
|
|
stmt.execute(params)
|
2013-09-20 04:06:45 +00:00
|
|
|
}
|
|
|
|
|
2015-12-07 00:46:06 +00:00
|
|
|
/// Executes a statement, returning the resulting rows.
|
2015-11-14 03:34:11 +00:00
|
|
|
///
|
2015-12-07 00:46:06 +00:00
|
|
|
/// A statement may contain parameters, specified by `$n` where `n` is the
|
|
|
|
/// index of the parameter in the list provided, 1-indexed.
|
2015-11-14 03:34:11 +00:00
|
|
|
///
|
2015-12-07 00:46:06 +00:00
|
|
|
/// If the same statement will be repeatedly executed (perhaps with
|
|
|
|
/// different query parameters), consider using the `prepare` and
|
|
|
|
/// `prepare_cached` methods.
|
2015-11-14 03:34:11 +00:00
|
|
|
///
|
2015-12-07 00:46:06 +00:00
|
|
|
/// # Panics
|
2015-11-14 03:34:11 +00:00
|
|
|
///
|
|
|
|
/// Panics if the number of parameters provided does not match the number
|
|
|
|
/// expected.
|
2015-12-07 00:46:06 +00:00
|
|
|
///
|
|
|
|
/// # Example
|
|
|
|
///
|
|
|
|
/// ```rust,no_run
|
|
|
|
/// # use postgres::{Connection, SslMode};
|
|
|
|
/// # let conn = Connection::connect("", SslMode::None).unwrap();
|
|
|
|
/// # let baz = true;
|
|
|
|
/// for row in &conn.query("SELECT foo FROM bar WHERE baz = $1", &[&baz]).unwrap() {
|
|
|
|
/// let foo: i32 = row.get("foo");
|
|
|
|
/// println!("foo: {}", foo);
|
|
|
|
/// }
|
|
|
|
/// ```
|
2015-11-14 03:34:11 +00:00
|
|
|
pub fn query<'a>(&'a self, query: &str, params: &[&ToSql]) -> Result<Rows<'a>> {
|
|
|
|
let (param_types, columns) = try!(self.conn.borrow_mut().raw_prepare("", query));
|
2016-01-03 05:02:54 +00:00
|
|
|
let info = Arc::new(StatementInfo {
|
|
|
|
name: String::new(),
|
|
|
|
param_types: param_types,
|
|
|
|
columns: columns,
|
|
|
|
});
|
|
|
|
let stmt = Statement::new(self, info, Cell::new(0), true);
|
2015-11-14 03:34:11 +00:00
|
|
|
stmt.into_query(params)
|
|
|
|
}
|
|
|
|
|
2015-12-07 00:08:37 +00:00
|
|
|
/// Begins a new transaction.
|
2013-10-15 05:41:03 +00:00
|
|
|
///
|
2015-12-07 00:08:37 +00:00
|
|
|
/// Returns a `Transaction` object which should be used instead of
|
|
|
|
/// the connection for the duration of the transaction. The transaction
|
|
|
|
/// is active until the `Transaction` object falls out of scope.
|
|
|
|
///
|
|
|
|
/// # Note
|
|
|
|
/// A transaction will roll back by default. The `set_commit`,
|
|
|
|
/// `set_rollback`, and `commit` methods alter this behavior.
|
|
|
|
///
|
|
|
|
/// # Panics
|
|
|
|
///
|
|
|
|
/// Panics if a transaction is already active.
|
|
|
|
///
|
|
|
|
/// # Example
|
|
|
|
///
|
|
|
|
/// ```rust,no_run
|
|
|
|
/// # use postgres::{Connection, SslMode};
|
2015-12-06 00:15:19 +00:00
|
|
|
/// # let conn = Connection::connect("", SslMode::None).unwrap();
|
2015-12-07 00:08:37 +00:00
|
|
|
/// let trans = conn.transaction().unwrap();
|
|
|
|
/// trans.execute("UPDATE foo SET bar = 10", &[]).unwrap();
|
|
|
|
/// // ...
|
|
|
|
///
|
|
|
|
/// trans.commit().unwrap();
|
|
|
|
/// ```
|
|
|
|
pub fn transaction<'a>(&'a self) -> Result<Transaction<'a>> {
|
2016-02-25 06:29:09 +00:00
|
|
|
self.transaction_with(&transaction::Config::new())
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Begins a new transaction with the specified configuration.
|
|
|
|
pub fn transaction_with<'a>(&'a self, config: &transaction::Config) -> Result<Transaction<'a>> {
|
2015-12-07 00:08:37 +00:00
|
|
|
let mut conn = self.conn.borrow_mut();
|
|
|
|
check_desync!(conn);
|
|
|
|
assert!(conn.trans_depth == 0,
|
|
|
|
"`transaction` must be called on the active transaction");
|
2016-02-25 06:29:09 +00:00
|
|
|
let mut query = "BEGIN".to_owned();
|
|
|
|
config.build_command(&mut query);
|
|
|
|
try!(conn.quick_query(&query));
|
2015-12-07 00:08:37 +00:00
|
|
|
conn.trans_depth += 1;
|
2016-02-24 07:43:28 +00:00
|
|
|
Ok(Transaction::new(self, 1))
|
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
|
|
|
///
|
2015-12-07 00:46:06 +00:00
|
|
|
/// If the same statement will be executed repeatedly, explicitly preparing
|
|
|
|
/// it can improve performance.
|
2013-09-30 02:12:20 +00:00
|
|
|
///
|
|
|
|
/// The statement is associated with the connection that created it and may
|
|
|
|
/// not outlive that connection.
|
2014-03-09 22:22:20 +00:00
|
|
|
///
|
2015-11-29 05:05:13 +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};
|
2015-11-30 04:00:25 +00:00
|
|
|
/// # let x = 10i32;
|
2015-12-06 00:15:19 +00:00
|
|
|
/// # let conn = Connection::connect("", SslMode::None).unwrap();
|
2015-12-13 04:21:44 +00:00
|
|
|
/// # let (a, b) = (0i32, 1i32);
|
|
|
|
/// # let updates = vec![(&a, &b)];
|
|
|
|
/// let stmt = conn.prepare("UPDATE foo SET bar = $1 WHERE baz = $2").unwrap();
|
|
|
|
/// for (bar, baz) in updates {
|
|
|
|
/// stmt.execute(&[bar, baz]).unwrap();
|
2015-11-30 04:00:25 +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)
|
|
|
|
}
|
|
|
|
|
2015-11-01 20:06:38 +00:00
|
|
|
/// Creates a cached prepared statement.
|
2015-01-23 06:24:47 +00:00
|
|
|
///
|
2015-01-23 06:55:18 +00:00
|
|
|
/// Like `prepare`, except that the statement is only prepared once over
|
|
|
|
/// the lifetime of the connection and then cached. If the same statement
|
2015-12-07 00:46:06 +00:00
|
|
|
/// is going to be prepared frequently, caching it can improve performance
|
|
|
|
/// by reducing the number of round trips to the Postgres backend.
|
2015-01-23 06:24:47 +00:00
|
|
|
///
|
2015-11-29 05:05:13 +00:00
|
|
|
/// # Example
|
2015-01-23 06:24:47 +00:00
|
|
|
///
|
|
|
|
/// ```rust,no_run
|
|
|
|
/// # use postgres::{Connection, SslMode};
|
|
|
|
/// # let x = 10i32;
|
2015-12-06 00:15:19 +00:00
|
|
|
/// # let conn = Connection::connect("", SslMode::None).unwrap();
|
2015-12-13 04:21:44 +00:00
|
|
|
/// # let (a, b) = (0i32, 1i32);
|
|
|
|
/// # let updates = vec![(&a, &b)];
|
|
|
|
/// let stmt = conn.prepare_cached("UPDATE foo SET bar = $1 WHERE baz = $2").unwrap();
|
|
|
|
/// for (bar, baz) in updates {
|
|
|
|
/// stmt.execute(&[bar, baz]).unwrap();
|
2015-01-23 06:24:47 +00:00
|
|
|
/// }
|
|
|
|
/// ```
|
|
|
|
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
|
|
|
}
|
|
|
|
|
2016-01-03 05:51:02 +00:00
|
|
|
/// Returns the isolation level which will be used for future transactions.
|
|
|
|
///
|
|
|
|
/// This is a simple wrapper around `SHOW TRANSACTION ISOLATION LEVEL`.
|
|
|
|
pub fn transaction_isolation(&self) -> Result<IsolationLevel> {
|
|
|
|
let mut conn = self.conn.borrow_mut();
|
|
|
|
check_desync!(conn);
|
|
|
|
let result = try!(conn.quick_query("SHOW TRANSACTION ISOLATION LEVEL"));
|
|
|
|
IsolationLevel::parse(result[0][0].as_ref().unwrap())
|
|
|
|
}
|
|
|
|
|
2016-02-25 06:29:09 +00:00
|
|
|
/// # Deprecated
|
2015-04-23 05:03:09 +00:00
|
|
|
///
|
2016-02-25 06:29:09 +00:00
|
|
|
/// Use `Connection::set_transaction_config` instead.
|
2015-04-23 05:03:09 +00:00
|
|
|
pub fn set_transaction_isolation(&self, level: IsolationLevel) -> Result<()> {
|
2016-02-24 08:01:22 +00:00
|
|
|
self.set_transaction_config(transaction::Config::new().isolation_level(level))
|
|
|
|
}
|
|
|
|
|
2016-02-25 06:29:09 +00:00
|
|
|
/// Sets the configuration that will be used for future transactions.
|
2016-02-24 08:01:22 +00:00
|
|
|
pub fn set_transaction_config(&self, config: &transaction::Config) -> Result<()> {
|
|
|
|
let mut command = "SET SESSION CHARACTERISTICS AS TRANSACTION".to_owned();
|
|
|
|
config.build_command(&mut command);
|
|
|
|
self.batch_execute(&command)
|
2015-04-23 05:03:09 +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.
|
|
|
|
///
|
2015-11-29 05:05:13 +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
|
2015-01-24 18:46:01 +00:00
|
|
|
/// data in the statement. Do not form statements via string concatenation
|
2014-06-08 23:07:15 +00:00
|
|
|
/// and feed them into this method.
|
|
|
|
///
|
2015-11-29 05:05:13 +00:00
|
|
|
/// # Example
|
2014-06-08 23:07:15 +00:00
|
|
|
///
|
2014-06-08 23:12:27 +00:00
|
|
|
/// ```rust,no_run
|
2015-11-30 04:00:25 +00:00
|
|
|
/// # use postgres::{Connection, SslMode, Result};
|
2015-12-06 00:15:19 +00:00
|
|
|
/// # let conn = Connection::connect("", SslMode::None).unwrap();
|
2015-11-30 04:00:25 +00:00
|
|
|
/// conn.batch_execute("
|
|
|
|
/// CREATE TABLE person (
|
|
|
|
/// id SERIAL PRIMARY KEY,
|
|
|
|
/// name NOT NULL
|
|
|
|
/// );
|
2014-06-08 23:07:15 +00:00
|
|
|
///
|
2015-11-30 04:00:25 +00:00
|
|
|
/// CREATE TABLE purchase (
|
|
|
|
/// id SERIAL PRIMARY KEY,
|
|
|
|
/// person INT NOT NULL REFERENCES person (id),
|
|
|
|
/// time TIMESTAMPTZ NOT NULL,
|
|
|
|
/// );
|
2014-06-08 23:07:15 +00:00
|
|
|
///
|
2015-11-30 04:00:25 +00:00
|
|
|
/// CREATE INDEX ON purchase (time);
|
|
|
|
/// ").unwrap();
|
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
|
|
|
}
|
|
|
|
|
2015-12-07 00:08:37 +00:00
|
|
|
/// Returns a structure providing access to asynchronous notifications.
|
|
|
|
///
|
|
|
|
/// Use the `LISTEN` command to register this connection for notifications.
|
|
|
|
pub fn notifications<'a>(&'a self) -> Notifications<'a> {
|
|
|
|
Notifications::new(self)
|
|
|
|
}
|
|
|
|
|
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
|
|
|
}
|
|
|
|
|
2015-05-22 05:28:51 +00:00
|
|
|
/// Returns the value of the specified Postgres backend parameter, such as
|
|
|
|
/// `timezone` or `server_version`.
|
2015-02-16 04:22:56 +00:00
|
|
|
pub fn parameter(&self, param: &str) -> Option<String> {
|
|
|
|
self.conn.borrow().parameters.get(param).cloned()
|
|
|
|
}
|
|
|
|
|
2015-12-07 00:08:37 +00:00
|
|
|
/// Sets the notice handler for the connection, returning the old handler.
|
|
|
|
pub fn set_notice_handler(&self, handler: Box<HandleNotice>) -> Box<HandleNotice> {
|
|
|
|
self.conn.borrow_mut().set_notice_handler(handler)
|
|
|
|
}
|
|
|
|
|
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
|
|
|
}
|
|
|
|
|
2015-01-27 05:09:50 +00:00
|
|
|
/// Determines if the `Connection` is currently "active", that is, if there
|
|
|
|
/// are no active transactions.
|
|
|
|
///
|
|
|
|
/// The `transaction` method can only be called on the active `Connection`
|
|
|
|
/// or `Transaction`.
|
|
|
|
pub fn is_active(&self) -> bool {
|
|
|
|
self.conn.borrow().trans_depth == 0
|
|
|
|
}
|
|
|
|
|
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
|
|
|
}
|
2013-08-17 22:09:26 +00:00
|
|
|
}
|
2013-08-18 02:09:56 +00:00
|
|
|
|
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::execute`.
|
2015-01-29 04:39:31 +00:00
|
|
|
fn execute(&self, query: &str, params: &[&ToSql]) -> Result<u64>;
|
2014-10-09 03:29:26 +00:00
|
|
|
|
2015-11-29 04:59:47 +00:00
|
|
|
/// Like `Connection::query`.
|
|
|
|
fn query<'a>(&'a self, query: &str, params: &[&ToSql]) -> Result<Rows<'a>>;
|
|
|
|
|
2016-01-03 05:51:02 +00:00
|
|
|
/// Like `Connection::prepare`.
|
|
|
|
fn prepare<'a>(&'a self, query: &str) -> Result<Statement<'a>>;
|
|
|
|
|
|
|
|
/// 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::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<()>;
|
2015-01-27 05:09:50 +00:00
|
|
|
|
|
|
|
/// Like `Connection::is_active`.
|
|
|
|
fn is_active(&self) -> bool;
|
2014-10-09 03:29:26 +00:00
|
|
|
}
|
|
|
|
|
2014-11-01 23:21:47 +00:00
|
|
|
impl GenericConnection for Connection {
|
2015-01-29 04:39:31 +00:00
|
|
|
fn execute(&self, query: &str, params: &[&ToSql]) -> Result<u64> {
|
2014-11-27 19:16:14 +00:00
|
|
|
self.execute(query, params)
|
|
|
|
}
|
|
|
|
|
2015-11-29 04:59:47 +00:00
|
|
|
fn query<'a>(&'a self, query: &str, params: &[&ToSql]) -> Result<Rows<'a>> {
|
|
|
|
self.query(query, params)
|
|
|
|
}
|
|
|
|
|
2016-01-03 05:51:02 +00:00
|
|
|
fn prepare<'a>(&'a self, query: &str) -> Result<Statement<'a>> {
|
|
|
|
self.prepare(query)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn prepare_cached<'a>(&'a self, query: &str) -> Result<Statement<'a>> {
|
|
|
|
self.prepare_cached(query)
|
|
|
|
}
|
|
|
|
|
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()
|
|
|
|
}
|
|
|
|
|
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)
|
|
|
|
}
|
2015-01-27 05:09:50 +00:00
|
|
|
|
|
|
|
fn is_active(&self) -> bool {
|
|
|
|
self.is_active()
|
|
|
|
}
|
2014-10-09 03:29:26 +00:00
|
|
|
}
|
|
|
|
|
2014-11-01 23:25:11 +00:00
|
|
|
impl<'a> GenericConnection for Transaction<'a> {
|
2015-01-29 04:39:31 +00:00
|
|
|
fn execute(&self, query: &str, params: &[&ToSql]) -> Result<u64> {
|
2014-11-27 19:16:14 +00:00
|
|
|
self.execute(query, params)
|
|
|
|
}
|
|
|
|
|
2015-11-29 04:59:47 +00:00
|
|
|
fn query<'b>(&'b self, query: &str, params: &[&ToSql]) -> Result<Rows<'b>> {
|
|
|
|
self.query(query, params)
|
|
|
|
}
|
|
|
|
|
2016-01-03 05:51:02 +00:00
|
|
|
fn prepare<'b>(&'b self, query: &str) -> Result<Statement<'b>> {
|
|
|
|
self.prepare(query)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn prepare_cached<'b>(&'b self, query: &str) -> Result<Statement<'b>> {
|
|
|
|
self.prepare_cached(query)
|
|
|
|
}
|
|
|
|
|
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-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)
|
|
|
|
}
|
2015-01-27 05:09:50 +00:00
|
|
|
|
|
|
|
fn is_active(&self) -> bool {
|
|
|
|
self.is_active()
|
|
|
|
}
|
2014-10-09 03:29:26 +00:00
|
|
|
}
|
2015-05-23 02:51:44 +00:00
|
|
|
|
|
|
|
trait OtherNew {
|
2015-09-26 20:23:55 +00:00
|
|
|
fn new(name: String, oid: Oid, kind: Kind, schema: String) -> Other;
|
2015-05-23 02:51:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
trait DbErrorNew {
|
|
|
|
fn new_raw(fields: Vec<(u8, String)>) -> result::Result<DbError, ()>;
|
|
|
|
fn new_connect<T>(fields: Vec<(u8, String)>) -> result::Result<T, ConnectError>;
|
|
|
|
fn new<T>(fields: Vec<(u8, String)>) -> Result<T>;
|
|
|
|
}
|
2015-05-27 04:47:42 +00:00
|
|
|
|
2015-05-30 05:54:10 +00:00
|
|
|
trait RowsNew<'a> {
|
|
|
|
fn new(stmt: &'a Statement<'a>, data: Vec<Vec<Option<Vec<u8>>>>) -> Rows<'a>;
|
2015-11-14 03:34:11 +00:00
|
|
|
fn new_owned(stmt: Statement<'a>, data: Vec<Vec<Option<Vec<u8>>>>) -> Rows<'a>;
|
2015-05-30 05:54:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
trait LazyRowsNew<'trans, 'stmt> {
|
|
|
|
fn new(stmt: &'stmt Statement<'stmt>,
|
|
|
|
data: VecDeque<Vec<Option<Vec<u8>>>>,
|
|
|
|
name: String,
|
|
|
|
row_limit: i32,
|
|
|
|
more_rows: bool,
|
|
|
|
finished: bool,
|
2015-11-16 03:51:04 +00:00
|
|
|
trans: &'trans Transaction<'trans>)
|
|
|
|
-> LazyRows<'trans, 'stmt>;
|
2015-05-30 05:54:10 +00:00
|
|
|
}
|
2015-06-02 05:39:04 +00:00
|
|
|
|
|
|
|
trait SessionInfoNew<'a> {
|
|
|
|
fn new(conn: &'a InnerConnection) -> SessionInfo<'a>;
|
|
|
|
}
|
2015-08-16 04:39:46 +00:00
|
|
|
|
|
|
|
trait StatementInternals<'conn> {
|
|
|
|
fn new(conn: &'conn Connection,
|
2016-01-03 05:02:54 +00:00
|
|
|
info: Arc<StatementInfo>,
|
2015-08-16 04:39:46 +00:00
|
|
|
next_portal_id: Cell<u32>,
|
2015-11-16 03:51:04 +00:00
|
|
|
finished: bool)
|
|
|
|
-> Statement<'conn>;
|
2015-08-16 04:39:46 +00:00
|
|
|
|
|
|
|
fn conn(&self) -> &'conn Connection;
|
2015-11-14 03:34:11 +00:00
|
|
|
|
|
|
|
fn into_query(self, params: &[&ToSql]) -> Result<Rows<'conn>>;
|
2015-08-16 04:39:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
trait ColumnNew {
|
|
|
|
fn new(name: String, type_: Type) -> Column;
|
|
|
|
}
|
2015-09-19 03:55:01 +00:00
|
|
|
|
|
|
|
trait NotificationsNew<'conn> {
|
|
|
|
fn new(conn: &'conn Connection) -> Notifications<'conn>;
|
|
|
|
}
|
2015-12-27 05:05:23 +00:00
|
|
|
|
|
|
|
trait WrongTypeNew {
|
|
|
|
fn new(ty: Type) -> WrongType;
|
|
|
|
}
|
2016-02-16 07:11:01 +00:00
|
|
|
|
|
|
|
trait FieldNew {
|
|
|
|
fn new(name: String, type_: Type) -> Field;
|
|
|
|
}
|
2016-02-24 07:43:28 +00:00
|
|
|
|
|
|
|
trait TransactionInternals<'conn> {
|
|
|
|
fn new(conn: &'conn Connection, depth: u32) -> Transaction<'conn>;
|
|
|
|
|
|
|
|
fn conn(&self) -> &'conn Connection;
|
|
|
|
|
|
|
|
fn depth(&self) -> u32;
|
|
|
|
}
|
2016-02-24 08:01:22 +00:00
|
|
|
|
|
|
|
trait ConfigInternals {
|
|
|
|
fn build_command(&self, s: &mut String);
|
|
|
|
}
|