2015-12-28 20:03:29 +00:00
|
|
|
package pgsql
|
|
|
|
|
|
|
|
import (
|
|
|
|
"github.com/coreos/clair/database"
|
2016-01-08 15:27:30 +00:00
|
|
|
cerrors "github.com/coreos/clair/utils/errors"
|
2015-12-28 20:03:29 +00:00
|
|
|
"github.com/coreos/clair/utils/types"
|
|
|
|
)
|
|
|
|
|
2016-01-08 15:27:30 +00:00
|
|
|
func (pgSQL *pgSQL) insertFeature(feature database.Feature) (int, error) {
|
2015-12-28 20:03:29 +00:00
|
|
|
if feature.Name == "" {
|
|
|
|
return 0, cerrors.NewBadRequestError("could not find/insert invalid Feature")
|
|
|
|
}
|
|
|
|
|
|
|
|
if pgSQL.cache != nil {
|
|
|
|
if id, found := pgSQL.cache.Get("feature:" + feature.Name); found {
|
|
|
|
return id.(int), nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Find or create Namespace.
|
|
|
|
namespaceID, err := pgSQL.insertNamespace(feature.Namespace)
|
|
|
|
if err != nil {
|
2016-01-08 15:27:30 +00:00
|
|
|
return 0, err
|
2015-12-28 20:03:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Find or create Feature.
|
2016-01-08 15:27:30 +00:00
|
|
|
var id int
|
2015-12-28 20:03:29 +00:00
|
|
|
err = pgSQL.QueryRow(getQuery("soi_feature"), feature.Name, namespaceID).Scan(&id)
|
2016-01-08 15:27:30 +00:00
|
|
|
if err != nil {
|
|
|
|
return 0, err
|
|
|
|
}
|
2015-12-28 20:03:29 +00:00
|
|
|
|
|
|
|
if pgSQL.cache != nil {
|
|
|
|
pgSQL.cache.Add("feature:"+feature.Name, id)
|
|
|
|
}
|
|
|
|
|
2016-01-08 15:27:30 +00:00
|
|
|
return id, nil
|
2015-12-28 20:03:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (pgSQL *pgSQL) insertFeatureVersion(featureVersion database.FeatureVersion) (id int, err error) {
|
2016-01-08 15:27:30 +00:00
|
|
|
if featureVersion.Version.String() == "" {
|
|
|
|
return 0, cerrors.NewBadRequestError("could not find/insert invalid FeatureVersion")
|
|
|
|
}
|
2015-12-28 20:03:29 +00:00
|
|
|
|
2016-01-08 15:27:30 +00:00
|
|
|
if pgSQL.cache != nil {
|
2015-12-28 20:03:29 +00:00
|
|
|
if id, found := pgSQL.cache.Get("featureversion:" + featureVersion.Feature.Name + ":" +
|
|
|
|
featureVersion.Version.String()); found {
|
|
|
|
return id.(int), nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Find or create Feature first.
|
|
|
|
featureID, err := pgSQL.insertFeature(featureVersion.Feature)
|
|
|
|
if err != nil {
|
2016-01-08 15:27:30 +00:00
|
|
|
return 0, err
|
2015-12-28 20:03:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Begin transaction.
|
|
|
|
tx, err := pgSQL.Begin()
|
|
|
|
if err != nil {
|
|
|
|
tx.Rollback()
|
2016-01-08 15:27:30 +00:00
|
|
|
return 0, err
|
2015-12-28 20:03:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Find or create FeatureVersion.
|
|
|
|
var newOrExisting string
|
2016-01-08 15:27:30 +00:00
|
|
|
err = tx.QueryRow(getQuery("soi_featureversion"), featureID, &featureVersion.Version).
|
2015-12-28 20:03:29 +00:00
|
|
|
Scan(&newOrExisting, &featureVersion.ID)
|
|
|
|
if err != nil {
|
|
|
|
tx.Rollback()
|
2016-01-08 15:27:30 +00:00
|
|
|
return 0, err
|
2015-12-28 20:03:29 +00:00
|
|
|
}
|
|
|
|
if newOrExisting == "exi" {
|
|
|
|
// That featureVersion already exists, return its id.
|
|
|
|
return featureVersion.ID, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Link the new FeatureVersion with every vulnerabilities that affect it, by inserting in
|
|
|
|
// Vulnerability_Affects_FeatureVersion.
|
|
|
|
|
|
|
|
// Lock Vulnerability_FixedIn_Feature because we can't let it to be modified while we modify
|
|
|
|
// Vulnerability_Affects_FeatureVersion.
|
|
|
|
_, err = tx.Exec(getQuery("l_share_vulnerability_fixedin_feature"))
|
|
|
|
if err != nil {
|
|
|
|
tx.Rollback()
|
2016-01-08 15:27:30 +00:00
|
|
|
return 0, err
|
2015-12-28 20:03:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Select every vulnerability and the fixed version that affect this Feature.
|
|
|
|
rows, err := tx.Query(getQuery("s_vulnerability_fixedin_feature"), featureID)
|
|
|
|
if err != nil {
|
|
|
|
tx.Rollback()
|
2016-01-08 15:27:30 +00:00
|
|
|
return 0, err
|
2015-12-28 20:03:29 +00:00
|
|
|
}
|
|
|
|
defer rows.Close()
|
|
|
|
|
|
|
|
var fixedInID, vulnerabilityID int
|
|
|
|
var fixedInVersion types.Version
|
|
|
|
for rows.Next() {
|
|
|
|
err := rows.Scan(&fixedInID, &vulnerabilityID, &fixedInVersion)
|
|
|
|
if err != nil {
|
|
|
|
tx.Rollback()
|
2016-01-08 15:27:30 +00:00
|
|
|
return 0, err
|
2015-12-28 20:03:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if featureVersion.Version.Compare(fixedInVersion) < 0 {
|
|
|
|
// The version of the FeatureVersion we are inserting is lower than the fixed version on this
|
|
|
|
// Vulnerability, thus, this FeatureVersion is affected by it.
|
2016-01-08 15:27:30 +00:00
|
|
|
// TODO(Quentin-M): Prepare.
|
2015-12-28 20:03:29 +00:00
|
|
|
_, err := tx.Exec(getQuery("i_vulnerability_affects_featureversion"), vulnerabilityID,
|
|
|
|
featureVersion.ID, fixedInID)
|
|
|
|
if err != nil {
|
|
|
|
tx.Rollback()
|
2016-01-08 15:27:30 +00:00
|
|
|
return 0, err
|
2015-12-28 20:03:29 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Commit transaction.
|
|
|
|
err = tx.Commit()
|
|
|
|
if err != nil {
|
|
|
|
tx.Rollback()
|
2016-01-08 15:27:30 +00:00
|
|
|
return 0, err
|
2015-12-28 20:03:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if pgSQL.cache != nil {
|
|
|
|
pgSQL.cache.Add("featureversion:"+featureVersion.Feature.Name+":"+
|
|
|
|
featureVersion.Version.String(), featureVersion.ID)
|
|
|
|
}
|
|
|
|
|
2016-01-08 15:27:30 +00:00
|
|
|
return featureVersion.ID, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO(Quentin-M): Batch me
|
|
|
|
func (pgSQL *pgSQL) insertFeatureVersions(featureVersions []database.FeatureVersion) ([]int, error) {
|
|
|
|
IDs := make([]int, 0, len(featureVersions))
|
|
|
|
|
|
|
|
for i := 0; i < len(featureVersions); i++ {
|
|
|
|
id, err := pgSQL.insertFeatureVersion(featureVersions[i])
|
|
|
|
if err != nil {
|
|
|
|
return IDs, err
|
|
|
|
}
|
|
|
|
IDs = append(IDs, id)
|
|
|
|
}
|
|
|
|
|
|
|
|
return IDs, nil
|
2015-12-28 20:03:29 +00:00
|
|
|
}
|