Skip to content

Commit

Permalink
postgres: rework query with join
Browse files Browse the repository at this point in the history
Looking at the query planner, this `JOIN` should actually speed things
up.

Signed-off-by: Hank Donnay <[email protected]>
  • Loading branch information
hdonnay authored and crozzy committed Jul 24, 2023
1 parent ec42862 commit 9c300a9
Show file tree
Hide file tree
Showing 3 changed files with 11 additions and 28 deletions.
16 changes: 1 addition & 15 deletions datastore/postgres/get.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,24 +44,10 @@ func (s *MatcherStore) Get(ctx context.Context, records []*claircore.IndexRecord
return nil, err
}
defer tx.Rollback(ctx)
latestUpdatesQuery := "SELECT id FROM latest_update_operations WHERE kind = 'vulnerability';"
rows, err := tx.Query(ctx, latestUpdatesQuery)
if err != nil {
return nil, err
}
uos := []uint64{}
for rows.Next() {
var id uint64
err := rows.Scan(&id)
if err != nil {
return nil, err
}
uos = append(uos, id)
}
// start a batch
batch := &pgx.Batch{}
for _, record := range records {
query, err := buildGetQuery(record, &opts, uos)
query, err := buildGetQuery(record, &opts)
if err != nil {
// if we cannot build a query for an individual record continue to the next
zlog.Debug(ctx).
Expand Down
14 changes: 5 additions & 9 deletions datastore/postgres/querybuilder.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,11 @@ import (
)

// getQueryBuilder validates a IndexRecord and creates a query string for vulnerability matching
func buildGetQuery(record *claircore.IndexRecord, opts *datastore.GetOpts, uos []uint64) (string, error) {
func buildGetQuery(record *claircore.IndexRecord, opts *datastore.GetOpts) (string, error) {
matchers := opts.Matchers
psql := goqu.Dialect("postgres")
exps := []goqu.Expression{}

// Check that uos isn't empty, if it is it will result in a query error
if len(uos) == 0 {
return "", fmt.Errorf("cannot query without update_operation IDs")
}

// Add package name as first condition in query.
if record.Package.Name == "" {
return "", fmt.Errorf("IndexRecord must provide a Package.Name")
Expand Down Expand Up @@ -98,10 +93,10 @@ func buildGetQuery(record *claircore.IndexRecord, opts *datastore.GetOpts, uos [
goqu.L("vulnerable_range @> "+lit.String()),
))
}
exps = append(exps, goqu.C("uo").In(uos))
exps = append(exps, goqu.I("latest_update_operations.kind").Eq("vulnerability"))

query := psql.Select(
"id",
"vuln.id",
"name",
"description",
"issued",
Expand All @@ -126,9 +121,10 @@ func buildGetQuery(record *claircore.IndexRecord, opts *datastore.GetOpts, uos [
"repo_key",
"repo_uri",
"fixed_in_version",
"updater",
"vuln.updater",
).From("vuln").
Join(goqu.I("uo_vuln"), goqu.On(goqu.Ex{"vuln.id": goqu.I("uo_vuln.vuln")})).
Join(goqu.I("latest_update_operations"), goqu.On(goqu.Ex{"latest_update_operations.id": goqu.I("uo_vuln.uo")})).
Where(exps...)

sql, _, err := query.ToSQL()
Expand Down
9 changes: 5 additions & 4 deletions datastore/postgres/querybuilder_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,14 @@ import (
func TestGetQueryBuilderDeterministicArgs(t *testing.T) {
const (
preamble = `SELECT
"id", "name", "description", "issued", "links", "severity", "normalized_severity", "package_name", "package_version",
"vuln"."id", "name", "description", "issued", "links", "severity", "normalized_severity", "package_name", "package_version",
"package_module", "package_arch", "package_kind", "dist_id", "dist_name", "dist_version", "dist_version_code_name",
"dist_version_id", "dist_arch", "dist_cpe", "dist_pretty_name", "arch_operation", "repo_name", "repo_key",
"repo_uri", "fixed_in_version", "updater"
"repo_uri", "fixed_in_version", "vuln"."updater"
FROM "vuln" INNER JOIN "uo_vuln" ON ("vuln"."id" = "uo_vuln"."vuln")
INNER JOIN "latest_update_operations" ON ("latest_update_operations"."id" = "uo_vuln"."uo")
WHERE `
epilogue = ` AND ("uo" IN (1, 2, 3, 4)))`
epilogue = ` AND ("latest_update_operations"."kind" = 'vulnerability'))`
both = `(((("package_name" = 'package-0') AND ("package_kind" = 'binary')) OR (("package_name" = 'source-package-0') AND ("package_kind" = 'source'))) AND `
noSource = `((("package_name" = 'package-0') AND ("package_kind" = 'binary')) AND `
)
Expand Down Expand Up @@ -216,7 +217,7 @@ func TestGetQueryBuilderDeterministicArgs(t *testing.T) {
Matchers: tt.matchExps,
VersionFiltering: tt.dbFilter,
}
query, err := buildGetQuery(ir, &opts, []uint64{1, 2, 3, 4})
query, err := buildGetQuery(ir, &opts)
if err != nil {
t.Fatalf("failed to create query: %v", err)
}
Expand Down

0 comments on commit 9c300a9

Please sign in to comment.