@@ -284,7 +284,8 @@ impl PipelinedProject {
284284#[ derive( Debug ) ]
285285pub enum PipelinedExecutor {
286286 TableScan ( PipelinedScan ) ,
287- IxScan ( PipelinedIxScan ) ,
287+ IxScanEq ( PipelinedIxScanEq ) ,
288+ IxScanRange ( PipelinedIxScanRange ) ,
288289 IxJoin ( PipelinedIxJoin ) ,
289290 IxDeltaScan ( PipelinedIxDeltaScan ) ,
290291 IxDeltaJoin ( PipelinedIxDeltaJoin ) ,
@@ -302,7 +303,22 @@ impl From<PhysicalPlan> for PipelinedExecutor {
302303 limit,
303304 delta,
304305 } ) ,
305- PhysicalPlan :: IxScan ( scan @ IxScan { delta : None , .. } , _) => Self :: IxScan ( scan. into ( ) ) ,
306+ PhysicalPlan :: IxScan (
307+ scan @ IxScan {
308+ delta : None ,
309+ arg : Sarg :: Eq ( ..) ,
310+ ..
311+ } ,
312+ _,
313+ ) => Self :: IxScanEq ( scan. into ( ) ) ,
314+ PhysicalPlan :: IxScan (
315+ scan @ IxScan {
316+ delta : None ,
317+ arg : Sarg :: Range ( ..) ,
318+ ..
319+ } ,
320+ _,
321+ ) => Self :: IxScanRange ( scan. into ( ) ) ,
306322 PhysicalPlan :: IxScan ( scan, _) => Self :: IxDeltaScan ( scan. into ( ) ) ,
307323 PhysicalPlan :: IxJoin (
308324 IxJoin {
@@ -391,15 +407,16 @@ impl PipelinedExecutor {
391407 lhs. visit ( f) ;
392408 rhs. visit ( f) ;
393409 }
394- Self :: TableScan ( ..) | Self :: IxScan ( ..) | Self :: IxDeltaScan ( ..) => { }
410+ Self :: TableScan ( ..) | Self :: IxScanEq ( .. ) | Self :: IxScanRange ( ..) | Self :: IxDeltaScan ( ..) => { }
395411 }
396412 }
397413
398414 /// Does this operation contain an empty delta scan?
399415 pub fn is_empty ( & self , tx : & impl DeltaStore ) -> bool {
400416 match self {
401417 Self :: TableScan ( scan) => scan. is_empty ( tx) ,
402- Self :: IxScan ( scan) => scan. is_empty ( tx) ,
418+ Self :: IxScanEq ( scan) => scan. is_empty ( tx) ,
419+ Self :: IxScanRange ( scan) => scan. is_empty ( tx) ,
403420 Self :: IxDeltaScan ( scan) => scan. is_empty ( tx) ,
404421 Self :: IxJoin ( join) => join. is_empty ( tx) ,
405422 Self :: IxDeltaJoin ( join) => join. is_empty ( tx) ,
@@ -418,7 +435,8 @@ impl PipelinedExecutor {
418435 ) -> Result < ( ) > {
419436 match self {
420437 Self :: TableScan ( scan) => scan. execute ( tx, metrics, f) ,
421- Self :: IxScan ( scan) => scan. execute ( tx, metrics, f) ,
438+ Self :: IxScanEq ( scan) => scan. execute ( tx, metrics, f) ,
439+ Self :: IxScanRange ( scan) => scan. execute ( tx, metrics, f) ,
422440 Self :: IxDeltaScan ( scan) => scan. execute ( tx, metrics, f) ,
423441 Self :: IxJoin ( join) => join. execute ( tx, metrics, f) ,
424442 Self :: IxDeltaJoin ( join) => join. execute ( tx, metrics, f) ,
@@ -506,7 +524,7 @@ impl PipelinedScan {
506524
507525/// An index scan executor for a delta table.
508526///
509- /// TODO: There is much overlap between this executor and [PipelinedIxScan ].
527+ /// TODO: There is much overlap between this executor and [PipelinedIxScanRange ].
510528/// But merging them requires merging the [Datastore] and [DeltaStore] traits,
511529/// since the index scan interface is right now split between both.
512530#[ derive( Debug ) ]
@@ -659,9 +677,9 @@ impl PipelinedIxDeltaScan {
659677 }
660678}
661679
662- /// A pipelined executor for scanning an index
680+ /// A pipelined executor for range scanning an index
663681#[ derive( Debug ) ]
664- pub struct PipelinedIxScan {
682+ pub struct PipelinedIxScanRange {
665683 /// The table id
666684 pub table_id : TableId ,
667685 /// The index id
@@ -675,7 +693,7 @@ pub struct PipelinedIxScan {
675693 pub upper : Bound < AlgebraicValue > ,
676694}
677695
678- impl From < IxScan > for PipelinedIxScan {
696+ impl From < IxScan > for PipelinedIxScanRange {
679697 fn from ( scan : IxScan ) -> Self {
680698 match scan {
681699 IxScan {
@@ -712,7 +730,7 @@ impl From<IxScan> for PipelinedIxScan {
712730 }
713731}
714732
715- impl PipelinedIxScan {
733+ impl PipelinedIxScanRange {
716734 /// We don't know statically if an index scan will return rows
717735 pub fn is_empty ( & self , _: & impl DeltaStore ) -> bool {
718736 false
@@ -794,6 +812,89 @@ impl PipelinedIxScan {
794812 }
795813}
796814
815+ /// A pipelined executor for equality scanning an index
816+ #[ derive( Debug ) ]
817+ pub struct PipelinedIxScanEq {
818+ /// The table id
819+ pub table_id : TableId ,
820+ /// The index id
821+ pub index_id : IndexId ,
822+ pub limit : Option < u64 > ,
823+ /// The point to scan the index for.
824+ pub point : AlgebraicValue ,
825+ }
826+
827+ impl From < IxScan > for PipelinedIxScanEq {
828+ fn from ( scan : IxScan ) -> Self {
829+ match scan {
830+ IxScan {
831+ schema,
832+ limit,
833+ delta : _,
834+ index_id,
835+ prefix,
836+ arg : Sarg :: Eq ( _, v) ,
837+ } => {
838+ let point = if prefix. is_empty ( ) {
839+ let mut elems = Vec :: with_capacity ( prefix. len ( ) + 1 ) ;
840+ elems. extend ( prefix. into_iter ( ) . map ( |( _, v) | v) ) ;
841+ elems. push ( v) ;
842+ AlgebraicValue :: product ( elems)
843+ } else {
844+ v
845+ } ;
846+
847+ Self {
848+ table_id : schema. table_id ,
849+ index_id,
850+ limit,
851+ point,
852+ }
853+ }
854+ IxScan {
855+ arg : Sarg :: Range ( ..) , ..
856+ } => unreachable ! ( ) ,
857+ }
858+ }
859+ }
860+
861+ impl PipelinedIxScanEq {
862+ /// We don't know statically if an index scan will return rows
863+ pub fn is_empty ( & self , _: & impl DeltaStore ) -> bool {
864+ false
865+ }
866+
867+ pub fn execute < ' a , Tx : Datastore + DeltaStore > (
868+ & self ,
869+ tx : & ' a Tx ,
870+ metrics : & mut ExecutionMetrics ,
871+ f : & mut dyn FnMut ( Tuple < ' a > ) -> Result < ( ) > ,
872+ ) -> Result < ( ) > {
873+ // Scan without a row limit.
874+ let scan = || tx. index_scan_point ( self . table_id , self . index_id , & self . point ) ;
875+ // Scan with an optional row limit.
876+ let scan_opt_limit = |limit| match limit {
877+ None => scan ( ) . map ( Either :: Left ) ,
878+ Some ( n) => scan ( ) . map ( |iter| iter. take ( n) ) . map ( Either :: Right ) ,
879+ } ;
880+ let mut n = 0 ;
881+ let mut f = |t| {
882+ n += 1 ;
883+ f ( t)
884+ } ;
885+ for ptr in scan_opt_limit ( self . limit . map ( |n| n as usize ) ) ?
886+ . map ( Row :: Ptr )
887+ . map ( Tuple :: Row )
888+ {
889+ f ( ptr) ?;
890+ }
891+
892+ metrics. index_seeks += 1 ;
893+ metrics. rows_scanned += n;
894+ Ok ( ( ) )
895+ }
896+ }
897+
797898/// A pipelined index join executor
798899#[ derive( Debug ) ]
799900pub struct PipelinedIxJoin {
0 commit comments