Skip to content

Commit 6ee8524

Browse files
perf: remove table headers from rows in query engine
Fixes #270
1 parent cc36a2e commit 6ee8524

File tree

9 files changed

+82
-82
lines changed

9 files changed

+82
-82
lines changed

crates/core/src/db/datastore/locking_tx_datastore/mod.rs

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -99,8 +99,8 @@ impl traits::Data for Data {
9999
/// which may or may not have an associated `DataKey`.
100100
#[derive(Clone)]
101101
pub struct DataRef {
102-
id: DataKey,
103-
data: ProductValue,
102+
pub id: DataKey,
103+
pub data: ProductValue,
104104
}
105105

106106
impl DataRef {
@@ -111,10 +111,6 @@ impl DataRef {
111111
pub fn view(&self) -> &ProductValue {
112112
&self.data
113113
}
114-
115-
pub fn id(&self) -> &DataKey {
116-
&self.id
117-
}
118114
}
119115

120116
pub struct MutTxId {

crates/core/src/sql/execute.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -446,7 +446,7 @@ pub(crate) mod tests {
446446
let mut result = result.first().unwrap().clone();
447447

448448
let row = product!(scalar(2u64), scalar("test"));
449-
input.data.push(RelValue::new(&input.head, &row, None));
449+
input.data.push(RelValue::new(row, None));
450450
input.data.sort();
451451
result.data.sort();
452452

@@ -528,7 +528,7 @@ pub(crate) mod tests {
528528

529529
let mut change = input;
530530
change.data.clear();
531-
change.data.push(RelValue::new(&change.head, &row, None));
531+
change.data.push(RelValue::new(row, None));
532532

533533
assert_eq!(
534534
change.as_without_table_name(),

crates/core/src/subscription/query.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ pub fn to_mem_table(of: QueryExpr, data: &DatabaseTableUpdate) -> QueryExpr {
5555
let mut new = row.row.clone();
5656
new.elements[pos] = row.op_type.into();
5757
let mut bytes: &[u8] = row.row_pk.as_ref();
58-
RelValue::new(&t.head, &new, Some(DataKey::decode(&mut bytes).unwrap()))
58+
RelValue::new(new, Some(DataKey::decode(&mut bytes).unwrap()))
5959
}));
6060
} else {
6161
t.head.fields.push(Column::new(
@@ -67,7 +67,7 @@ pub fn to_mem_table(of: QueryExpr, data: &DatabaseTableUpdate) -> QueryExpr {
6767
new.elements.push(row.op_type.into());
6868
let mut bytes: &[u8] = row.row_pk.as_ref();
6969
t.data
70-
.push(RelValue::new(&t.head, &new, Some(DataKey::decode(&mut bytes).unwrap())));
70+
.push(RelValue::new(new, Some(DataKey::decode(&mut bytes).unwrap())));
7171
}
7272
}
7373

crates/core/src/vm.rs

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -49,14 +49,16 @@ pub fn build_query<'a>(
4949
for q in query.query {
5050
result = match q {
5151
Query::Select(cmp) => {
52-
let iter = result.select(move |row| cmp.compare(row));
52+
let header = result.head().clone();
53+
let iter = result.select(move |row| cmp.compare(row, &header));
5354
Box::new(iter)
5455
}
5556
Query::Project(cols) => {
5657
if cols.is_empty() {
5758
result
5859
} else {
59-
let iter = result.project(&cols.clone(), move |row| Ok(row.project(&cols)?))?;
60+
let header = result.head().clone();
61+
let iter = result.project(&cols.clone(), move |row| Ok(row.project(&cols, &header)?))?;
6062
Box::new(iter)
6163
}
6264
}
@@ -76,21 +78,25 @@ pub fn build_query<'a>(
7678
}
7779
};
7880
let lhs = result;
81+
let key_lhs_header = lhs.head().clone();
82+
let key_rhs_header = rhs.head().clone();
83+
let col_lhs_header = lhs.head().clone();
84+
let col_rhs_header = rhs.head().clone();
7985

8086
let iter = lhs.join_inner(
8187
rhs,
8288
move |row| {
83-
let f = row.get(&key_lhs);
89+
let f = row.get(&key_lhs, &key_lhs_header);
8490
Ok(f.into())
8591
},
8692
move |row| {
87-
let f = row.get(&key_rhs);
93+
let f = row.get(&key_rhs, &key_rhs_header);
8894
Ok(f.into())
8995
},
90-
move |lhs, rhs| {
91-
let lhs = lhs.get(&col_lhs);
92-
let rhs = rhs.get(&col_rhs);
93-
Ok(lhs == rhs)
96+
move |l, r| {
97+
let l = l.get(&col_lhs, &col_lhs_header);
98+
let r = r.get(&col_rhs, &col_rhs_header);
99+
Ok(l == r)
94100
},
95101
)?;
96102
Box::new(iter)
@@ -343,7 +349,7 @@ impl RelOps for TableCursor<'_> {
343349
#[tracing::instrument(skip_all)]
344350
fn next(&mut self) -> Result<Option<RelValue>, ErrorVm> {
345351
if let Some(row) = self.iter.next() {
346-
return Ok(Some(RelValue::new(self.head(), row.view(), Some(*row.id()))));
352+
return Ok(Some(RelValue::new(row.data, Some(row.id))));
347353
};
348354
Ok(None)
349355
}
@@ -370,7 +376,7 @@ where
370376
#[tracing::instrument(skip_all)]
371377
fn next(&mut self) -> Result<Option<RelValue>, ErrorVm> {
372378
if let Some(row) = self.iter.next() {
373-
return Ok(Some(RelValue::new(self.head(), &row, None)));
379+
return Ok(Some(RelValue::new(row, None)));
374380
};
375381
Ok(None)
376382
}

crates/lib/src/relation.rs

Lines changed: 20 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -414,47 +414,44 @@ impl<T> RelIter<T> {
414414
}
415415
}
416416

417+
/// A borrowed version of [RelValue].
417418
#[derive(Debug, Clone, Copy)]
418419
pub struct RelValueRef<'a> {
419-
pub head: &'a Header,
420420
pub data: &'a ProductValue,
421421
}
422422

423423
impl<'a> RelValueRef<'a> {
424-
pub fn new(head: &'a Header, data: &'a ProductValue) -> Self {
425-
Self { head, data }
424+
pub fn new(data: &'a ProductValue) -> Self {
425+
Self { data }
426426
}
427427

428-
pub fn get(&self, col: &'a FieldExpr) -> &'a AlgebraicValue {
428+
pub fn get(&self, col: &'a FieldExpr, header: &'a Header) -> &'a AlgebraicValue {
429429
match col {
430430
FieldExpr::Name(col) => {
431-
if let Some(pos) = self.head.column_pos(col) {
431+
if let Some(pos) = header.column_pos(col) {
432432
if let Some(v) = self.data.elements.get(pos) {
433433
v
434434
} else {
435435
unreachable!("Field `{col}` at pos {pos} not found on row: {:?}", self.data.elements)
436436
}
437437
} else {
438-
unreachable!(
439-
"Field `{col}` not found on `{}`. Fields:{}",
440-
self.head.table_name, self.head
441-
)
438+
unreachable!("Field `{col}` not found on `{}`. Fields:{}", header.table_name, header)
442439
}
443440
}
444441
FieldExpr::Value(x) => x,
445442
}
446443
}
447444

448-
pub fn project(&self, cols: &[FieldExpr]) -> Result<ProductValue, RelationError> {
445+
pub fn project(&self, cols: &[FieldExpr], header: &'a Header) -> Result<ProductValue, RelationError> {
449446
let mut elements = Vec::with_capacity(cols.len());
450447

451448
for col in cols {
452449
match col {
453450
FieldExpr::Name(col) => {
454-
if let Some(pos) = self.head.column_pos(col) {
451+
if let Some(pos) = header.column_pos(col) {
455452
elements.push(self.data.elements[pos].clone());
456453
} else {
457-
return Err(RelationError::FieldNotFound(self.head.clone(), col.clone()));
454+
return Err(RelationError::FieldNotFound(header.clone(), col.clone()));
458455
}
459456
}
460457
FieldExpr::Value(col) => {
@@ -467,41 +464,29 @@ impl<'a> RelValueRef<'a> {
467464
}
468465
}
469466

470-
impl Relation for RelValueRef<'_> {
471-
fn head(&self) -> Header {
472-
self.head.clone()
473-
}
474-
475-
fn row_count(&self) -> RowCount {
476-
RowCount::exact(1)
477-
}
478-
}
479-
480-
/// The row/tuple generated by a [Relation] operator
467+
/// RelValue represents a materialized row during query execution.
468+
/// In particular it is the type generated/consumed by a [Relation] operator.
469+
/// This is in contrast to a `DataRef` which represents a row belonging to a table.
470+
/// The difference being that a RelValue's [DataKey] is optional since relational
471+
/// operators can modify their input rows.
481472
#[derive(Debug, Clone, Eq)]
482473
pub struct RelValue {
483474
pub id: Option<DataKey>,
484-
pub head: Header,
485475
pub data: ProductValue,
486476
}
487477

488478
impl RelValue {
489-
pub fn new(head: &Header, data: &ProductValue, id: Option<DataKey>) -> Self {
490-
Self {
491-
id,
492-
head: head.clone(),
493-
data: data.clone(),
494-
}
479+
pub fn new(data: ProductValue, id: Option<DataKey>) -> Self {
480+
Self { id, data }
495481
}
496482

497483
pub fn as_val_ref(&self) -> RelValueRef {
498-
RelValueRef::new(&self.head, &self.data)
484+
RelValueRef::new(&self.data)
499485
}
500486

501-
pub fn extend(self, head: &Header, with: RelValue) -> RelValue {
487+
pub fn extend(self, with: RelValue) -> RelValue {
502488
let mut x = self;
503489
x.id = None;
504-
x.head = head.clone();
505490
x.data.elements.extend(with.data.elements);
506491
x
507492
}
@@ -558,14 +543,14 @@ impl MemTable {
558543

559544
pub fn from_value(of: AlgebraicValue) -> Self {
560545
let head = Header::for_mem_table(of.type_of().into());
561-
let row = RelValue::new(&head, &of.into(), None);
546+
let row = RelValue::new(of.into(), None);
562547
Self::new(&head, StAccess::Public, &[row])
563548
}
564549

565550
pub fn from_iter(head: &Header, data: impl Iterator<Item = ProductValue>) -> Self {
566551
Self {
567552
head: head.clone(),
568-
data: data.map(|row| RelValue::new(head, &row, None)).collect(),
553+
data: data.map(|row| RelValue::new(row, None)).collect(),
569554
table_access: StAccess::Public,
570555
}
571556
}

crates/vm/src/eval.rs

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -407,14 +407,16 @@ pub fn build_query(mut result: Box<IterRows>, query: Vec<Query>) -> Result<Box<I
407407
for q in query {
408408
result = match q {
409409
Query::Select(cmp) => {
410-
let iter = result.select(move |row| cmp.compare(row));
410+
let header = result.head().clone();
411+
let iter = result.select(move |row| cmp.compare(row, &header));
411412
Box::new(iter)
412413
}
413414
Query::Project(cols) => {
414415
if cols.is_empty() {
415416
result
416417
} else {
417-
let iter = result.project(&cols.clone(), move |row| Ok(row.project(&cols)?))?;
418+
let header = result.head().clone();
419+
let iter = result.project(&cols.clone(), move |row| Ok(row.project(&cols, &header)?))?;
418420
Box::new(iter)
419421
}
420422
}
@@ -440,21 +442,25 @@ pub fn build_query(mut result: Box<IterRows>, query: Vec<Query>) -> Result<Box<I
440442
};
441443

442444
let lhs = result;
445+
let key_lhs_header = lhs.head().clone();
446+
let key_rhs_header = rhs.head().clone();
447+
let col_lhs_header = lhs.head().clone();
448+
let col_rhs_header = rhs.head().clone();
443449

444450
let iter = lhs.join_inner(
445451
rhs,
446452
move |row| {
447-
let f = row.get(&key_lhs);
453+
let f = row.get(&key_lhs, &key_lhs_header);
448454
Ok(f.into())
449455
},
450456
move |row| {
451-
let f = row.get(&key_rhs);
457+
let f = row.get(&key_rhs, &key_rhs_header);
452458
Ok(f.into())
453459
},
454-
move |lhs, rhs| {
455-
let lhs = lhs.get(&col_lhs);
456-
let rhs = rhs.get(&col_rhs);
457-
Ok(lhs == rhs)
460+
move |l, r| {
461+
let l = l.get(&col_lhs, &col_lhs_header);
462+
let r = r.get(&col_rhs, &col_rhs_header);
463+
Ok(l == r)
458464
},
459465
)?;
460466
Box::new(iter)
@@ -720,7 +726,7 @@ mod tests {
720726
let head = q.source.head();
721727

722728
let result = run_ast(p, q.into());
723-
let row = RelValue::new(&head, &scalar(1).into(), None);
729+
let row = RelValue::new(scalar(1).into(), None);
724730
assert_eq!(
725731
result,
726732
Code::Table(MemTable::new(&head, StAccess::Public, &[row])),
@@ -740,7 +746,7 @@ mod tests {
740746
let head = q.source.head();
741747

742748
let result = run_ast(p, q.into());
743-
let row = RelValue::new(&head, &input.into(), None);
749+
let row = RelValue::new(input.into(), None);
744750
assert_eq!(
745751
result,
746752
Code::Table(MemTable::new(&head, StAccess::Public, &[row])),

crates/vm/src/expr.rs

Lines changed: 21 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -87,32 +87,39 @@ impl ColumnOp {
8787
}
8888
}
8989

90-
fn reduce(&self, row: RelValueRef, value: &ColumnOp) -> Result<AlgebraicValue, ErrorLang> {
90+
fn reduce(&self, row: RelValueRef, value: &ColumnOp, header: &Header) -> Result<AlgebraicValue, ErrorLang> {
9191
match value {
92-
ColumnOp::Field(field) => Ok(row.get(field).clone()),
93-
ColumnOp::Cmp { op, lhs, rhs } => Ok(self.compare_bin_op(row, *op, lhs, rhs)?.into()),
92+
ColumnOp::Field(field) => Ok(row.get(field, header).clone()),
93+
ColumnOp::Cmp { op, lhs, rhs } => Ok(self.compare_bin_op(row, *op, lhs, rhs, header)?.into()),
9494
}
9595
}
9696

97-
fn reduce_bool(&self, row: RelValueRef, value: &ColumnOp) -> Result<bool, ErrorLang> {
97+
fn reduce_bool(&self, row: RelValueRef, value: &ColumnOp, header: &Header) -> Result<bool, ErrorLang> {
9898
match value {
9999
ColumnOp::Field(field) => {
100-
let field = row.get(field);
100+
let field = row.get(field, header);
101101

102102
match field.as_bool() {
103103
Some(b) => Ok(*b),
104104
None => Err(ErrorType::FieldBool(field.clone()).into()),
105105
}
106106
}
107-
ColumnOp::Cmp { op, lhs, rhs } => Ok(self.compare_bin_op(row, *op, lhs, rhs)?),
107+
ColumnOp::Cmp { op, lhs, rhs } => Ok(self.compare_bin_op(row, *op, lhs, rhs, header)?),
108108
}
109109
}
110110

111-
fn compare_bin_op(&self, row: RelValueRef, op: OpQuery, lhs: &ColumnOp, rhs: &ColumnOp) -> Result<bool, ErrorVm> {
111+
fn compare_bin_op(
112+
&self,
113+
row: RelValueRef,
114+
op: OpQuery,
115+
lhs: &ColumnOp,
116+
rhs: &ColumnOp,
117+
header: &Header,
118+
) -> Result<bool, ErrorVm> {
112119
match op {
113120
OpQuery::Cmp(op) => {
114-
let lhs = self.reduce(row, lhs)?;
115-
let rhs = self.reduce(row, rhs)?;
121+
let lhs = self.reduce(row, lhs, header)?;
122+
let rhs = self.reduce(row, rhs, header)?;
116123

117124
Ok(match op {
118125
OpCmp::Eq => lhs == rhs,
@@ -124,8 +131,8 @@ impl ColumnOp {
124131
})
125132
}
126133
OpQuery::Logic(op) => {
127-
let lhs = self.reduce_bool(row, lhs)?;
128-
let rhs = self.reduce_bool(row, rhs)?;
134+
let lhs = self.reduce_bool(row, lhs, header)?;
135+
let rhs = self.reduce_bool(row, rhs, header)?;
129136

130137
Ok(match op {
131138
OpLogic::And => lhs && rhs,
@@ -135,13 +142,13 @@ impl ColumnOp {
135142
}
136143
}
137144

138-
pub fn compare(&self, row: RelValueRef) -> Result<bool, ErrorVm> {
145+
pub fn compare(&self, row: RelValueRef, header: &Header) -> Result<bool, ErrorVm> {
139146
match self {
140147
ColumnOp::Field(field) => {
141-
let lhs = row.get(field);
148+
let lhs = row.get(field, header);
142149
Ok(*lhs.as_bool().unwrap())
143150
}
144-
ColumnOp::Cmp { op, lhs, rhs } => self.compare_bin_op(row, *op, lhs, rhs),
151+
ColumnOp::Cmp { op, lhs, rhs } => self.compare_bin_op(row, *op, lhs, rhs, header),
145152
}
146153
}
147154
}

0 commit comments

Comments
 (0)