From 3da60e6c29a3c800a803c2e23bd29ec7d0410dce Mon Sep 17 00:00:00 2001 From: Dan Spencer Date: Tue, 31 Mar 2015 12:51:25 -0600 Subject: [PATCH] Add Group trait, used to yield rows and perform aggregate functions. --- src/databasestorage.rs | 8 +++++++- src/queryplan/execute.rs | 36 +++++++++++++++++++++++++++++------- src/tempdb/mod.rs | 27 +++++++++++++++++++++------ 3 files changed, 57 insertions(+), 14 deletions(-) diff --git a/src/databasestorage.rs b/src/databasestorage.rs index 2ed7955..04c7c60 100644 --- a/src/databasestorage.rs +++ b/src/databasestorage.rs @@ -4,5 +4,11 @@ pub trait DatabaseStorage { type Info: DatabaseInfo; fn scan_table<'a>(&'a self, table: &'a ::Table) - -> Box::ColumnValue]>> + 'a>; + -> Box::ColumnValue> + 'a>; +} + +pub trait Group { + type ColumnValue: Sized + 'static; + + fn iter<'a>(&'a self) -> Box> + 'a>; } diff --git a/src/queryplan/execute.rs b/src/queryplan/execute.rs index 355e245..1cef944 100644 --- a/src/queryplan/execute.rs +++ b/src/queryplan/execute.rs @@ -1,24 +1,45 @@ use columnvalueops::ColumnValueOps; use databaseinfo::DatabaseInfo; -use databasestorage::DatabaseStorage; +use databasestorage::{DatabaseStorage, Group}; use super::sexpression::{BinaryOp, SExpression}; +enum SourceType<'a, ColumnValue: Sized + 'static> { + Row(&'a [ColumnValue]), + Group(&'a Group) +} + struct Source<'a, ColumnValue: Sized + 'static> { parent: Option<&'a Source<'a, ColumnValue>>, source_id: u32, - row: &'a [ColumnValue], + source_type: SourceType<'a, ColumnValue> } impl<'a, ColumnValue: Sized> Source<'a, ColumnValue> { fn find_row_from_source_id(&self, source_id: u32) -> Option<&[ColumnValue]> { if self.source_id == source_id { - Some(self.row) + match &self.source_type { + &SourceType::Row(row) => Some(row), + _ => None + } } else if let Some(parent) = self.parent { parent.find_row_from_source_id(source_id) } else { None } } + + fn find_group_from_source_id(&self, source_id: u32) -> Option<&Group> { + if self.source_id == source_id { + match &self.source_type { + &SourceType::Group(group) => Some(group), + _ => None + } + } else if let Some(parent) = self.parent { + parent.find_group_from_source_id(source_id) + } else { + None + } + } } /// The query plan is currently defined as a recursive language. @@ -55,11 +76,12 @@ where ::Table: 'a { match expr { &SExpression::Scan { table, source_id, ref yield_fn } => { - for row in self.storage.scan_table(table) { + let group = self.storage.scan_table(table); + for row in group.iter() { let new_source = Source { parent: source, source_id: source_id, - row: &row + source_type: SourceType::Row(&row) }; try!(self.execute(yield_fn, result_cb, Some(&new_source))); @@ -72,7 +94,7 @@ where ::Table: 'a let new_source = Source { parent: source, source_id: source_id, - row: row + source_type: SourceType::Row(row) }; self.execute(yield_out_fn, result_cb, Some(&new_source)) @@ -152,7 +174,7 @@ where ::Table: 'a let new_source = Source { parent: source, source_id: source_id, - row: &row + source_type: SourceType::Row(&row) }; self.resolve_value(yield_out_fn, Some(&new_source)) diff --git a/src/tempdb/mod.rs b/src/tempdb/mod.rs index 0c27237..87d7235 100644 --- a/src/tempdb/mod.rs +++ b/src/tempdb/mod.rs @@ -8,7 +8,7 @@ use std::collections::BTreeSet; use columnvalueops::ColumnValueOps; use databaseinfo::{DatabaseInfo, TableInfo, ColumnInfo}; -use databasestorage::DatabaseStorage; +use databasestorage::{Group, DatabaseStorage}; use identifier::Identifier; use types::{DbType, Variant}; use sqlsyntax::ast; @@ -41,12 +41,15 @@ impl DatabaseInfo for TempDb { } } -impl DatabaseStorage for TempDb { - type Info = TempDb; +struct ScanGroup<'a> { + table: &'a Table +} - fn scan_table<'a>(&'a self, table: &'a Table) - -> Box> + 'a> - { +impl<'a> Group for ScanGroup<'a> { + type ColumnValue = Variant; + + fn iter<'b>(&'b self) -> Box> + 'b> { + let table = self.table; let columns: &'a [self::table::Column] = &table.columns; Box::new(table.rowid_index.iter().map(move |key_v| { @@ -95,6 +98,18 @@ impl DatabaseStorage for TempDb { } } +impl DatabaseStorage for TempDb { + type Info = TempDb; + + fn scan_table<'a>(&'a self, table: &'a Table) + -> Box + 'a> + { + Box::new(ScanGroup { + table: table + }) + } +} + impl TempDb { pub fn new() -> TempDb { TempDb {