@@ -126,6 +126,8 @@ func (r *Reader) Read(ctx context.Context, s []Row) (n int, err error) {
126
126
count , err := r .inner .ReadColumns (ctx , r .dl .PrimaryColumns (), s [:readSize ])
127
127
if err != nil && ! errors .Is (err , io .EOF ) {
128
128
return n , err
129
+ } else if count == 0 && errors .Is (err , io .EOF ) {
130
+ return 0 , io .EOF
129
131
}
130
132
131
133
var passCount int // passCount tracks how many rows pass the predicate.
@@ -196,6 +198,12 @@ func checkPredicate(p Predicate, lookup map[Column]int, row Row) bool {
196
198
case OrPredicate :
197
199
return checkPredicate (p .Left , lookup , row ) || checkPredicate (p .Right , lookup , row )
198
200
201
+ case NotPredicate :
202
+ return ! checkPredicate (p .Inner , lookup , row )
203
+
204
+ case FalsePredicate :
205
+ return false
206
+
199
207
case EqualPredicate :
200
208
columnIndex , ok := lookup [p .Column ]
201
209
if ! ok {
@@ -350,7 +358,7 @@ func (r *Reader) validatePredicate() error {
350
358
err = process (p .Column )
351
359
case FuncPredicate :
352
360
err = process (p .Column )
353
- case AndPredicate , OrPredicate , nil :
361
+ case AndPredicate , OrPredicate , NotPredicate , FalsePredicate , nil :
354
362
// No columns to process.
355
363
default :
356
364
panic (fmt .Sprintf ("dataset.Reader.validatePredicate: unsupported predicate type %T" , p ))
@@ -422,7 +430,7 @@ func (r *Reader) fillPrimaryMask(mask *bitmask.Mask) {
422
430
process (p .Column )
423
431
case FuncPredicate :
424
432
process (p .Column )
425
- case AndPredicate , OrPredicate , nil :
433
+ case AndPredicate , OrPredicate , NotPredicate , FalsePredicate , nil :
426
434
// No columns to process.
427
435
default :
428
436
panic (fmt .Sprintf ("dataset.Reader.fillPrimaryMask: unsupported predicate type %T" , p ))
@@ -463,6 +471,25 @@ func (r *Reader) buildPredicateRanges(ctx context.Context, p Predicate) (rowRang
463
471
}
464
472
return unionRanges (nil , left , right ), nil
465
473
474
+ case NotPredicate :
475
+ // De Morgan's laws must be applied to reduce the NotPredicate to a set of
476
+ // predicates that can be applied to pages.
477
+ //
478
+ // See comment on [simplifyNotPredicate] for more information.
479
+ simplified , err := simplifyNotPredicate (p )
480
+ if err != nil {
481
+ // Predicate can't be simplfied, so we permit the full range.
482
+ var rowsCount uint64
483
+ for _ , column := range r .dl .AllColumns () {
484
+ rowsCount = max (rowsCount , uint64 (column .ColumnInfo ().RowsCount ))
485
+ }
486
+ return rowRanges {{Start : 0 , End : rowsCount - 1 }}, nil
487
+ }
488
+ return r .buildPredicateRanges (ctx , simplified )
489
+
490
+ case FalsePredicate :
491
+ return nil , nil // No valid ranges.
492
+
466
493
case EqualPredicate :
467
494
return r .buildColumnPredicateRanges (ctx , p .Column , p )
468
495
@@ -489,6 +516,67 @@ func (r *Reader) buildPredicateRanges(ctx context.Context, p Predicate) (rowRang
489
516
}
490
517
}
491
518
519
+ // simplifyNotPredicate applies De Morgan's laws to a NotPredicate to permit
520
+ // page filtering.
521
+ //
522
+ // While during evaluation, a NotPredicate inverts the result of the inner
523
+ // predicate, the same can't be done for page filtering. For example, imagine
524
+ // that a page is included from a rule "a > 10." If we inverted that inclusion,
525
+ // we may be incorrectly filtering out that page, as that page may also have
526
+ // values less than 10.
527
+ //
528
+ // To correctly apply page filtering to a NotPredicate, we reduce the
529
+ // NotPredicate to a set of predicates that can be applied to pages. This may
530
+ // result in other NotPredicates that also need to be simplified.
531
+ //
532
+ // If the NotPredicate can't be simplified, simplifyNotPredicate returns an
533
+ // error.
534
+ func simplifyNotPredicate (p NotPredicate ) (Predicate , error ) {
535
+ switch inner := p .Inner .(type ) {
536
+ case AndPredicate : // De Morgan's law: !(A && B) == !A || !B
537
+ return OrPredicate {
538
+ Left : NotPredicate {Inner : inner .Left },
539
+ Right : NotPredicate {Inner : inner .Right },
540
+ }, nil
541
+
542
+ case OrPredicate : // De Morgan's law: !(A || B) == !A && !B
543
+ return AndPredicate {
544
+ Left : NotPredicate {Inner : inner .Left },
545
+ Right : NotPredicate {Inner : inner .Right },
546
+ }, nil
547
+
548
+ case NotPredicate : // De Morgan's law: !!A == A
549
+ return inner .Inner , nil
550
+
551
+ case FalsePredicate :
552
+ return nil , fmt .Errorf ("can't simplify FalsePredicate" )
553
+
554
+ case EqualPredicate : // De Morgan's law: !(A == B) == A != B == A < B || A > B
555
+ return OrPredicate {
556
+ Left : LessThanPredicate (inner ),
557
+ Right : GreaterThanPredicate (inner ),
558
+ }, nil
559
+
560
+ case GreaterThanPredicate : // De Morgan's law: !(A > B) == A <= B
561
+ return OrPredicate {
562
+ Left : EqualPredicate (inner ),
563
+ Right : LessThanPredicate (inner ),
564
+ }, nil
565
+
566
+ case LessThanPredicate : // De Morgan's law: !(A < B) == A >= B
567
+ return OrPredicate {
568
+ Left : EqualPredicate (inner ),
569
+ Right : GreaterThanPredicate (inner ),
570
+ }, nil
571
+
572
+ case FuncPredicate :
573
+ return nil , fmt .Errorf ("can't simplify FuncPredicate" )
574
+
575
+ default :
576
+ panic (fmt .Sprintf ("unsupported predicate type %T" , inner ))
577
+ }
578
+ }
579
+
492
580
// buildColumnPredicateRanges returns a set of rowRanges that are valid based
493
581
// on whether EqualPredicate, GreaterThanPredicate, or LessThanPredicate may be
494
582
// true for each page in a column.
@@ -536,10 +624,10 @@ func (r *Reader) buildColumnPredicateRanges(ctx context.Context, c Column, p Pre
536
624
switch p := p .(type ) {
537
625
case EqualPredicate : // EqualPredicate may be true if p.Value is inside the range of the page.
538
626
include = CompareValues (p .Value , minValue ) >= 0 && CompareValues (p .Value , maxValue ) <= 0
539
- case GreaterThanPredicate : // GreaterThanPredicate may be true if p.Value is greater than the min value.
540
- include = CompareValues (p .Value , minValue ) > 0
541
- case LessThanPredicate : // LessThanPredicate may be true if p.Value is less than the max value.
542
- include = CompareValues (p .Value , maxValue ) < 0
627
+ case GreaterThanPredicate : // GreaterThanPredicate may be true if maxValue of a page is greater than p.Value
628
+ include = CompareValues (maxValue , p .Value ) > 0
629
+ case LessThanPredicate : // LessThanPredicate may be true if minValue of a page is less than p.Value
630
+ include = CompareValues (minValue , p .Value ) < 0
543
631
default :
544
632
panic (fmt .Sprintf ("unsupported predicate type %T" , p ))
545
633
}
0 commit comments