Skip to main content

Client

Struct Client 

Source
pub struct Client { /* private fields */ }
Expand description

A synchronous client for Hyper database.

The client handles connection management and query execution. It is thread-safe and can be shared between threads using Arc.

§Thread Safety

The Client is thread-safe and can be shared between threads using Arc<Client>. All methods use internal mutexes to synchronize access to the underlying connection.

§Example

use hyperdb_api_core::client::{Client, Config};

let config = Config::new()
    .with_host("localhost")
    .with_port(7483)
    .with_database("test.hyper");

let client = Client::connect(&config)?;
let rows = client.query("SELECT 1")?;
client.close()?;

Implementations§

Source§

impl Client

Source

pub fn connect(config: &Config) -> Result<Self>

Connects to a Hyper server using the given configuration.

Establishes a TCP connection, performs authentication, and initializes the client. Returns an error if the connection fails or authentication is rejected.

§Arguments
  • config - Connection configuration (host, port, credentials, etc.)
§Errors

Returns Error if:

  • Connection to the server fails
  • Authentication fails
  • Protocol handshake fails
§Example
let config = Config::new()
    .with_host("localhost")
    .with_port(7483)
    .with_user("myuser")
    .with_password("mypass")
    .with_database("test.hyper");

let client = Client::connect(&config)?;
Source

pub fn connect_unix( socket_path: impl AsRef<Path>, config: &Config, ) -> Result<Self>

Connects to a Hyper server via Unix Domain Socket (Unix only).

§Example
let socket_path = Path::new("/tmp/hyper/.s.PGSQL.12345");
let config = Config::new().with_database("test.hyper");
let client = Client::connect_unix(socket_path, &config)?;
§Errors
  • Returns Error (connection) if the Unix domain socket cannot be connected.
  • Propagates any Error from the startup handshake (authentication, protocol error, I/O error).
Source

pub fn connect_endpoint( endpoint: &ConnectionEndpoint, config: &Config, ) -> Result<Self>

Connects to a Hyper server using a ConnectionEndpoint.

This is a lower-level method that accepts a pre-parsed endpoint.

§Errors

Delegates to Client::connect, Client::connect_unix, or Client::connect_named_pipe depending on the endpoint variant, and propagates their errors unchanged.

Source

pub fn endpoint(&self) -> &ConnectionEndpoint

Returns the connection endpoint.

Source

pub fn process_id(&self) -> i32

Returns the server process ID for this connection.

Source

pub fn secret_key(&self) -> i32

Returns the secret key for cancel requests.

Source

pub fn cancel(&self) -> Result<()>

Cancels the currently executing query on this connection.

This method is thread-safe and can be called from any thread while a query is running on another thread. It works by opening a separate TCP connection to the server and sending a cancel request.

§How It Works
  1. Opens a new TCP connection to the same server
  2. Sends a cancel request containing the process ID and secret key
  3. The server receives this and cancels the running query
  4. The original query will fail with error code 57014 (query_canceled)
§Thread Safety

This method does NOT acquire the connection mutex, so it can be called while another thread is blocked waiting for query results.

§Relation to the Cancellable trait

This is the fallible user-facing cancel API: it returns a Result<()> so explicit callers can observe transport-level failures (network errors, socket issues) and react accordingly — e.g. record a metric, show “cancel failed” UX, or retry.

For Drop-path and other internal cleanup contexts where error propagation is impossible, the separate impl Cancellable for Client wraps this method and swallows errors (logged via tracing::warn!). The two coexist by design — each serves a different consumer.

§Example
use std::thread;
use std::sync::Arc;
use std::time::Duration;
use hyperdb_api_core::client::{Client, Config};

let client = Arc::new(Client::connect(&config)?);
let client_clone = Arc::clone(&client);

// Start a long query in another thread
let handle = thread::spawn(move || {
    client_clone.query("SELECT pg_sleep(60)")
});

// Cancel from the main thread
thread::sleep(Duration::from_millis(100));
client.cancel()?;

// The query thread will get a cancellation error
let result = handle.join().unwrap();
assert!(result.is_err());
§Errors
  • Returns Error (connection) if the fresh cancel-side socket cannot be opened (TCP / UDS / named-pipe, depending on Self::endpoint).
  • Returns Error (I/O) if writing or flushing the cancel request fails.
Source

pub fn parameter_status(&self, name: &str) -> Option<String>

Returns a server parameter value by name.

Server parameters are sent by the server during connection startup. Common parameters include:

  • server_version - The server version string
  • server_encoding - The server’s character encoding
  • client_encoding - The client’s character encoding
§Example
if let Some(version) = client.parameter_status("server_version") {
    println!("Connected to Hyper version: {}", version);
}
Source

pub fn set_notice_receiver(&mut self, receiver: Option<NoticeReceiver>)

Sets the notice receiver for this connection.

Notice and warning messages generated by the server are not returned by query execution functions since they don’t indicate failure. Instead, they are passed to a notice handling function.

The default behavior is to log notices at the warn level.

§Arguments
  • receiver - The callback function that will be called with each notice. Pass None to restore default logging behavior.
§Example
client.set_notice_receiver(Some(Box::new(|notice| {
    println!("Server notice: {}", notice);
})));

// Or capture notices in a Vec
let notices = Arc::new(Mutex::new(Vec::new()));
let notices_clone = notices.clone();
client.set_notice_receiver(Some(Box::new(move |notice| {
    notices_clone.lock().unwrap().push(notice);
})));
Source

pub fn query(&self, query: &str) -> Result<Vec<Row>>

Executes a simple query and returns the rows.

§Errors
  • Returns Error (connection) if the connection mutex is poisoned.
  • Returns Error (server) for any SQL error the server reports (syntax error, constraint violation, type mismatch).
  • Returns Error (I/O) on wire-protocol I/O failure.
  • Propagates any Error from row construction (invalid row description or data row bytes).
Source

pub fn query_fast(&self, query: &str) -> Result<Vec<StreamRow>>

Executes a query using HyperBinary format for maximum performance.

Returns StreamRows which compute offsets on-demand without pre-allocation, making them faster for large result sets where each row is processed once. Uses the extended query protocol with HyperBinary format (format code 2) for direct binary access without text parsing overhead.

§Errors

Same as Self::query: connection-mutex poisoning, SQL errors from the server, and wire-protocol I/O failures all surface as Error.

Source

pub fn query_streaming<'a>( &'a self, query: &str, chunk_size: usize, ) -> Result<QueryStream<'a>>

Executes a query with streaming results for minimum memory usage.

Combines HyperBinary format with incremental row fetching.

§Errors
  • Returns Error (connection) if the connection mutex is poisoned.
  • Returns Error (server) or Error (I/O) if the initial Parse/Bind/Execute sequence for the streaming query fails on the server or on the wire.
Source

pub fn exec(&self, query: &str) -> Result<u64>

Executes a SQL command that doesn’t return rows (e.g., INSERT, UPDATE).

§Errors

Same error modes as Self::query — connection-mutex poisoning, server-side SQL errors, and wire-protocol I/O failures all surface as Error.

Source

pub fn batch_execute(&self, query: &str) -> Result<()>

Executes a batch of statements separated by semicolons.

§Errors

Same error modes as Self::query — connection-mutex poisoning, server-side SQL errors, and wire-protocol I/O failures.

Source

pub fn prepare(&self, query: &str) -> Result<OwnedPreparedStatement>

Prepares a statement for execution with the [params!] macro.

Returns an prepare::OwnedPreparedStatement that automatically closes when dropped.

§Example
let stmt = client.prepare("SELECT * FROM users WHERE id = $1")?;
let rows = client.execute(&stmt, params![42_i32])?;
§Errors

Propagates any Error from prepare::prepare_owned — connection-mutex poisoning, server-side Parse failures (SQL syntax, type resolution), and wire-protocol I/O failures.

Source

pub fn prepare_typed( &self, query: &str, param_types: &[Oid], ) -> Result<OwnedPreparedStatement>

Prepares a statement with explicit parameter types.

§Errors

Same failure modes as Self::prepare.

Source

pub fn execute<P: AsRef<[Option<Vec<u8>>]>>( &self, statement: &OwnedPreparedStatement, params: P, ) -> Result<Vec<Row>>

Executes a prepared statement with parameters.

Use the [params!] macro for ergonomic parameter encoding:

let stmt = client.prepare("SELECT * FROM users WHERE id = $1 AND name = $2")?;
let rows = client.execute(&stmt, params![42_i32, "Alice"])?;
§Errors

Propagates any Error from prepare::execute_prepared — parameter-count or type mismatch, server-side SQL errors, and wire-protocol I/O failures.

Source

pub fn execute_no_result<P: AsRef<[Option<Vec<u8>>]>>( &self, statement: &OwnedPreparedStatement, params: P, ) -> Result<u64>

Executes a prepared statement that doesn’t return rows.

§Errors

Same failure modes as Self::execute.

Source

pub fn execute_streaming<'a, P: AsRef<[Option<Vec<u8>>]>>( &'a self, statement: &OwnedPreparedStatement, params: P, chunk_size: usize, ) -> Result<PreparedQueryStream<'a>>

Executes a prepared statement with streaming results.

Returns a PreparedQueryStream that yields rows in chunks, keeping memory bounded regardless of result size. This is the prepared-statement analog of query_streaming.

The connection mutex is held for the duration of iteration; dropping the stream before completion issues a best-effort cancel.

§Errors
  • Returns Error (connection) if the connection mutex is poisoned.
  • Returns Error (server) or Error (I/O) if the initial Bind/Execute sequence for the prepared statement fails on the server or on the wire.
Source

pub fn close(self) -> Result<()>

Closes the connection.

§Errors
  • Returns Error (connection) if the connection mutex is poisoned.
  • Returns Error (I/O) if writing the Terminate message or flushing the socket fails.
Source

pub fn copy_in( &self, table_name: &str, columns: &[&str], ) -> Result<CopyInWriter<'_>>

Starts a COPY IN operation for bulk data insertion.

Returns a CopyInWriter that can be used to send data in HyperBinary format.

§Example
let mut writer = client.copy_in("\"my_table\"", &["col1", "col2"])?;
writer.send(binary_data)?;
let rows = writer.finish()?;
§Errors

Delegates to Self::copy_in_with_format; see that method for the concrete failure modes.

Source

pub fn copy_in_with_format( &self, table_name: &str, columns: &[&str], format: &str, ) -> Result<CopyInWriter<'_>>

Starts a COPY IN operation with a specified data format.

Returns a CopyInWriter that can be used to send data in the specified format.

§Arguments
  • table_name - The target table name (should be properly quoted if needed)
  • columns - Column names to insert into
  • format - The data format string: “HYPERBINARY” or “ARROWSTREAM”
§Example
// For Arrow IPC stream format
let mut writer = client.copy_in_with_format("\"my_table\"", &["col1", "col2"], "ARROWSTREAM")?;
writer.send(arrow_ipc_data)?;
let rows = writer.finish()?;
§Errors
  • Returns Error (connection) if the connection mutex is poisoned.
  • Returns Error (server) if the server rejects the generated COPY ... FROM STDIN statement (for example, missing table or mismatched columns).
  • Returns Error (I/O) on wire-protocol I/O failure while initiating the COPY.
Source

pub fn copy_in_raw(&self, query: &str) -> Result<CopyInWriter<'_>>

Starts a COPY IN operation from a raw SQL query string.

The query must be a complete COPY ... FROM STDIN ... statement. This is useful for text-format imports (CSV, TSV) where you need full control over the COPY options.

§Security

The query is validated to start with COPY (case-insensitive) as a defense-in-depth measure. Callers are still responsible for proper escaping of table names and other identifiers within the query. Prefer copy_in() or copy_in_with_format() when possible, as they handle escaping automatically.

§Example
let mut writer = client.copy_in_raw(
    "COPY \"my_table\" FROM STDIN WITH (FORMAT csv, HEADER true)"
)?;
writer.send(b"1,Alice\n2,Bob\n")?;
let rows = writer.finish()?;
§Errors
  • Returns ErrorKind::Query if query (trimmed) does not start with COPY (defense-in-depth check against non-COPY statements).
  • Returns Error (connection) if the connection mutex is poisoned.
  • Returns Error (server) or Error (I/O) if the server rejects the COPY statement or the wire write fails.
Source

pub fn is_alive(&self) -> bool

Returns true if the connection is alive (no error has occurred).

Source

pub fn copy_out(&self, query: &str) -> Result<Vec<u8>>

Executes a COPY … TO STDOUT query and returns all output data.

This is used for queries like: COPY (SELECT ...) TO STDOUT WITH (format arrowstream)

§Arguments
  • query - The COPY TO STDOUT query to execute
§Returns

The raw bytes from all CopyData messages concatenated together.

§Example
let arrow_data = client.copy_out(
    "COPY (SELECT * FROM my_table) TO STDOUT WITH (format arrowstream)"
)?;
§Errors
  • Returns Error (connection) if the connection mutex is poisoned.
  • Returns Error (server) if the server rejects the COPY ... TO STDOUT statement.
  • Returns Error (I/O) if the wire read fails while collecting COPY output.
Source

pub fn copy_out_to_writer( &self, query: &str, writer: &mut dyn Write, ) -> Result<u64>

Executes a COPY … TO STDOUT query and streams output to a writer.

Unlike copy_out which collects all data into memory, this method streams each CopyData chunk directly to the provided writer, keeping memory usage constant regardless of result size.

Returns the total number of bytes written.

§Example
let mut file = std::fs::File::create("output.csv")?;
let bytes_written = client.copy_out_to_writer(
    "COPY (SELECT * FROM my_table) TO STDOUT WITH (FORMAT csv, HEADER true)",
    &mut file,
)?;
println!("Wrote {} bytes", bytes_written);
§Errors

Same failure modes as Self::copy_out, plus Error (I/O) when the supplied writer returns an error while receiving COPY chunks.

Trait Implementations§

Source§

impl Cancellable for Client

Source§

fn cancel(&self)

Fire-and-forget cancel via PG wire protocol CancelRequest on a fresh connection. Swallows errors (logged via tracing::warn!) because cancellation is a best-effort signal and callers cannot meaningfully recover from a failed cancel.

Source§

impl Debug for Client

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoRequest<T> for T

Source§

fn into_request(self) -> Request<T>

Wrap the input message T in a tonic::Request
Source§

impl<L> LayerExt<L> for L

Source§

fn named_layer<S>(&self, service: S) -> Layered<<L as Layer<S>>::Service, S>
where L: Layer<S>,

Applies the layer to a service and wraps it in Layered.
Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more