Skip to content
This repository was archived by the owner on Jan 28, 2021. It is now read-only.

Commit 6c98f53

Browse files
authored
Merge pull request #289 from mcarmonaa/improvement/add-negate-index
sql/analyzer: add negate index
2 parents dc1cf80 + 60ca3a5 commit 6c98f53

File tree

4 files changed

+542
-49
lines changed

4 files changed

+542
-49
lines changed

sql/analyzer/assign_indexes.go

Lines changed: 189 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -121,21 +121,36 @@ func getIndexes(e sql.Expression, a *Analyzer) (map[string]*indexLookup, error)
121121
result[table] = lookup
122122
}
123123
}
124-
case *expression.In:
124+
case *expression.In, *expression.NotIn:
125+
c, ok := e.(expression.Comparer)
126+
if !ok {
127+
return nil, nil
128+
}
129+
130+
_, negate := e.(*expression.NotIn)
131+
125132
// Take the index of a SOMETHING IN SOMETHING expression only if:
126133
// the right branch is evaluable and the indexlookup supports set
127134
// operations.
128-
if !isEvaluable(e.Left()) && isEvaluable(e.Right()) {
129-
idx := a.Catalog.IndexByExpression(a.CurrentDatabase, e.Left())
135+
if !isEvaluable(c.Left()) && isEvaluable(c.Right()) {
136+
idx := a.Catalog.IndexByExpression(a.CurrentDatabase, c.Left())
130137
if idx != nil {
138+
var nidx sql.NegateIndex
139+
if negate {
140+
nidx, ok = idx.(sql.NegateIndex)
141+
if !ok {
142+
return nil, nil
143+
}
144+
}
145+
131146
// release the index if it was not used
132147
defer func() {
133148
if _, ok := result[idx.Table()]; !ok {
134149
a.Catalog.ReleaseIndex(idx)
135150
}
136151
}()
137152

138-
value, err := e.Right().Eval(sql.NewEmptyContext(), nil)
153+
value, err := c.Right().Eval(sql.NewEmptyContext(), nil)
139154
if err != nil {
140155
return nil, err
141156
}
@@ -145,14 +160,30 @@ func getIndexes(e sql.Expression, a *Analyzer) (map[string]*indexLookup, error)
145160
return nil, errInvalidInRightEvaluation.New(value)
146161
}
147162

148-
lookup, err := idx.Get(values[0])
149-
if err != nil {
163+
var lookup sql.IndexLookup
164+
var errLookup error
165+
if negate {
166+
lookup, errLookup = nidx.Not(values[0])
167+
} else {
168+
lookup, errLookup = idx.Get(values[0])
169+
170+
}
171+
172+
if errLookup != nil {
150173
return nil, err
151174
}
152175

153176
for _, v := range values[1:] {
154-
lookup2, err := idx.Get(v)
155-
if err != nil {
177+
var lookup2 sql.IndexLookup
178+
var errLookup error
179+
if negate {
180+
lookup2, errLookup = nidx.Not(v)
181+
} else {
182+
lookup2, errLookup = idx.Get(v)
183+
184+
}
185+
186+
if errLookup != nil {
156187
return nil, err
157188
}
158189

@@ -161,7 +192,11 @@ func getIndexes(e sql.Expression, a *Analyzer) (map[string]*indexLookup, error)
161192
return result, nil
162193
}
163194

164-
lookup = lookup.(sql.SetOperations).Union(lookup2)
195+
if negate {
196+
lookup = lookup.(sql.SetOperations).Intersection(lookup2)
197+
} else {
198+
lookup = lookup.(sql.SetOperations).Union(lookup2)
199+
}
165200
}
166201

167202
result[idx.Table()] = &indexLookup{
@@ -184,6 +219,15 @@ func getIndexes(e sql.Expression, a *Analyzer) (map[string]*indexLookup, error)
184219
indexes: []sql.Index{idx},
185220
lookup: lookup,
186221
}
222+
case *expression.Not:
223+
r, err := getNegatedIndexes(a, e)
224+
if err != nil {
225+
return nil, err
226+
}
227+
228+
for table, indexLookup := range r {
229+
result[table] = indexLookup
230+
}
187231
case *expression.Between:
188232
if !isEvaluable(e.Val) && isEvaluable(e.Upper) && isEvaluable(e.Lower) {
189233
idx := a.Catalog.IndexByExpression(a.CurrentDatabase, e.Val)
@@ -351,6 +395,90 @@ func comparisonIndexLookup(
351395
return nil, nil
352396
}
353397

398+
func getNegatedIndexes(a *Analyzer, not *expression.Not) (map[string]*indexLookup, error) {
399+
switch e := not.Child.(type) {
400+
case *expression.Not:
401+
return getIndexes(e.Child, a)
402+
case *expression.Equals:
403+
left, right := e.Left(), e.Right()
404+
// if the form is SOMETHING OP {INDEXABLE EXPR}, swap it, so it's {INDEXABLE EXPR} OP SOMETHING
405+
if !isEvaluable(right) {
406+
left, right = right, left
407+
}
408+
409+
if isEvaluable(left) || !isEvaluable(right) {
410+
return nil, nil
411+
}
412+
413+
idx := a.Catalog.IndexByExpression(a.CurrentDatabase, left)
414+
if idx == nil {
415+
return nil, nil
416+
}
417+
418+
index, ok := idx.(sql.NegateIndex)
419+
if !ok {
420+
return nil, nil
421+
}
422+
423+
value, err := right.Eval(sql.NewEmptyContext(), nil)
424+
if err != nil {
425+
a.Catalog.ReleaseIndex(idx)
426+
return nil, err
427+
}
428+
429+
lookup, err := index.Not(value)
430+
if err != nil || lookup == nil {
431+
a.Catalog.ReleaseIndex(idx)
432+
return nil, err
433+
}
434+
435+
result := map[string]*indexLookup{
436+
idx.Table(): &indexLookup{
437+
indexes: []sql.Index{idx},
438+
lookup: lookup,
439+
},
440+
}
441+
442+
return result, nil
443+
case *expression.GreaterThan:
444+
lte := expression.NewLessThanOrEqual(e.Left(), e.Right())
445+
return getIndexes(lte, a)
446+
case *expression.GreaterThanOrEqual:
447+
lt := expression.NewLessThan(e.Left(), e.Right())
448+
return getIndexes(lt, a)
449+
case *expression.LessThan:
450+
gte := expression.NewGreaterThanOrEqual(e.Left(), e.Right())
451+
return getIndexes(gte, a)
452+
case *expression.LessThanOrEqual:
453+
gt := expression.NewGreaterThan(e.Left(), e.Right())
454+
return getIndexes(gt, a)
455+
case *expression.Between:
456+
or := expression.NewOr(
457+
expression.NewLessThan(e.Val, e.Lower),
458+
expression.NewGreaterThan(e.Val, e.Upper),
459+
)
460+
461+
return getIndexes(or, a)
462+
case *expression.Or:
463+
and := expression.NewAnd(
464+
expression.NewNot(e.Left),
465+
expression.NewNot(e.Right),
466+
)
467+
468+
return getIndexes(and, a)
469+
case *expression.And:
470+
or := expression.NewOr(
471+
expression.NewNot(e.Left),
472+
expression.NewNot(e.Right),
473+
)
474+
475+
return getIndexes(or, a)
476+
default:
477+
return nil, nil
478+
479+
}
480+
}
481+
354482
func indexesIntersection(
355483
a *Analyzer,
356484
left, right map[string]*indexLookup,
@@ -366,6 +494,7 @@ func indexesIntersection(
366494
a.Catalog.ReleaseIndex(idx)
367495
}
368496
}
497+
369498
result[table] = idx
370499
}
371500

@@ -538,46 +667,65 @@ func columnExprsByTable(exprs []sql.Expression) map[string][]columnExpr {
538667
var result = make(map[string][]columnExpr)
539668

540669
for _, expr := range exprs {
541-
var left, right sql.Expression
542-
switch e := expr.(type) {
543-
case *expression.Equals,
544-
*expression.GreaterThan,
545-
*expression.LessThan,
546-
*expression.GreaterThanOrEqual,
547-
*expression.LessThanOrEqual:
548-
cmp := e.(expression.Comparer)
549-
left, right = cmp.Left(), cmp.Right()
550-
if !isEvaluable(right) {
551-
left, right = right, left
552-
}
670+
table, colExpr := extractColumnExpr(expr)
671+
if colExpr == nil {
672+
continue
673+
}
553674

554-
if !isEvaluable(right) {
555-
continue
556-
}
675+
result[table] = append(result[table], *colExpr)
676+
}
557677

558-
col, ok := left.(*expression.GetField)
559-
if !ok {
560-
continue
561-
}
678+
return result
679+
}
562680

563-
result[col.Table()] = append(result[col.Table()], columnExpr{col, right, e})
564-
case *expression.Between:
565-
if !isEvaluable(e.Upper) || !isEvaluable(e.Lower) || isEvaluable(e.Val) {
566-
continue
681+
func extractColumnExpr(e sql.Expression) (string, *columnExpr) {
682+
switch e := e.(type) {
683+
case *expression.Not:
684+
table, colExpr := extractColumnExpr(e.Child)
685+
if colExpr != nil {
686+
colExpr = &columnExpr{
687+
col: colExpr.col,
688+
val: colExpr.val,
689+
expr: expression.NewNot(colExpr.expr),
567690
}
691+
}
568692

569-
col, ok := e.Val.(*expression.GetField)
570-
if !ok {
571-
continue
572-
}
693+
return table, colExpr
694+
case *expression.Equals,
695+
*expression.GreaterThan,
696+
*expression.LessThan,
697+
*expression.GreaterThanOrEqual,
698+
*expression.LessThanOrEqual:
699+
cmp := e.(expression.Comparer)
700+
left, right := cmp.Left(), cmp.Right()
701+
if !isEvaluable(right) {
702+
left, right = right, left
703+
}
573704

574-
result[col.Table()] = append(result[col.Table()], columnExpr{col, nil, e})
575-
default:
576-
continue
705+
if !isEvaluable(right) {
706+
return "", nil
577707
}
578-
}
579708

580-
return result
709+
col, ok := left.(*expression.GetField)
710+
if !ok {
711+
return "", nil
712+
}
713+
714+
return col.Table(), &columnExpr{col, right, e}
715+
case *expression.Between:
716+
if !isEvaluable(e.Upper) || !isEvaluable(e.Lower) || isEvaluable(e.Val) {
717+
return "", nil
718+
}
719+
720+
col, ok := e.Val.(*expression.GetField)
721+
if !ok {
722+
return "", nil
723+
}
724+
725+
return col.Table(), &columnExpr{col, nil, e}
726+
default:
727+
return "", nil
728+
}
581729
}
582730

583731
func containsColumns(e sql.Expression) bool {

0 commit comments

Comments
 (0)