Skip to content

Commit

Permalink
sql: fix index out of range error in inverted filterer
Browse files Browse the repository at this point in the history
Prior to this commit, it was possible that the SpansToRead in
an inverted.SpanExpression were a superset of the spans that were
needed to evaluate the span expression. This could result in an index
out of range error in the invertedFilterer when a span from the input
didn't exist in its list of needed spans. This commit fixes the
problem by ensuring that SpansToRead does not contain spans that are
not needed to evaluate the span expression.

Fixes cockroachdb#63180

Release note (bug fix): Fixed an internal error that could occur
when executing queries using an inverted index. The error was an index
out of range error, and could occur in rare cases when a filter or
join predicate contained at least two JSON, Array, Geometry or
Geography expressions that were combined with AND. This has now been
fixed.
  • Loading branch information
rytaft committed Apr 18, 2021
1 parent 0f4525d commit da906a7
Show file tree
Hide file tree
Showing 3 changed files with 26 additions and 7 deletions.
26 changes: 22 additions & 4 deletions pkg/sql/opt/invertedexpr/expression.go
Original file line number Diff line number Diff line change
Expand Up @@ -617,11 +617,16 @@ func opSpanExpressionAndDefault(

// Intersects two SpanExpressions.
func intersectSpanExpressions(left, right *SpanExpression) *SpanExpression {
// Since we simply union into SpansToRead, we can end up with
// FactoredUnionSpans as a subset of SpanToRead *and* both children pruned.
// TODO(sumeer): tighten the SpansToRead for this case.
expr := &SpanExpression{
Tight: left.Tight && right.Tight,
Tight: left.Tight && right.Tight,

// We calculate SpansToRead as the union of the left and right sides as a
// first approximation, but this may result in too many spans if either of
// the children are pruned below. SpansToRead will be recomputed in
// tryPruneChildren if needed. (It is important that SpansToRead be exactly
// what would be computed if a caller traversed the tree and explicitly
// unioned all the FactoredUnionSpans, and no looser, since the execution
// code path relies on this property.)
SpansToRead: unionSpans(left.SpansToRead, right.SpansToRead),
FactoredUnionSpans: intersectSpans(left.FactoredUnionSpans, right.FactoredUnionSpans),
Operator: SetIntersection,
Expand Down Expand Up @@ -675,6 +680,19 @@ func tryPruneChildren(expr *SpanExpression, op SetOperator) {
expr.Operator = child.Operator
expr.Left = child.Left
expr.Right = child.Right

// If child.FactoredUnionSpans is non-empty, we need to recalculate
// SpansToRead since it may have contained some spans that were removed by
// discarding child.FactoredUnionSpans.
if child.FactoredUnionSpans != nil {
expr.SpansToRead = expr.FactoredUnionSpans
if expr.Left != nil {
expr.SpansToRead = unionSpans(expr.SpansToRead, expr.Left.(*SpanExpression).SpansToRead)
}
if expr.Right != nil {
expr.SpansToRead = unionSpans(expr.SpansToRead, expr.Right.(*SpanExpression).SpansToRead)
}
}
}
promoteLeft := expr.Left != nil && expr.Right == nil
promoteRight := expr.Left == nil && expr.Right != nil
Expand Down
4 changes: 2 additions & 2 deletions pkg/sql/opt/invertedexpr/testdata/expression
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,7 @@ and result=_ left=b right=ac
----
span expression
├── tight: true
├── to read: ["a", "c")
├── to read: ["b", "b"]
└── union spans: ["b", "b"]

new-span-leaf name=bj tight=true span=b,j
Expand All @@ -265,7 +265,7 @@ and result=_ left=b right=bj
----
span expression
├── tight: true
├── to read: ["b", "j")
├── to read: ["b", "b"]
└── union spans: ["b", "b"]

# [b, j) or [a, c) = [a, j)
Expand Down
3 changes: 2 additions & 1 deletion pkg/sql/opt/xform/testdata/rules/select
Original file line number Diff line number Diff line change
Expand Up @@ -2009,7 +2009,8 @@ project
│ ├── inverted constraint: /7/1
│ │ └── spans
│ │ ├── ["B\xfdL\x00\x00\x00\x00\x00\x00\x00", "B\xfdL\x00\x00\x00\x00\x00\x00\x00"]
│ │ └── ["B\xfdN\x00\x00\x00\x00\x00\x00\x01", "B\xfdP\x00\x00\x00\x00\x00\x00\x01")
│ │ ├── ["B\xfdO\x00\x00\x00\x00\x00\x00\x00", "B\xfdO\x00\x00\x00\x00\x00\x00\x00"]
│ │ └── ["B\xfdP\x00\x00\x00\x00\x00\x00\x00", "B\xfdP\x00\x00\x00\x00\x00\x00\x00"]
│ ├── key: (1)
│ └── fd: (1)-->(7)
└── filters
Expand Down

0 comments on commit da906a7

Please sign in to comment.