@@ -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 ;
@@ -209,32 +209,21 @@ pub struct IncrementalJoin {
209
209
210
210
/// One side of an [`IncrementalJoin`].
211
211
///
212
- /// Holds the "physical" [`DbTable`] this side of the join operates on, as well
213
- /// as the [`DatabaseTableUpdate`]s pertaining that table.
212
+ /// Holds the updates pertaining to a table on one side of the join.
214
213
struct JoinSide {
215
- table_id : TableId ,
216
- table_name : String ,
217
- inserts : Vec < TableOp > ,
218
- deletes : Vec < TableOp > ,
214
+ inserts : Vec < ProductValue > ,
215
+ deletes : Vec < ProductValue > ,
219
216
}
220
217
221
218
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
- }
219
+ /// Return a list of updates consisting of only insert operations.
220
+ pub fn inserts ( & self ) -> Vec < ProductValue > {
221
+ self . inserts . clone ( )
229
222
}
230
223
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
- }
224
+ /// Return a list of updates with only delete operations.
225
+ pub fn deletes ( & self ) -> Vec < ProductValue > {
226
+ self . deletes . clone ( )
238
227
}
239
228
240
229
/// Does this table update include inserts?
@@ -249,18 +238,6 @@ impl JoinSide {
249
238
}
250
239
251
240
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
241
fn optimize_query ( join : IndexJoin ) -> QueryExpr {
265
242
let expr = QueryExpr :: from ( join) ;
266
243
// Because (at least) one of the two tables will be a `MemTable`,
@@ -313,21 +290,15 @@ impl IncrementalJoin {
313
290
. context ( "expected a physical database table" ) ?
314
291
. clone ( ) ;
315
292
316
- let ( virtual_index_plan, _sources) =
317
- with_delta_table ( join. clone ( ) , Some ( Self :: dummy_table_update ( & index_table) ) , None ) ;
293
+ let ( virtual_index_plan, _sources) = with_delta_table ( join. clone ( ) , Some ( Vec :: new ( ) ) , None ) ;
318
294
debug_assert_eq ! ( _sources. len( ) , 1 ) ;
319
295
let virtual_index_plan = Self :: optimize_query ( virtual_index_plan) ;
320
296
321
- let ( virtual_probe_plan, _sources) =
322
- with_delta_table ( join. clone ( ) , None , Some ( Self :: dummy_table_update ( & probe_table) ) ) ;
297
+ let ( virtual_probe_plan, _sources) = with_delta_table ( join. clone ( ) , None , Some ( Vec :: new ( ) ) ) ;
323
298
debug_assert_eq ! ( _sources. len( ) , 1 ) ;
324
299
let virtual_probe_plan = Self :: optimize_query ( virtual_probe_plan) ;
325
300
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
- ) ;
301
+ let ( virtual_plan, _sources) = with_delta_table ( join. clone ( ) , Some ( Vec :: new ( ) ) , Some ( Vec :: new ( ) ) ) ;
331
302
debug_assert_eq ! ( _sources. len( ) , 2 ) ;
332
303
let virtual_plan = virtual_plan. to_inner_join ( ) ;
333
304
@@ -360,46 +331,53 @@ impl IncrementalJoin {
360
331
& self ,
361
332
updates : impl IntoIterator < Item = & ' a DatabaseTableUpdate > ,
362
333
) -> Option < ( JoinSide , JoinSide ) > {
363
- let mut lhs_ops = Vec :: new ( ) ;
364
- let mut rhs_ops = Vec :: new ( ) ;
334
+ let mut lhs_inserts = Vec :: new ( ) ;
335
+ let mut lhs_deletes = Vec :: new ( ) ;
336
+ let mut rhs_inserts = Vec :: new ( ) ;
337
+ let mut rhs_deletes = Vec :: new ( ) ;
338
+
339
+ // Partitions `updates` into `deletes` and `inserts`.
340
+ let partition_into = |deletes : & mut Vec < _ > , inserts : & mut Vec < _ > , updates : & DatabaseTableUpdate | {
341
+ for update in & updates. ops {
342
+ if update. op_type == 0 {
343
+ & mut * deletes
344
+ } else {
345
+ & mut * inserts
346
+ }
347
+ . push ( update. row . clone ( ) ) ;
348
+ }
349
+ } ;
365
350
351
+ // Partitions all updates into the `(l|r)hs_(insert|delete)_ops` above.
366
352
for update in updates {
367
353
if update. table_id == self . lhs . table_id {
368
- lhs_ops . extend ( update. ops . iter ( ) . cloned ( ) ) ;
354
+ partition_into ( & mut lhs_deletes , & mut lhs_inserts , update) ;
369
355
} else if update. table_id == self . rhs . table_id {
370
- rhs_ops . extend ( update. ops . iter ( ) . cloned ( ) ) ;
356
+ partition_into ( & mut rhs_deletes , & mut rhs_inserts , update) ;
371
357
}
372
358
}
373
359
374
- if lhs_ops. is_empty ( ) && rhs_ops. is_empty ( ) {
360
+ // No updates at all? Return `None`.
361
+ if [ & lhs_inserts, & lhs_deletes, & rhs_inserts, & rhs_deletes]
362
+ . iter ( )
363
+ . all ( |ops| ops. is_empty ( ) )
364
+ {
375
365
return None ;
376
366
}
377
367
378
- let lhs = JoinSide {
379
- table_id : self . lhs . table_id ,
380
- table_name : self . lhs . head . table_name . clone ( ) ,
381
- inserts : lhs_ops. iter ( ) . filter ( |op| op. op_type == 1 ) . cloned ( ) . collect ( ) ,
382
- deletes : lhs_ops. iter ( ) . filter ( |op| op. op_type == 0 ) . cloned ( ) . collect ( ) ,
383
- } ;
384
-
385
- let rhs = JoinSide {
386
- table_id : self . rhs . table_id ,
387
- table_name : self . rhs . head . table_name . clone ( ) ,
388
- inserts : rhs_ops. iter ( ) . filter ( |op| op. op_type == 1 ) . cloned ( ) . collect ( ) ,
389
- deletes : rhs_ops. iter ( ) . filter ( |op| op. op_type == 0 ) . cloned ( ) . collect ( ) ,
390
- } ;
391
-
392
- Some ( ( lhs, rhs) )
368
+ // Stich together the `JoinSide`s.
369
+ let join_side = |deletes, inserts| JoinSide { deletes, inserts } ;
370
+ Some ( ( join_side ( lhs_deletes, lhs_inserts) , join_side ( rhs_deletes, rhs_inserts) ) )
393
371
}
394
372
395
373
/// Evaluate join plan for lhs updates.
396
374
fn eval_lhs (
397
375
& self ,
398
376
db : & RelationalDB ,
399
377
tx : & Tx ,
400
- lhs : DatabaseTableUpdate ,
378
+ lhs : Vec < ProductValue > ,
401
379
) -> Result < impl Iterator < Item = ProductValue > , DBError > {
402
- let lhs = to_mem_table ( self . lhs . head . clone ( ) , self . lhs . table_access , lhs) ;
380
+ let lhs = MemTable :: new ( self . lhs . head . clone ( ) , self . lhs . table_access , lhs) ;
403
381
let mut sources = SourceSet :: default ( ) ;
404
382
sources. add_mem_table ( lhs) ;
405
383
eval_updates ( db, tx, self . plan_for_delta_lhs ( ) , sources)
@@ -410,9 +388,9 @@ impl IncrementalJoin {
410
388
& self ,
411
389
db : & RelationalDB ,
412
390
tx : & Tx ,
413
- rhs : DatabaseTableUpdate ,
391
+ rhs : Vec < ProductValue > ,
414
392
) -> Result < impl Iterator < Item = ProductValue > , DBError > {
415
- let rhs = to_mem_table ( self . rhs . head . clone ( ) , self . rhs . table_access , rhs) ;
393
+ let rhs = MemTable :: new ( self . rhs . head . clone ( ) , self . rhs . table_access , rhs) ;
416
394
let mut sources = SourceSet :: default ( ) ;
417
395
sources. add_mem_table ( rhs) ;
418
396
eval_updates ( db, tx, self . plan_for_delta_rhs ( ) , sources)
@@ -423,11 +401,11 @@ impl IncrementalJoin {
423
401
& self ,
424
402
db : & RelationalDB ,
425
403
tx : & Tx ,
426
- lhs : DatabaseTableUpdate ,
427
- rhs : DatabaseTableUpdate ,
404
+ lhs : Vec < ProductValue > ,
405
+ rhs : Vec < ProductValue > ,
428
406
) -> Result < impl Iterator < Item = ProductValue > , DBError > {
429
- let lhs = to_mem_table ( self . lhs . head . clone ( ) , self . lhs . table_access , lhs) ;
430
- let rhs = to_mem_table ( self . rhs . head . clone ( ) , self . rhs . table_access , rhs) ;
407
+ let lhs = MemTable :: new ( self . lhs . head . clone ( ) , self . lhs . table_access , lhs) ;
408
+ let rhs = MemTable :: new ( self . rhs . head . clone ( ) , self . rhs . table_access , rhs) ;
431
409
let mut sources = SourceSet :: default ( ) ;
432
410
let ( index_side, probe_side) = if self . return_index_rows { ( lhs, rhs) } else { ( rhs, lhs) } ;
433
411
sources. add_mem_table ( index_side) ;
@@ -571,39 +549,25 @@ impl IncrementalJoin {
571
549
}
572
550
}
573
551
574
- /// Construct a [`MemTable`] containing the updates from `delta`,
575
- /// which must be derived from a table with `head` and `table_access`.
576
- fn to_mem_table ( head : Arc < Header > , table_access : StAccess , delta : DatabaseTableUpdate ) -> MemTable {
577
- MemTable :: new (
578
- head,
579
- table_access,
580
- delta. ops . into_iter ( ) . map ( |op| op. row ) . collect :: < Vec < _ > > ( ) ,
581
- )
582
- }
583
-
584
552
/// Replace an [IndexJoin]'s scan or fetch operation with a delta table.
585
553
/// A delta table consists purely of updates or changes to the base table.
586
554
fn with_delta_table (
587
555
mut join : IndexJoin ,
588
- index_side : Option < DatabaseTableUpdate > ,
589
- probe_side : Option < DatabaseTableUpdate > ,
556
+ index_side : Option < Vec < ProductValue > > ,
557
+ probe_side : Option < Vec < ProductValue > > ,
590
558
) -> ( IndexJoin , SourceSet ) {
591
559
let mut sources = SourceSet :: default ( ) ;
592
560
593
561
if let Some ( index_side) = index_side {
594
562
let head = join. index_side . head ( ) . clone ( ) ;
595
563
let table_access = join. index_side . table_access ( ) ;
596
- let mem_table = to_mem_table ( head, table_access, index_side) ;
597
- let source_expr = sources. add_mem_table ( mem_table) ;
598
- join. index_side = source_expr;
564
+ join. index_side = sources. add_mem_table ( MemTable :: new ( head, table_access, index_side) ) ;
599
565
}
600
566
601
567
if let Some ( probe_side) = probe_side {
602
568
let head = join. probe_side . source . head ( ) . clone ( ) ;
603
569
let table_access = join. probe_side . source . table_access ( ) ;
604
- let mem_table = to_mem_table ( head, table_access, probe_side) ;
605
- let source_expr = sources. add_mem_table ( mem_table) ;
606
- join. probe_side . source = source_expr;
570
+ join. probe_side . source = sources. add_mem_table ( MemTable :: new ( head, table_access, probe_side) ) ;
607
571
}
608
572
609
573
( join, sources)
@@ -720,7 +684,6 @@ pub(crate) fn get_all(relational_db: &RelationalDB, tx: &Tx, auth: &AuthCtx) ->
720
684
mod tests {
721
685
use super :: * ;
722
686
use crate :: db:: relational_db:: tests_utils:: make_test_db;
723
- use crate :: host:: module_host:: TableOp ;
724
687
use crate :: sql:: compiler:: compile_sql;
725
688
use spacetimedb_lib:: error:: ResultTest ;
726
689
use spacetimedb_sats:: relation:: { DbTable , FieldName } ;
@@ -736,7 +699,7 @@ mod tests {
736
699
// Create table [lhs] with index on [b]
737
700
let schema = & [ ( "a" , AlgebraicType :: U64 ) , ( "b" , AlgebraicType :: U64 ) ] ;
738
701
let indexes = & [ ( 1 . into ( ) , "b" ) ] ;
739
- let lhs_id = db. create_table_for_test ( "lhs" , schema, indexes) ?;
702
+ let _ = db. create_table_for_test ( "lhs" , schema, indexes) ?;
740
703
741
704
// Create table [rhs] with index on [b, c]
742
705
let schema = & [
@@ -766,11 +729,7 @@ mod tests {
766
729
} ;
767
730
768
731
// Create an insert for an incremental update.
769
- let delta = DatabaseTableUpdate {
770
- table_id : lhs_id,
771
- table_name : String :: from ( "lhs" ) ,
772
- ops : vec ! [ TableOp :: insert( product![ 0u64 , 0u64 ] ) ] ,
773
- } ;
732
+ let delta = vec ! [ product![ 0u64 , 0u64 ] ] ;
774
733
775
734
// Optimize the query plan for the incremental update.
776
735
let ( expr, _sources) = with_delta_table ( join, Some ( delta) , None ) ;
@@ -834,7 +793,7 @@ mod tests {
834
793
( "d" , AlgebraicType :: U64 ) ,
835
794
] ;
836
795
let indexes = & [ ( 0 . into ( ) , "b" ) , ( 1 . into ( ) , "c" ) ] ;
837
- let rhs_id = db. create_table_for_test ( "rhs" , schema, indexes) ?;
796
+ let _ = db. create_table_for_test ( "rhs" , schema, indexes) ?;
838
797
839
798
let tx = db. begin_tx ( ) ;
840
799
// Should generate an index join since there is an index on `lhs.b`.
@@ -855,11 +814,7 @@ mod tests {
855
814
} ;
856
815
857
816
// Create an insert for an incremental update.
858
- let delta = DatabaseTableUpdate {
859
- table_id : rhs_id,
860
- table_name : String :: from ( "rhs" ) ,
861
- ops : vec ! [ TableOp :: insert( product![ 0u64 , 0u64 , 0u64 ] ) ] ,
862
- } ;
817
+ let delta = vec ! [ product![ 0u64 , 0u64 , 0u64 ] ] ;
863
818
864
819
// Optimize the query plan for the incremental update.
865
820
let ( expr, _sources) = with_delta_table ( join, None , Some ( delta) ) ;
0 commit comments