rust-postgres/tokio-postgres/src/client.rs

477 lines
16 KiB
Rust
Raw Normal View History

2019-08-02 01:43:38 +00:00
#[cfg(feature = "runtime")]
use crate::cancel_query;
2019-07-24 02:54:22 +00:00
use crate::codec::BackendMessages;
2019-07-30 04:36:07 +00:00
use crate::config::{Host, SslMode};
2019-07-24 02:54:22 +00:00
use crate::connection::{Request, RequestMessages};
2019-10-09 02:01:34 +00:00
use crate::copy_out::CopyStream;
use crate::query::RowStream;
2019-10-10 23:03:48 +00:00
use crate::simple_query::SimpleQueryStream;
use crate::slice_iter;
2019-07-30 04:36:07 +00:00
#[cfg(feature = "runtime")]
use crate::tls::MakeTlsConnect;
use crate::tls::TlsConnect;
use crate::to_statement::ToStatement;
2019-07-25 02:18:15 +00:00
use crate::types::{Oid, ToSql, Type};
2019-07-30 04:36:07 +00:00
#[cfg(feature = "runtime")]
use crate::Socket;
2019-08-02 01:43:38 +00:00
use crate::{cancel_query_raw, copy_in, copy_out, query, Transaction};
2019-07-28 22:52:46 +00:00
use crate::{prepare, SimpleQueryMessage};
2019-07-29 00:48:32 +00:00
use crate::{simple_query, Row};
2019-07-24 02:54:22 +00:00
use crate::{Error, Statement};
2019-10-13 00:47:47 +00:00
use bytes::{BytesMut, IntoBuf};
2019-07-24 02:54:22 +00:00
use fallible_iterator::FallibleIterator;
use futures::channel::mpsc;
2019-10-10 00:04:24 +00:00
use futures::{future, TryStream, TryStreamExt};
2019-07-25 02:18:15 +00:00
use futures::{ready, StreamExt};
2019-07-24 03:16:31 +00:00
use parking_lot::Mutex;
2019-10-10 23:03:48 +00:00
use pin_utils::pin_mut;
2019-07-24 02:54:22 +00:00
use postgres_protocol::message::backend::Message;
2019-07-24 03:16:31 +00:00
use std::collections::HashMap;
2019-07-31 04:25:30 +00:00
use std::error;
2019-07-24 02:54:22 +00:00
use std::sync::Arc;
use std::task::{Context, Poll};
2019-07-30 04:36:07 +00:00
use std::time::Duration;
use tokio::io::{AsyncRead, AsyncWrite};
2019-07-24 02:54:22 +00:00
pub struct Responses {
receiver: mpsc::Receiver<BackendMessages>,
cur: BackendMessages,
}
impl Responses {
2019-07-25 02:18:15 +00:00
pub fn poll_next(&mut self, cx: &mut Context<'_>) -> Poll<Result<Message, Error>> {
2019-07-24 02:54:22 +00:00
loop {
match self.cur.next().map_err(Error::parse)? {
2019-07-25 02:18:15 +00:00
Some(Message::ErrorResponse(body)) => return Poll::Ready(Err(Error::db(body))),
Some(message) => return Poll::Ready(Ok(message)),
2019-07-24 02:54:22 +00:00
None => {}
}
2019-07-25 02:18:15 +00:00
match ready!(self.receiver.poll_next_unpin(cx)) {
2019-07-24 02:54:22 +00:00
Some(messages) => self.cur = messages,
2019-07-25 02:18:15 +00:00
None => return Poll::Ready(Err(Error::closed())),
2019-07-24 02:54:22 +00:00
}
}
}
2019-07-25 02:18:15 +00:00
pub async fn next(&mut self) -> Result<Message, Error> {
future::poll_fn(|cx| self.poll_next(cx)).await
}
2019-07-24 02:54:22 +00:00
}
2019-07-24 03:16:31 +00:00
struct State {
2019-07-27 03:11:34 +00:00
typeinfo: Option<Statement>,
typeinfo_composite: Option<Statement>,
typeinfo_enum: Option<Statement>,
2019-07-24 03:16:31 +00:00
types: HashMap<Oid, Type>,
buf: BytesMut,
2019-07-24 03:16:31 +00:00
}
2019-07-24 02:54:22 +00:00
pub struct InnerClient {
sender: mpsc::UnboundedSender<Request>,
2019-07-24 03:16:31 +00:00
state: Mutex<State>,
2019-07-24 02:54:22 +00:00
}
impl InnerClient {
pub fn send(&self, messages: RequestMessages) -> Result<Responses, Error> {
let (sender, receiver) = mpsc::channel(1);
let request = Request { messages, sender };
self.sender
.unbounded_send(request)
.map_err(|_| Error::closed())?;
Ok(Responses {
receiver,
cur: BackendMessages::empty(),
})
}
2019-07-24 03:16:31 +00:00
2019-07-27 03:11:34 +00:00
pub fn typeinfo(&self) -> Option<Statement> {
self.state.lock().typeinfo.clone()
2019-07-24 03:16:31 +00:00
}
2019-07-27 03:11:34 +00:00
pub fn set_typeinfo(&self, statement: &Statement) {
self.state.lock().typeinfo = Some(statement.clone());
2019-07-24 03:16:31 +00:00
}
2019-07-27 03:11:34 +00:00
pub fn typeinfo_composite(&self) -> Option<Statement> {
self.state.lock().typeinfo_composite.clone()
2019-07-24 03:16:31 +00:00
}
2019-07-27 03:11:34 +00:00
pub fn set_typeinfo_composite(&self, statement: &Statement) {
self.state.lock().typeinfo_composite = Some(statement.clone());
2019-07-24 03:16:31 +00:00
}
2019-07-27 03:11:34 +00:00
pub fn typeinfo_enum(&self) -> Option<Statement> {
self.state.lock().typeinfo_enum.clone()
2019-07-24 03:16:31 +00:00
}
2019-07-27 03:11:34 +00:00
pub fn set_typeinfo_enum(&self, statement: &Statement) {
self.state.lock().typeinfo_enum = Some(statement.clone());
2019-07-24 03:16:31 +00:00
}
pub fn type_(&self, oid: Oid) -> Option<Type> {
self.state.lock().types.get(&oid).cloned()
}
2019-07-27 03:11:34 +00:00
pub fn set_type(&self, oid: Oid, type_: &Type) {
self.state.lock().types.insert(oid, type_.clone());
2019-07-24 03:16:31 +00:00
}
2019-10-13 00:47:47 +00:00
pub fn with_buf<F, R>(&self, f: F) -> R
where
F: FnOnce(&mut BytesMut) -> R,
{
let mut state = self.state.lock();
let r = f(&mut state.buf);
state.buf.clear();
r
}
2019-07-24 02:54:22 +00:00
}
2019-07-30 04:36:07 +00:00
#[derive(Clone)]
pub(crate) struct SocketConfig {
pub host: Host,
pub port: u16,
pub connect_timeout: Option<Duration>,
pub keepalives: bool,
pub keepalives_idle: Duration,
}
2019-08-02 01:40:14 +00:00
/// An asynchronous PostgreSQL client.
///
/// The client is one half of what is returned when a connection is established. Users interact with the database
/// through this client object.
2019-07-24 02:54:22 +00:00
pub struct Client {
inner: Arc<InnerClient>,
2019-08-02 01:43:38 +00:00
#[cfg(feature = "runtime")]
2019-07-30 04:36:07 +00:00
socket_config: Option<SocketConfig>,
ssl_mode: SslMode,
process_id: i32,
secret_key: i32,
}
impl Client {
pub(crate) fn new(
sender: mpsc::UnboundedSender<Request>,
2019-07-30 04:36:07 +00:00
ssl_mode: SslMode,
process_id: i32,
secret_key: i32,
) -> Client {
Client {
2019-07-24 03:16:31 +00:00
inner: Arc::new(InnerClient {
sender,
state: Mutex::new(State {
2019-07-27 03:11:34 +00:00
typeinfo: None,
typeinfo_composite: None,
typeinfo_enum: None,
2019-07-24 03:16:31 +00:00
types: HashMap::new(),
buf: BytesMut::new(),
2019-07-24 03:16:31 +00:00
}),
}),
2019-08-02 01:43:38 +00:00
#[cfg(feature = "runtime")]
2019-07-30 04:36:07 +00:00
socket_config: None,
ssl_mode,
process_id,
secret_key,
}
}
2019-07-24 02:54:22 +00:00
pub(crate) fn inner(&self) -> &Arc<InnerClient> {
&self.inner
2019-07-24 02:54:22 +00:00
}
2019-08-02 01:43:38 +00:00
#[cfg(feature = "runtime")]
2019-07-30 04:36:07 +00:00
pub(crate) fn set_socket_config(&mut self, socket_config: SocketConfig) {
self.socket_config = Some(socket_config);
}
2019-07-28 22:52:46 +00:00
/// Creates a new prepared statement.
///
/// Prepared statements can be executed repeatedly, and may contain query parameters (indicated by `$1`, `$2`, etc),
/// which are set when executed. Prepared statements can only be used with the connection that created them.
2019-09-28 14:48:15 +00:00
pub async fn prepare(&self, query: &str) -> Result<Statement, Error> {
self.prepare_typed(query, &[]).await
2019-07-24 02:54:22 +00:00
}
2019-07-28 22:52:46 +00:00
/// Like `prepare`, but allows the types of query parameters to be explicitly specified.
///
/// The list of types may be smaller than the number of parameters - the types of the remaining parameters will be
/// inferred. For example, `client.prepare_typed(query, &[])` is equivalent to `client.prepare(query)`.
2019-09-28 14:48:15 +00:00
pub async fn prepare_typed(
&self,
2019-07-27 03:11:34 +00:00
query: &str,
parameter_types: &[Type],
2019-09-28 14:48:15 +00:00
) -> Result<Statement, Error> {
prepare::prepare(&self.inner, query, parameter_types).await
2019-07-24 02:54:22 +00:00
}
2019-07-25 02:18:15 +00:00
/// Executes a statement, returning a vector of the resulting rows.
2019-07-28 22:52:46 +00:00
///
2019-10-10 00:45:53 +00:00
/// A statement may contain parameters, specified by `$n`, where `n` is the index of the parameter of the list
/// provided, 1-indexed.
///
/// The `statement` argument can either be a `Statement`, or a raw query string. If the same statement will be
/// repeatedly executed (perhaps with different query parameters), consider preparing the statement up front
/// with the `prepare` method.
///
2019-07-28 22:52:46 +00:00
/// # Panics
///
/// Panics if the number of parameters provided does not match the number expected.
pub async fn query<T>(
&self,
statement: &T,
params: &[&(dyn ToSql + Sync)],
) -> Result<Vec<Row>, Error>
where
T: ?Sized + ToStatement,
{
self.query_raw(statement, slice_iter(params))
.await?
.try_collect()
.await
2019-07-25 02:18:15 +00:00
}
2019-10-10 00:45:53 +00:00
/// Executes a statement which returns a single row, returning it.
///
/// A statement may contain parameters, specified by `$n`, where `n` is the index of the parameter of the list
/// provided, 1-indexed.
///
/// The `statement` argument can either be a `Statement`, or a raw query string. If the same statement will be
/// repeatedly executed (perhaps with different query parameters), consider preparing the statement up front
/// with the `prepare` method.
///
/// Returns an error if the query does not return exactly one row.
///
/// # Panics
///
/// Panics if the number of parameters provided does not match the number expected.
pub async fn query_one<T>(
&self,
statement: &T,
params: &[&(dyn ToSql + Sync)],
) -> Result<Row, Error>
where
2019-10-10 23:03:48 +00:00
T: ?Sized + ToStatement,
2019-10-10 00:45:53 +00:00
{
let stream = self.query_raw(statement, slice_iter(params)).await?;
pin_mut!(stream);
let row = match stream.try_next().await? {
Some(row) => row,
None => return Err(Error::row_count()),
};
if stream.try_next().await?.is_some() {
return Err(Error::row_count());
}
Ok(row)
}
/// The maximally flexible version of [`query`].
///
2019-10-10 00:45:53 +00:00
/// A statement may contain parameters, specified by `$n`, where `n` is the index of the parameter of the list
/// provided, 1-indexed.
///
/// The `statement` argument can either be a `Statement`, or a raw query string. If the same statement will be
/// repeatedly executed (perhaps with different query parameters), consider preparing the statement up front
/// with the `prepare` method.
///
/// # Panics
///
/// Panics if the number of parameters provided does not match the number expected.
2019-07-28 22:52:46 +00:00
///
/// [`query`]: #method.query
pub async fn query_raw<'a, T, I>(&self, statement: &T, params: I) -> Result<RowStream, Error>
2019-07-25 02:18:15 +00:00
where
T: ?Sized + ToStatement,
I: IntoIterator<Item = &'a dyn ToSql>,
2019-07-25 02:18:15 +00:00
I::IntoIter: ExactSizeIterator,
{
let statement = statement.__convert().into_statement(self).await?;
query::query(&self.inner, statement, params).await
2019-07-25 02:18:15 +00:00
}
2019-07-28 22:52:46 +00:00
/// Executes a statement, returning the number of rows modified.
///
2019-10-10 00:45:53 +00:00
/// A statement may contain parameters, specified by `$n`, where `n` is the index of the parameter of the list
/// provided, 1-indexed.
///
/// The `statement` argument can either be a `Statement`, or a raw query string. If the same statement will be
/// repeatedly executed (perhaps with different query parameters), consider preparing the statement up front
/// with the `prepare` method.
///
2019-07-28 22:52:46 +00:00
/// If the statement does not modify any rows (e.g. `SELECT`), 0 is returned.
///
/// # Panics
///
/// Panics if the number of parameters provided does not match the number expected.
pub async fn execute<T>(
2019-09-28 14:48:15 +00:00
&self,
statement: &T,
params: &[&(dyn ToSql + Sync)],
) -> Result<u64, Error>
where
T: ?Sized + ToStatement,
{
self.execute_raw(statement, slice_iter(params)).await
2019-07-25 02:18:15 +00:00
}
/// The maximally flexible version of [`execute`].
///
2019-10-10 00:45:53 +00:00
/// A statement may contain parameters, specified by `$n`, where `n` is the index of the parameter of the list
/// provided, 1-indexed.
///
/// The `statement` argument can either be a `Statement`, or a raw query string. If the same statement will be
/// repeatedly executed (perhaps with different query parameters), consider preparing the statement up front
/// with the `prepare` method.
///
/// # Panics
///
/// Panics if the number of parameters provided does not match the number expected.
2019-07-28 22:52:46 +00:00
///
/// [`execute`]: #method.execute
pub async fn execute_raw<'a, T, I>(&self, statement: &T, params: I) -> Result<u64, Error>
2019-07-25 02:18:15 +00:00
where
T: ?Sized + ToStatement,
2019-07-27 03:11:34 +00:00
I: IntoIterator<Item = &'a dyn ToSql>,
2019-07-25 02:18:15 +00:00
I::IntoIter: ExactSizeIterator,
{
let statement = statement.__convert().into_statement(self).await?;
query::execute(self.inner(), statement, params).await
2019-07-25 02:18:15 +00:00
}
2019-07-28 22:52:46 +00:00
2019-07-31 04:25:30 +00:00
/// Executes a `COPY FROM STDIN` statement, returning the number of rows created.
///
/// The data in the provided stream is passed along to the server verbatim; it is the caller's responsibility to
/// ensure it uses the proper format.
///
/// # Panics
///
/// Panics if the number of parameters provided does not match the number expected.
pub async fn copy_in<T, S>(
2019-09-28 14:48:15 +00:00
&self,
statement: &T,
params: &[&(dyn ToSql + Sync)],
2019-07-31 04:25:30 +00:00
stream: S,
) -> Result<u64, Error>
2019-07-31 04:25:30 +00:00
where
T: ?Sized + ToStatement,
2019-07-31 04:25:30 +00:00
S: TryStream,
S::Ok: IntoBuf,
<S::Ok as IntoBuf>::Buf: 'static + Send,
S::Error: Into<Box<dyn error::Error + Sync + Send>>,
{
let statement = statement.__convert().into_statement(self).await?;
let params = slice_iter(params);
copy_in::copy_in(self.inner(), statement, params, stream).await
2019-07-31 04:25:30 +00:00
}
2019-08-01 03:15:17 +00:00
/// Executes a `COPY TO STDOUT` statement, returning a stream of the resulting data.
///
/// # Panics
///
/// Panics if the number of parameters provided does not match the number expected.
2019-10-09 02:01:34 +00:00
pub async fn copy_out<T>(
&self,
statement: &T,
params: &[&(dyn ToSql + Sync)],
) -> Result<CopyStream, Error>
where
T: ?Sized + ToStatement,
{
2019-10-09 02:01:34 +00:00
let statement = statement.__convert().into_statement(self).await?;
let params = slice_iter(params);
copy_out::copy_out(self.inner(), statement, params).await
2019-08-01 03:15:17 +00:00
}
2019-07-28 22:52:46 +00:00
/// Executes a sequence of SQL statements using the simple query protocol, returning the resulting rows.
///
/// Statements should be separated by semicolons. If an error occurs, execution of the sequence will stop at that
/// point. The simple query protocol returns the values in rows as strings rather than in their binary encodings,
/// so the associated row type doesn't work with the `FromSql` trait. Rather than simply returning a stream over the
/// rows, this method returns a stream over an enum which indicates either the completion of one of the commands,
/// or a row of data. This preserves the framing between the separate statements in the request.
///
/// # Warning
///
/// Prepared statements should be use for any query which contains user-specified data, as they provided the
/// functionality to safely embed that data in the request. Do not form statements via string concatenation and pass
/// them to this method!
2019-10-10 23:03:48 +00:00
pub async fn simple_query(&self, query: &str) -> Result<Vec<SimpleQueryMessage>, Error> {
2019-10-10 00:04:24 +00:00
self.simple_query_raw(query).await?.try_collect().await
}
pub(crate) async fn simple_query_raw(&self, query: &str) -> Result<SimpleQueryStream, Error> {
simple_query::simple_query(self.inner(), query).await
2019-07-28 22:52:46 +00:00
}
/// Executes a sequence of SQL statements using the simple query protocol.
///
/// Statements should be separated by semicolons. If an error occurs, execution of the sequence will stop at that
/// point. This is intended for use when, for example, initializing a database schema.
///
/// # Warning
///
/// Prepared statements should be use for any query which contains user-specified data, as they provided the
/// functionality to safely embed that data in the request. Do not form statements via string concatenation and pass
/// them to this method!
pub async fn batch_execute(&self, query: &str) -> Result<(), Error> {
simple_query::batch_execute(self.inner(), query).await
2019-07-28 22:52:46 +00:00
}
2019-07-30 04:36:07 +00:00
2019-07-31 02:54:30 +00:00
/// Begins a new database transaction.
///
/// The transaction will roll back by default - use the `commit` method to commit it.
pub async fn transaction(&mut self) -> Result<Transaction<'_>, Error> {
self.batch_execute("BEGIN").await?;
Ok(Transaction::new(self))
}
2019-07-30 04:36:07 +00:00
/// Attempts to cancel an in-progress query.
///
/// The server provides no information about whether a cancellation attempt was successful or not. An error will
/// only be returned if the client was unable to connect to the database.
///
/// Requires the `runtime` Cargo feature (enabled by default).
2019-07-31 02:54:30 +00:00
#[cfg(feature = "runtime")]
pub async fn cancel_query<T>(&self, tls: T) -> Result<(), Error>
2019-07-30 04:36:07 +00:00
where
T: MakeTlsConnect<Socket>,
{
cancel_query::cancel_query(
self.socket_config.clone(),
self.ssl_mode,
tls,
self.process_id,
self.secret_key,
)
.await
2019-07-30 04:36:07 +00:00
}
/// Like `cancel_query`, but uses a stream which is already connected to the server rather than opening a new
/// connection itself.
pub async fn cancel_query_raw<S, T>(&self, stream: S, tls: T) -> Result<(), Error>
2019-07-30 04:36:07 +00:00
where
S: AsyncRead + AsyncWrite + Unpin,
T: TlsConnect<S>,
{
cancel_query_raw::cancel_query_raw(
stream,
self.ssl_mode,
tls,
self.process_id,
self.secret_key,
)
.await
2019-07-30 04:36:07 +00:00
}
2019-08-04 01:09:27 +00:00
/// Determines if the connection to the server has already closed.
///
/// In that case, all future queries will fail.
pub fn is_closed(&self) -> bool {
self.inner.sender.is_closed()
}
}