@@ -40,7 +40,7 @@ use spacetimedb_lib::identity::AuthCtx;
40
40
use spacetimedb_lib:: ProductValue ;
41
41
use spacetimedb_primitives:: TableId ;
42
42
use spacetimedb_sats:: db:: auth:: { StAccess , StTableType } ;
43
- use spacetimedb_sats:: relation:: { DbTable , Header } ;
43
+ use spacetimedb_sats:: relation:: DbTable ;
44
44
use spacetimedb_vm:: expr:: { self , IndexJoin , Query , QueryExpr , SourceSet } ;
45
45
use spacetimedb_vm:: rel_ops:: RelOps ;
46
46
use spacetimedb_vm:: relation:: MemTable ;
@@ -210,31 +210,21 @@ pub struct IncrementalJoin {
210
210
/// One side of an [`IncrementalJoin`].
211
211
///
212
212
/// Holds the "physical" [`DbTable`] this side of the join operates on, as well
213
- /// as the [`DatabaseTableUpdate`]s pertaining that table.
213
+ /// as the updates pertaining to that table.
214
214
struct JoinSide {
215
- table_id : TableId ,
216
- table_name : String ,
217
- inserts : Vec < TableOp > ,
218
- deletes : Vec < TableOp > ,
215
+ inserts : Vec < ProductValue > ,
216
+ deletes : Vec < ProductValue > ,
219
217
}
220
218
221
219
impl JoinSide {
222
- /// Return a [`DatabaseTableUpdate`] consisting of only insert operations.
223
- pub fn inserts ( & self ) -> DatabaseTableUpdate {
224
- DatabaseTableUpdate {
225
- table_id : self . table_id ,
226
- table_name : self . table_name . clone ( ) ,
227
- ops : self . inserts . to_vec ( ) ,
228
- }
220
+ /// Return a list of updates consisting of only insert operations.
221
+ pub fn inserts ( & self ) -> Vec < ProductValue > {
222
+ self . inserts . clone ( )
229
223
}
230
224
231
- /// Return a [`DatabaseTableUpdate`] with only delete operations.
232
- pub fn deletes ( & self ) -> DatabaseTableUpdate {
233
- DatabaseTableUpdate {
234
- table_id : self . table_id ,
235
- table_name : self . table_name . clone ( ) ,
236
- ops : self . deletes . to_vec ( ) ,
237
- }
225
+ /// Return a list of updates with only delete operations.
226
+ pub fn deletes ( & self ) -> Vec < ProductValue > {
227
+ self . deletes . clone ( )
238
228
}
239
229
240
230
/// Does this table update include inserts?
@@ -249,18 +239,6 @@ impl JoinSide {
249
239
}
250
240
251
241
impl IncrementalJoin {
252
- /// Construct an empty [`DatabaseTableUpdate`] with the schema of `table`
253
- /// to use as a source when pre-compiling `eval_incr` queries.
254
- fn dummy_table_update ( table : & DbTable ) -> DatabaseTableUpdate {
255
- let table_id = table. table_id ;
256
- let table_name = table. head . table_name . clone ( ) ;
257
- DatabaseTableUpdate {
258
- table_id,
259
- table_name,
260
- ops : vec ! [ ] ,
261
- }
262
- }
263
-
264
242
fn optimize_query ( join : IndexJoin ) -> QueryExpr {
265
243
let expr = QueryExpr :: from ( join) ;
266
244
// Because (at least) one of the two tables will be a `MemTable`,
@@ -313,21 +291,15 @@ impl IncrementalJoin {
313
291
. context ( "expected a physical database table" ) ?
314
292
. clone ( ) ;
315
293
316
- let ( virtual_index_plan, _sources) =
317
- with_delta_table ( join. clone ( ) , Some ( Self :: dummy_table_update ( & index_table) ) , None ) ;
294
+ let ( virtual_index_plan, _sources) = with_delta_table ( join. clone ( ) , Some ( Vec :: new ( ) ) , None ) ;
318
295
debug_assert_eq ! ( _sources. len( ) , 1 ) ;
319
296
let virtual_index_plan = Self :: optimize_query ( virtual_index_plan) ;
320
297
321
- let ( virtual_probe_plan, _sources) =
322
- with_delta_table ( join. clone ( ) , None , Some ( Self :: dummy_table_update ( & probe_table) ) ) ;
298
+ let ( virtual_probe_plan, _sources) = with_delta_table ( join. clone ( ) , None , Some ( Vec :: new ( ) ) ) ;
323
299
debug_assert_eq ! ( _sources. len( ) , 1 ) ;
324
300
let virtual_probe_plan = Self :: optimize_query ( virtual_probe_plan) ;
325
301
326
- let ( virtual_plan, _sources) = with_delta_table (
327
- join. clone ( ) ,
328
- Some ( Self :: dummy_table_update ( & index_table) ) ,
329
- Some ( Self :: dummy_table_update ( & probe_table) ) ,
330
- ) ;
302
+ let ( virtual_plan, _sources) = with_delta_table ( join. clone ( ) , Some ( Vec :: new ( ) ) , Some ( Vec :: new ( ) ) ) ;
331
303
debug_assert_eq ! ( _sources. len( ) , 2 ) ;
332
304
let virtual_plan = virtual_plan. to_inner_join ( ) ;
333
305
@@ -360,41 +332,48 @@ impl IncrementalJoin {
360
332
& self ,
361
333
updates : impl IntoIterator < Item = & ' a DatabaseTableUpdate > ,
362
334
) -> Option < ( JoinSide , JoinSide ) > {
363
- let mut lhs_ops = Vec :: new ( ) ;
364
- let mut rhs_ops = Vec :: new ( ) ;
335
+ let mut lhs_inserts = Vec :: new ( ) ;
336
+ let mut lhs_deletes = Vec :: new ( ) ;
337
+ let mut rhs_inserts = Vec :: new ( ) ;
338
+ let mut rhs_deletes = Vec :: new ( ) ;
339
+
340
+ // Partitions deletes of `update` into `ds` and inserts into `is`.
341
+ let partition_into = |ds : & mut Vec < _ > , is : & mut Vec < _ > , updates : & DatabaseTableUpdate | {
342
+ for update in & updates. ops {
343
+ if update. op_type == 0 { & mut * ds } else { & mut * is } . push ( update. row . clone ( ) ) ;
344
+ }
345
+ } ;
365
346
347
+ // Partitions all updates into the `l/rhs_insert/delete_ops` above.
366
348
for update in updates {
367
349
if update. table_id == self . lhs . table_id {
368
- lhs_ops . extend ( update. ops . iter ( ) ) ;
350
+ partition_into ( & mut lhs_deletes , & mut lhs_inserts , update) ;
369
351
} else if update. table_id == self . rhs . table_id {
370
- rhs_ops . extend ( update. ops . iter ( ) ) ;
352
+ partition_into ( & mut rhs_deletes , & mut rhs_inserts , update) ;
371
353
}
372
354
}
373
355
374
- if lhs_ops. is_empty ( ) && rhs_ops. is_empty ( ) {
356
+ // No updates at all? Return `None`.
357
+ if [ & lhs_inserts, & lhs_deletes, & rhs_inserts, & rhs_deletes]
358
+ . iter ( )
359
+ . all ( |ops| ops. is_empty ( ) )
360
+ {
375
361
return None ;
376
362
}
377
363
378
- let join_side = |table : & DbTable , ops : Vec < & TableOp > | {
379
- let ( deletes, inserts) = ops. into_iter ( ) . cloned ( ) . partition ( |op| op. op_type == 0 ) ;
380
- JoinSide {
381
- table_id : table. table_id ,
382
- table_name : table. head . table_name . clone ( ) ,
383
- deletes,
384
- inserts,
385
- }
386
- } ;
387
- Some ( ( join_side ( & self . lhs , lhs_ops) , join_side ( & self . rhs , rhs_ops) ) )
364
+ // Stich together the `JoinSide`s.
365
+ let join_side = |deletes, inserts| JoinSide { deletes, inserts } ;
366
+ Some ( ( join_side ( lhs_deletes, lhs_inserts) , join_side ( rhs_deletes, rhs_inserts) ) )
388
367
}
389
368
390
369
/// Evaluate join plan for lhs updates.
391
370
fn eval_lhs (
392
371
& self ,
393
372
db : & RelationalDB ,
394
373
tx : & Tx ,
395
- lhs : DatabaseTableUpdate ,
374
+ lhs : Vec < ProductValue > ,
396
375
) -> Result < impl Iterator < Item = ProductValue > , DBError > {
397
- let lhs = to_mem_table ( self . lhs . head . clone ( ) , self . lhs . table_access , lhs) ;
376
+ let lhs = MemTable :: new ( self . lhs . head . clone ( ) , self . lhs . table_access , lhs) ;
398
377
let mut sources = SourceSet :: default ( ) ;
399
378
sources. add_mem_table ( lhs) ;
400
379
eval_updates ( db, tx, self . plan_for_delta_lhs ( ) , sources)
@@ -405,9 +384,9 @@ impl IncrementalJoin {
405
384
& self ,
406
385
db : & RelationalDB ,
407
386
tx : & Tx ,
408
- rhs : DatabaseTableUpdate ,
387
+ rhs : Vec < ProductValue > ,
409
388
) -> Result < impl Iterator < Item = ProductValue > , DBError > {
410
- let rhs = to_mem_table ( self . rhs . head . clone ( ) , self . rhs . table_access , rhs) ;
389
+ let rhs = MemTable :: new ( self . rhs . head . clone ( ) , self . rhs . table_access , rhs) ;
411
390
let mut sources = SourceSet :: default ( ) ;
412
391
sources. add_mem_table ( rhs) ;
413
392
eval_updates ( db, tx, self . plan_for_delta_rhs ( ) , sources)
@@ -418,11 +397,11 @@ impl IncrementalJoin {
418
397
& self ,
419
398
db : & RelationalDB ,
420
399
tx : & Tx ,
421
- lhs : DatabaseTableUpdate ,
422
- rhs : DatabaseTableUpdate ,
400
+ lhs : Vec < ProductValue > ,
401
+ rhs : Vec < ProductValue > ,
423
402
) -> Result < impl Iterator < Item = ProductValue > , DBError > {
424
- let lhs = to_mem_table ( self . lhs . head . clone ( ) , self . lhs . table_access , lhs) ;
425
- let rhs = to_mem_table ( self . rhs . head . clone ( ) , self . rhs . table_access , rhs) ;
403
+ let lhs = MemTable :: new ( self . lhs . head . clone ( ) , self . lhs . table_access , lhs) ;
404
+ let rhs = MemTable :: new ( self . rhs . head . clone ( ) , self . rhs . table_access , rhs) ;
426
405
let mut sources = SourceSet :: default ( ) ;
427
406
let ( index_side, probe_side) = if self . return_index_rows { ( lhs, rhs) } else { ( rhs, lhs) } ;
428
407
sources. add_mem_table ( index_side) ;
@@ -566,39 +545,25 @@ impl IncrementalJoin {
566
545
}
567
546
}
568
547
569
- /// Construct a [`MemTable`] containing the updates from `delta`,
570
- /// which must be derived from a table with `head` and `table_access`.
571
- fn to_mem_table ( head : Arc < Header > , table_access : StAccess , delta : DatabaseTableUpdate ) -> MemTable {
572
- MemTable :: new (
573
- head,
574
- table_access,
575
- delta. ops . into_iter ( ) . map ( |op| op. row ) . collect :: < Vec < _ > > ( ) ,
576
- )
577
- }
578
-
579
548
/// Replace an [IndexJoin]'s scan or fetch operation with a delta table.
580
549
/// A delta table consists purely of updates or changes to the base table.
581
550
fn with_delta_table (
582
551
mut join : IndexJoin ,
583
- index_side : Option < DatabaseTableUpdate > ,
584
- probe_side : Option < DatabaseTableUpdate > ,
552
+ index_side : Option < Vec < ProductValue > > ,
553
+ probe_side : Option < Vec < ProductValue > > ,
585
554
) -> ( IndexJoin , SourceSet ) {
586
555
let mut sources = SourceSet :: default ( ) ;
587
556
588
557
if let Some ( index_side) = index_side {
589
558
let head = join. index_side . head ( ) . clone ( ) ;
590
559
let table_access = join. index_side . table_access ( ) ;
591
- let mem_table = to_mem_table ( head, table_access, index_side) ;
592
- let source_expr = sources. add_mem_table ( mem_table) ;
593
- join. index_side = source_expr;
560
+ join. index_side = sources. add_mem_table ( MemTable :: new ( head, table_access, index_side) ) ;
594
561
}
595
562
596
563
if let Some ( probe_side) = probe_side {
597
564
let head = join. probe_side . source . head ( ) . clone ( ) ;
598
565
let table_access = join. probe_side . source . table_access ( ) ;
599
- let mem_table = to_mem_table ( head, table_access, probe_side) ;
600
- let source_expr = sources. add_mem_table ( mem_table) ;
601
- join. probe_side . source = source_expr;
566
+ join. probe_side . source = sources. add_mem_table ( MemTable :: new ( head, table_access, probe_side) ) ;
602
567
}
603
568
604
569
( join, sources)
@@ -715,7 +680,6 @@ pub(crate) fn get_all(relational_db: &RelationalDB, tx: &Tx, auth: &AuthCtx) ->
715
680
mod tests {
716
681
use super :: * ;
717
682
use crate :: db:: relational_db:: tests_utils:: make_test_db;
718
- use crate :: host:: module_host:: TableOp ;
719
683
use crate :: sql:: compiler:: compile_sql;
720
684
use spacetimedb_lib:: error:: ResultTest ;
721
685
use spacetimedb_sats:: relation:: { DbTable , FieldName } ;
@@ -731,7 +695,7 @@ mod tests {
731
695
// Create table [lhs] with index on [b]
732
696
let schema = & [ ( "a" , AlgebraicType :: U64 ) , ( "b" , AlgebraicType :: U64 ) ] ;
733
697
let indexes = & [ ( 1 . into ( ) , "b" ) ] ;
734
- let lhs_id = db. create_table_for_test ( "lhs" , schema, indexes) ?;
698
+ let _ = db. create_table_for_test ( "lhs" , schema, indexes) ?;
735
699
736
700
// Create table [rhs] with index on [b, c]
737
701
let schema = & [
@@ -761,11 +725,7 @@ mod tests {
761
725
} ;
762
726
763
727
// Create an insert for an incremental update.
764
- let delta = DatabaseTableUpdate {
765
- table_id : lhs_id,
766
- table_name : String :: from ( "lhs" ) ,
767
- ops : vec ! [ TableOp :: insert( product![ 0u64 , 0u64 ] ) ] ,
768
- } ;
728
+ let delta = vec ! [ product![ 0u64 , 0u64 ] ] ;
769
729
770
730
// Optimize the query plan for the incremental update.
771
731
let ( expr, _sources) = with_delta_table ( join, Some ( delta) , None ) ;
@@ -829,7 +789,7 @@ mod tests {
829
789
( "d" , AlgebraicType :: U64 ) ,
830
790
] ;
831
791
let indexes = & [ ( 0 . into ( ) , "b" ) , ( 1 . into ( ) , "c" ) ] ;
832
- let rhs_id = db. create_table_for_test ( "rhs" , schema, indexes) ?;
792
+ let _ = db. create_table_for_test ( "rhs" , schema, indexes) ?;
833
793
834
794
let tx = db. begin_tx ( ) ;
835
795
// Should generate an index join since there is an index on `lhs.b`.
@@ -850,11 +810,7 @@ mod tests {
850
810
} ;
851
811
852
812
// Create an insert for an incremental update.
853
- let delta = DatabaseTableUpdate {
854
- table_id : rhs_id,
855
- table_name : String :: from ( "rhs" ) ,
856
- ops : vec ! [ TableOp :: insert( product![ 0u64 , 0u64 , 0u64 ] ) ] ,
857
- } ;
813
+ let delta = vec ! [ product![ 0u64 , 0u64 , 0u64 ] ] ;
858
814
859
815
// Optimize the query plan for the incremental update.
860
816
let ( expr, _sources) = with_delta_table ( join, None , Some ( delta) ) ;
0 commit comments