Skip to content

Commit 18aed5f

Browse files
committed
refactor: reuse arena result tuple across execution pipeline
1 parent 90aea99 commit 18aed5f

56 files changed

Lines changed: 1150 additions & 607 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

examples/hello_world.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414

1515
#[cfg(all(not(target_arch = "wasm32"), feature = "orm"))]
1616
mod app {
17-
use kite_sql::db::{DataBaseBuilder, Database, ResultIter};
17+
use kite_sql::db::{DataBaseBuilder, Database};
1818
use kite_sql::errors::DatabaseError;
1919
use kite_sql::storage::Storage;
2020
use kite_sql::Model;

examples/transaction.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414

1515
#[cfg(not(target_arch = "wasm32"))]
1616
mod app {
17-
use kite_sql::db::{DataBaseBuilder, ResultIter};
17+
use kite_sql::db::DataBaseBuilder;
1818
use kite_sql::errors::DatabaseError;
1919
use kite_sql::types::tuple::Tuple;
2020
use kite_sql::types::value::DataValue;

src/bin/server.rs

Lines changed: 51 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
use async_trait::async_trait;
1616
use clap::Parser;
1717
use futures::stream;
18-
use kite_sql::db::{DBTransaction, DataBaseBuilder, Database, ResultIter};
18+
use kite_sql::db::{BorrowResultIter, DBTransaction, DataBaseBuilder, Database};
1919
use kite_sql::errors::DatabaseError;
2020
use kite_sql::storage::rocksdb::RocksStorage;
2121
use kite_sql::types::tuple::{SchemaRef, Tuple};
@@ -28,6 +28,7 @@ use pgwire::api::query::{PlaceholderExtendedQueryHandler, SimpleQueryHandler};
2828
use pgwire::api::results::{DataRowEncoder, FieldFormat, FieldInfo, QueryResponse, Response, Tag};
2929
use pgwire::api::{ClientInfo, NoopErrorHandler, PgWireServerHandlers, Type};
3030
use pgwire::error::{ErrorInfo, PgWireError, PgWireResult};
31+
use pgwire::messages::data::DataRow;
3132
use pgwire::tokio::process_socket;
3233
use std::fmt::Debug;
3334
use std::io;
@@ -213,43 +214,48 @@ impl SimpleQueryHandler for SessionBackend {
213214
_ => {
214215
let mut guard = self.tx.lock();
215216

216-
let mut tuples = Vec::new();
217217
let response = if let Some(transaction) = guard.as_mut() {
218218
let mut iter = unsafe { transaction.as_mut().run(query) }
219219
.map_err(|e| PgWireError::ApiError(Box::new(e)))?;
220-
for tuple in iter.by_ref() {
221-
tuples.push(tuple.map_err(|e| PgWireError::ApiError(Box::new(e)))?);
222-
}
223-
let schema = iter.schema().clone();
220+
let response = encode_query_result(&mut iter)?;
224221
iter.done()
225222
.map_err(|e| PgWireError::ApiError(Box::new(e)))?;
226-
encode_tuples(&schema, tuples)?
223+
response
227224
} else {
228225
let mut iter = self
229226
.inner
230227
.run(query)
231228
.map_err(|e| PgWireError::ApiError(Box::new(e)))?;
232-
for tuple in iter.by_ref() {
233-
tuples.push(tuple.map_err(|e| PgWireError::ApiError(Box::new(e)))?);
234-
}
235-
let schema = iter.schema().clone();
229+
let response = encode_query_result(&mut iter)?;
236230
iter.done()
237231
.map_err(|e| PgWireError::ApiError(Box::new(e)))?;
238-
encode_tuples(&schema, tuples)?
232+
response
239233
};
240234
Ok(vec![Response::Query(response)])
241235
}
242236
}
243237
}
244238
}
245239

246-
fn encode_tuples<'a>(schema: &SchemaRef, tuples: Vec<Tuple>) -> PgWireResult<QueryResponse<'a>> {
247-
if tuples.is_empty() {
248-
return Ok(QueryResponse::new(Arc::new(vec![]), stream::empty()));
240+
fn encode_query_result<'a, I>(iter: &mut I) -> PgWireResult<QueryResponse<'a>>
241+
where
242+
I: BorrowResultIter,
243+
{
244+
let fields = encode_fields(iter.schema())?;
245+
let mut results = Vec::new();
246+
247+
while let Some(tuple) = iter
248+
.next_borrowed_tuple()
249+
.map_err(|e| PgWireError::ApiError(Box::new(e)))?
250+
{
251+
results.push(encode_tuple(fields.clone(), tuple));
249252
}
250253

251-
let mut results = Vec::with_capacity(tuples.len());
252-
let schema = Arc::new(
254+
Ok(QueryResponse::new(fields, stream::iter(results)))
255+
}
256+
257+
fn encode_fields(schema: &SchemaRef) -> PgWireResult<Arc<Vec<FieldInfo>>> {
258+
Ok(Arc::new(
253259
schema
254260
.iter()
255261
.map(|column| {
@@ -264,41 +270,37 @@ fn encode_tuples<'a>(schema: &SchemaRef, tuples: Vec<Tuple>) -> PgWireResult<Que
264270
))
265271
})
266272
.collect::<PgWireResult<Vec<FieldInfo>>>()?,
267-
);
268-
269-
for tuple in tuples {
270-
let mut encoder = DataRowEncoder::new(schema.clone());
271-
for value in tuple.values {
272-
match value.logical_type() {
273-
LogicalType::SqlNull => encoder.encode_field(&None::<i8>),
274-
LogicalType::Boolean => encoder.encode_field(&value.bool()),
275-
LogicalType::Tinyint => encoder.encode_field(&value.i8()),
276-
LogicalType::UTinyint => encoder.encode_field(&value.u8().map(|v| v as i8)),
277-
LogicalType::Smallint => encoder.encode_field(&value.i16()),
278-
LogicalType::USmallint => encoder.encode_field(&value.u16().map(|v| v as i16)),
279-
LogicalType::Integer => encoder.encode_field(&value.i32()),
280-
LogicalType::UInteger => encoder.encode_field(&value.u32()),
281-
LogicalType::Bigint => encoder.encode_field(&value.i64()),
282-
LogicalType::UBigint => encoder.encode_field(&value.u64().map(|v| v as i64)),
283-
LogicalType::Float => encoder.encode_field(&value.float()),
284-
LogicalType::Double => encoder.encode_field(&value.double()),
285-
LogicalType::Char(..) | LogicalType::Varchar(..) => {
286-
encoder.encode_field(&value.utf8())
287-
}
288-
LogicalType::Date => encoder.encode_field(&value.date()),
289-
LogicalType::DateTime => encoder.encode_field(&value.datetime()),
290-
LogicalType::Time(_) => encoder.encode_field(&value.time()),
291-
LogicalType::Decimal(_, _) => {
292-
encoder.encode_field(&value.decimal().map(|decimal| decimal.to_string()))
293-
}
294-
_ => unreachable!(),
295-
}?;
296-
}
273+
))
274+
}
297275

298-
results.push(encoder.finish());
276+
fn encode_tuple(schema: Arc<Vec<FieldInfo>>, tuple: &Tuple) -> PgWireResult<DataRow> {
277+
let mut encoder = DataRowEncoder::new(schema);
278+
for value in &tuple.values {
279+
match value.logical_type() {
280+
LogicalType::SqlNull => encoder.encode_field(&None::<i8>),
281+
LogicalType::Boolean => encoder.encode_field(&value.bool()),
282+
LogicalType::Tinyint => encoder.encode_field(&value.i8()),
283+
LogicalType::UTinyint => encoder.encode_field(&value.u8().map(|v| v as i8)),
284+
LogicalType::Smallint => encoder.encode_field(&value.i16()),
285+
LogicalType::USmallint => encoder.encode_field(&value.u16().map(|v| v as i16)),
286+
LogicalType::Integer => encoder.encode_field(&value.i32()),
287+
LogicalType::UInteger => encoder.encode_field(&value.u32()),
288+
LogicalType::Bigint => encoder.encode_field(&value.i64()),
289+
LogicalType::UBigint => encoder.encode_field(&value.u64().map(|v| v as i64)),
290+
LogicalType::Float => encoder.encode_field(&value.float()),
291+
LogicalType::Double => encoder.encode_field(&value.double()),
292+
LogicalType::Char(..) | LogicalType::Varchar(..) => encoder.encode_field(&value.utf8()),
293+
LogicalType::Date => encoder.encode_field(&value.date()),
294+
LogicalType::DateTime => encoder.encode_field(&value.datetime()),
295+
LogicalType::Time(_) => encoder.encode_field(&value.time()),
296+
LogicalType::Decimal(_, _) => {
297+
encoder.encode_field(&value.decimal().map(|decimal| decimal.to_string()))
298+
}
299+
_ => unreachable!(),
300+
}?;
299301
}
300302

301-
Ok(QueryResponse::new(schema, stream::iter(results)))
303+
encoder.finish()
302304
}
303305

304306
fn into_pg_type(data_type: &LogicalType) -> PgWireResult<Type> {

src/db.rs

Lines changed: 133 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -666,14 +666,38 @@ impl<S: Storage> Database<S> {
666666
}
667667
}
668668

669-
/// Common interface for result iterators returned by database execution APIs.
670-
///
671-
/// A result iterator streams [`Tuple`] values and exposes the output schema of
672-
/// the current statement.
673-
pub trait ResultIter: Iterator<Item = Result<Tuple, DatabaseError>> {
669+
/// Borrowing interface for result iterators returned by database execution APIs.
670+
pub trait BorrowResultIter {
674671
/// Returns the output schema for the current result set.
675672
fn schema(&self) -> &SchemaRef;
676673

674+
/// Returns the next row as a borrowed tuple.
675+
fn next_borrowed_tuple(&mut self) -> Result<Option<&Tuple>, DatabaseError>;
676+
677+
/// Creates a mapped iterator that transforms borrowed tuples into owned output values.
678+
fn map_result<F, O>(self, mapper: F) -> MappedResultIter<Self, F, O>
679+
where
680+
Self: Sized,
681+
F: for<'a> FnMut(&'a SchemaRef, &'a Tuple) -> Result<O, DatabaseError>,
682+
{
683+
let schema = self.schema().clone();
684+
MappedResultIter {
685+
inner: self,
686+
mapper,
687+
schema,
688+
_marker: PhantomData,
689+
}
690+
}
691+
692+
/// Finishes consuming the iterator and flushes any remaining work.
693+
fn done(self) -> Result<(), DatabaseError>;
694+
}
695+
696+
/// Common interface for owned-tuple result iterators.
697+
///
698+
/// This remains for compatibility with existing callers that expect
699+
/// `Iterator<Item = Result<Tuple, DatabaseError>>`.
700+
pub trait ResultIter: BorrowResultIter + Iterator<Item = Result<Tuple, DatabaseError>> {
677701
#[cfg(feature = "orm")]
678702
/// Converts this iterator into a typed ORM iterator.
679703
///
@@ -687,9 +711,46 @@ pub trait ResultIter: Iterator<Item = Result<Tuple, DatabaseError>> {
687711
{
688712
OrmIter::new(self)
689713
}
714+
}
690715

691-
/// Finishes consuming the iterator and flushes any remaining work.
692-
fn done(self) -> Result<(), DatabaseError>;
716+
impl<I> ResultIter for I where I: BorrowResultIter + Iterator<Item = Result<Tuple, DatabaseError>> {}
717+
718+
/// Typed adapter over a borrowing result iterator.
719+
pub struct MappedResultIter<I, F, O> {
720+
inner: I,
721+
mapper: F,
722+
schema: SchemaRef,
723+
_marker: PhantomData<O>,
724+
}
725+
726+
impl<I, F, O> MappedResultIter<I, F, O>
727+
where
728+
I: BorrowResultIter,
729+
F: for<'a> FnMut(&'a SchemaRef, &'a Tuple) -> Result<O, DatabaseError>,
730+
{
731+
pub fn schema(&self) -> &SchemaRef {
732+
&self.schema
733+
}
734+
735+
pub fn done(self) -> Result<(), DatabaseError> {
736+
self.inner.done()
737+
}
738+
}
739+
740+
impl<I, F, O> Iterator for MappedResultIter<I, F, O>
741+
where
742+
I: BorrowResultIter,
743+
F: for<'a> FnMut(&'a SchemaRef, &'a Tuple) -> Result<O, DatabaseError>,
744+
{
745+
type Item = Result<O, DatabaseError>;
746+
747+
fn next(&mut self) -> Option<Self::Item> {
748+
match self.inner.next_borrowed_tuple() {
749+
Ok(Some(tuple)) => Some((self.mapper)(&self.schema, tuple)),
750+
Ok(None) => None,
751+
Err(err) => Some(Err(err)),
752+
}
753+
}
693754
}
694755

695756
#[cfg(feature = "orm")]
@@ -760,6 +821,33 @@ impl<S: Storage> Drop for DatabaseIter<'_, S> {
760821
}
761822
}
762823

824+
impl<S: Storage> DatabaseIter<'_, S> {
825+
#[inline]
826+
pub fn schema(&self) -> &SchemaRef {
827+
unsafe { (*self.inner).schema() }
828+
}
829+
830+
#[inline]
831+
pub fn next_borrowed_tuple(&mut self) -> Result<Option<&Tuple>, DatabaseError> {
832+
let result = unsafe { (*self.inner).next_borrowed_tuple() };
833+
if result.as_ref().is_ok_and(Option::is_none) {
834+
self._guard = None;
835+
}
836+
result
837+
}
838+
839+
#[inline]
840+
pub fn done(mut self) -> Result<(), DatabaseError> {
841+
unsafe {
842+
Box::from_raw(mem::replace(&mut self.inner, std::ptr::null_mut())).done()?;
843+
}
844+
unsafe {
845+
Box::from_raw(mem::replace(&mut self.transaction, std::ptr::null_mut())).commit()?;
846+
}
847+
Ok(())
848+
}
849+
}
850+
763851
impl<S: Storage> Iterator for DatabaseIter<'_, S> {
764852
type Item = Result<Tuple, DatabaseError>;
765853

@@ -772,19 +860,17 @@ impl<S: Storage> Iterator for DatabaseIter<'_, S> {
772860
}
773861
}
774862

775-
impl<S: Storage> ResultIter for DatabaseIter<'_, S> {
863+
impl<S: Storage> BorrowResultIter for DatabaseIter<'_, S> {
776864
fn schema(&self) -> &SchemaRef {
777-
unsafe { (*self.inner).schema() }
865+
DatabaseIter::schema(self)
778866
}
779867

780-
fn done(mut self) -> Result<(), DatabaseError> {
781-
unsafe {
782-
Box::from_raw(mem::replace(&mut self.inner, std::ptr::null_mut())).done()?;
783-
}
784-
unsafe {
785-
Box::from_raw(mem::replace(&mut self.transaction, std::ptr::null_mut())).commit()?;
786-
}
787-
Ok(())
868+
fn next_borrowed_tuple(&mut self) -> Result<Option<&Tuple>, DatabaseError> {
869+
DatabaseIter::next_borrowed_tuple(self)
870+
}
871+
872+
fn done(self) -> Result<(), DatabaseError> {
873+
DatabaseIter::done(self)
788874
}
789875
}
790876

@@ -851,34 +937,55 @@ impl<'a, T: Transaction + 'a> TransactionIter<'a, T> {
851937
fn new(schema: SchemaRef, executor: Executor<'a, T>) -> Self {
852938
Self { executor, schema }
853939
}
940+
941+
#[inline]
942+
pub fn schema(&self) -> &SchemaRef {
943+
&self.schema
944+
}
945+
946+
#[inline]
947+
pub fn next_borrowed_tuple(&mut self) -> Result<Option<&Tuple>, DatabaseError> {
948+
self.executor.next_tuple()
949+
}
950+
951+
#[inline]
952+
pub fn done(mut self) -> Result<(), DatabaseError> {
953+
while self.next_borrowed_tuple()?.is_some() {}
954+
Ok(())
955+
}
854956
}
855957

856958
impl<T: Transaction> Iterator for TransactionIter<'_, T> {
857959
type Item = Result<Tuple, DatabaseError>;
858960

859961
fn next(&mut self) -> Option<Self::Item> {
860-
self.executor.next()
962+
match self.executor.next_tuple() {
963+
Ok(Some(tuple)) => Some(Ok(tuple.clone())),
964+
Ok(None) => None,
965+
Err(err) => Some(Err(err)),
966+
}
861967
}
862968
}
863969

864-
impl<T: Transaction> ResultIter for TransactionIter<'_, T> {
970+
impl<T: Transaction> BorrowResultIter for TransactionIter<'_, T> {
865971
fn schema(&self) -> &SchemaRef {
866-
&self.schema
972+
TransactionIter::schema(self)
867973
}
868974

869-
fn done(mut self) -> Result<(), DatabaseError> {
870-
for result in self.by_ref() {
871-
let _ = result?;
872-
}
873-
Ok(())
975+
fn next_borrowed_tuple(&mut self) -> Result<Option<&Tuple>, DatabaseError> {
976+
TransactionIter::next_borrowed_tuple(self)
977+
}
978+
979+
fn done(self) -> Result<(), DatabaseError> {
980+
TransactionIter::done(self)
874981
}
875982
}
876983

877984
#[cfg(all(test, not(target_arch = "wasm32")))]
878985
pub(crate) mod test {
879986
use crate::binder::{Binder, BinderContext};
880987
use crate::catalog::{ColumnCatalog, ColumnDesc, ColumnRef};
881-
use crate::db::{DataBaseBuilder, DatabaseError, ResultIter};
988+
use crate::db::{DataBaseBuilder, DatabaseError};
882989
use crate::expression::ScalarExpression;
883990
use crate::planner::operator::join::JoinCondition;
884991
use crate::planner::operator::Operator;

0 commit comments

Comments
 (0)