Skip to main content

Rowset

Struct Rowset 

Source
pub struct Rowset<'conn> { /* private fields */ }
Expand description

A streaming result set from a SQL query.

Rowset provides memory-efficient streaming access to query results. Results are fetched on-demand in chunks, keeping memory usage constant regardless of result set size. This makes it safe for any result size, from a single row to billions of rows.

§Example

let mut result = conn.execute_query("SELECT * FROM big_table")?;
while let Some(chunk) = result.next_chunk()? {
    for row in &chunk {
        // Generic typed access (like C++ row.get<T>())
        let id: Option<i32> = row.get(0);
        let value: Option<f64> = row.get(1);

        // Or direct accessors for performance
        let id = row.get_i32(0);
        let value = row.get_f64(1);
    }
}

§Memory Behavior

  • Only one chunk is held in memory at a time
  • Default chunk size is 64K rows (~few MB depending on row width)
  • Memory usage is O(chunk_size), not O(total_rows)
  • Safe for billion-row results

Implementations§

Source§

impl<'conn> Rowset<'conn>

Source

pub fn schema(&self) -> Option<ResultSchema>

Returns the schema (column metadata) for the result set.

For TCP connections, the schema is captured from the RowDescription message after the first chunk is read. For gRPC connections, the schema is available immediately from the Arrow data.

Returns None if no data has been read yet (TCP only).

§Example
let mut result = conn.execute_query("SELECT id, name FROM users")?;
// Read first chunk to capture schema (TCP) or get it immediately (gRPC)
let _ = result.next_chunk()?;
if let Some(schema) = result.schema() {
    for col in schema.columns() {
        println!("Column: {} ({})", col.name(), col.sql_type());
    }
}
Source

pub fn next_chunk(&mut self) -> Result<Option<Vec<Row>>>

Returns the next chunk of rows from the result set.

Each chunk contains up to chunk_size rows (default 64K). Returns Ok(None) when all rows have been consumed.

§Example
while let Some(chunk) = result.next_chunk()? {
    for row in &chunk {
        let id: Option<i32> = row.get(0);  // Generic typed access
        let value = row.get_f64(1);        // Direct accessor
    }
}
§Errors
Source

pub fn rows(self) -> RowIterator<'conn>

Returns an iterator over all rows in the result set.

This provides a C++-like iteration experience while maintaining Rust’s explicit error handling. Chunks are fetched internally as needed, keeping memory usage constant.

§Example
// Simple iteration (like C++)
let result = conn.execute_query("SELECT * FROM users")?;
for row in result.rows() {
    let row = row?;  // Handle potential network errors
    let id: Option<i32> = row.get(0);
    let name: Option<String> = row.get(1);
    println!("User: {:?} - {:?}", id, name);
}
§Error Handling

Unlike C++ which uses exceptions, Rust requires explicit error handling. Each item in the iterator is a Result<LightweightRow> to handle potential network or protocol errors during streaming.

§Comparison with next_chunk()
Aspectrows()next_chunk()
SyntaxSimpler, C++-likeMore verbose
Error handlingPer-row with ?Per-chunk
Batch opsUse .collect()Natural
Best forSimple iterationBatch processing
Source

pub fn collect_rows(self) -> Result<Vec<Row>>

Collects all rows into a Vec.

This is a convenience method that handles error collection more elegantly than the standard collect::<Result<Vec<_>, _>>() pattern.

§Example
let result = conn.execute_query("SELECT id, name FROM users")?;
let rows = result.collect_rows()?;  // Much cleaner than collect::<Result<Vec<_>, _>>()

for row in rows {
    let id: Option<i32> = row.get(0);
    let name: Option<String> = row.get(1);
    println!("User: {:?} - {:?}", id, name);
}
§Errors

Returns the first error produced by next_chunk while draining the stream (transport I/O failure or server-side error).

Source

pub fn collect_column<T: RowValue>(self) -> Result<Vec<Option<T>>>

Collects the first column of each row into a Vec.

This is useful for single-column queries or when you only need one column.

§Example
let result = conn.execute_query("SELECT name FROM users")?;
let names: Vec<Option<String>> = result.collect_column()?;

for name in names {
    if let Some(name) = name {
        println!("User: {}", name);
    }
}
§Errors

Returns the first streaming error from next_chunk. SQL NULL cells yield Option::None entries, not errors.

Source

pub fn collect_column_non_null<T: RowValue>(self) -> Result<Vec<T>>

Collects the first column, filtering out NULL values.

This is useful when you know the column doesn’t contain NULLs or want to ignore them.

§Example
let result = conn.execute_query("SELECT name FROM users WHERE name IS NOT NULL")?;
let names: Vec<String> = result.collect_column_non_null()?;

for name in names {
    println!("User: {}", name);  // No need to handle Option
}
§Errors

Returns the first streaming error from collect_column.

Source

pub fn first_row(self) -> Result<Option<Row>>

Gets the first row of the result set.

This is useful for queries that are expected to return exactly one row, such as aggregate queries or lookups by unique key.

§Example
let result = conn.execute_query("SELECT COUNT(*) FROM users")?;
if let Some(row) = result.first_row()? {
    let count: Option<i64> = row.get(0);
    println!("User count: {:?}", count);
}
§Errors

Returns the error from next_chunk. An empty result set yields Ok(None), not an error.

Source

pub fn require_first_row(self) -> Result<Row>

Gets the first row or returns an error if no rows were found.

This is useful when you expect exactly one row and want to fail if that’s not the case.

§Example
let result = conn.execute_query("SELECT id, name FROM users WHERE id = 1")?;
let row = result.require_first_row()?;  // Fails if no row found
let id: Option<i32> = row.get(0);
let name: Option<String> = row.get(1);
println!("Found user: {:?} - {:?}", id, name);
§Errors
Source

pub fn scalar<T: RowValue>(self) -> Result<Option<T>>

Gets a scalar value from the first row, first column.

This is a convenience method for scalar queries like SELECT COUNT(*) or SELECT MAX(id).

§Example
let result = conn.execute_query("SELECT COUNT(*) FROM users")?;
let count: Option<i64> = result.scalar()?;  // Much cleaner than manual row handling
println!("User count: {:?}", count);
§Errors

Returns the error from require_first_row: streaming error or empty result. SQL NULL in the single cell yields Ok(None).

Source

pub fn require_scalar<T: RowValue>(self) -> Result<T>

Gets a scalar value from the first row, first column, or returns an error if NULL.

This is useful when you expect a non-NULL scalar result.

§Example
let result = conn.execute_query("SELECT COUNT(*) FROM users")?;
let count: i64 = result.require_scalar()?;  // Fails if NULL
println!("User count: {}", count);
§Errors
  • Returns the error from scalar.
  • Returns crate::Error::Other with message "Scalar query returned NULL" if the single cell is SQL NULL.

Trait Implementations§

Source§

impl Debug for Rowset<'_>

Source§

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

Formats the value using the given formatter. Read more

Auto Trait Implementations§

§

impl<'conn> Freeze for Rowset<'conn>

§

impl<'conn> !RefUnwindSafe for Rowset<'conn>

§

impl<'conn> !Send for Rowset<'conn>

§

impl<'conn> !Sync for Rowset<'conn>

§

impl<'conn> Unpin for Rowset<'conn>

§

impl<'conn> UnsafeUnpin for Rowset<'conn>

§

impl<'conn> !UnwindSafe for Rowset<'conn>

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