Commit 07bde3b0 authored by Quentin Smith's avatar Quentin Smith

storage: optimize queries for label presence

The query term "key>" can be used to search for records that have any
value for the key. This optimizes the query with a separate SQL
expression and adds tests for this behavior.

Change-Id: I5e2734734e0911a3ed12c87e7ada776ad309a90d
Reviewed-on: https://go-review.googlesource.com/36590Reviewed-by: default avatarRuss Cox <rsc@golang.org>
parent c133759b
...@@ -377,6 +377,10 @@ func parseQueryPart(part string) (sql string, args []interface{}, err error) { ...@@ -377,6 +377,10 @@ func parseQueryPart(part string) (sql string, args []interface{}, err error) {
} }
return "SELECT UploadID, RecordID FROM RecordLabels WHERE Name = ? AND Value = ?", []interface{}{key, value}, nil return "SELECT UploadID, RecordID FROM RecordLabels WHERE Name = ? AND Value = ?", []interface{}{key, value}, nil
case '>', '<': case '>', '<':
if sep == '>' && value == "" {
// Simplify queries for any value.
return "SELECT UploadID, RecordID FROM RecordLabels WHERE Name = ?", []interface{}{key}, nil
}
return fmt.Sprintf("SELECT UploadID, RecordID FROM RecordLabels WHERE Name = ? AND Value %c ?", sep), []interface{}{key, value}, nil return fmt.Sprintf("SELECT UploadID, RecordID FROM RecordLabels WHERE Name = ? AND Value %c ?", sep), []interface{}{key, value}, nil
} }
return "", nil, fmt.Errorf("query part %q has invalid key", part) return "", nil, fmt.Errorf("query part %q has invalid key", part)
......
...@@ -12,6 +12,7 @@ import ( ...@@ -12,6 +12,7 @@ import (
"os" "os"
"os/exec" "os/exec"
"reflect" "reflect"
"sort"
"strconv" "strconv"
"strings" "strings"
"testing" "testing"
...@@ -273,8 +274,10 @@ func TestQuery(t *testing.T) { ...@@ -273,8 +274,10 @@ func TestQuery(t *testing.T) {
{"label0:0 label0:5", []int{}}, {"label0:0 label0:5", []int{}},
{"bogus query", nil}, {"bogus query", nil},
{"label1<2 label3:0", []int{0, 1, 2, 3}}, {"label1<2 label3:0", []int{0, 1, 2, 3}},
{"label1>510", []int{1022, 1023}}, {"label1>510 label1<52", []int{1022, 1023}},
{"", allRecords}, {"", allRecords},
{"missing>", []int{}},
{"label0>", allRecords},
} }
for _, test := range tests { for _, test := range tests {
t.Run("query="+test.q, func(t *testing.T) { t.Run("query="+test.q, func(t *testing.T) {
...@@ -293,21 +296,35 @@ func TestQuery(t *testing.T) { ...@@ -293,21 +296,35 @@ func TestQuery(t *testing.T) {
t.Errorf("Close: %v", err) t.Errorf("Close: %v", err)
} }
}() }()
for i, num := range test.want { var have []int
for i := range test.want {
if !q.Next() { if !q.Next() {
t.Fatalf("#%d: Next() = false", i) t.Fatalf("#%d: Next() = false", i)
} }
r := q.Result() r := q.Result()
if r.Labels["label0"] != fmt.Sprintf("%d", num) { n, err := strconv.Atoi(r.Labels["label0"])
t.Errorf("result[%d].label0 = %q, want %d", i, r.Labels["label0"], num) if err != nil {
t.Fatalf("unexpected label0 value %q: %v", r.Labels["label0"], err)
} }
have = append(have, n)
if r.NameLabels["name"] != "Name" { if r.NameLabels["name"] != "Name" {
t.Errorf("result[%d].name = %q, want %q", i, r.NameLabels["name"], "Name") t.Errorf("result[%d].name = %q, want %q", i, r.NameLabels["name"], "Name")
} }
} }
for q.Next() {
r := q.Result()
t.Errorf("Next() = true, want false (got labels %v)", r.Labels)
}
if err := q.Err(); err != nil { if err := q.Err(); err != nil {
t.Errorf("Err() = %v, want nil", err) t.Errorf("Err() = %v, want nil", err)
} }
sort.Ints(have)
if len(have) == 0 {
have = []int{}
}
if !reflect.DeepEqual(have, test.want) {
t.Errorf("label0[] = %v, want %v", have, test.want)
}
}) })
} }
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment