Skip to main content

ReaderQuery

Struct ReaderQuery 

Source
pub struct ReaderQuery<'r> { /* private fields */ }
Expand description

Borrows a Reader exclusively while the query is being constructed and (eventually) the cursor is live.

ReaderQuery is Send, but not safe for concurrent access. It may be moved to another thread after an explicit happens-before hand-off. Any installed failover callback must therefore also be Send; it runs on whichever thread subsequently drives the cursor.

Implementations§

Source§

impl<'r> ReaderQuery<'r>

Source

pub fn initial_credit(self, credit: u64) -> Self

Override the initial_credit (bytes; 0 = unbounded).

Source

pub fn reset_symbol_dict(self, reset: bool) -> Self

Request a query-scoped SYMBOL dict: the server resets the connection dict before streaming this query so it never inherits symbols from earlier queries on the same connection. Silently no-op against a server that does not advertise CAP_QUERY_FLAGS.

Source

pub fn on_failover_reset<F>(self, callback: F) -> Self
where F: FnMut(&FailoverResetEvent) + Send + 'r,

Install a callback fired every time the cursor’s underlying connection is replaced via mid-query failover. The closure receives a FailoverResetEvent describing the new endpoint and runs before any replayed RESULT_BATCH arrives — the user-side handler must use this signal to discard rows it had accumulated from the previous (now-dead) connection. The query restarts from batch_seq=0 against the new endpoint with a fresh request_id.

Installing this callback is the caller’s opt-in to “I will handle replay-after-data-delivered correctly.” Without it, Cursor::next_batch refuses to fail over once any batch has been yielded — returning crate::ErrorCode::FailoverWouldDuplicate instead — to avoid silently doubling up rows in the caller’s accumulator. Initial-connect failover (before any batch is yielded) is transparent and does not require this callback.

Calling this method twice on the same ReaderQuery replaces the previous closure — only the most recent callback is invoked. The callback must be Send: a query/cursor may be handed to another thread, and the callback then runs and is dropped on that destination thread. This bound is required even if the caller never migrates the handle.

Mirrors the Java client’s onFailoverReset(newNode) contract.

§Panics from the callback

The callback is invoked synchronously from inside Cursor::next_batch (specifically, from the failover-replay path). If the callback panics, the unwind propagates through next_batch to the caller. The cursor’s Drop still runs, which closes the WebSocket cleanly, so no resources are leaked — but the Cursor is gone. There is no “swallow and resume” behavior; treat a panicking callback as a bug and either catch_unwind inside the callback yourself or ensure the callback is panic-free. The C FFI binding wraps the callback in catch_unwind + abort() (panics across the C boundary are undefined behavior); the pure-Rust API leaves them as normal unwinds.

use std::sync::{Arc, Mutex};
use questdb::egress::{FailoverResetEvent, Reader};

let mut reader = Reader::from_conf(
    "ws::addr=db-a:9000,db-b:9000;target=primary",
)?;
// The handler accumulates rows in a buffer shared with the
// callback. On failover the callback discards what was buffered
// — the replayed query restarts at `batch_seq=0` against the
// new endpoint, so anything already pushed would otherwise
// double up.
let rows: Arc<Mutex<Vec<i64>>> = Arc::new(Mutex::new(Vec::new()));
let rows_for_cb = Arc::clone(&rows);
let mut cursor = reader
    .prepare("select x from t order by ts")
    .on_failover_reset(move |ev: &FailoverResetEvent| {
        eprintln!(
            "failover: {} → {} after {} attempt(s) ({:?}, trigger={:?}: {})",
            ev.failed_addr, ev.new_addr,
            ev.attempts, ev.elapsed,
            ev.trigger.code(), ev.trigger.msg(),
        );
        rows_for_cb.lock().unwrap().clear();
    })
    .execute()?;
while let Some(_batch) = cursor.next_batch()? {
    // ... project `_batch` into `rows.lock().unwrap()` ...
}
Source

pub fn on_failover_progress<F>(self, callback: F) -> Self
where F: FnMut(&FailoverProgressEvent) + Send + 'r,

Install a callback fired at every phase of a mid-query failover lifecycle: Disconnected when the cursor’s connection dies, Retrying before each reconnect dial attempt, Reset after a successful failover (immediately before Self::on_failover_reset runs), and GaveUp when the retry budget is exhausted.

This callback is observational: installing it does not authorize replay after a batch has already reached the caller. Install Self::on_failover_reset as well when the caller can discard partial results safely. Without a reset callback, a post-delivery failure still returns ErrorCode::FailoverWouldDuplicate.

Calling this method twice on the same ReaderQuery replaces the previous closure — only the most recent callback is invoked. The callback must be Send: a query/cursor may be handed to another thread, and the callback then runs and is dropped on that destination thread. This bound is required even if the caller never migrates the handle.

§Reentrancy

The callback is invoked synchronously on the cursor’s drive thread, while Cursor::next_batch (or add_credit) is mid-mutation of the underlying Reader. The same contract as Self::on_failover_reset applies:

  • Must not call back into the originating reader, query, or cursor — including read-only stat getters.
  • Must not panic / longjmp / unwind across the boundary (the FFI trampoline catch_unwind + aborts on escape).
  • Must not block indefinitely — every batch read, CREDIT grant, and cancel waits until the callback returns.
Source

pub fn bind(self, value: Bind) -> Self

Append a typed bind parameter.

Source

pub fn bind_null(self, kind: SimpleNullKind) -> Self

Source

pub fn bind_bool(self, v: bool) -> Self

Source

pub fn bind_i8(self, v: i8) -> Self

Source

pub fn bind_i16(self, v: i16) -> Self

Source

pub fn bind_i32(self, v: i32) -> Self

Source

pub fn bind_i64(self, v: i64) -> Self

Source

pub fn bind_f32(self, v: f32) -> Self

Source

pub fn bind_f64(self, v: f64) -> Self

Source

pub fn bind_timestamp_micros(self, v: i64) -> Self

Source

pub fn bind_timestamp_nanos(self, v: i64) -> Self

Source

pub fn bind_date_millis(self, v: i64) -> Self

Source

pub fn bind_uuid(self, v: [u8; 16]) -> Self

Source

pub fn bind_long256(self, v: [u8; 32]) -> Self

Source

pub fn bind_char(self, v: u16) -> Self

Source

pub fn bind_ipv4(self, v: Ipv4Addr) -> Self

Source

pub fn bind_varchar<S: Into<String>>(self, v: S) -> Self

Source

pub fn bind_decimal64(self, value: i64, scale: i8) -> Self

Source

pub fn bind_decimal128(self, value: i128, scale: i8) -> Self

Source

pub fn bind_decimal256(self, bytes: [u8; 32], scale: i8) -> Self

Source

pub fn bind_geohash(self, value: u64, precision_bits: u8) -> Self

Source

pub fn bind_binary<B: Into<Vec<u8>>>(self, v: B) -> Self

Source

pub fn bind_null_varchar(self) -> Self

Source

pub fn bind_null_binary(self) -> Self

Source

pub fn bind_null_decimal64(self, scale: i8) -> Self

Source

pub fn bind_null_decimal128(self, scale: i8) -> Self

Source

pub fn bind_null_decimal256(self, scale: i8) -> Self

Source

pub fn bind_null_geohash(self, precision_bits: u8) -> Self

Source

pub fn execute(self) -> Result<Cursor<'r>>

Send the QUERY_REQUEST and return a streaming Cursor.

Auto Trait Implementations§

§

impl<'r> !RefUnwindSafe for ReaderQuery<'r>

§

impl<'r> !Sync for ReaderQuery<'r>

§

impl<'r> !UnwindSafe for ReaderQuery<'r>

§

impl<'r> Freeze for ReaderQuery<'r>

§

impl<'r> Send for ReaderQuery<'r>

§

impl<'r> Unpin for ReaderQuery<'r>

§

impl<'r> UnsafeUnpin for ReaderQuery<'r>

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<'a, T, E> AsTaggedExplicit<'a, E> for T
where T: 'a,

Source§

fn explicit(self, class: Class, tag: u32) -> TaggedParser<'a, Explicit, Self, E>

Source§

impl<'a, T, E> AsTaggedImplicit<'a, E> for T
where T: 'a,

Source§

fn implicit( self, class: Class, constructed: bool, tag: u32, ) -> TaggedParser<'a, Implicit, Self, E>

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<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

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> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

impl<T> Pointable for T

Source§

const ALIGN: usize

The alignment of pointer.
Source§

type Init = T

The type for initializers.
Source§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
Source§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
Source§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
Source§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
Source§

impl<T> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,

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<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V