in query/aql_compiler.go [658:766]
func (qc *AQLQueryContext) matchPrefilters() {
// Format of candidateFilters:
// [tableID]map[columnID]{filterIDs for lower bound, upper bound, equality}
// tableID is query scoped, while columnID is schema scoped.
candidateFilters := make([]map[int][3]int, len(qc.TableScanners))
for tableID := range qc.TableScanners {
candidateFilters[tableID] = make(map[int][3]int)
}
// Index candidate filters by table/column
for filterID, filter := range qc.Query.FiltersParsed {
f, _ := filter.(*expr.BinaryExpr)
if f == nil {
switch f := filter.(type) {
case *expr.VarRef:
// Match `column` format
if f.ExprType == expr.Boolean {
candidateFilters[f.TableID][f.ColumnID] = [3]int{-1, -1, filterID}
}
case *expr.UnaryExpr:
// Match `not column` format
if f.Op == expr.NOT {
f, _ := f.Expr.(*expr.VarRef)
if f != nil && f.ExprType == expr.Boolean {
candidateFilters[f.TableID][f.ColumnID] = [3]int{-1, -1, filterID}
}
}
// TODO: IS_NULL can be matched as an equality filter.
// TODO: IS_NOT_NULL can be matched as the final range filter.
}
continue
}
// Match `column op value` format, where op can be =, <, <=, >, >=.
if f.Op < expr.EQ || f.Op > expr.GTE {
continue
}
lhs, _ := f.LHS.(*expr.VarRef)
if lhs == nil {
continue
}
columnToFilterMap := candidateFilters[lhs.TableID]
filters, exists := columnToFilterMap[lhs.ColumnID]
if !exists {
filters = [3]int{-1, -1, -1}
}
switch f.Op {
case expr.GT, expr.GTE:
filters[0] = filterID
case expr.LT, expr.LTE:
filters[1] = filterID
case expr.EQ:
filters[2] = filterID
}
columnToFilterMap[lhs.ColumnID] = filters
}
// Prefilter matching
for tableID, scanner := range qc.TableScanners {
// Match in archiving sort column order
for _, columnID := range scanner.Schema.Schema.ArchivingSortColumns {
filterIndex, exists := candidateFilters[tableID][columnID]
if !exists {
// Stop on first missing column
break
}
// Equality
if filterIndex[2] >= 0 {
value, _, success := qc.extractFilter(filterIndex[2])
if !success {
// Stop if the value fails to be extracted
break
}
scanner.EqualityPrefilterValues = append(
scanner.EqualityPrefilterValues, value)
qc.Prefilters = append(qc.Prefilters, filterIndex[2])
scanner.ColumnUsages[columnID] |= columnUsedByPrefilter
// Continue matching the next column
continue
}
// Lower bound
if filterIndex[0] >= 0 {
value, boundaryType, success := qc.extractFilter(filterIndex[0])
if success {
scanner.RangePrefilterValues[0] = value
scanner.RangePrefilterBoundaries[0] = boundaryType
qc.Prefilters = append(qc.Prefilters, filterIndex[0])
scanner.ColumnUsages[columnID] |= columnUsedByPrefilter
}
}
// Upper bound
if filterIndex[1] >= 0 {
value, boundaryType, success := qc.extractFilter(filterIndex[1])
if success {
scanner.RangePrefilterValues[1] = value
scanner.RangePrefilterBoundaries[1] = boundaryType
qc.Prefilters = append(qc.Prefilters, filterIndex[1])
scanner.ColumnUsages[columnID] |= columnUsedByPrefilter
}
}
// Stop after the first range filter
break
}
}
sort.Ints(qc.Prefilters)
}