Skip to main content

QueryResult

Struct QueryResult 

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

The rows a query produced, with the names and types of its columns.

Materialized rather than streamed. A streaming result would have to hold the operator tree, which holds a borrow of the plan and of the catalog, and that would make a result set a value nobody can put in a struct. Section 7.5’s streaming result is the M1 answer and it arrives as a second type beside this one rather than as a change to it, because the overwhelming majority of queries somebody embeds a database to run produce a result that fits in memory and the API for those should not be the harder one.

The chunks are kept as chunks rather than flattened into rows. Anything that wants the columnar form gets it without a transpose, which is what an Arrow export and a dataframe binding both want, and anything that wants a row gets it through QueryResult::row.

Implementations§

Source§

impl QueryResult

Source

pub fn names(&self) -> &[String]

The column names, in order.

Source

pub fn types(&self) -> &[LogicalType]

The column types, in order.

Source

pub fn footprint(&self) -> u64

How many bytes this result is charged against the database’s memory limit.

The chunks, not the names and the types, and it is what rudb_common::Memory::used stops counting when this is dropped. Worth reading for a program deciding whether to keep a result or re-run the query for it.

Source

pub fn metrics(&self) -> Option<&Document>

What the execution measured about itself, for a result that came from one.

There is nothing here for a statement that ran no plan, which is a SET, a CREATE with no query in it, or an EXPLAIN, since none of those execute anything to measure. Everything else carries a document with a row per operator and a row per pipeline, which is what EXPLAIN ANALYZE prints and what --metrics writes out as JSON.

It hangs off the result rather than off the connection because a result outlives the query and two of them can be held at once. Numbers kept on the connection would be the numbers of whichever query ran most recently, which is not a question anybody is asking when they are holding the result of a particular one.

Source

pub fn width(&self) -> usize

How many columns.

Source

pub fn len(&self) -> usize

How many rows, across every chunk.

Source

pub fn is_empty(&self) -> bool

Whether the query produced no rows.

Source

pub fn column_name(&self, column: usize) -> &str

The name of one column, or the empty string if there is no such column.

Source

pub fn column_type(&self, column: usize) -> LogicalType

The type of one column, or NULL if there is no such column.

Source

pub fn chunks(&self) -> &[Chunk]

The batches, for a caller that wants the columnar form.

Source

pub fn chunk_count(&self) -> usize

How many batches the result is in.

A caller that walks the columnar form walks this rather than the row count, which is the whole point of having it: a result of ten million rows is a few thousand chunks and reading it that way never builds a row.

Source

pub fn chunk(&self, at: usize) -> Option<&Chunk>

One batch, or None if it is past the end.

Source

pub fn chunk_iter(&self) -> impl ExactSizeIterator<Item = &Chunk>

The batches, one at a time.

The same walk as chunks().iter() and the name a caller looks for. What it is not is a promise about where the rows came from: they are all here already, and a result that does not materialize is section 7.5’s streaming result, which is a second type beside this one.

Source

pub fn into_chunks(self) -> Vec<Chunk>

The batches, taken rather than borrowed.

For a caller that is turning the result into something else, an Arrow record batch or a table to append to, and would otherwise clone every chunk to do it.

Source

pub fn value_at(&self, row: usize, column: usize) -> Value

One value, or null if the row or the column is past the end.

Null for a row that does not exist rather than an option, because every caller that asks for a value in range would then have to unwrap one, and a query result is read in a loop over QueryResult::len.

Source

pub fn row(&self, row: usize) -> Option<Vec<Value>>

One row, left to right, or None if it is past the end.

Source

pub fn rows(&self) -> impl Iterator<Item = Vec<Value>> + '_

Every row in order, which is the shape a test and a script both want.

Source

pub fn column(&self, column: usize) -> impl Iterator<Item = Value> + '_

One column, top to bottom, across every chunk.

Empty for a column that is not there. This is the read that matches how the rows are held, so a program summing a column or handing one to a plotting library never transposes anything.

Source

pub fn arrow_schema(&self) -> Result<Schema>

The column names and Arrow types, without converting any values.

Separate from QueryResult::to_arrow because a result of no rows has no batches and still has columns, and a consumer that reads the schema off the first batch would have nothing to read it off. Cheap enough to call on its own: it looks at the types and never at the rows.

§Errors

For a column of a type Arrow has no counterpart for here yet.

Source

pub fn to_arrow(&self) -> Result<Vec<RecordBatch>>

The result as Arrow record batches, one per chunk.

One per chunk rather than one for the whole result, because the chunks are what the executor produced and concatenating them would mean copying every value a second time to build a single large batch that most consumers immediately walk in pieces anyway. A consumer that does want one batch has every column in hand to build it.

A result of no rows converts to no batches. The schema is QueryResult::arrow_schema, and RecordBatch::empty turns it into the empty batch for a consumer that needs one.

§Errors

For a column of a type Arrow has no counterpart for here yet, and for a chunk whose values are not the layout its type says they are.

Trait Implementations§

Source§

impl Clone for QueryResult

Source§

fn clone(&self) -> QueryResult

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for QueryResult

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> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
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> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

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

Source§

type Error = !

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

fn try_from(value: U) -> Result<T, !>

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.